auction_fun_core 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module BidContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for create new bids for closed auctions.
|
|
8
|
+
#
|
|
9
|
+
class CreateBidClosedOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["contracts.bid_context.create_bid_closed_contract"]
|
|
11
|
+
include Import["repos.bid_context.bid_repository"]
|
|
12
|
+
|
|
13
|
+
# @todo Add custom doc
|
|
14
|
+
def self.call(attributes, &block)
|
|
15
|
+
operation = new.call(attributes)
|
|
16
|
+
|
|
17
|
+
return operation unless block
|
|
18
|
+
|
|
19
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @todo Add custom doc
|
|
23
|
+
def call(attributes)
|
|
24
|
+
values = yield validate(attributes)
|
|
25
|
+
|
|
26
|
+
bid_repository.transaction do |_t|
|
|
27
|
+
@bid = yield persist(values)
|
|
28
|
+
yield publish_bid_created(@bid)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Success(@bid)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Calls the bid creation contract class to perform the validation
|
|
35
|
+
# of the informed attributes.
|
|
36
|
+
# @param attrs [Hash] bid attributes
|
|
37
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
38
|
+
def validate(attrs)
|
|
39
|
+
contract = create_bid_closed_contract.call(attrs)
|
|
40
|
+
|
|
41
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
42
|
+
|
|
43
|
+
Success(contract.to_h)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Calls the bid repository class to persist the attributes in the database.
|
|
47
|
+
# @param result [Hash] Bid validated attributes
|
|
48
|
+
# @return [ROM::Struct::Bid]
|
|
49
|
+
def persist(result)
|
|
50
|
+
Success(bid_repository.create(result))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Triggers the publication of event *bids.created*.
|
|
54
|
+
# @param bid [ROM::Struct::Bid] Bid object
|
|
55
|
+
# @return [Dry::Monads::Result::Success]
|
|
56
|
+
def publish_bid_created(bid)
|
|
57
|
+
Application[:event].publish("bids.created", bid.to_h)
|
|
58
|
+
|
|
59
|
+
Success()
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module BidContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for create new bids for penny auctions.
|
|
8
|
+
#
|
|
9
|
+
class CreateBidPennyOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["contracts.bid_context.create_bid_penny_contract"]
|
|
11
|
+
include Import["repos.bid_context.bid_repository"]
|
|
12
|
+
|
|
13
|
+
# @todo Add custom doc
|
|
14
|
+
def self.call(attributes, &block)
|
|
15
|
+
operation = new.call(attributes)
|
|
16
|
+
|
|
17
|
+
return operation unless block
|
|
18
|
+
|
|
19
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @todo Add custom doc
|
|
23
|
+
def call(attributes)
|
|
24
|
+
values = yield validate(attributes)
|
|
25
|
+
|
|
26
|
+
bid_repository.transaction do |_t|
|
|
27
|
+
@bid = yield persist(values)
|
|
28
|
+
yield publish_bid_created(@bid)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Success(@bid)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Calls the bid creation contract class to perform the validation
|
|
35
|
+
# of the informed attributes.
|
|
36
|
+
# @param attrs [Hash] bid attributes
|
|
37
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
38
|
+
def validate(attrs)
|
|
39
|
+
contract = create_bid_penny_contract.call(attrs)
|
|
40
|
+
|
|
41
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
42
|
+
|
|
43
|
+
Success(contract.to_h)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Calls the bid repository class to persist the attributes in the database.
|
|
47
|
+
# @param result [Hash] Bid validated attributes
|
|
48
|
+
# @return [ROM::Struct::Bid]
|
|
49
|
+
def persist(result)
|
|
50
|
+
Success(bid_repository.create(result))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Triggers the publication of event *bids.created*.
|
|
54
|
+
# @param bid [ROM::Struct::Bid] Bid Object
|
|
55
|
+
# @return [Dry::Monads::Result::Success]
|
|
56
|
+
def publish_bid_created(bid)
|
|
57
|
+
Application[:event].publish("bids.created", bid.to_h)
|
|
58
|
+
|
|
59
|
+
Success()
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module BidContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for create new bids for standard auctions.
|
|
8
|
+
#
|
|
9
|
+
class CreateBidStandardOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
INCREASE = 0.1
|
|
11
|
+
include Import["contracts.bid_context.create_bid_standard_contract"]
|
|
12
|
+
include Import["repos.auction_context.auction_repository"]
|
|
13
|
+
include Import["repos.bid_context.bid_repository"]
|
|
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
|
+
# @todo Add custom doc
|
|
25
|
+
def call(attributes)
|
|
26
|
+
values = yield validate(attributes)
|
|
27
|
+
|
|
28
|
+
bid_repository.transaction do |_t|
|
|
29
|
+
@bid = yield persist(values)
|
|
30
|
+
yield calculate_standard_auction_new_minimal_bid_value(@bid.auction_id, @bid.value_cents)
|
|
31
|
+
yield publish_bid_created(@bid)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Success(@bid)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Calls the bid creation contract class to perform the validation
|
|
38
|
+
# of the informed attributes.
|
|
39
|
+
# @param attrs [Hash] bid attributes
|
|
40
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
41
|
+
def validate(attrs)
|
|
42
|
+
contract = create_bid_standard_contract.call(attrs)
|
|
43
|
+
|
|
44
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
45
|
+
|
|
46
|
+
Success(contract.to_h)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Calculates the new minimum next bid amount.
|
|
50
|
+
def calculate_standard_auction_new_minimal_bid_value(auction_id, bid_cents)
|
|
51
|
+
minimal_bid_cents = (bid_cents + (bid_cents * INCREASE))
|
|
52
|
+
|
|
53
|
+
Success(auction_repository.update(auction_id, minimal_bid_cents: minimal_bid_cents))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Calls the bid repository class to persist the attributes in the database.
|
|
57
|
+
# @param result [Hash] Bid validated attributes
|
|
58
|
+
# @return [ROM::Struct::Bid]
|
|
59
|
+
def persist(result)
|
|
60
|
+
Success(bid_repository.create(result))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Triggers the publication of event *bids.created*.
|
|
64
|
+
# @param bid [ROM::Struct::Bid] Bid Object
|
|
65
|
+
# @return [Dry::Monads::Result::Success]
|
|
66
|
+
def publish_bid_created(bid)
|
|
67
|
+
Application[:event].publish("bids.created", bid.to_h)
|
|
68
|
+
|
|
69
|
+
Success()
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module StaffContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for authenticate staff members.
|
|
8
|
+
#
|
|
9
|
+
class AuthenticationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["contracts.staff_context.authentication_contract"]
|
|
11
|
+
|
|
12
|
+
def self.call(attributes, &block)
|
|
13
|
+
operation = new.call(attributes)
|
|
14
|
+
|
|
15
|
+
return operation unless block
|
|
16
|
+
|
|
17
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @todo Add custom doc
|
|
21
|
+
def call(attributes)
|
|
22
|
+
staff = yield validate_contract(attributes)
|
|
23
|
+
|
|
24
|
+
yield publish_staff_authentication(staff.id)
|
|
25
|
+
|
|
26
|
+
Success(staff)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Calls the authentication contract class to perform the validation
|
|
30
|
+
# and authentication of the informed attributes.
|
|
31
|
+
# @param attrs [Hash] Staff attributes
|
|
32
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
33
|
+
def validate_contract(attrs)
|
|
34
|
+
contract = authentication_contract.call(attrs)
|
|
35
|
+
|
|
36
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
37
|
+
|
|
38
|
+
Success(contract.context[:staff])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Triggers the publication of event *staffs.registration*.
|
|
42
|
+
# @param staff_id [Integer] Staff ID
|
|
43
|
+
# @return [Dry::Monads::Result::Success]
|
|
44
|
+
def publish_staff_authentication(staff_id, time = Time.current)
|
|
45
|
+
Success(
|
|
46
|
+
Application[:event].publish("staffs.authentication", {staff_id: staff_id, time: time})
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module StaffContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for create new staff member.
|
|
8
|
+
#
|
|
9
|
+
class RegistrationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["contracts.staff_context.registration_contract"]
|
|
11
|
+
include Import["repos.staff_context.staff_repository"]
|
|
12
|
+
|
|
13
|
+
def self.call(attributes, &block)
|
|
14
|
+
operation = new.call(attributes)
|
|
15
|
+
|
|
16
|
+
return operation unless block
|
|
17
|
+
|
|
18
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @todo Add custom doc
|
|
22
|
+
def call(attributes)
|
|
23
|
+
values = yield validate_contract(attributes)
|
|
24
|
+
values_with_encrypt_password = yield encrypt_password(values)
|
|
25
|
+
|
|
26
|
+
staff_repository.transaction do |_t|
|
|
27
|
+
@staff = yield persist(values_with_encrypt_password)
|
|
28
|
+
|
|
29
|
+
yield publish_staff_registration(@staff.id)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Success(@staff)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Calls registration contract class to perform the validation
|
|
36
|
+
# of the informed attributes.
|
|
37
|
+
# @param attrs [Hash] staff attributes
|
|
38
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
39
|
+
def validate_contract(attrs)
|
|
40
|
+
contract = registration_contract.call(attrs)
|
|
41
|
+
|
|
42
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
43
|
+
|
|
44
|
+
Success(contract.to_h)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Transforms the password attribute, encrypting it to be saved in the database.
|
|
48
|
+
# @param result [Hash] Staff valid contract attributes
|
|
49
|
+
# @return [Hash] Valid staff database
|
|
50
|
+
def encrypt_password(attrs)
|
|
51
|
+
attributes = attrs.to_h.except(:password)
|
|
52
|
+
|
|
53
|
+
Success(
|
|
54
|
+
{**attributes, password_digest: BCrypt::Password.create(attrs[:password])}
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Calls the staff repository class to persist the attributes in the database.
|
|
59
|
+
# @param result [Hash] Staff validated attributes
|
|
60
|
+
# @return [ROM::Struct::Staff]
|
|
61
|
+
def persist(result)
|
|
62
|
+
Success(staff_repository.create(result))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Triggers the publication of event *staffs.registration*.
|
|
66
|
+
# @param staff_id [Integer] Staff ID
|
|
67
|
+
# @return [Dry::Monads::Result::Success]
|
|
68
|
+
def publish_staff_registration(staff_id)
|
|
69
|
+
staff = staff_repository.by_id!(staff_id)
|
|
70
|
+
|
|
71
|
+
Success(Application[:event].publish("staffs.registration", staff.info))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module UserContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for authenticate users.
|
|
8
|
+
#
|
|
9
|
+
class AuthenticationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["contracts.user_context.authentication_contract"]
|
|
11
|
+
|
|
12
|
+
def self.call(attributes, &block)
|
|
13
|
+
operation = new.call(attributes)
|
|
14
|
+
|
|
15
|
+
return operation unless block
|
|
16
|
+
|
|
17
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @todo Add custom doc
|
|
21
|
+
def call(attributes)
|
|
22
|
+
user = yield validate_contract(attributes)
|
|
23
|
+
|
|
24
|
+
yield publish_user_authentication(user.id)
|
|
25
|
+
|
|
26
|
+
Success(user)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Calls the authentication contract class to perform the validation
|
|
30
|
+
# and authentication of the informed attributes.
|
|
31
|
+
# @param attrs [Hash] user attributes
|
|
32
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
33
|
+
def validate_contract(attrs)
|
|
34
|
+
contract = authentication_contract.call(attrs)
|
|
35
|
+
|
|
36
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
37
|
+
|
|
38
|
+
Success(contract.context[:user])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Triggers the publication of event *users.registration*.
|
|
42
|
+
# @param user_id [Integer] User ID
|
|
43
|
+
# @return [Dry::Monads::Result::Success]
|
|
44
|
+
def publish_user_authentication(user_id, time = Time.current)
|
|
45
|
+
Success(
|
|
46
|
+
Application[:event].publish("users.authentication", {user_id: user_id, time: time})
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module UserContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for confirm users by token via email.
|
|
8
|
+
#
|
|
9
|
+
class EmailConfirmationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["repos.user_context.user_repository"]
|
|
11
|
+
include Import["contracts.user_context.email_confirmation_contract"]
|
|
12
|
+
|
|
13
|
+
def self.call(attributes, &block)
|
|
14
|
+
operation = new.call(attributes)
|
|
15
|
+
|
|
16
|
+
return operation unless block
|
|
17
|
+
|
|
18
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @todo Add custom doc
|
|
22
|
+
def call(attributes)
|
|
23
|
+
user = yield validate_contract(attributes)
|
|
24
|
+
|
|
25
|
+
user_repository.transaction do |_t|
|
|
26
|
+
user = yield persist(user.id)
|
|
27
|
+
|
|
28
|
+
yield publish_user_confirmation(user.id, user.confirmed_at)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Success(user)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Calls the authentication contract class to perform the validation
|
|
35
|
+
# and authentication of the informed attributes.
|
|
36
|
+
# @param attrs [Hash] user attributes
|
|
37
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
38
|
+
def validate_contract(attrs)
|
|
39
|
+
contract = email_confirmation_contract.call(attrs)
|
|
40
|
+
|
|
41
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
42
|
+
|
|
43
|
+
Success(contract.context[:user])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Calls the user repository class to update database fields.
|
|
47
|
+
# @param user_id [Integer] User ID
|
|
48
|
+
# @param time [Time] Confirmation time
|
|
49
|
+
# @return [ROM::Struct::User]
|
|
50
|
+
def persist(user_id, time = Time.current)
|
|
51
|
+
result = {email_confirmation_token: nil, email_confirmed_at: time, confirmed_at: time}
|
|
52
|
+
|
|
53
|
+
Success(user_repository.update(user_id, result))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Triggers the publication of event *users.registration*.
|
|
57
|
+
# @param user_id [Integer] User ID
|
|
58
|
+
# @return [Dry::Monads::Result::Success]
|
|
59
|
+
def publish_user_confirmation(user_id, time = Time.current)
|
|
60
|
+
Success(
|
|
61
|
+
Application[:event].publish("users.confirmation", {user_id: user_id, time: time})
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module UserContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for confirm users by token via phone.
|
|
8
|
+
#
|
|
9
|
+
class PhoneConfirmationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["repos.user_context.user_repository"]
|
|
11
|
+
include Import["contracts.user_context.phone_confirmation_contract"]
|
|
12
|
+
|
|
13
|
+
def self.call(attributes, &block)
|
|
14
|
+
operation = new.call(attributes)
|
|
15
|
+
|
|
16
|
+
return operation unless block
|
|
17
|
+
|
|
18
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @todo Add custom doc
|
|
22
|
+
def call(attributes)
|
|
23
|
+
user = yield validate_contract(attributes)
|
|
24
|
+
|
|
25
|
+
user_repository.transaction do |_t|
|
|
26
|
+
user = yield persist(user.id)
|
|
27
|
+
|
|
28
|
+
yield publish_user_confirmation(user.id, user.confirmed_at)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Success(user)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Calls the authentication contract class to perform the validation
|
|
35
|
+
# and authentication of the informed attributes.
|
|
36
|
+
# @param attrs [Hash] user attributes
|
|
37
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
38
|
+
def validate_contract(attrs)
|
|
39
|
+
contract = phone_confirmation_contract.call(attrs)
|
|
40
|
+
|
|
41
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
42
|
+
|
|
43
|
+
Success(contract.context[:user])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Calls the user repository class to update database fields.
|
|
47
|
+
# @param user_id [Integer] User ID
|
|
48
|
+
# @param time [Time] Confirmation time
|
|
49
|
+
# @return [ROM::Struct::User]
|
|
50
|
+
def persist(user_id, time = Time.current)
|
|
51
|
+
result = {phone_confirmation_token: nil, phone_confirmed_at: time, confirmed_at: time}
|
|
52
|
+
|
|
53
|
+
Success(user_repository.update(user_id, result))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Triggers the publication of event *users.registration*.
|
|
57
|
+
# @param user_id [Integer] User ID
|
|
58
|
+
# @return [Dry::Monads::Result::Success]
|
|
59
|
+
def publish_user_confirmation(user_id, time = Time.current)
|
|
60
|
+
Success(
|
|
61
|
+
Application[:event].publish("users.confirmation", {user_id: user_id, time: time})
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AuctionFunCore
|
|
4
|
+
module Operations
|
|
5
|
+
module UserContext
|
|
6
|
+
##
|
|
7
|
+
# Operation class for create new users.
|
|
8
|
+
#
|
|
9
|
+
class RegistrationOperation < AuctionFunCore::Operations::Base
|
|
10
|
+
include Import["repos.user_context.user_repository"]
|
|
11
|
+
include Import["contracts.user_context.registration_contract"]
|
|
12
|
+
|
|
13
|
+
def self.call(attributes, &block)
|
|
14
|
+
operation = new.call(attributes)
|
|
15
|
+
|
|
16
|
+
return operation unless block
|
|
17
|
+
|
|
18
|
+
Dry::Matcher::ResultMatcher.call(operation, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @todo Add custom doc
|
|
22
|
+
def call(attributes)
|
|
23
|
+
values = yield validate_contract(attributes)
|
|
24
|
+
values_with_encrypt_password = yield encrypt_password(values)
|
|
25
|
+
values_with_confirmation_attributes = yield confirmation_attributes(values_with_encrypt_password)
|
|
26
|
+
|
|
27
|
+
user_repository.transaction do |_t|
|
|
28
|
+
@user = yield persist(values_with_confirmation_attributes)
|
|
29
|
+
|
|
30
|
+
yield publish_user_registration(@user.id)
|
|
31
|
+
yield send_welcome_email(@user.id)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Success(@user)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Calls registration contract class to perform the validation
|
|
38
|
+
# of the informed attributes.
|
|
39
|
+
# @param attrs [Hash] user attributes
|
|
40
|
+
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
|
|
41
|
+
def validate_contract(attrs)
|
|
42
|
+
contract = registration_contract.call(attrs)
|
|
43
|
+
|
|
44
|
+
return Failure(contract.errors.to_h) if contract.failure?
|
|
45
|
+
|
|
46
|
+
Success(contract.to_h)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Transforms the password attribute, encrypting it to be saved in the database.
|
|
50
|
+
# @param result [Hash] User valid contract attributes
|
|
51
|
+
# @return [Hash] Valid user database
|
|
52
|
+
def encrypt_password(attrs)
|
|
53
|
+
attributes = attrs.to_h.except(:password, :password_confirmation)
|
|
54
|
+
|
|
55
|
+
Success(
|
|
56
|
+
{**attributes, password_digest: BCrypt::Password.create(attrs[:password])}
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Adds confirmation parameters to the given attributes.
|
|
61
|
+
# @param result [Hash] User valid contract attributes with password
|
|
62
|
+
# @return [Hash] Valid user database
|
|
63
|
+
def confirmation_attributes(attrs)
|
|
64
|
+
Success({**attrs, email_confirmation_token: generate_email_token})
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Calls the user repository class to persist the attributes in the database.
|
|
68
|
+
# @param result [Hash] User validated attributes
|
|
69
|
+
# @return [ROM::Struct::User]
|
|
70
|
+
def persist(result)
|
|
71
|
+
Success(user_repository.create(result))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Triggers the publication of event *users.registration*.
|
|
75
|
+
# @param user_id [Integer] User ID
|
|
76
|
+
# @return [Dry::Monads::Result::Success]
|
|
77
|
+
def publish_user_registration(user_id)
|
|
78
|
+
user = user_repository.by_id!(user_id)
|
|
79
|
+
|
|
80
|
+
Success(Application[:event].publish("users.registration", user.info))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Schedule the asynchronous sending of a welcome email.
|
|
84
|
+
# @param user_id [Integer] User ID
|
|
85
|
+
# @return [Dry::Monads::Result::Success]
|
|
86
|
+
def send_welcome_email(user_id)
|
|
87
|
+
Success(registration_mailer_job.perform_async(user_id))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Since the shipping code structure does not follow project conventions,
|
|
91
|
+
# making the default injection dependency would be more complicated.
|
|
92
|
+
# Therefore, here I directly explain the class to be called.
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def registration_mailer_job
|
|
96
|
+
AuctionFunCore::Workers::Services::Mail::UserContext::RegistrationMailerJob
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def generate_email_token
|
|
100
|
+
::AuctionFunCore::Business::TokenGenerator.generate_email_token
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|