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,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
|