auction_fun_core 0.8.7 → 0.8.9

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 (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]