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.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +12 -0
  3. data/.env.development.template +7 -0
  4. data/.env.test.template +7 -0
  5. data/.rspec +3 -0
  6. data/.standard.yml +3 -0
  7. data/.tool-versions +5 -0
  8. data/CHANGELOG.md +145 -0
  9. data/CODE_OF_CONDUCT.md +84 -0
  10. data/LICENSE.txt +21 -0
  11. data/Procfile +4 -0
  12. data/README.md +141 -0
  13. data/Rakefile +13 -0
  14. data/auction_fun_core.gemspec +57 -0
  15. data/config/app.rb +5 -0
  16. data/config/application.rb +37 -0
  17. data/config/boot.rb +15 -0
  18. data/db/migrate/20240216200926_enable_postgres_extensions.rb +13 -0
  19. data/db/migrate/20240217115734_create_users.rb +28 -0
  20. data/db/migrate/20240220140151_create_custom_types.rb +11 -0
  21. data/db/migrate/20240220140254_create_staffs.rb +20 -0
  22. data/db/migrate/20240229142933_create_custom_types.rb +13 -0
  23. data/db/migrate/20240229143000_create_auctions.rb +29 -0
  24. data/db/migrate/20240304144422_create_bids.rb +19 -0
  25. data/db/seeds.rb +116 -0
  26. data/i18n/en-US/contracts/contracts.en-US.yml +72 -0
  27. data/i18n/en-US/mail/user_context/registration.en-US.yml +11 -0
  28. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +72 -0
  29. data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +12 -0
  30. data/lib/auction_fun_core/business/configuration.rb +18 -0
  31. data/lib/auction_fun_core/business/token_generator.rb +17 -0
  32. data/lib/auction_fun_core/commands/auction_context/create_auction.rb +19 -0
  33. data/lib/auction_fun_core/commands/auction_context/delete_auction.rb +15 -0
  34. data/lib/auction_fun_core/commands/auction_context/update_auction.rb +18 -0
  35. data/lib/auction_fun_core/commands/bid_context/create_bid.rb +19 -0
  36. data/lib/auction_fun_core/commands/bid_context/delete_bid.rb +15 -0
  37. data/lib/auction_fun_core/commands/bid_context/update_bid.rb +18 -0
  38. data/lib/auction_fun_core/commands/staff_context/create_staff.rb +19 -0
  39. data/lib/auction_fun_core/commands/user_context/create_user.rb +19 -0
  40. data/lib/auction_fun_core/contracts/application_contract.rb +55 -0
  41. data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +101 -0
  42. data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +27 -0
  43. data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +34 -0
  44. data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +46 -0
  45. data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +34 -0
  46. data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +79 -0
  47. data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +69 -0
  48. data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +68 -0
  49. data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +47 -0
  50. data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +52 -0
  51. data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +47 -0
  52. data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +40 -0
  53. data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +40 -0
  54. data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +63 -0
  55. data/lib/auction_fun_core/entities/auction.rb +17 -0
  56. data/lib/auction_fun_core/entities/bid.rb +10 -0
  57. data/lib/auction_fun_core/entities/staff.rb +21 -0
  58. data/lib/auction_fun_core/entities/user.rb +37 -0
  59. data/lib/auction_fun_core/events/app.rb +27 -0
  60. data/lib/auction_fun_core/events/listener.rb +89 -0
  61. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +77 -0
  62. data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +61 -0
  63. data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +57 -0
  64. data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +84 -0
  65. data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +57 -0
  66. data/lib/auction_fun_core/operations/base.rb +11 -0
  67. data/lib/auction_fun_core/operations/bid_context/create_bid_closed_operation.rb +64 -0
  68. data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +64 -0
  69. data/lib/auction_fun_core/operations/bid_context/create_bid_standard_operation.rb +74 -0
  70. data/lib/auction_fun_core/operations/staff_context/authentication_operation.rb +52 -0
  71. data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +76 -0
  72. data/lib/auction_fun_core/operations/user_context/authentication_operation.rb +52 -0
  73. data/lib/auction_fun_core/operations/user_context/email_confirmation_operation.rb +67 -0
  74. data/lib/auction_fun_core/operations/user_context/phone_confirmation_operation.rb +67 -0
  75. data/lib/auction_fun_core/operations/user_context/registration_operation.rb +105 -0
  76. data/lib/auction_fun_core/relations/auctions.rb +119 -0
  77. data/lib/auction_fun_core/relations/bids.rb +28 -0
  78. data/lib/auction_fun_core/relations/staffs.rb +27 -0
  79. data/lib/auction_fun_core/relations/users.rb +26 -0
  80. data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +42 -0
  81. data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -0
  82. data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +64 -0
  83. data/lib/auction_fun_core/repos/user_context/user_repository.rb +78 -0
  84. data/lib/auction_fun_core/services/mail/templates/layout.html.erb +72 -0
  85. data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +170 -0
  86. data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +25 -0
  87. data/lib/auction_fun_core/version.rb +8 -0
  88. data/lib/auction_fun_core/workers/application_job.rb +22 -0
  89. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish_operation_job.rb +32 -0
  90. data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +32 -0
  91. data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +40 -0
  92. data/lib/auction_fun_core.rb +21 -0
  93. data/lib/tasks/database.rake +87 -0
  94. data/system/providers/background_job.rb +15 -0
  95. data/system/providers/core.rb +35 -0
  96. data/system/providers/db.rb +26 -0
  97. data/system/providers/events.rb +13 -0
  98. data/system/providers/logger.rb +11 -0
  99. data/system/providers/mail.rb +25 -0
  100. data/system/providers/persistence.rb +18 -0
  101. data/system/providers/settings.rb +26 -0
  102. metadata +400 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ ROM::SQL.migration do
4
+ change do
5
+ create_table(:auctions) do
6
+ primary_key :id
7
+ foreign_key :staff_id, :staffs, null: false
8
+ column :title, String, null: false
9
+ column :description, :text
10
+ column :kind, :auction_kinds, null: false
11
+ column :status, :auction_statuses, null: false
12
+ column :started_at, DateTime, null: false
13
+ column :finished_at, DateTime
14
+ column :stopwatch, Integer, null: false, default: 0
15
+ column :initial_bid_cents, Integer, null: false, default: 0
16
+ column :initial_bid_currency, String, null: false, default: "USD"
17
+ column :minimal_bid_cents, Integer, null: false, default: 0
18
+ column :minimal_bid_currency, String, null: false, default: "USD"
19
+ column :metadata, :jsonb, null: false, default: "{}"
20
+ column :statistics, :jsonb, null: false, default: "{}"
21
+
22
+ column :created_at, DateTime, null: false
23
+ column :updated_at, DateTime, null: false
24
+ end
25
+
26
+ add_index :auctions, %i[staff_id], name: "idx_admin"
27
+ add_index :auctions, %i[kind status], name: "idx_kind_status"
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ ROM::SQL.migration do
4
+ change do
5
+ create_table :bids do
6
+ primary_key :id
7
+ foreign_key :user_id, :users, null: false
8
+ foreign_key :auction_id, :auctions, null: false
9
+
10
+ column :value_cents, Integer, null: false, default: 0
11
+ column :value_currency, String, null: false, default: "USD"
12
+
13
+ column :created_at, DateTime, null: false
14
+ column :updated_at, DateTime, null: false
15
+ end
16
+
17
+ add_index :bids, %i[auction_id user_id], name: "idx_user_auction"
18
+ end
19
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry"
4
+ require "faker"
5
+
6
+ I18n.enforce_available_locales = false
7
+ Faker::Config.locale = "pt-BR"
8
+
9
+ # Constants
10
+ STOPWATCH_OPTIONS = [15, 30, 45, 60].freeze
11
+
12
+ # Start application
13
+ AuctionFunCore::Application.start(:core)
14
+
15
+ # Instantiate repos
16
+ auction_repository = AuctionFunCore::Repos::AuctionContext::AuctionRepository.new
17
+ staff_repository = AuctionFunCore::Repos::StaffContext::StaffRepository.new
18
+
19
+ # Create root staff. Create as a regular user using the normal flow and after that
20
+ # just change the type directly in the db.
21
+
22
+ root_staff_attributes = {
23
+ kind: "root", name: "Root Bot", email: "rootbot@auctionfun.net",
24
+ phone: Faker::PhoneNumber.unique.cell_phone_in_e164,
25
+ password: "password", password_confirmation: "password"
26
+ }
27
+
28
+ AuctionFunCore::Operations::StaffContext::RegistrationOperation.call(root_staff_attributes) do |result|
29
+ result.failure { |failure| raise "Error to create root staff: #{failure}" }
30
+ result.success { |root| @root = root }
31
+ end
32
+ staff_repository.update(@root.id, kind: "root")
33
+
34
+ # Add common staff
35
+
36
+ common_staff_attributes = {
37
+ name: "Staff Bot", email: "staffbot@auctionfun.net",
38
+ phone: Faker::PhoneNumber.unique.cell_phone_in_e164,
39
+ password: "password", password_confirmation: "password"
40
+ }
41
+
42
+ AuctionFunCore::Operations::StaffContext::RegistrationOperation.call(common_staff_attributes) do |result|
43
+ result.failure { |failure| raise "Error to create common staff: #{failure}" }
44
+ result.success { |staff| @staff = staff }
45
+ end
46
+
47
+ # Create some standard auctions
48
+ (1..15).each do |i|
49
+ attributes = {
50
+ staff_id: @staff.id, title: Faker::Commerce.product_name, description: Faker::Lorem.paragraph_by_chars,
51
+ kind: "standard", started_at: i.hour.from_now, finished_at: i.day.from_now,
52
+ initial_bid_cents: (i * 100), minimal_bid_cents: (i * 100)
53
+ }
54
+ AuctionFunCore::Operations::AuctionContext::CreateOperation.call(attributes) do |result|
55
+ result.failure { |failure| raise "Error to create standard auction: #{failure}" }
56
+ result.success { |auction| puts "Create standard auction with: #{auction.to_h}" }
57
+ end
58
+ end
59
+
60
+ # Create some penny auctions
61
+ (1..10).each do |i|
62
+ stopwatch = STOPWATCH_OPTIONS.sample
63
+ started_at = i.hour.from_now
64
+ finished_at = started_at + stopwatch.seconds
65
+
66
+ attributes = {
67
+ staff_id: @staff.id, title: Faker::Commerce.product_name, description: Faker::Lorem.paragraph_by_chars,
68
+ kind: "penny", started_at: started_at, finished_at: finished_at, stopwatch: stopwatch
69
+ }
70
+ AuctionFunCore::Operations::AuctionContext::CreateOperation.call(attributes) do |result|
71
+ result.failure { |failure| raise "Error to create penny auction: #{failure}" }
72
+ result.success { |auction| puts "Create penny auction with: #{auction.to_h}" }
73
+ end
74
+ end
75
+
76
+ # Create some closed auctions
77
+ (1..3).each do |i|
78
+ attributes = {
79
+ staff_id: @staff.id, title: Faker::Commerce.product_name, kind: "closed",
80
+ started_at: i.hour.from_now, finished_at: i.day.from_now.end_of_day,
81
+ initial_bid_cents: (i * 1000)
82
+ }
83
+ AuctionFunCore::Operations::AuctionContext::CreateOperation.call(attributes) do |result|
84
+ result.failure { |failure| raise "Error to create closed auction: #{failure}" }
85
+ result.success { |auction| puts "Create closed auction with: #{auction.to_h}" }
86
+ end
87
+ end
88
+
89
+ # Add some users
90
+ 100.times do
91
+ attributes = {
92
+ name: Faker::Name.name, email: Faker::Internet.unique.email,
93
+ phone: Faker::PhoneNumber.unique.cell_phone_in_e164, password: "password",
94
+ password_confirmation: "password"
95
+ }
96
+ AuctionFunCore::Operations::UserContext::RegistrationOperation.call(attributes) do |result|
97
+ result.failure { |failure| raise "Error to create user: #{failure}" }
98
+ result.success { |user| puts "Create user with: #{user.to_h}" }
99
+ end
100
+ end
101
+
102
+ # Create some bids
103
+ auction_repository.all.each do |auction|
104
+ next if auction.id.even?
105
+
106
+ bid_params = {
107
+ auction_id: auction.id,
108
+ user_id: rand(2..100),
109
+ value_cents: auction.minimal_bid_cents + (auction.minimal_bid_cents * 0.10)
110
+ }
111
+
112
+ "AuctionFunCore::Operations::BidContext::CreateBid#{auction.kind.capitalize}Operation".constantize.call(bid_params) do |result|
113
+ result.failure { |failure| raise "Error to create bid: #{failure}" }
114
+ result.success { |bid| puts "Create bid with: #{bid.to_h}" }
115
+ end
116
+ end
@@ -0,0 +1,72 @@
1
+ en-US:
2
+ contracts:
3
+ errors:
4
+ or: "or"
5
+ array?: "must be an array"
6
+ empty?: "must be empty"
7
+ excludes?: "must not include %{value}"
8
+ excluded_from?:
9
+ arg:
10
+ default: "must not be one of: %{list}"
11
+ range: "must not be one of: %{list_left} - %{list_right}"
12
+ exclusion?: "must not be one of: %{list}"
13
+ eql?: "must be equal to %{left}"
14
+ not_eql?: "must not be equal to %{left}"
15
+ filled?: "must be filled"
16
+ format?: "is in invalid format"
17
+ number?: "must be a number"
18
+ odd?: "must be odd"
19
+ even?: "must be even"
20
+ gt?: "must be greater than %{num}"
21
+ gteq?: "must be greater than or equal to %{num}"
22
+ hash?: "must be a hash"
23
+ included_in?:
24
+ arg:
25
+ default: "must be one of: %{list}"
26
+ range: "must be one of: %{list_left} - %{list_right}"
27
+ inclusion?: "must be one of: %{list}"
28
+ includes?: "must include %{value}"
29
+ bool?: "must be boolean"
30
+ true?: "must be true"
31
+ false?: "must be false"
32
+ int?: "must be an integer"
33
+ float?: "must be a float"
34
+ decimal?: "must be a decimal"
35
+ date?: "must be a date"
36
+ date_time?: "must be a date time"
37
+ time?: "must be a time"
38
+ key?: "is required"
39
+ attr?: "is required"
40
+ lt?: "must be less than %{num}"
41
+ lteq?: "must be less than or equal to %{num}"
42
+ max_size?: "size cannot be greater than %{num}"
43
+ min_size?: "size cannot be less than %{num}"
44
+ none?: "cannot be defined"
45
+ str?: "must be a string"
46
+ type?: "must be %{type}"
47
+ size?:
48
+ arg:
49
+ default: "size must be %{size}"
50
+ range: "size must be within %{size_left} - %{size_right}"
51
+ value:
52
+ string:
53
+ arg:
54
+ default: "length must be %{size}"
55
+ range: "length must be within %{size_left} - %{size_right}"
56
+ custom:
57
+ default:
58
+ taken: "has already been taken"
59
+ not_found: "not found"
60
+ password_confirmation: "doesn't match password"
61
+ login_not_found: "Invalid credentials"
62
+ inactive_account: "Your account is suspended or inactive"
63
+ future: "must be in the future"
64
+ macro:
65
+ email_format: "need to be a valid email"
66
+ login_format: "invalid login"
67
+ name_format: "must be between %{min} and %{max} characters"
68
+ password_format: "must be between %{min} and %{max} characters"
69
+ phone_format: "need to be a valid mobile number"
70
+ auction_context:
71
+ create:
72
+ finished_at: "must be after started time"
@@ -0,0 +1,11 @@
1
+ en-US:
2
+ mail:
3
+ general:
4
+ hello: "Hi %{name}"
5
+ app_name: "AuctionFun"
6
+ team: "Team AuctionFun"
7
+ user_context:
8
+ registration:
9
+ subject: "Welcome to AuctionFun"
10
+ body:
11
+ description: "Welcome to our platform! We are delighted to have you on board. If you have any questions or need assistance, feel free to reach out."
@@ -0,0 +1,72 @@
1
+ pt-BR:
2
+ contracts:
3
+ errors:
4
+ or: "ou"
5
+ array?: "deve ser um array"
6
+ empty?: "deve ficar vazio"
7
+ excludes?: "não deve incluir %{value}"
8
+ excluded_from?:
9
+ arg:
10
+ default: "não deve ser um de: %{list}"
11
+ range: "não deve ser um de: %{list_left} - %{list_right}"
12
+ exclusion?: "não deve ser um de: %{list}"
13
+ eql?: "deve ser igual a %{left}"
14
+ not_eql?: "não deve ser igual a %{left}"
15
+ filled?: "deve ser preenchido"
16
+ format?: "está em formato inválido"
17
+ number?: "deve ser um número"
18
+ odd?: "deve ser ímpar"
19
+ even?: "deve ser par"
20
+ gt?: "deve ser maior que %{num}"
21
+ gteq?: "deve ser maior ou igual a %{num}"
22
+ hash?: "deve ser do tipo hash"
23
+ included_in?:
24
+ arg:
25
+ default: "deve ser um de: %{list}"
26
+ range: "deve ser um de: %{list_left} - %{list_right}"
27
+ inclusion?: "deve ser um de: %{list}"
28
+ includes?: "deve incluir %{value}"
29
+ bool?: "deve ser booleano"
30
+ true?: "deve ser verdadeiro"
31
+ false?: "deve ser falso"
32
+ int?: "deve ser um número inteiro"
33
+ float?: "deve ser um número real"
34
+ decimal?: "deve ser um número decimal"
35
+ date?: "deve ser no formato de data"
36
+ date_time?: "deve ser no formato de data e hora"
37
+ time?: "deve ser no formato de tempo"
38
+ key?: "é requerido"
39
+ attr?: "é requerido"
40
+ lt?: "deve ser menor que %{num}"
41
+ lteq?: "deve ser menor ou igual a %{num}"
42
+ max_size?: "tamanho não pode ser maior que %{num}"
43
+ min_size?: "tamanho não pode ser menor que %{num}"
44
+ none?: "não pode ser definido"
45
+ str?: "deve ser do tipo texto"
46
+ type?: "deve ser do tipo %{type}"
47
+ size?:
48
+ arg:
49
+ default: "tamanho deve ser %{size}"
50
+ range: "tamanho deve ser entre %{size_left} e %{size_right}"
51
+ value:
52
+ string:
53
+ arg:
54
+ default: "deve ser %{size} caracteres"
55
+ range: "deve ser entre %{size_left} e %{size_right} caracteres"
56
+ custom:
57
+ default:
58
+ taken: "não está disponível"
59
+ not_found: "não encontrado"
60
+ password_confirmation: "não corresponde à senha"
61
+ login_not_found: "Credenciais inválidas"
62
+ inactive_account: "Sua conta está suspensa ou inativa"
63
+ future: "deve ser no futuro"
64
+ macro:
65
+ email_format: "não é um email válido"
66
+ login_format: "login inválido"
67
+ name_format: "deve ter entre %{min} e %{max} caracteres"
68
+ password_format: "deve ter entre %{min} e %{max} caracteres"
69
+ phone_format: "não é um número de celular válido"
70
+ auction_context:
71
+ create:
72
+ finished_at: "deve ser depois da hora de início"
@@ -0,0 +1,12 @@
1
+ pt-BR:
2
+ mail:
3
+ general:
4
+ hello: "Olá %{name}"
5
+ app_name: "AuctionFun"
6
+ team: "Time AuctionFun"
7
+ user_context:
8
+ registration:
9
+ subject: "Bem vindo a AuctionFun"
10
+ body:
11
+ description: "Bem-vindo/a à nossa plataforma! Estamos encantados por tê-lo/a conosco. Se tiver alguma dúvida ou precisar de ajuda, não hesite em entrar em contato."
12
+ email_confirmation_token: "Esse é o seu token de confirmação: <b>%{token}</b>"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Business
5
+ module Configuration
6
+ AUCTION_KINDS = Relations::Auctions::KINDS.values
7
+ AUCTION_STATUSES = Relations::Auctions::STATUSES.values
8
+ AUCTION_MIN_TITLE_LENGTH = 6
9
+ AUCTION_MAX_TITLE_LENGTH = 255
10
+ AUCTION_STOPWATCH_MIN_VALUE = 15
11
+ AUCTION_STOPWATCH_MAX_VALUE = 60
12
+ MIN_NAME_LENGTH = 6
13
+ MAX_NAME_LENGTH = 128
14
+ MIN_PASSWORD_LENGTH = 6
15
+ MAX_PASSWORD_LENGTH = 128
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Business
5
+ # Responsible for generating interaction tokens with system users for general operations.
6
+ module TokenGenerator
7
+ def self.generate_email_token(length = 20)
8
+ rlength = (length * 3) / 4
9
+ SecureRandom.urlsafe_base64(rlength).tr("lIO0", "sxyz")
10
+ end
11
+
12
+ def self.generate_phone_token(length = 6)
13
+ rand(0o00000..999_999).to_s.rjust(length, "0")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module AuctionContext
6
+ ##
7
+ # Abstract base class for insert new tuples on auctions table.
8
+ # @abstract
9
+ class CreateAuction < ROM::Commands::Create[:sql]
10
+ relation :auctions
11
+ register_as :create
12
+ result :one
13
+
14
+ use :timestamps
15
+ timestamp :created_at, :updated_at
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module AuctionContext
6
+ ##
7
+ # Abstract base class for removes tuples in auctions table.
8
+ # @abstract
9
+ class DeleteAuction < ROM::Commands::Delete[:sql]
10
+ relation :auctions
11
+ register_as :delete
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module AuctionContext
6
+ ##
7
+ # Abstract base class for updates all tuples in its auctions table with new attributes
8
+ # @abstract
9
+ class UpdateAuction < ROM::Commands::Update[:sql]
10
+ relation :auctions
11
+ register_as :update
12
+
13
+ use :timestamps
14
+ timestamp :updated_at
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module BidContext
6
+ ##
7
+ # Abstract base class for insert new tuples on bids table.
8
+ # @abstract
9
+ class CreateBid < ROM::Commands::Create[:sql]
10
+ relation :bids
11
+ register_as :create
12
+ result :one
13
+
14
+ use :timestamps
15
+ timestamp :created_at, :updated_at
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module BidContext
6
+ ##
7
+ # Abstract base class for removes tuples in bids table.
8
+ # @abstract
9
+ class DeleteBid < ROM::Commands::Delete[:sql]
10
+ relation :bids
11
+ register_as :delete
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module BidContext
6
+ ##
7
+ # Abstract base class for updates all tuples in its bids table with new attributes
8
+ # @abstract
9
+ class UpdateBid < ROM::Commands::Update[:sql]
10
+ relation :bids
11
+ register_as :update
12
+
13
+ use :timestamps
14
+ timestamp :updated_at
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module StaffContext
6
+ ##
7
+ # Abstract base class for insert new tuples on staffs table.
8
+ # @abstract
9
+ class CreateStaff < ROM::Commands::Create[:sql]
10
+ relation :staffs
11
+ register_as :create
12
+ result :one
13
+
14
+ use :timestamps
15
+ timestamp :created_at, :updated_at
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Commands
5
+ module UserContext
6
+ ##
7
+ # Abstract base class for insert new tuples on users table.
8
+ # @abstract
9
+ class CreateUser < ROM::Commands::Create[:sql]
10
+ relation :users
11
+ register_as :create
12
+ result :one
13
+
14
+ use :timestamps
15
+ timestamp :created_at, :updated_at
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "phonelib"
4
+
5
+ module AuctionFunCore
6
+ module Contracts
7
+ # Abstract base class for contracts.
8
+ # @abstract
9
+ class ApplicationContract < Dry::Validation::Contract
10
+ include AuctionFunCore::Business::Configuration
11
+
12
+ I18N_MACRO_SCOPE = "contracts.errors.custom.macro"
13
+ EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d-]+(\.[a-z\d-]+)*\.[a-z]+\z/i
14
+
15
+ config.messages.backend = :i18n
16
+ config.messages.default_locale = I18n.default_locale
17
+ config.messages.top_namespace = "contracts"
18
+ config.messages.load_paths << Application.root.join("i18n/#{I18n.default_locale}/contracts/contracts.#{I18n.default_locale}.yml").to_s
19
+
20
+ register_macro(:email_format) do
21
+ next if EMAIL_REGEX.match?(value)
22
+
23
+ key.failure(I18n.t(:email_format, scope: I18N_MACRO_SCOPE))
24
+ end
25
+
26
+ register_macro(:login_format) do
27
+ next if EMAIL_REGEX.match?(value) || Phonelib.parse(value).valid?
28
+
29
+ key.failure(I18n.t(:login_format, scope: I18N_MACRO_SCOPE))
30
+ end
31
+
32
+ register_macro(:name_format) do
33
+ next if value.length.between?(MIN_NAME_LENGTH, MAX_NAME_LENGTH)
34
+
35
+ key.failure(
36
+ I18n.t(:name_format, scope: I18N_MACRO_SCOPE, min: MIN_NAME_LENGTH, max: MAX_NAME_LENGTH)
37
+ )
38
+ end
39
+
40
+ register_macro(:phone_format) do
41
+ next if ::Phonelib.parse(value).valid?
42
+
43
+ key.failure(I18n.t(:phone_format, scope: I18N_MACRO_SCOPE))
44
+ end
45
+
46
+ register_macro(:password_format) do
47
+ next if value.length.between?(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH)
48
+
49
+ key.failure(
50
+ I18n.t(:password_format, scope: I18N_MACRO_SCOPE, min: MIN_PASSWORD_LENGTH, max: MAX_PASSWORD_LENGTH)
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end