auction_fun_core 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +12 -0
- data/.env.development.template +7 -0
- data/.env.test.template +7 -0
- data/.rspec +3 -0
- data/.standard.yml +3 -0
- data/.tool-versions +5 -0
- data/CHANGELOG.md +145 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/Procfile +4 -0
- data/README.md +141 -0
- data/Rakefile +13 -0
- data/auction_fun_core.gemspec +57 -0
- data/config/app.rb +5 -0
- data/config/application.rb +37 -0
- data/config/boot.rb +15 -0
- data/db/migrate/20240216200926_enable_postgres_extensions.rb +13 -0
- data/db/migrate/20240217115734_create_users.rb +28 -0
- data/db/migrate/20240220140151_create_custom_types.rb +11 -0
- data/db/migrate/20240220140254_create_staffs.rb +20 -0
- data/db/migrate/20240229142933_create_custom_types.rb +13 -0
- data/db/migrate/20240229143000_create_auctions.rb +29 -0
- data/db/migrate/20240304144422_create_bids.rb +19 -0
- data/db/seeds.rb +116 -0
- data/i18n/en-US/contracts/contracts.en-US.yml +72 -0
- data/i18n/en-US/mail/user_context/registration.en-US.yml +11 -0
- data/i18n/pt-BR/contracts/contracts.pt-BR.yml +72 -0
- data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +12 -0
- data/lib/auction_fun_core/business/configuration.rb +18 -0
- data/lib/auction_fun_core/business/token_generator.rb +17 -0
- data/lib/auction_fun_core/commands/auction_context/create_auction.rb +19 -0
- data/lib/auction_fun_core/commands/auction_context/delete_auction.rb +15 -0
- data/lib/auction_fun_core/commands/auction_context/update_auction.rb +18 -0
- data/lib/auction_fun_core/commands/bid_context/create_bid.rb +19 -0
- data/lib/auction_fun_core/commands/bid_context/delete_bid.rb +15 -0
- data/lib/auction_fun_core/commands/bid_context/update_bid.rb +18 -0
- data/lib/auction_fun_core/commands/staff_context/create_staff.rb +19 -0
- data/lib/auction_fun_core/commands/user_context/create_user.rb +19 -0
- data/lib/auction_fun_core/contracts/application_contract.rb +55 -0
- data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +101 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +27 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +34 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +46 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +34 -0
- data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +79 -0
- data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +69 -0
- data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +68 -0
- data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +47 -0
- data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +52 -0
- data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +47 -0
- data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +40 -0
- data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +40 -0
- data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +63 -0
- data/lib/auction_fun_core/entities/auction.rb +17 -0
- data/lib/auction_fun_core/entities/bid.rb +10 -0
- data/lib/auction_fun_core/entities/staff.rb +21 -0
- data/lib/auction_fun_core/entities/user.rb +37 -0
- data/lib/auction_fun_core/events/app.rb +27 -0
- data/lib/auction_fun_core/events/listener.rb +89 -0
- data/lib/auction_fun_core/operations/auction_context/create_operation.rb +77 -0
- data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +61 -0
- data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +57 -0
- data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +84 -0
- data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +57 -0
- data/lib/auction_fun_core/operations/base.rb +11 -0
- data/lib/auction_fun_core/operations/bid_context/create_bid_closed_operation.rb +64 -0
- data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +64 -0
- data/lib/auction_fun_core/operations/bid_context/create_bid_standard_operation.rb +74 -0
- data/lib/auction_fun_core/operations/staff_context/authentication_operation.rb +52 -0
- data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +76 -0
- data/lib/auction_fun_core/operations/user_context/authentication_operation.rb +52 -0
- data/lib/auction_fun_core/operations/user_context/email_confirmation_operation.rb +67 -0
- data/lib/auction_fun_core/operations/user_context/phone_confirmation_operation.rb +67 -0
- data/lib/auction_fun_core/operations/user_context/registration_operation.rb +105 -0
- data/lib/auction_fun_core/relations/auctions.rb +119 -0
- data/lib/auction_fun_core/relations/bids.rb +28 -0
- data/lib/auction_fun_core/relations/staffs.rb +27 -0
- data/lib/auction_fun_core/relations/users.rb +26 -0
- data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +42 -0
- data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -0
- data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +64 -0
- data/lib/auction_fun_core/repos/user_context/user_repository.rb +78 -0
- data/lib/auction_fun_core/services/mail/templates/layout.html.erb +72 -0
- data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +170 -0
- data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +25 -0
- data/lib/auction_fun_core/version.rb +8 -0
- data/lib/auction_fun_core/workers/application_job.rb +22 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish_operation_job.rb +32 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +32 -0
- data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +40 -0
- data/lib/auction_fun_core.rb +21 -0
- data/lib/tasks/database.rake +87 -0
- data/system/providers/background_job.rb +15 -0
- data/system/providers/core.rb +35 -0
- data/system/providers/db.rb +26 -0
- data/system/providers/events.rb +13 -0
- data/system/providers/logger.rb +11 -0
- data/system/providers/mail.rb +25 -0
- data/system/providers/persistence.rb +18 -0
- data/system/providers/settings.rb +26 -0
- metadata +400 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Contracts
|
5
|
+
module UserContext
|
6
|
+
# Contract class responsible for validating the confirmation token for phone number.
|
7
|
+
class PhoneConfirmationContract < ApplicationContract
|
8
|
+
I18N_SCOPE = "contracts.errors.custom.default"
|
9
|
+
|
10
|
+
option :user_repository, default: proc { Repos::UserContext::UserRepository.new }
|
11
|
+
|
12
|
+
params do
|
13
|
+
required(:phone_confirmation_token)
|
14
|
+
|
15
|
+
before(:value_coercer) do |result|
|
16
|
+
result.to_h.compact
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validation for token_confirmation_token.
|
21
|
+
# Searches for the user in the database from the phone_confirmation_token
|
22
|
+
rule do |context:|
|
23
|
+
next if schema_error?(:phone_confirmation_token)
|
24
|
+
|
25
|
+
context[:user] ||= user_repository.by_phone_confirmation_token(values[:phone_confirmation_token])
|
26
|
+
|
27
|
+
next if context[:user].present?
|
28
|
+
|
29
|
+
key(:phone_confirmation_token).failure(I18n.t("not_found", scope: I18N_SCOPE))
|
30
|
+
end
|
31
|
+
|
32
|
+
rule do |context:|
|
33
|
+
next if context[:user].blank? || context[:user].active?
|
34
|
+
|
35
|
+
key(:base).failure(I18n.t("inactive_account", scope: I18N_SCOPE))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Contracts
|
5
|
+
module UserContext
|
6
|
+
# Contract class to create new users.
|
7
|
+
class RegistrationContract < ApplicationContract
|
8
|
+
I18N_SCOPE = "contracts.errors.custom.default"
|
9
|
+
|
10
|
+
option :user_repository, default: proc { Repos::UserContext::UserRepository.new }
|
11
|
+
|
12
|
+
# @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations.
|
13
|
+
params do
|
14
|
+
required(:name)
|
15
|
+
required(:email)
|
16
|
+
required(:phone)
|
17
|
+
required(:password)
|
18
|
+
required(:password_confirmation)
|
19
|
+
|
20
|
+
before(:value_coercer) do |result|
|
21
|
+
result.to_h.compact
|
22
|
+
end
|
23
|
+
|
24
|
+
# Normalize and add default values
|
25
|
+
after(:value_coercer) do |result|
|
26
|
+
result.update(email: result[:email].strip.downcase) if result[:email]
|
27
|
+
result.update(phone: result[:phone].tr_s("^0-9", "")) if result[:phone]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
rule(:name).validate(:name_format)
|
32
|
+
|
33
|
+
# Validation for email.
|
34
|
+
# It must validate the format and uniqueness in the database.
|
35
|
+
rule(:email).validate(:email_format)
|
36
|
+
rule(:email) do
|
37
|
+
# Email should be unique on database
|
38
|
+
if !rule_error?(:email) && user_repository.exists?(email: value)
|
39
|
+
key.failure(I18n.t(:taken, scope: I18N_SCOPE))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validation for phone.
|
44
|
+
# It must validate the format and uniqueness in the database.
|
45
|
+
rule(:phone).validate(:phone_format)
|
46
|
+
rule(:phone) do
|
47
|
+
if !rule_error?(:phone) && user_repository.exists?(phone: value)
|
48
|
+
key.failure(I18n.t(:taken, scope: I18N_SCOPE))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Validation for password.
|
53
|
+
# Check if the confirmation matches the password.
|
54
|
+
rule(:password).validate(:password_format)
|
55
|
+
rule(:password, :password_confirmation) do
|
56
|
+
if !rule_error?(:password) && values[:password] != values[:password_confirmation]
|
57
|
+
key(:password_confirmation).failure(I18n.t(:password_confirmation, scope: I18N_SCOPE))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Entities
|
5
|
+
# Auction Relations class. This return simple objects with attribute readers
|
6
|
+
# to represent data in your auction.
|
7
|
+
class Auction < ROM::Struct
|
8
|
+
def initial_bid
|
9
|
+
Money.new(initial_bid_cents, initial_bid_currency)
|
10
|
+
end
|
11
|
+
|
12
|
+
def minimal_bid
|
13
|
+
Money.new(minimal_bid_cents, minimal_bid_currency)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Entities
|
5
|
+
# Staff Relations class. This return simple objects with attribute readers
|
6
|
+
# to represent data in your staff.
|
7
|
+
class Staff < ROM::Struct
|
8
|
+
def active?
|
9
|
+
active
|
10
|
+
end
|
11
|
+
|
12
|
+
def inactive?
|
13
|
+
!active
|
14
|
+
end
|
15
|
+
|
16
|
+
def info
|
17
|
+
attributes.except(:password_digest)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Entities
|
5
|
+
# User Relations class. This return simple objects with attribute readers
|
6
|
+
# to represent data in your user.
|
7
|
+
class User < ROM::Struct
|
8
|
+
def active?
|
9
|
+
active
|
10
|
+
end
|
11
|
+
|
12
|
+
def inactive?
|
13
|
+
!active
|
14
|
+
end
|
15
|
+
|
16
|
+
def confirmed?
|
17
|
+
confirmed_at.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def email_confirmed?
|
21
|
+
email_confirmation_at.present?
|
22
|
+
end
|
23
|
+
|
24
|
+
def phone_confirmed?
|
25
|
+
phone_confirmation_at.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def info
|
29
|
+
attributes.except(:password_digest)
|
30
|
+
end
|
31
|
+
|
32
|
+
def balance
|
33
|
+
Money.new(balance_cents, balance_currency)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Events
|
5
|
+
# Event class to register business events on system.
|
6
|
+
# @see https://dry-rb.org/gems/dry-events/main/
|
7
|
+
class App
|
8
|
+
# @!parser include Dry::Events::Publisher[:app]
|
9
|
+
include Dry::Events::Publisher[:app]
|
10
|
+
|
11
|
+
register_event("auctions.created")
|
12
|
+
register_event("auctions.started")
|
13
|
+
register_event("auctions.finished")
|
14
|
+
register_event("auctions.paused")
|
15
|
+
register_event("auctions.unpaused")
|
16
|
+
|
17
|
+
register_event("bids.created")
|
18
|
+
|
19
|
+
register_event("staffs.authentication")
|
20
|
+
register_event("staffs.registration")
|
21
|
+
|
22
|
+
register_event("users.authentication")
|
23
|
+
register_event("users.registration")
|
24
|
+
register_event("users.confirmation")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Events
|
5
|
+
# Event class that can listen business events.
|
6
|
+
# @see https://dry-rb.org/gems/dry-events/main/#event-listeners
|
7
|
+
class Listener
|
8
|
+
# Listener for to *auctions.created* event.
|
9
|
+
# @param auction [ROM::Struct::Auction] the auction object
|
10
|
+
def on_auctions_created(auction)
|
11
|
+
logger("Create auction with: #{auction.to_h}")
|
12
|
+
end
|
13
|
+
|
14
|
+
# Listener for to *auctions.started* event.
|
15
|
+
# @param auction [ROM::Struct::Auction] the auction object
|
16
|
+
def on_auctions_started(auction)
|
17
|
+
logger("Started auction with: #{auction.to_h}")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Listener for to *auctions.finished* event.
|
21
|
+
# @param auction [ROM::Struct::Auction] the auction object
|
22
|
+
def on_auctions_finished(auction)
|
23
|
+
logger("Finished auction: #{auction.to_h}")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Listener for to *auctions.paused* event.
|
27
|
+
# @param event [ROM::Struct::Auction] the auction object
|
28
|
+
def on_auctions_paused(auction)
|
29
|
+
logger("Paused auction with: #{auction.to_h}")
|
30
|
+
end
|
31
|
+
|
32
|
+
# Listener for to *auctions.unpaused* event.
|
33
|
+
# @param event [ROM::Struct::Auction] the auction object
|
34
|
+
def on_auctions_unpaused(auction)
|
35
|
+
logger("Unpaused auction with: #{auction.to_h}")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Listener for to *bids.created* event.
|
39
|
+
# @param event [Integer] Auction ID
|
40
|
+
def on_bids_created(bid)
|
41
|
+
logger("Create bid with: #{bid.to_h}")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Listener for to *staffs.authentication* event.
|
45
|
+
# @param attributes [Hash] Authentication attributes
|
46
|
+
# @option staff_id [Integer] Staff ID
|
47
|
+
# @option time [DateTime] Authentication time
|
48
|
+
def on_staffs_authentication(attributes)
|
49
|
+
logger("Staff #{attributes[:staff_id]} authenticated on: #{attributes[:time].iso8601}")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Listener for to *staffs.registration* event.
|
53
|
+
# @param user [ROM::Struct::Staff] the staff object
|
54
|
+
def on_staffs_registration(staff)
|
55
|
+
logger("New registered staff: #{staff.to_h}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Listener for to *users.registration* event.
|
59
|
+
# @param user [ROM::Struct::User] the user object
|
60
|
+
def on_users_registration(user)
|
61
|
+
logger("New registered user: #{user.to_h}")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Listener for to *users.authentication* event.
|
65
|
+
# @param attributes [Hash] Authentication attributes
|
66
|
+
# @option user_id [Integer] User ID
|
67
|
+
# @option time [DateTime] Authentication time
|
68
|
+
def on_users_authentication(attributes)
|
69
|
+
logger("User #{attributes[:user_id]} authenticated on: #{attributes[:time].iso8601}")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Listener for to *users.confirmation* event.
|
73
|
+
# @param attributes [Hash] Confirmation attributes
|
74
|
+
# @option user_id [Integer] User ID
|
75
|
+
# @option time [DateTime] Authentication time
|
76
|
+
def on_users_confirmation(attributes)
|
77
|
+
logger("User #{attributes[:user_id]} confirmed at: #{attributes[:time].iso8601}")
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Append message to system log.
|
83
|
+
# @param message [String] the message
|
84
|
+
def logger(message)
|
85
|
+
Application[:logger].info(message)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Operations
|
5
|
+
module AuctionContext
|
6
|
+
##
|
7
|
+
# Operation class for creating auctions.
|
8
|
+
#
|
9
|
+
class CreateOperation < AuctionFunCore::Operations::Base
|
10
|
+
include Import["repos.auction_context.auction_repository"]
|
11
|
+
include Import["contracts.auction_context.create_contract"]
|
12
|
+
include Import["workers.operations.auction_context.processor.start_operation_job"]
|
13
|
+
|
14
|
+
# @todo Add custom doc
|
15
|
+
def self.call(attributes, &block)
|
16
|
+
operation = new.call(attributes)
|
17
|
+
|
18
|
+
return operation unless block
|
19
|
+
|
20
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(attributes)
|
24
|
+
values = yield validate(attributes)
|
25
|
+
|
26
|
+
auction_repository.transaction do |_t|
|
27
|
+
@auction = yield persist(values)
|
28
|
+
yield scheduled_start_auction(@auction)
|
29
|
+
yield publish_auctions_created(@auction)
|
30
|
+
end
|
31
|
+
|
32
|
+
Success(@auction)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Calls the auction creation contract class to perform the validation
|
38
|
+
# of the informed attributes.
|
39
|
+
# @param attrs [Hash] auction attributes
|
40
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
41
|
+
def validate(attrs)
|
42
|
+
contract = create_contract.call(attrs)
|
43
|
+
|
44
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
45
|
+
|
46
|
+
Success(contract.to_h)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Calls the auction repository class to persist the attributes in the database.
|
50
|
+
# @param result [Hash] Auction validated attributes
|
51
|
+
# @return [ROM::Struct::Auction]
|
52
|
+
def persist(result)
|
53
|
+
Success(auction_repository.create(result))
|
54
|
+
end
|
55
|
+
|
56
|
+
# Triggers the publication of event *auctions.created*.
|
57
|
+
# @param auction [Hash] Auction persisted attributes
|
58
|
+
# @return [Dry::Monads::Result::Success]
|
59
|
+
def publish_auctions_created(auction)
|
60
|
+
Application[:event].publish("auctions.created", auction.to_h)
|
61
|
+
|
62
|
+
Success()
|
63
|
+
end
|
64
|
+
|
65
|
+
# Calls the background job class that will schedule the start of the auction.
|
66
|
+
# Added a small delay to perform operations (such as sending broadcasts and/or other operations).
|
67
|
+
# @param auction [ROM::Struct::Auction]
|
68
|
+
# @return [String] sidekiq jid
|
69
|
+
def scheduled_start_auction(auction)
|
70
|
+
perform_at = auction.started_at
|
71
|
+
|
72
|
+
Success(start_operation_job.class.perform_at(perform_at, auction.id))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Operations
|
5
|
+
module AuctionContext
|
6
|
+
module Processor
|
7
|
+
##
|
8
|
+
# Operation class for dispatch finish auction.
|
9
|
+
# By default, this change auction status from 'running' to 'finished'.
|
10
|
+
#
|
11
|
+
class FinishOperation < AuctionFunCore::Operations::Base
|
12
|
+
include Import["repos.auction_context.auction_repository"]
|
13
|
+
include Import["contracts.auction_context.processor.finish_contract"]
|
14
|
+
|
15
|
+
# @todo Add custom doc
|
16
|
+
def self.call(auction_id, &block)
|
17
|
+
operation = new.call(auction_id)
|
18
|
+
|
19
|
+
return operation unless block
|
20
|
+
|
21
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# It only performs the basic processing of completing an auction.
|
25
|
+
# It just changes the status at the database level and triggers the finished event.
|
26
|
+
# @param auction_id [Integer] Auction ID
|
27
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
28
|
+
def call(auction_id)
|
29
|
+
yield validate(auction_id: auction_id)
|
30
|
+
|
31
|
+
auction_repository.transaction do |_t|
|
32
|
+
@auction, _ = auction_repository.update(auction_id, status: "finished")
|
33
|
+
|
34
|
+
publish_auction_finish_event(@auction)
|
35
|
+
end
|
36
|
+
|
37
|
+
Success(@auction)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Calls the finish contract class to perform the validation
|
43
|
+
# of the informed attributes.
|
44
|
+
# @param attributes [Hash] auction attributes
|
45
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
46
|
+
def validate(attributes)
|
47
|
+
contract = finish_contract.call(attributes)
|
48
|
+
|
49
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
50
|
+
|
51
|
+
Success(contract.to_h)
|
52
|
+
end
|
53
|
+
|
54
|
+
def publish_auction_finish_event(auction)
|
55
|
+
Application[:event].publish("auctions.finished", auction.to_h)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Operations
|
5
|
+
module AuctionContext
|
6
|
+
module Processor
|
7
|
+
##
|
8
|
+
# Operation class for dispatch pause auction.
|
9
|
+
# By default, this change auction status from 'running' to 'paused'.
|
10
|
+
#
|
11
|
+
class PauseOperation < AuctionFunCore::Operations::Base
|
12
|
+
include Import["repos.auction_context.auction_repository"]
|
13
|
+
include Import["contracts.auction_context.processor.pause_contract"]
|
14
|
+
|
15
|
+
# @todo Add custom doc
|
16
|
+
def self.call(attributes, &block)
|
17
|
+
operation = new.call(attributes)
|
18
|
+
|
19
|
+
return operation unless block
|
20
|
+
|
21
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(attributes)
|
25
|
+
attrs = yield validate(attributes)
|
26
|
+
|
27
|
+
auction_repository.transaction do |_t|
|
28
|
+
@auction, _ = auction_repository.update(attrs[:auction_id], status: "paused")
|
29
|
+
|
30
|
+
publish_auction_pause_event(@auction)
|
31
|
+
end
|
32
|
+
|
33
|
+
Success(attrs[:auction_id])
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Calls the finish contract class to perform the validation
|
39
|
+
# of the informed attributes.
|
40
|
+
# @param attrs [Hash] auction attributes
|
41
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
42
|
+
def validate(attributes)
|
43
|
+
contract = pause_contract.call(attributes)
|
44
|
+
|
45
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
46
|
+
|
47
|
+
Success(contract.to_h)
|
48
|
+
end
|
49
|
+
|
50
|
+
def publish_auction_pause_event(auction)
|
51
|
+
Application[:event].publish("auctions.paused", auction.to_h)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Operations
|
5
|
+
module AuctionContext
|
6
|
+
module Processor
|
7
|
+
##
|
8
|
+
# Operation class for dispatch start auction.
|
9
|
+
# By default, this change auction status from 'scheduled' to 'running'
|
10
|
+
# and schedule a job to execute the auction finalization when auction is not penny.
|
11
|
+
class StartOperation < AuctionFunCore::Operations::Base
|
12
|
+
include Import["repos.auction_context.auction_repository"]
|
13
|
+
include Import["contracts.auction_context.processor.start_contract"]
|
14
|
+
include Import["workers.operations.auction_context.processor.finish_operation_job"]
|
15
|
+
|
16
|
+
# @todo Add custom doc
|
17
|
+
def self.call(attributes, &block)
|
18
|
+
operation = new.call(attributes)
|
19
|
+
|
20
|
+
return operation unless block
|
21
|
+
|
22
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param [Hash] attributes needed to start a auction
|
26
|
+
# @option opts [String] :auction_id auction id
|
27
|
+
# @option opts [String] :auction_kind auction kind
|
28
|
+
# @option opts [Integer] :stopwatch auction stopwatch
|
29
|
+
# @return [ROM::Struct::Auction] auction object
|
30
|
+
def call(attributes)
|
31
|
+
attrs = yield validate(attributes)
|
32
|
+
|
33
|
+
auction_repository.transaction do |_t|
|
34
|
+
@auction, _ = auction_repository.update(attrs[:auction_id], update_params(attrs))
|
35
|
+
|
36
|
+
yield publish_auction_start_event(@auction)
|
37
|
+
yield scheduled_finished_auction(@auction)
|
38
|
+
end
|
39
|
+
|
40
|
+
Success(@auction)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Calls the start contract class to perform the validation
|
46
|
+
# of the informed attributes.
|
47
|
+
# @param attributes [Hash] auction attributes
|
48
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
49
|
+
def validate(attributes)
|
50
|
+
contract = start_contract.call(attributes)
|
51
|
+
|
52
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
53
|
+
|
54
|
+
Success(contract.to_h)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Updates the status of the auction and depending on the type of auction,
|
58
|
+
# it already sets the final date.
|
59
|
+
# @param attrs [Hash] auction attributes
|
60
|
+
# @return [Hash]
|
61
|
+
def update_params(attrs)
|
62
|
+
return {status: "running"} unless attrs[:kind] == "penny"
|
63
|
+
|
64
|
+
{status: "running", finished_at: attrs[:stopwatch].seconds.from_now}
|
65
|
+
end
|
66
|
+
|
67
|
+
def publish_auction_start_event(auction)
|
68
|
+
Success(Application[:event].publish("auctions.started", auction.to_h))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Calls the background job class that will schedule the finish of the auction.
|
72
|
+
# Added a small delay to perform operations (such as sending broadcasts and/or other operations).
|
73
|
+
# @param auction [ROM::Struct::Auction]
|
74
|
+
# @return [String] sidekiq jid
|
75
|
+
def scheduled_finished_auction(auction)
|
76
|
+
return Success() if auction.kind == "penny"
|
77
|
+
|
78
|
+
Success(finish_operation_job.class.perform_at(auction.finished_at, auction.id))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AuctionFunCore
|
4
|
+
module Operations
|
5
|
+
module AuctionContext
|
6
|
+
module Processor
|
7
|
+
##
|
8
|
+
# Operation class for dispatch unpause auction.
|
9
|
+
# By default, this change auction status from 'paused' to 'running'.
|
10
|
+
#
|
11
|
+
class UnpauseOperation < AuctionFunCore::Operations::Base
|
12
|
+
include Import["repos.auction_context.auction_repository"]
|
13
|
+
include Import["contracts.auction_context.processor.unpause_contract"]
|
14
|
+
|
15
|
+
# @todo Add custom doc
|
16
|
+
def self.call(attributes, &block)
|
17
|
+
operation = new.call(attributes)
|
18
|
+
|
19
|
+
return operation unless block
|
20
|
+
|
21
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(attributes)
|
25
|
+
attrs = yield validate(attributes)
|
26
|
+
|
27
|
+
auction_repository.transaction do |_t|
|
28
|
+
@auction, _ = auction_repository.update(attrs[:auction_id], status: "running")
|
29
|
+
|
30
|
+
publish_auction_unpause_event(@auction)
|
31
|
+
end
|
32
|
+
|
33
|
+
Success(attrs[:auction_id])
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Calls the unpause contract class to perform the validation
|
39
|
+
# of the informed attributes.
|
40
|
+
# @param attrs [Hash] auction attributes
|
41
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
42
|
+
def validate(attributes)
|
43
|
+
contract = unpause_contract.call(attributes)
|
44
|
+
|
45
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
46
|
+
|
47
|
+
Success(contract.to_h)
|
48
|
+
end
|
49
|
+
|
50
|
+
def publish_auction_unpause_event(auction)
|
51
|
+
Application[:event].publish("auctions.unpaused", auction.to_h)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|