auction_fun_core 0.8.7 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +2 -0
  3. data/CHANGELOG.md +23 -0
  4. data/Procfile +1 -0
  5. data/README.md +34 -32
  6. data/Rakefile +1 -1
  7. data/i18n/en-US/contracts/contracts.en-US.yml +3 -0
  8. data/i18n/en-US/mail/application.en-US.yml +7 -0
  9. data/i18n/en-US/mail/auction_context/pre_auction/auction_start_reminder.en-US.yml +11 -0
  10. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +3 -0
  11. data/i18n/pt-BR/mail/application.pt-BR.yml +7 -0
  12. data/i18n/pt-BR/mail/auction_context/pre_auction/auction_start_reminder.pt-BR.yml +11 -0
  13. data/lib/auction_fun_core/business/configuration.rb +31 -0
  14. data/lib/auction_fun_core/business/token_generator.rb +19 -1
  15. data/lib/auction_fun_core/contracts/application_contract.rb +9 -1
  16. data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +35 -20
  17. data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +23 -1
  18. data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +22 -1
  19. data/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb +48 -0
  20. data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +19 -7
  21. data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +19 -7
  22. data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +19 -7
  23. data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +16 -4
  24. data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +17 -5
  25. data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +16 -4
  26. data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +20 -11
  27. data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +18 -9
  28. data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +19 -10
  29. data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +18 -4
  30. data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +20 -8
  31. data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +18 -4
  32. data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +17 -2
  33. data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +17 -2
  34. data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +26 -8
  35. data/lib/auction_fun_core/entities/auction.rb +48 -4
  36. data/lib/auction_fun_core/entities/bid.rb +3 -2
  37. data/lib/auction_fun_core/entities/staff.rb +15 -2
  38. data/lib/auction_fun_core/entities/user.rb +31 -2
  39. data/lib/auction_fun_core/events/app.rb +8 -2
  40. data/lib/auction_fun_core/events/listener.rb +19 -16
  41. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +25 -9
  42. data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +36 -3
  43. data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +36 -2
  44. data/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb +96 -0
  45. data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +82 -10
  46. data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +81 -10
  47. data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +81 -12
  48. data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +36 -1
  49. data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +36 -1
  50. data/lib/auction_fun_core/relations/auctions.rb +178 -97
  51. data/lib/auction_fun_core/relations/bids.rb +18 -0
  52. data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +40 -11
  53. data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -5
  54. data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +63 -21
  55. data/lib/auction_fun_core/repos/user_context/user_repository.rb +69 -25
  56. data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +7 -1
  57. data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +7 -1
  58. data/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb +35 -0
  59. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +1 -1
  60. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +1 -1
  61. data/lib/auction_fun_core/services/mail/templates/auction_context/pre_auction/auction_start_reminder.html.erb +192 -0
  62. data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +6 -0
  63. data/lib/auction_fun_core/version.rb +1 -1
  64. data/lib/auction_fun_core/workers/application_job.rb +10 -0
  65. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +7 -2
  66. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +6 -2
  67. data/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb +44 -0
  68. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +6 -3
  69. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +6 -3
  70. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +6 -2
  71. data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +6 -3
  72. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +12 -7
  73. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +11 -5
  74. data/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb +48 -0
  75. data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +8 -6
  76. data/system/providers/background_job.rb +6 -0
  77. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3dc7fade29c1849f1e1c8d9a67cd060e0ceeac555290cf9cc3588a27eab72ee0
4
- data.tar.gz: 7995c3ca65daa279c8e989771f7989e06695fcbdef4d7472c4f5aee0c02048f1
3
+ metadata.gz: a93057cdc62225a319b45c2836b5cfd713935664c8a7d9bdf2d39678909dacc7
4
+ data.tar.gz: 87f51a7eb83f0b47bc13394c36e37f36821a8ef5f4c429ec18e272155d9a1261
5
5
  SHA512:
6
- metadata.gz: ddfa76b5f57846ed62986520b98c367f46490c6d74aebd55b45ff033f84ddfb31f95dc370afec5159b49e93bdf678b4d63437b58bcc47e63c6461b5963aa6d31
7
- data.tar.gz: eddbd9f79955aed50f5ac48605a16454bb93329e3e87fb21eb8437c0af43291b0ec84f3b29099635fa7cb89cab0e4cd0cdc8cfec433b3e003d1b69a94ace1f4a
6
+ metadata.gz: 70b11f00396f1195ae8e7060eb8316141abbe3e3f30621d80769d94b63b4d1469695b6ca0a35a9910419e7579f047b2bd9d4f7a3ad469803cf47cb3aae4efc75
7
+ data.tar.gz: 520de3854f324a0e79bca1c4bfdfe69288077e208de37831b3c25cd84e75acb2664f79cf87372cee2ffb4a4a3800398b0fd72c537cb83a330b925c2d0113cdbe
data/.standard.yml CHANGED
@@ -1,3 +1,5 @@
1
1
  # For available configuration options, see:
2
2
  # https://github.com/standardrb/standard
3
+ format: progress
4
+ parallel: true
3
5
  ruby_version: 3.0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.8.9] - 2024-04-29
4
+
5
+ ### Added
6
+
7
+ - Using yadr as a standard documentation tool;
8
+
9
+ ### Changed
10
+
11
+ - Upgrade README;
12
+ - Updating CI to run lint;
13
+ - Using the heredoc standard to build SQL queries;
14
+
15
+ ## [0.8.8] - 2024-04-25
16
+
17
+ ### Added
18
+
19
+ - Auction start reminder sent to participants;
20
+ - I18n time format;
21
+
22
+ ### Fixed:
23
+
24
+ - I18n messages for winner and auction participant emails;
25
+
3
26
  ## [0.8.7] - 2024-04-23
4
27
 
5
28
  ### Added
data/Procfile CHANGED
@@ -2,3 +2,4 @@ database: postgres
2
2
  redis: redis-server
3
3
  mailserver: maildev --hide-extensions STARTTLS
4
4
  background: bundle exec sidekiq -r ./config/app.rb
5
+ documentation: bundle exec yard server --reload
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AuctionFunCore
2
2
 
3
- This lib contains all the business logic necessary to run the auctions. A principle and standard must be strictly followed: The [SRP principle](https://en.wikipedia.org/wiki/Single_responsibility_principle)The principle of single responsibility and some standard [clean architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) concepts.
3
+ This lib contains all the business logic necessary to run the auctions. A principle and standard must be strictly followed: The [The principle of single responsibility](https://en.wikipedia.org/wiki/Single_responsibility_principle) and [clean architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) concepts.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,13 +13,13 @@ gem 'auction_fun_core'
13
13
  And then execute:
14
14
 
15
15
  ```sh
16
- user@host:~$ bundle install
16
+ bundle install
17
17
  ```
18
18
 
19
19
  Or install it yourself as:
20
20
 
21
21
  ```sh
22
- user@host:~$ gem install auction_fun_core
22
+ gem install auction_fun_core
23
23
  ```
24
24
 
25
25
  ## Getting Started
@@ -27,10 +27,10 @@ user@host:~$ gem install auction_fun_core
27
27
  Initially, download the project remotely and copy the templates from the project's environment variables:
28
28
 
29
29
  ```sh
30
- user@host:~$ git clone git@github.com:ricardopacheco/auction-fun-core.git core
31
- user@host:~$ cd core
32
- user@host:~$ cp .env.development.template .env.development
33
- user@host:~$ cp .env.test.template .env.test
30
+ git clone git@github.com:ricardopacheco/auction-fun-core.git core
31
+ cd core
32
+ cp .env.development.template .env.development
33
+ cp .env.test.template .env.test
34
34
  ```
35
35
 
36
36
  > As the idea of this project is to be a lib, it was decided to use a specific environment variable called `APP_ENV`, so as not to conflict with others if the lib is used by a framework.
@@ -40,7 +40,7 @@ user@host:~$ cp .env.test.template .env.test
40
40
  Configure the `.env.development` file with the values according to your machine or network.
41
41
 
42
42
  Run the commands below to create the database and its structure, remembering to replace
43
- the `userdb` by the user of your postgresql service. By default, if `APP_ENV` is not provided
43
+ the `postgres` by the user of your postgresql service. By default, if `APP_ENV` is not provided
44
44
  is considered the value `development` by default.
45
45
 
46
46
  ### OS dependencies
@@ -52,50 +52,50 @@ is considered the value `development` by default.
52
52
  #### Database (PostgreSQL)
53
53
 
54
54
  ```sh
55
- user@host:~$ sudo apt install build-essential libssl-dev libreadline-dev zlib1g-dev libcurl4-openssl-dev uuid-dev
56
- user@host:~$ asdf plugin add postgres
57
- user@host:~$ asdf install postgres 16.1
58
- user@host:~$ rm -rf $HOME/.asdf/installs/postgres/16.1/data
59
- user@host:~$ initdb -D $HOME/.asdf/installs/postgres/16.1/data -U postgres
55
+ sudo apt install build-essential libssl-dev libreadline-dev zlib1g-dev libcurl4-openssl-dev uuid-dev
56
+ asdf plugin add postgres
57
+ asdf install postgres 16.1
58
+ rm -rf $HOME/.asdf/installs/postgres/16.1/data
59
+ initdb -D $HOME/.asdf/installs/postgres/16.1/data -U postgres
60
60
  ```
61
61
 
62
62
  ```sh
63
- user@host:~$ sudo apt install autoconf patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev
64
- user@host:~$ asdf plugin add ruby
65
- user@host:~$ asdf install ruby 3.3.0
66
- user@host:~$ gem install pg -v 1.5.5 --verbose -- --with-pg-config=$HOME/.asdf/installs/postgres/16.1/bin/pg_config # Fix pg_config
67
- user@host:~$ bin/setup
63
+ sudo apt install autoconf patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev
64
+ asdf plugin add ruby
65
+ asdf install ruby 3.3.0
66
+ gem install pg -v 1.5.5 --verbose -- --with-pg-config=$HOME/.asdf/installs/postgres/16.1/bin/pg_config # Fix pg_config
67
+ bin/setup
68
68
  ```
69
69
 
70
70
  #### Overmind (Procfile manager)
71
71
 
72
72
  ```sh
73
- user@host:~$ asdf install golang latest
74
- user@host:~$ go install github.com/DarthSim/overmind/v2
75
- user@host:~$ asdf reshim
73
+ asdf install golang latest
74
+ go install github.com/DarthSim/overmind/v2
75
+ asdf reshim
76
76
  ```
77
77
 
78
78
  #### Create database for development environment
79
79
 
80
- > **[postgres]** in rake commands is a name of user for postgres. Change if needed
80
+ - **postgres** in rake commands is a name of user for postgres. Change if needed
81
81
 
82
82
  In current tab:
83
83
 
84
84
  ```sh
85
- user@host:~$ overmind s -l database
85
+ overmind s -l database
86
86
  ```
87
87
 
88
88
  Open a new tab and create development database:
89
89
 
90
90
  ```sh
91
- user@host:~$ bundle exec rake 'auction_fun_core:db:create_database[postgres]'
92
- user@host:~$ bundle exec rake 'auction_fun_core:db:migrate'
91
+ bundle exec rake 'auction_fun_core:db:create_database[postgres]'
92
+ bundle exec rake 'auction_fun_core:db:migrate'
93
93
  ```
94
94
 
95
95
  Now come back to overmind tab, kill the current database process using **Ctrl+c**. After that:
96
96
 
97
97
  ```sh
98
- user@host:~$ overmind start
98
+ overmind start
99
99
  ```
100
100
 
101
101
  This will start all required services needed to run core application.
@@ -103,7 +103,7 @@ This will start all required services needed to run core application.
103
103
  In new tab, you could run seed data for development with
104
104
 
105
105
  ```sh
106
- user@host:~$ bundle exec rake 'auction_fun_core:db:seed'
106
+ bundle exec rake 'auction_fun_core:db:seed'
107
107
  ```
108
108
 
109
109
  ## Interactive prompt
@@ -117,9 +117,9 @@ Configure the `.env.test` file with the values according to your machine or netw
117
117
  Run the test suite with the coverage report using the command:
118
118
 
119
119
  ```sh
120
- user@host:~$ APP_ENV=test bundle exec rake auction_fun_core:db:create_database[userdb]
121
- user@host:~$ APP_ENV=test bundle exec rake auction_fun_core:db:migrate
122
- user@host:~$ CI=true APP_ENV=test bundle exec rspec .
120
+ APP_ENV=test bundle exec rake auction_fun_core:db:create_database[postgres]
121
+ APP_ENV=test bundle exec rake auction_fun_core:db:migrate
122
+ CI=true APP_ENV=test bundle exec rspec .
123
123
  ```
124
124
 
125
125
  ## Documentation
@@ -127,10 +127,12 @@ user@host:~$ CI=true APP_ENV=test bundle exec rspec .
127
127
  This project uses `yadr` as a documentation tool. To generate documentation and view it, run
128
128
 
129
129
  ```sh
130
- user@host:~$ bundle exec yard server --reload
130
+ bundle exec yard server --reload
131
131
  ```
132
132
 
133
- Documentation will be available at `http://localhost:8808`
133
+ Documentation will be available at `http://localhost:8808`.
134
+
135
+ > If you already use overmind, the documentation server starts automatically.
134
136
 
135
137
  ## External resources
136
138
 
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'config/application'
3
+ require_relative "config/application"
4
4
  require "bundler/gem_tasks"
5
5
  require "rspec/core/rake_task"
6
6
 
@@ -70,6 +70,9 @@ en-US:
70
70
  auction_context:
71
71
  create:
72
72
  finished_at: "must be after started time"
73
+ pre_auction:
74
+ auction_start_reminder:
75
+ auction_already_started: "auction already started"
73
76
  post_auction:
74
77
  participant:
75
78
  none: "there was no participation from this user in the auction reported"
@@ -52,6 +52,13 @@ en-US:
52
52
  - :year
53
53
  - :month
54
54
  - :day
55
+ time:
56
+ am: am
57
+ formats:
58
+ default: "%a, %d %b %Y %H:%M:%S %z"
59
+ long: "%B %d, %Y %H:%M"
60
+ short: "%d %b %H:%M"
61
+ pm: pm
55
62
  application:
56
63
  general:
57
64
  hello: "Hi %{name}"
@@ -0,0 +1,11 @@
1
+ pt-BR:
2
+ mail:
3
+ auction_context:
4
+ pre_auction:
5
+ auction_start_reminder_mailer:
6
+ subject: "The %{title} auction will start soon!"
7
+ body:
8
+ description: "We are excited to inform you that the auction you are participating in will begin soon!"
9
+ auction_date: "Start Time"
10
+ link_to_auction: "Click the link below to view auction details"
11
+ thanks: "Thank you for your participation and we wish you good luck!"
@@ -70,6 +70,9 @@ pt-BR:
70
70
  auction_context:
71
71
  create:
72
72
  finished_at: "deve ser depois da hora de início"
73
+ pre_auction:
74
+ auction_start_reminder:
75
+ auction_already_started: "leilão já foi iniciado"
73
76
  post_auction:
74
77
  participant:
75
78
  none: "não houve nenhuma participação deste usuário no leilão informado"
@@ -52,6 +52,13 @@ pt-BR:
52
52
  - :day
53
53
  - :month
54
54
  - :year
55
+ time:
56
+ am: am
57
+ formats:
58
+ default: "%a, %d de %B de %Y, %H:%M:%S %z"
59
+ long: "%d de %B de %Y, %H:%M"
60
+ short: "%d de %B, %H:%M"
61
+ pm: pm
55
62
  application:
56
63
  general:
57
64
  hello: "Olá %{name}"
@@ -0,0 +1,11 @@
1
+ pt-BR:
2
+ mail:
3
+ auction_context:
4
+ pre_auction:
5
+ auction_start_reminder_mailer:
6
+ subject: "O leilão %{title} começará em breve!"
7
+ body:
8
+ description: "Estamos entusiasmados em informar que o leilão em que você está participando começará em breve!"
9
+ auction_date: "Hora de Início"
10
+ link_to_auction: "Clique no link abaixo para ver os detalhes do leilão"
11
+ thanks: "Agradecemos pela sua participação e desejamos boa sorte!"
@@ -2,16 +2,47 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Business
5
+ # The Configuration module contains constants that configure various aspects of auctions,
6
+ # user settings, and other business rules within the AuctionFun application.
5
7
  module Configuration
8
+ # An array of available auction kinds derived from auction relations.
9
+ # @return [Array<String>] a list of all possible auction kinds
6
10
  AUCTION_KINDS = Relations::Auctions::KINDS.values
11
+
12
+ # An array of valid auction statuses derived from auction relations.
13
+ # @return [Array<String>] a list of all valid auction statuses
7
14
  AUCTION_STATUSES = Relations::Auctions::STATUSES.values
15
+
16
+ # The minimum length for an auction title.
17
+ # @return [Integer] the minimum number of characters allowed in an auction title
8
18
  AUCTION_MIN_TITLE_LENGTH = 6
19
+
20
+ # The maximum length for an auction title.
21
+ # @return [Integer] the maximum number of characters allowed in an auction title
9
22
  AUCTION_MAX_TITLE_LENGTH = 255
23
+
24
+ # The minimum value for the auction stopwatch timer.
25
+ # @return [Integer] the minimum seconds count for the auction stopwatch timer
10
26
  AUCTION_STOPWATCH_MIN_VALUE = 15
27
+
28
+ # The maximum value for the auction stopwatch timer.
29
+ # @return [Integer] the maximum seconds count for the auction stopwatch timer
11
30
  AUCTION_STOPWATCH_MAX_VALUE = 60
31
+
32
+ # The minimum length for a user's name.
33
+ # @return [Integer] the minimum number of characters allowed in a person's name
12
34
  MIN_NAME_LENGTH = 6
35
+
36
+ # The maximum length for a user's name.
37
+ # @return [Integer] the maximum number of characters allowed in a person's name
13
38
  MAX_NAME_LENGTH = 128
39
+
40
+ # The minimum length for a user's password.
41
+ # @return [Integer] the minimum number of characters required in a person's password
14
42
  MIN_PASSWORD_LENGTH = 6
43
+
44
+ # The maximum length for a user's password.
45
+ # @return [Integer] the maximum number of characters allowed in a person's password
15
46
  MAX_PASSWORD_LENGTH = 128
16
47
  end
17
48
  end
@@ -2,13 +2,31 @@
2
2
 
3
3
  module AuctionFunCore
4
4
  module Business
5
- # Responsible for generating interaction tokens with system users for general operations.
5
+ # The TokenGenerator module is responsible for generating interaction tokens
6
+ # used in various parts of the AuctionFun application for authentication and
7
+ # verification purposes, particularly in interactions with system users.
6
8
  module TokenGenerator
9
+ # Generates a secure, URL-safe base64 token primarily used for email verification.
10
+ # This method modifies certain characters to avoid common readability issues.
11
+ #
12
+ # @param length [Integer] the desired length of the generated token before modification
13
+ # @return [String] a URL-safe, base64 encoded string suitable for email verification links
14
+ # @example Generating an email token
15
+ # email_token = AuctionFunCore::Business::TokenGenerator.generate_email_token(20)
16
+ # puts email_token # Output example: "V4Ph2wkJG_bRzs_zuGyJ"
7
17
  def self.generate_email_token(length = 20)
8
18
  rlength = (length * 3) / 4
9
19
  SecureRandom.urlsafe_base64(rlength).tr("lIO0", "sxyz")
10
20
  end
11
21
 
22
+ # Generates a numerical token used for phone verification processes.
23
+ # The token is zero-padded to ensure it meets the required length.
24
+ #
25
+ # @param length [Integer] the desired length of the numerical token
26
+ # @return [String] a string of digits, zero-padded to the specified length
27
+ # @example Generating a phone token
28
+ # phone_token = AuctionFunCore::Business::TokenGenerator.generate_phone_token(6)
29
+ # puts phone_token # Output example: "045673"
12
30
  def self.generate_phone_token(length = 6)
13
31
  rand(0o00000..999_999).to_s.rjust(length, "0")
14
32
  end
@@ -4,7 +4,10 @@ require "phonelib"
4
4
 
5
5
  module AuctionFunCore
6
6
  module Contracts
7
- # Abstract base class for contracts.
7
+ ##
8
+ # The class includes several macros for common validation tasks, such as validating email format,
9
+ # login format, name format, phone number format, and password format. These macros utilize
10
+ # regular expressions and predefined length ranges to ensure the input data meets specific criteria.
8
11
  # @abstract
9
12
  class ApplicationContract < Dry::Validation::Contract
10
13
  include AuctionFunCore::Business::Configuration
@@ -17,18 +20,21 @@ module AuctionFunCore
17
20
  config.messages.top_namespace = "contracts"
18
21
  config.messages.load_paths << Application.root.join("i18n/#{I18n.default_locale}/contracts/contracts.#{I18n.default_locale}.yml").to_s
19
22
 
23
+ # Validates whether the provided value matches the standard email format.
20
24
  register_macro(:email_format) do
21
25
  next if EMAIL_REGEX.match?(value)
22
26
 
23
27
  key.failure(I18n.t(:email_format, scope: I18N_MACRO_SCOPE))
24
28
  end
25
29
 
30
+ # Validates whether the provided value matches either the email format or a valid phone number format using Phonelib.
26
31
  register_macro(:login_format) do
27
32
  next if EMAIL_REGEX.match?(value) || Phonelib.parse(value).valid?
28
33
 
29
34
  key.failure(I18n.t(:login_format, scope: I18N_MACRO_SCOPE))
30
35
  end
31
36
 
37
+ # Validates whether the length of the provided name falls within the specified range.
32
38
  register_macro(:name_format) do
33
39
  next if value.length.between?(MIN_NAME_LENGTH, MAX_NAME_LENGTH)
34
40
 
@@ -37,12 +43,14 @@ module AuctionFunCore
37
43
  )
38
44
  end
39
45
 
46
+ # Validates whether the provided value matches a valid phone number format using Phonelib.
40
47
  register_macro(:phone_format) do
41
48
  next if ::Phonelib.parse(value).valid?
42
49
 
43
50
  key.failure(I18n.t(:phone_format, scope: I18N_MACRO_SCOPE))
44
51
  end
45
52
 
53
+ # Validates whether the length of the provided password falls within the specified range.
46
54
  register_macro(:password_format) do
47
55
  next if value.length.between?(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH)
48
56
 
@@ -3,15 +3,36 @@
3
3
  module AuctionFunCore
4
4
  module Contracts
5
5
  module AuctionContext
6
- # Contract class to create new auctions.
6
+ # This class is designed to validate the creation of new auctions.
7
+ # It includes various validations such as staff existence, auction kind, timing, and initial bids.
8
+ #
9
+ # @example Creating a new auction
10
+ # contract = AuctionFunCore::Contracts::AuctionContext::CreateContract.new
11
+ # attributes = {
12
+ # staff_id: 1,
13
+ # title: "Rare Antique Vase",
14
+ # kind: "standard",
15
+ # started_at: Time.current + 5.days,
16
+ # finished_at: Time.current + 10.days,
17
+ # initial_bid_cents: 5000
18
+ # }
19
+ # result = contract.call(attributes)
20
+ # if result.success?
21
+ # puts "Auction created successfully."
22
+ # else
23
+ # puts "Failed to create auction: #{result.errors.to_h}"
24
+ # end
25
+ #
7
26
  class CreateContract < Contracts::ApplicationContract
8
27
  include AuctionFunCore::Business::Configuration
9
28
 
29
+ # Additional validations specific for non-penny auctions.
10
30
  REQUIRED_FINISHED_AT = AUCTION_KINDS - ["penny"]
11
31
 
32
+ # Repository initialized to retrieve staff data for validation.
12
33
  option :staff_repo, default: proc { Repos::StaffContext::StaffRepository.new }
13
34
 
14
- # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations.
35
+ # Defines necessary parameters and initializes some default values.
15
36
  params do
16
37
  required(:staff_id).filled(:integer)
17
38
  required(:title).filled(:string, size?: (AUCTION_MIN_TITLE_LENGTH..AUCTION_MAX_TITLE_LENGTH))
@@ -22,7 +43,7 @@ module AuctionFunCore
22
43
  optional(:initial_bid_cents).filled(:integer)
23
44
  optional(:stopwatch).filled(:integer)
24
45
 
25
- # Keys with a blank value are discarded.
46
+ # Parameters specifying the required input types and fields.
26
47
  before(:value_coercer) do |result|
27
48
  result.to_h.compact
28
49
  end
@@ -33,59 +54,53 @@ module AuctionFunCore
33
54
  end
34
55
  end
35
56
 
36
- # Validation for staff.
37
- # Validate whether the given staff is valid at the database level.
57
+ # Validates the existence of the staff.
38
58
  rule(:staff_id) do |context:|
39
59
  context[:staff] ||= staff_repo.by_id(value)
40
60
  key.failure(I18n.t("contracts.errors.custom.default.not_found")) unless context[:staff]
41
61
  end
42
62
 
43
- # Validation for started_at.
44
- # Validates if the entered date is greater than or equal to the current time.
63
+ # Validates that the starting time of the auction is in the future.
45
64
  rule(:started_at) do
46
65
  key.failure(I18n.t("contracts.errors.custom.default.future")) if key? && value <= Time.current
47
66
  end
48
67
 
49
- # Specific validation when the auction type is informed and it is not penny,
50
- # it must be mandatory to inform the auction closing date/time
68
+ # Validates that the finished_at time is specified for auctions types that require it,
69
+ # and is not specified for "penny" auctions.
51
70
  rule(:finished_at, :kind) do
52
71
  if key?(:kind) && !key?(:finished_at) && REQUIRED_FINISHED_AT.include?(values[:kind])
53
72
  key.failure(I18n.t("contracts.errors.filled?"))
54
73
  end
55
74
  end
56
75
 
57
- # Basic specific validation to check if the auction end time
58
- # is less than or equal to the start time.
76
+ # Validates that the auction end time is later than the start time.
59
77
  rule(:finished_at, :started_at) do
60
78
  if key?(:finished_at) && (values[:finished_at] <= values[:started_at])
61
79
  key.failure(I18n.t("contracts.errors.custom.auction_context.create.finished_at"))
62
80
  end
63
81
  end
64
82
 
65
- # Validation for initial bid amount.
66
- #
83
+ # Validates the initial bid amount based on auction type.
67
84
  rule(:initial_bid_cents) do
68
- # Must be filled if auction kind is not type penny.
85
+ # Must be specified and positive for non-penny auction types.
69
86
  key.failure(I18n.t("contracts.errors.filled?")) if !key? && REQUIRED_FINISHED_AT.include?(values[:kind])
70
87
 
71
- # Must be greater than zero if action kind is not type penny.
72
88
  if key? && REQUIRED_FINISHED_AT.include?(values[:kind]) && values[:initial_bid_cents] <= 0
73
89
  key.failure(I18n.t("contracts.errors.gt?", num: 0))
74
90
  end
75
91
 
76
- # Must be equal to zero if auction kind is type penny.
92
+ # Must be zero for penny auctions to ensure fairness.
77
93
  if key? && values[:kind] == "penny" && !values[:initial_bid_cents].zero?
78
94
  key.failure(I18n.t("contracts.errors.eql?", left: 0))
79
95
  end
80
96
  end
81
97
 
82
- # Validation for stopwatch.
83
- #
98
+ # Validates stopwatch settings for penny auctions.
84
99
  rule(:stopwatch) do
85
- # Must be filled if auction kind is type penny.
100
+ # Stopwatch must be specified for penny auctions.
86
101
  key.failure(I18n.t("contracts.errors.filled?")) if !key? && values[:kind] == "penny"
87
102
 
88
- # Must be an integer between 15 and 60.
103
+ # Stopwatch value must fall within the specified range.
89
104
  if key? && values[:kind] == "penny" && !value.between?(AUCTION_STOPWATCH_MIN_VALUE, AUCTION_STOPWATCH_MAX_VALUE)
90
105
  key.failure(
91
106
  I18n.t(
@@ -5,30 +5,52 @@ module AuctionFunCore
5
5
  module AuctionContext
6
6
  module PostAuction
7
7
  ##
8
- # Contract class for validate participation auction.
8
+ # This class is used to validate the participation of users in an auction.
9
+ # This contract ensures that both the auction and the participant exist and that the participant
10
+ # has already at least placed a bid. It utilizes repositories to fetch data about auctions, users, and bids.
11
+ #
12
+ # @example Using this class to validate a participant
13
+ # contract = AuctionFunCore::Contracts::AuctionContext::PostAuction::ParticipantContract.new
14
+ # attributes = { auction_id: 1, participant_id: 102 }
15
+ # validation_result = contract.call(attributes)
16
+ # if validation_result.success?
17
+ # puts "Participant validation passed"
18
+ # else
19
+ # puts "Participant validation failed: #{validation_result.errors.to_h}"
20
+ # end
9
21
  #
10
22
  class ParticipantContract < Contracts::ApplicationContract
23
+ # Scope for internationalization (i18n) entries specific to errors in this contract.
11
24
  I18N_SCOPE = "contracts.errors.custom.auction_context.post_auction.participation"
12
25
 
26
+ # Repository options initialized by default. These repositories handle data retrieval.
13
27
  option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new }
14
28
  option :user_repository, default: proc { Repos::UserContext::UserRepository.new }
15
29
  option :bid_repository, default: proc { Repos::BidContext::BidRepository.new }
16
30
 
31
+ # Defines the data types and required fields for the contract.
17
32
  params do
18
33
  required(:auction_id).filled(:integer)
19
34
  required(:participant_id).filled(:integer)
20
35
  end
21
36
 
37
+ # Validation rule for auction_id to ensure the auction exists.
38
+ # @param context [Hash] Optional context hash to store data and state during validation.
22
39
  rule(:auction_id) do |context:|
23
40
  context[:auction] ||= auction_repository.by_id(value)
24
41
  key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction]
25
42
  end
26
43
 
44
+ # Validation rule for participant_id to ensure the participant exists.
45
+ # @param context [Hash] Optional context hash to store data and state during validation.
27
46
  rule(:participant_id) do |context:|
28
47
  context[:participant] ||= user_repository.by_id(value)
29
48
  key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:participant]
30
49
  end
31
50
 
51
+ # Combined validation rule for auction_id and participant_id to check that the participant
52
+ # has not already placed a bid in the auction.
53
+ # @param context [Hash] Context containing the auction and participant objects.
32
54
  rule(:auction_id, :participant_id) do |context:|
33
55
  next if (rule_error?(:auction_id) || schema_error?(:auction_id)) || (rule_error?(:winner_id) || schema_error?(:winner_id))
34
56
  next if bid_repository.exists?(auction_id: values[:auction_id], user_id: values[:participant_id])
@@ -5,29 +5,50 @@ module AuctionFunCore
5
5
  module AuctionContext
6
6
  module PostAuction
7
7
  ##
8
- # Contract class for validate winner auction.
8
+ # This class validates the identification of the winning bidder
9
+ # in an auction context. It ensures that both the auction and the winner exist
10
+ # and are correctly associated within the system.
11
+ #
12
+ # @example Using this class to validate a winner
13
+ # contract = AuctionFunCore::Contracts::AuctionContext::PostAuction::WinnerContract.new
14
+ # attributes = { auction_id: 1, winner_id: 102 }
15
+ # validation_result = contract.call(attributes)
16
+ # if validation_result.success?
17
+ # puts "Winner validation passed"
18
+ # else
19
+ # puts "Winner validation failed: #{validation_result.errors.to_h}"
20
+ # end
9
21
  #
10
22
  class WinnerContract < Contracts::ApplicationContract
23
+ # Internationalization (i18n) scope for error messages related to winner validation.
11
24
  I18N_SCOPE = "contracts.errors.custom.auction_context.post_auction.winner"
12
25
 
26
+ # Repositories initialized by default to handle data retrieval for validation.
13
27
  option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new }
14
28
  option :user_repository, default: proc { Repos::UserContext::UserRepository.new }
15
29
 
30
+ # Parameters defining the expected input types and required fields.
16
31
  params do
17
32
  required(:auction_id).filled(:integer)
18
33
  required(:winner_id).filled(:integer)
19
34
  end
20
35
 
36
+ # Validation rule to ensure the auction exists.
37
+ # @param context [Hash] Optional context hash to store data and state during validation.
21
38
  rule(:auction_id) do |context:|
22
39
  context[:auction] ||= auction_repository.by_id(value)
23
40
  key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction]
24
41
  end
25
42
 
43
+ # Validation rule to ensure the winner exists.
44
+ # @param context [Hash] Optional context hash to store data and state during validation.
26
45
  rule(:winner_id) do |context:|
27
46
  context[:winner] ||= user_repository.by_id(value)
28
47
  key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:winner]
29
48
  end
30
49
 
50
+ # Combined rule to ensure that the declared winner is the actual winner recorded in the auction.
51
+ # @param context [Hash] Context containing the auction and winner objects.
31
52
  rule(:auction_id, :winner_id) do |context:|
32
53
  next if (rule_error?(:auction_id) || schema_error?(:auction_id)) || (rule_error?(:winner_id) || schema_error?(:winner_id))
33
54
  next if context[:auction].winner_id == values[:winner_id]