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.
- checksums.yaml +4 -4
- data/.standard.yml +2 -0
- data/CHANGELOG.md +23 -0
- data/Procfile +1 -0
- data/README.md +34 -32
- data/Rakefile +1 -1
- data/i18n/en-US/contracts/contracts.en-US.yml +3 -0
- data/i18n/en-US/mail/application.en-US.yml +7 -0
- data/i18n/en-US/mail/auction_context/pre_auction/auction_start_reminder.en-US.yml +11 -0
- data/i18n/pt-BR/contracts/contracts.pt-BR.yml +3 -0
- data/i18n/pt-BR/mail/application.pt-BR.yml +7 -0
- data/i18n/pt-BR/mail/auction_context/pre_auction/auction_start_reminder.pt-BR.yml +11 -0
- data/lib/auction_fun_core/business/configuration.rb +31 -0
- data/lib/auction_fun_core/business/token_generator.rb +19 -1
- data/lib/auction_fun_core/contracts/application_contract.rb +9 -1
- data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +35 -20
- data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +23 -1
- data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +22 -1
- data/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb +48 -0
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +19 -7
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +19 -7
- data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +19 -7
- data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +16 -4
- data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +17 -5
- data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +16 -4
- data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +20 -11
- data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +18 -9
- data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +19 -10
- data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +18 -4
- data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +20 -8
- data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +18 -4
- data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +17 -2
- data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +17 -2
- data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +26 -8
- data/lib/auction_fun_core/entities/auction.rb +48 -4
- data/lib/auction_fun_core/entities/bid.rb +3 -2
- data/lib/auction_fun_core/entities/staff.rb +15 -2
- data/lib/auction_fun_core/entities/user.rb +31 -2
- data/lib/auction_fun_core/events/app.rb +8 -2
- data/lib/auction_fun_core/events/listener.rb +19 -16
- data/lib/auction_fun_core/operations/auction_context/create_operation.rb +25 -9
- data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +36 -3
- data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +36 -2
- data/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb +96 -0
- data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +82 -10
- data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +81 -10
- data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +81 -12
- data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +36 -1
- data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +36 -1
- data/lib/auction_fun_core/relations/auctions.rb +178 -97
- data/lib/auction_fun_core/relations/bids.rb +18 -0
- data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +40 -11
- data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -5
- data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +63 -21
- data/lib/auction_fun_core/repos/user_context/user_repository.rb +69 -25
- data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +7 -1
- data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +7 -1
- data/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb +35 -0
- data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +1 -1
- data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +1 -1
- data/lib/auction_fun_core/services/mail/templates/auction_context/pre_auction/auction_start_reminder.html.erb +192 -0
- data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +6 -0
- data/lib/auction_fun_core/version.rb +1 -1
- data/lib/auction_fun_core/workers/application_job.rb +10 -0
- data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +7 -2
- data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +6 -2
- data/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb +44 -0
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +6 -3
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +6 -3
- data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +6 -2
- data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +6 -3
- data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +12 -7
- data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +11 -5
- data/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb +48 -0
- data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +8 -6
- data/system/providers/background_job.rb +6 -0
- metadata +10 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a93057cdc62225a319b45c2836b5cfd713935664c8a7d9bdf2d39678909dacc7
|
|
4
|
+
data.tar.gz: 87f51a7eb83f0b47bc13394c36e37f36821a8ef5f4c429ec18e272155d9a1261
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70b11f00396f1195ae8e7060eb8316141abbe3e3f30621d80769d94b63b4d1469695b6ca0a35a9910419e7579f047b2bd9d4f7a3ad469803cf47cb3aae4efc75
|
|
7
|
+
data.tar.gz: 520de3854f324a0e79bca1c4bfdfe69288077e208de37831b3c25cd84e75acb2664f79cf87372cee2ffb4a4a3800398b0fd72c537cb83a330b925c2d0113cdbe
|
data/.standard.yml
CHANGED
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
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 [
|
|
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
|
-
|
|
16
|
+
bundle install
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Or install it yourself as:
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 `
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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
|
@@ -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"
|
|
@@ -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"
|
|
@@ -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
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
50
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
66
|
-
#
|
|
83
|
+
# Validates the initial bid amount based on auction type.
|
|
67
84
|
rule(:initial_bid_cents) do
|
|
68
|
-
# Must be
|
|
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
|
|
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
|
-
#
|
|
83
|
-
#
|
|
98
|
+
# Validates stopwatch settings for penny auctions.
|
|
84
99
|
rule(:stopwatch) do
|
|
85
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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]
|