From 80fa3ece116159e47ef7bf64910be1c6c184b1c2 Mon Sep 17 00:00:00 2001 From: Ricardo Pacheco Date: Mon, 29 Apr 2024 12:57:39 -0300 Subject: [PATCH] [AF-43] Add documentation (#44) * Add documentation * Using the heredoc standard to build SQL queries --- .github/workflows/main.yml | 2 + .standard.yml | 2 + CHANGELOG.md | 12 + Gemfile | 4 + Gemfile.lock | 4 +- Procfile | 1 + README.md | 66 +++-- Rakefile | 2 +- .../business/configuration.rb | 31 ++ .../business/token_generator.rb | 20 +- .../contracts/application_contract.rb | 10 +- .../auction_context/create_contract.rb | 55 ++-- .../post_auction/participant_contract.rb | 24 +- .../post_auction/winner_contract.rb | 23 +- .../auction_start_reminder_contract.rb | 22 +- .../processor/finish/closed_contract.rb | 26 +- .../processor/finish/penny_contract.rb | 26 +- .../processor/finish/standard_contract.rb | 26 +- .../processor/pause_contract.rb | 20 +- .../processor/start_contract.rb | 22 +- .../processor/unpause_contract.rb | 20 +- .../bid_context/create_bid_closed_contract.rb | 31 +- .../bid_context/create_bid_penny_contract.rb | 27 +- .../create_bid_standard_contract.rb | 29 +- .../staff_context/authentication_contract.rb | 22 +- .../staff_context/registration_contract.rb | 28 +- .../user_context/authentication_contract.rb | 22 +- .../email_confirmation_contract.rb | 19 +- .../phone_confirmation_contract.rb | 19 +- .../user_context/registration_contract.rb | 34 ++- lib/auction_fun_core/entities/auction.rb | 7 +- lib/auction_fun_core/entities/bid.rb | 5 +- lib/auction_fun_core/entities/staff.rb | 17 +- lib/auction_fun_core/entities/user.rb | 33 ++- lib/auction_fun_core/events/app.rb | 10 +- lib/auction_fun_core/events/listener.rb | 35 ++- .../post_auction/participant_operation.rb | 39 ++- .../post_auction/winner_operation.rb | 38 ++- .../auction_start_reminder_operation.rb | 36 ++- .../processor/finish/closed_operation.rb | 92 +++++- .../processor/finish/penny_operation.rb | 91 +++++- .../processor/finish/standard_operation.rb | 93 +++++- .../processor/pause_operation.rb | 37 ++- .../processor/unpause_operation.rb | 37 ++- lib/auction_fun_core/relations/auctions.rb | 275 ++++++++++++------ .../auction_context/auction_repository.rb | 51 +++- .../repos/bid_context/bid_repository.rb | 32 +- .../repos/staff_context/staff_repository.rb | 84 ++++-- .../repos/user_context/user_repository.rb | 94 ++++-- .../post_auction/participant_mailer.rb | 8 +- .../post_auction/winner_mailer.rb | 8 +- .../auction_start_reminder_mailer.rb | 6 + .../mail/user_context/registration_mailer.rb | 6 + lib/auction_fun_core/version.rb | 2 +- .../workers/application_job.rb | 10 + .../post_auction/participant_operation_job.rb | 9 +- .../post_auction/winner_operation_job.rb | 8 +- .../auction_start_reminder_operation_job.rb | 14 +- .../processor/finish/closed_operation_job.rb | 9 +- .../processor/finish/penny_operation_job.rb | 9 +- .../finish/standard_operation_job.rb | 8 +- .../processor/start_operation_job.rb | 9 +- .../post_auction/participant_mailer_job.rb | 19 +- .../post_auction/winner_mailer_job.rb | 16 +- .../auction_start_reminder_mailer_job.rb | 17 +- .../user_context/registration_mailer_job.rb | 14 +- spec/auction_fun_core_spec.rb | 2 +- system/providers/background_job.rb | 6 + 68 files changed, 1503 insertions(+), 432 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1aeb94f..f1d6683 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,5 +51,7 @@ jobs: bundle exec rake auction_fun_core:db:migrate env: POSTGRES_HOST: localhost + - name: Run lint + run: bundle exec standardrb - name: Run suite run: bundle exec rspec spec/ --color --format progress diff --git a/.standard.yml b/.standard.yml index 6d67c99..1a73f9d 100644 --- a/.standard.yml +++ b/.standard.yml @@ -1,3 +1,5 @@ # For available configuration options, see: # https://github.com/standardrb/standard +format: progress +parallel: true ruby_version: 3.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f83d73..fc1837a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ ## [Unreleased] +## [0.8.9] - 2024-04-29 + +### Added + +- Using yadr as a standard documentation tool; + +### Changed + +- Upgrade README; +- Updating CI to run lint; +- Using the heredoc standard to build SQL queries; + ## [0.8.8] - 2024-04-25 ### Added diff --git a/Gemfile b/Gemfile index e095dbc..9b175c1 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,11 @@ group :development, :test do gem "faker", "3.3.1" gem "pry", "0.14.2" gem "rspec", "3.13.0" +end + +group :development do gem "standard", "1.35.1" + gem "webrick", "1.8.1" end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 50860b9..6ee4b5e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - auction_fun_core (0.8.8) + auction_fun_core (0.8.9) activesupport (= 7.1.3.2) bcrypt (= 3.1.20) dotenv (= 3.1.0) @@ -252,6 +252,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) + webrick (1.8.1) yard (0.9.36) zeitwerk (2.6.13) @@ -268,6 +269,7 @@ DEPENDENCIES rspec (= 3.13.0) simplecov (= 0.22.0) standard (= 1.35.1) + webrick (= 1.8.1) BUNDLED WITH 2.5.6 diff --git a/Procfile b/Procfile index e820116..9bb4269 100644 --- a/Procfile +++ b/Procfile @@ -2,3 +2,4 @@ database: postgres redis: redis-server mailserver: maildev --hide-extensions STARTTLS background: bundle exec sidekiq -r ./config/app.rb +documentation: bundle exec yard server --reload diff --git a/README.md b/README.md index 23e599e..c84baa0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AuctionFunCore -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. +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. ## Installation @@ -13,13 +13,13 @@ gem 'auction_fun_core' And then execute: ```sh -user@host:~$ bundle install +bundle install ``` Or install it yourself as: ```sh -user@host:~$ gem install auction_fun_core +gem install auction_fun_core ``` ## Getting Started @@ -27,10 +27,10 @@ user@host:~$ gem install auction_fun_core Initially, download the project remotely and copy the templates from the project's environment variables: ```sh -user@host:~$ git clone git@github.com:ricardopacheco/auction-fun-core.git core -user@host:~$ cd core -user@host:~$ cp .env.development.template .env.development -user@host:~$ cp .env.test.template .env.test +git clone git@github.com:ricardopacheco/auction-fun-core.git core +cd core +cp .env.development.template .env.development +cp .env.test.template .env.test ``` > 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 Configure the `.env.development` file with the values according to your machine or network. Run the commands below to create the database and its structure, remembering to replace -the `userdb` by the user of your postgresql service. By default, if `APP_ENV` is not provided +the `postgres` by the user of your postgresql service. By default, if `APP_ENV` is not provided is considered the value `development` by default. ### OS dependencies @@ -52,50 +52,50 @@ is considered the value `development` by default. #### Database (PostgreSQL) ```sh - user@host:~$ sudo apt install build-essential libssl-dev libreadline-dev zlib1g-dev libcurl4-openssl-dev uuid-dev - user@host:~$ asdf plugin add postgres - user@host:~$ asdf install postgres 16.1 - user@host:~$ rm -rf $HOME/.asdf/installs/postgres/16.1/data - user@host:~$ initdb -D $HOME/.asdf/installs/postgres/16.1/data -U postgres +sudo apt install build-essential libssl-dev libreadline-dev zlib1g-dev libcurl4-openssl-dev uuid-dev +asdf plugin add postgres +asdf install postgres 16.1 +rm -rf $HOME/.asdf/installs/postgres/16.1/data +initdb -D $HOME/.asdf/installs/postgres/16.1/data -U postgres ``` ```sh - 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 - user@host:~$ asdf plugin add ruby - user@host:~$ asdf install ruby 3.3.0 - 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 - user@host:~$ bin/setup +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 +asdf plugin add ruby +asdf install ruby 3.3.0 +gem install pg -v 1.5.5 --verbose -- --with-pg-config=$HOME/.asdf/installs/postgres/16.1/bin/pg_config # Fix pg_config +bin/setup ``` #### Overmind (Procfile manager) ```sh - user@host:~$ asdf install golang latest - user@host:~$ go install github.com/DarthSim/overmind/v2 - user@host:~$ asdf reshim +asdf install golang latest +go install github.com/DarthSim/overmind/v2 +asdf reshim ``` #### Create database for development environment -> **[postgres]** in rake commands is a name of user for postgres. Change if needed +- **postgres** in rake commands is a name of user for postgres. Change if needed In current tab: ```sh -user@host:~$ overmind s -l database +overmind s -l database ``` Open a new tab and create development database: ```sh -user@host:~$ bundle exec rake 'auction_fun_core:db:create_database[postgres]' -user@host:~$ bundle exec rake 'auction_fun_core:db:migrate' +bundle exec rake 'auction_fun_core:db:create_database[postgres]' +bundle exec rake 'auction_fun_core:db:migrate' ``` Now come back to overmind tab, kill the current database process using **Ctrl+c**. After that: ```sh -user@host:~$ overmind start +overmind start ``` 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. In new tab, you could run seed data for development with ```sh -user@host:~$ bundle exec rake 'auction_fun_core:db:seed' +bundle exec rake 'auction_fun_core:db:seed' ``` ## Interactive prompt @@ -117,9 +117,9 @@ Configure the `.env.test` file with the values according to your machine or netw Run the test suite with the coverage report using the command: ```sh -user@host:~$ APP_ENV=test bundle exec rake auction_fun_core:db:create_database[userdb] -user@host:~$ APP_ENV=test bundle exec rake auction_fun_core:db:migrate -user@host:~$ CI=true APP_ENV=test bundle exec rspec . +APP_ENV=test bundle exec rake auction_fun_core:db:create_database[postgres] +APP_ENV=test bundle exec rake auction_fun_core:db:migrate +CI=true APP_ENV=test bundle exec rspec . ``` ## Documentation @@ -127,10 +127,12 @@ user@host:~$ CI=true APP_ENV=test bundle exec rspec . This project uses `yadr` as a documentation tool. To generate documentation and view it, run ```sh - user@host:~$ bundle exec yard server --reload +bundle exec yard server --reload ``` -Documentation will be available at `http://localhost:8808` +Documentation will be available at `http://localhost:8808`. + +> If you already use overmind, the documentation server starts automatically. ## External resources diff --git a/Rakefile b/Rakefile index 47a65ce..2a8aa29 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative 'config/application' +require_relative "config/application" require "bundler/gem_tasks" require "rspec/core/rake_task" diff --git a/lib/auction_fun_core/business/configuration.rb b/lib/auction_fun_core/business/configuration.rb index 1d9062f..0e3d80b 100644 --- a/lib/auction_fun_core/business/configuration.rb +++ b/lib/auction_fun_core/business/configuration.rb @@ -2,16 +2,47 @@ module AuctionFunCore module Business + # The Configuration module contains constants that configure various aspects of auctions, + # user settings, and other business rules within the AuctionFun application. module Configuration + # An array of available auction kinds derived from auction relations. + # @return [Array] a list of all possible auction kinds AUCTION_KINDS = Relations::Auctions::KINDS.values + + # An array of valid auction statuses derived from auction relations. + # @return [Array] a list of all valid auction statuses AUCTION_STATUSES = Relations::Auctions::STATUSES.values + + # The minimum length for an auction title. + # @return [Integer] the minimum number of characters allowed in an auction title AUCTION_MIN_TITLE_LENGTH = 6 + + # The maximum length for an auction title. + # @return [Integer] the maximum number of characters allowed in an auction title AUCTION_MAX_TITLE_LENGTH = 255 + + # The minimum value for the auction stopwatch timer. + # @return [Integer] the minimum seconds count for the auction stopwatch timer AUCTION_STOPWATCH_MIN_VALUE = 15 + + # The maximum value for the auction stopwatch timer. + # @return [Integer] the maximum seconds count for the auction stopwatch timer AUCTION_STOPWATCH_MAX_VALUE = 60 + + # The minimum length for a user's name. + # @return [Integer] the minimum number of characters allowed in a person's name MIN_NAME_LENGTH = 6 + + # The maximum length for a user's name. + # @return [Integer] the maximum number of characters allowed in a person's name MAX_NAME_LENGTH = 128 + + # The minimum length for a user's password. + # @return [Integer] the minimum number of characters required in a person's password MIN_PASSWORD_LENGTH = 6 + + # The maximum length for a user's password. + # @return [Integer] the maximum number of characters allowed in a person's password MAX_PASSWORD_LENGTH = 128 end end diff --git a/lib/auction_fun_core/business/token_generator.rb b/lib/auction_fun_core/business/token_generator.rb index 7f14199..0517f9d 100644 --- a/lib/auction_fun_core/business/token_generator.rb +++ b/lib/auction_fun_core/business/token_generator.rb @@ -2,13 +2,31 @@ module AuctionFunCore module Business - # Responsible for generating interaction tokens with system users for general operations. + # The TokenGenerator module is responsible for generating interaction tokens + # used in various parts of the AuctionFun application for authentication and + # verification purposes, particularly in interactions with system users. module TokenGenerator + # Generates a secure, URL-safe base64 token primarily used for email verification. + # This method modifies certain characters to avoid common readability issues. + # + # @param length [Integer] the desired length of the generated token before modification + # @return [String] a URL-safe, base64 encoded string suitable for email verification links + # @example Generating an email token + # email_token = AuctionFunCore::Business::TokenGenerator.generate_email_token(20) + # puts email_token # Output example: "V4Ph2wkJG_bRzs_zuGyJ" def self.generate_email_token(length = 20) rlength = (length * 3) / 4 SecureRandom.urlsafe_base64(rlength).tr("lIO0", "sxyz") end + # Generates a numerical token used for phone verification processes. + # The token is zero-padded to ensure it meets the required length. + # + # @param length [Integer] the desired length of the numerical token + # @return [String] a string of digits, zero-padded to the specified length + # @example Generating a phone token + # phone_token = AuctionFunCore::Business::TokenGenerator.generate_phone_token(6) + # puts phone_token # Output example: "045673" def self.generate_phone_token(length = 6) rand(0o00000..999_999).to_s.rjust(length, "0") end diff --git a/lib/auction_fun_core/contracts/application_contract.rb b/lib/auction_fun_core/contracts/application_contract.rb index 8fd1c84..da48fcc 100644 --- a/lib/auction_fun_core/contracts/application_contract.rb +++ b/lib/auction_fun_core/contracts/application_contract.rb @@ -4,7 +4,10 @@ module AuctionFunCore module Contracts - # Abstract base class for contracts. + ## + # The class includes several macros for common validation tasks, such as validating email format, + # login format, name format, phone number format, and password format. These macros utilize + # regular expressions and predefined length ranges to ensure the input data meets specific criteria. # @abstract class ApplicationContract < Dry::Validation::Contract include AuctionFunCore::Business::Configuration @@ -17,18 +20,21 @@ class ApplicationContract < Dry::Validation::Contract config.messages.top_namespace = "contracts" config.messages.load_paths << Application.root.join("i18n/#{I18n.default_locale}/contracts/contracts.#{I18n.default_locale}.yml").to_s + # Validates whether the provided value matches the standard email format. register_macro(:email_format) do next if EMAIL_REGEX.match?(value) key.failure(I18n.t(:email_format, scope: I18N_MACRO_SCOPE)) end + # Validates whether the provided value matches either the email format or a valid phone number format using Phonelib. register_macro(:login_format) do next if EMAIL_REGEX.match?(value) || Phonelib.parse(value).valid? key.failure(I18n.t(:login_format, scope: I18N_MACRO_SCOPE)) end + # Validates whether the length of the provided name falls within the specified range. register_macro(:name_format) do next if value.length.between?(MIN_NAME_LENGTH, MAX_NAME_LENGTH) @@ -37,12 +43,14 @@ class ApplicationContract < Dry::Validation::Contract ) end + # Validates whether the provided value matches a valid phone number format using Phonelib. register_macro(:phone_format) do next if ::Phonelib.parse(value).valid? key.failure(I18n.t(:phone_format, scope: I18N_MACRO_SCOPE)) end + # Validates whether the length of the provided password falls within the specified range. register_macro(:password_format) do next if value.length.between?(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH) diff --git a/lib/auction_fun_core/contracts/auction_context/create_contract.rb b/lib/auction_fun_core/contracts/auction_context/create_contract.rb index daeb96e..5d1daad 100644 --- a/lib/auction_fun_core/contracts/auction_context/create_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/create_contract.rb @@ -3,15 +3,36 @@ module AuctionFunCore module Contracts module AuctionContext - # Contract class to create new auctions. + # This class is designed to validate the creation of new auctions. + # It includes various validations such as staff existence, auction kind, timing, and initial bids. + # + # @example Creating a new auction + # contract = AuctionFunCore::Contracts::AuctionContext::CreateContract.new + # attributes = { + # staff_id: 1, + # title: "Rare Antique Vase", + # kind: "standard", + # started_at: Time.current + 5.days, + # finished_at: Time.current + 10.days, + # initial_bid_cents: 5000 + # } + # result = contract.call(attributes) + # if result.success? + # puts "Auction created successfully." + # else + # puts "Failed to create auction: #{result.errors.to_h}" + # end + # class CreateContract < Contracts::ApplicationContract include AuctionFunCore::Business::Configuration + # Additional validations specific for non-penny auctions. REQUIRED_FINISHED_AT = AUCTION_KINDS - ["penny"] + # Repository initialized to retrieve staff data for validation. option :staff_repo, default: proc { Repos::StaffContext::StaffRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Defines necessary parameters and initializes some default values. params do required(:staff_id).filled(:integer) required(:title).filled(:string, size?: (AUCTION_MIN_TITLE_LENGTH..AUCTION_MAX_TITLE_LENGTH)) @@ -22,7 +43,7 @@ class CreateContract < Contracts::ApplicationContract optional(:initial_bid_cents).filled(:integer) optional(:stopwatch).filled(:integer) - # Keys with a blank value are discarded. + # Parameters specifying the required input types and fields. before(:value_coercer) do |result| result.to_h.compact end @@ -33,59 +54,53 @@ class CreateContract < Contracts::ApplicationContract end end - # Validation for staff. - # Validate whether the given staff is valid at the database level. + # Validates the existence of the staff. rule(:staff_id) do |context:| context[:staff] ||= staff_repo.by_id(value) key.failure(I18n.t("contracts.errors.custom.default.not_found")) unless context[:staff] end - # Validation for started_at. - # Validates if the entered date is greater than or equal to the current time. + # Validates that the starting time of the auction is in the future. rule(:started_at) do key.failure(I18n.t("contracts.errors.custom.default.future")) if key? && value <= Time.current end - # Specific validation when the auction type is informed and it is not penny, - # it must be mandatory to inform the auction closing date/time + # Validates that the finished_at time is specified for auctions types that require it, + # and is not specified for "penny" auctions. rule(:finished_at, :kind) do if key?(:kind) && !key?(:finished_at) && REQUIRED_FINISHED_AT.include?(values[:kind]) key.failure(I18n.t("contracts.errors.filled?")) end end - # Basic specific validation to check if the auction end time - # is less than or equal to the start time. + # Validates that the auction end time is later than the start time. rule(:finished_at, :started_at) do if key?(:finished_at) && (values[:finished_at] <= values[:started_at]) key.failure(I18n.t("contracts.errors.custom.auction_context.create.finished_at")) end end - # Validation for initial bid amount. - # + # Validates the initial bid amount based on auction type. rule(:initial_bid_cents) do - # Must be filled if auction kind is not type penny. + # Must be specified and positive for non-penny auction types. key.failure(I18n.t("contracts.errors.filled?")) if !key? && REQUIRED_FINISHED_AT.include?(values[:kind]) - # Must be greater than zero if action kind is not type penny. if key? && REQUIRED_FINISHED_AT.include?(values[:kind]) && values[:initial_bid_cents] <= 0 key.failure(I18n.t("contracts.errors.gt?", num: 0)) end - # Must be equal to zero if auction kind is type penny. + # Must be zero for penny auctions to ensure fairness. if key? && values[:kind] == "penny" && !values[:initial_bid_cents].zero? key.failure(I18n.t("contracts.errors.eql?", left: 0)) end end - # Validation for stopwatch. - # + # Validates stopwatch settings for penny auctions. rule(:stopwatch) do - # Must be filled if auction kind is type penny. + # Stopwatch must be specified for penny auctions. key.failure(I18n.t("contracts.errors.filled?")) if !key? && values[:kind] == "penny" - # Must be an integer between 15 and 60. + # Stopwatch value must fall within the specified range. if key? && values[:kind] == "penny" && !value.between?(AUCTION_STOPWATCH_MIN_VALUE, AUCTION_STOPWATCH_MAX_VALUE) key.failure( I18n.t( diff --git a/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb b/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb index cc6e9f5..695519d 100644 --- a/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb @@ -5,30 +5,52 @@ module Contracts module AuctionContext module PostAuction ## - # Contract class for validate participation auction. + # This class is used to validate the participation of users in an auction. + # This contract ensures that both the auction and the participant exist and that the participant + # has already at least placed a bid. It utilizes repositories to fetch data about auctions, users, and bids. + # + # @example Using this class to validate a participant + # contract = AuctionFunCore::Contracts::AuctionContext::PostAuction::ParticipantContract.new + # attributes = { auction_id: 1, participant_id: 102 } + # validation_result = contract.call(attributes) + # if validation_result.success? + # puts "Participant validation passed" + # else + # puts "Participant validation failed: #{validation_result.errors.to_h}" + # end # class ParticipantContract < Contracts::ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.auction_context.post_auction.participation" + # Repository options initialized by default. These repositories handle data retrieval. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } option :user_repository, default: proc { Repos::UserContext::UserRepository.new } option :bid_repository, default: proc { Repos::BidContext::BidRepository.new } + # Defines the data types and required fields for the contract. params do required(:auction_id).filled(:integer) required(:participant_id).filled(:integer) end + # Validation rule for auction_id to ensure the auction exists. + # @param context [Hash] Optional context hash to store data and state during validation. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end + # Validation rule for participant_id to ensure the participant exists. + # @param context [Hash] Optional context hash to store data and state during validation. rule(:participant_id) do |context:| context[:participant] ||= user_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:participant] end + # Combined validation rule for auction_id and participant_id to check that the participant + # has not already placed a bid in the auction. + # @param context [Hash] Context containing the auction and participant objects. rule(:auction_id, :participant_id) do |context:| next if (rule_error?(:auction_id) || schema_error?(:auction_id)) || (rule_error?(:winner_id) || schema_error?(:winner_id)) next if bid_repository.exists?(auction_id: values[:auction_id], user_id: values[:participant_id]) diff --git a/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb b/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb index 7214892..570ebde 100644 --- a/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb @@ -5,29 +5,50 @@ module Contracts module AuctionContext module PostAuction ## - # Contract class for validate winner auction. + # This class validates the identification of the winning bidder + # in an auction context. It ensures that both the auction and the winner exist + # and are correctly associated within the system. + # + # @example Using this class to validate a winner + # contract = AuctionFunCore::Contracts::AuctionContext::PostAuction::WinnerContract.new + # attributes = { auction_id: 1, winner_id: 102 } + # validation_result = contract.call(attributes) + # if validation_result.success? + # puts "Winner validation passed" + # else + # puts "Winner validation failed: #{validation_result.errors.to_h}" + # end # class WinnerContract < Contracts::ApplicationContract + # Internationalization (i18n) scope for error messages related to winner validation. I18N_SCOPE = "contracts.errors.custom.auction_context.post_auction.winner" + # Repositories initialized by default to handle data retrieval for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } option :user_repository, default: proc { Repos::UserContext::UserRepository.new } + # Parameters defining the expected input types and required fields. params do required(:auction_id).filled(:integer) required(:winner_id).filled(:integer) end + # Validation rule to ensure the auction exists. + # @param context [Hash] Optional context hash to store data and state during validation. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end + # Validation rule to ensure the winner exists. + # @param context [Hash] Optional context hash to store data and state during validation. rule(:winner_id) do |context:| context[:winner] ||= user_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:winner] end + # Combined rule to ensure that the declared winner is the actual winner recorded in the auction. + # @param context [Hash] Context containing the auction and winner objects. rule(:auction_id, :winner_id) do |context:| next if (rule_error?(:auction_id) || schema_error?(:auction_id)) || (rule_error?(:winner_id) || schema_error?(:winner_id)) next if context[:auction].winner_id == values[:winner_id] diff --git a/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb b/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb index d7a4e04..142b06f 100644 --- a/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb @@ -4,26 +4,38 @@ module AuctionFunCore module Contracts module AuctionContext module PreAuction - ## - # Contract class for validate schedule reminder notification. + # The AuctionStartReminderContract class validates the scheduled reminder for the auction start. + # It checks if the auction associated with the provided auction ID has not started yet and validates accordingly. + # + # @example Validating auction reminder + # contract = AuctionFunCore::Contracts::AuctionContext::PreAuction::AuctionStartReminderContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Reminder setup is valid." + # else + # puts "Failed to validate reminder: #{result.errors.to_h}" + # end # class AuctionStartReminderContract < Contracts::ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.auction_context.pre_auction.auction_start_reminder" + # Default repository initialization to retrieve auction data. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Defines the necessary parameters and their types. params do required(:auction_id).filled(:integer) end + # Validation rule to ensure the referenced auction exists. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end - # Validation to start. - # Checks whether the auction has started or not. - # + # Additional validation to confirm the auction has not started yet. rule do |context:| next if context[:auction].present? && context[:auction].not_started? diff --git a/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb index f899e3c..0df3297 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb @@ -6,34 +6,46 @@ module AuctionContext module Processor module Finish ## - # Contract class for finishing closed auctions. + # This class is designed for validate the finishing closed auctions. It ensures that + # the auction to be closed exists, is of the correct kind ('closed'), and is in the correct + # status ('running') to be finalized. + # + # @example Validating a closed auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::Finish::ClosedContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction can be finished." + # else + # puts "Failed to finish auction: #{result.errors.to_h}" + # end # class ClosedContract < Contracts::ApplicationContract + # Internationalization (i18n) scope for error messages. I18N_SCOPE = "contracts.errors.custom.auction_context.processor.finish" + # Repository initialized to retrieve auction data for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database. + # Validates the existence of the auction. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end - # Validation for kind. - # + # Validates the kind of the auction to ensure it is 'closed'. rule do |context:| next if context[:auction].present? && context[:auction].kind == "closed" key(:base).failure(I18n.t("invalid_kind", scope: I18N_SCOPE)) end - # Validation for status. - # + # Validates the status of the auction to ensure it is 'running'. rule do |context:| next if context[:auction].present? && context[:auction].status == "running" diff --git a/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb index e6519e1..9093479 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb @@ -6,35 +6,47 @@ module AuctionContext module Processor module Finish ## - # Contract class for finishing penny auctions. + # This class is designed for validate the finishing penny auctions. It ensures that + # the auction to be penny exists, is of the correct kind ('penny'), and is in the correct + # status ('running') to be finalized. + # + # @example Validating a penny auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::Finish::PennyContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction can be finished." + # else + # puts "Failed to finish auction: #{result.errors.to_h}" + # end # class PennyContract < Contracts::ApplicationContract + # Internationalization (i18n) scope for error messages. I18N_SCOPE = "contracts.errors.custom.auction_context.processor.finish" + # Repository initialized to retrieve auction data for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database. + # Validates the existence of the auction. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end - # Validation for kind. - # + # Validates the kind of the auction to ensure it is 'penny'. rule do |context:| next if context[:auction].present? && context[:auction].kind == "penny" key(:base).failure(I18n.t("invalid_kind", scope: I18N_SCOPE)) end - # Validation for status. - # + # Validates the status of the auction to ensure it is 'running'. rule do |context:| next if context[:auction].present? && context[:auction].status == "running" diff --git a/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb index b0d2b1d..2b57d8c 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb @@ -6,35 +6,47 @@ module AuctionContext module Processor module Finish ## - # Contract class for finishing standard auctions. + # This class is designed for validate the finishing standard auctions. It ensures that + # the auction to be standard exists, is of the correct kind ('standard'), and is in the correct + # status ('running') to be finalized. + # + # @example Validating a standard auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::Finish::StandardContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction can be finished." + # else + # puts "Failed to finish auction: #{result.errors.to_h}" + # end # class StandardContract < Contracts::ApplicationContract + # Internationalization (i18n) scope for error messages. I18N_SCOPE = "contracts.errors.custom.auction_context.processor.finish" + # Repository initialized to retrieve auction data for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database. + # Validates the existence of the auction. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end - # Validation for kind. - # + # Validates the kind of the auction to ensure it is 'standard'. rule do |context:| next if context[:auction].present? && context[:auction].kind == "standard" key(:base).failure(I18n.t("invalid_kind", scope: I18N_SCOPE)) end - # Validation for status. - # + # Validates the status of the auction to ensure it is 'running'. rule do |context:| next if context[:auction].present? && context[:auction].status == "running" diff --git a/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb index a363408..6e55654 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb @@ -5,18 +5,30 @@ module Contracts module AuctionContext module Processor ## - # Contract class for pause auction. + # This class is designed to validate pausing an auction. It ensures + # that the auction exists in the database and checks that only auctions with + # a "running" status can be paused. + # + # @example Pausing an auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::PauseContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction paused successfully." + # else + # puts "Failed to pause auction: #{result.errors.to_h}" + # end # class PauseContract < Contracts::ApplicationContract + # Repository initialized to retrieve auction data for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database and check if only auctions - # with a "running" status can be paused. + # Validates the existence of the auction and its status. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] diff --git a/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb index a74c6ff..0eeac5a 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb @@ -5,28 +5,40 @@ module Contracts module AuctionContext module Processor ## - # Contract class for start auctions. + # This class is designed to validate the initiation of auctions. It ensures + # the auction exists and is of a valid kind, and also manages specific rules for auctions + # that require a stopwatch, such as penny auctions. + # + # @example Starting an auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::StartContract.new + # attributes = { auction_id: 123, kind: "penny", stopwatch: 30 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction started successfully." + # else + # puts "Failed to start auction: #{result.errors.to_h}" + # end # class StartContract < Contracts::ApplicationContract include AuctionFunCore::Business::Configuration + # Repository initialized to retrieve auction data for validation. option :auction_repo, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) required(:kind).value(included_in?: AUCTION_KINDS) optional(:stopwatch).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database. + # Validates the existence of the auction. rule(:auction_id) do |context:| context[:auction] ||= auction_repo.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] end - # Validation for stopwatch. - # + # Validates the requirements for the stopwatch in penny auctions. rule(:stopwatch) do # Must be filled if auction kind is type penny. key.failure(I18n.t("contracts.errors.filled?")) if !key? && values[:kind] == "penny" diff --git a/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb b/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb index 0168a3a..18b3c50 100644 --- a/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +++ b/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb @@ -5,18 +5,30 @@ module Contracts module AuctionContext module Processor ## - # Contract class for unpause auction. + # This class is designed to validate the resumption of auctions. + # It ensures that the auction exists in the database and checks that the auction + # is currently in a "paused" status, allowing it to be unpaused. + # + # @example Unpausing an auction + # contract = AuctionFunCore::Contracts::AuctionContext::Processor::UnpauseContract.new + # attributes = { auction_id: 123 } + # result = contract.call(attributes) + # if result.success? + # puts "Auction resumed successfully." + # else + # puts "Failed to resume auction: #{result.errors.to_h}" + # end # class UnpauseContract < Contracts::ApplicationContract + # Repository initialized to retrieve auction data for validation. option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) end - # Validation for auction. - # Validates if the auction exists in the database and and checks if the - # auction has a paused status. + # Validates the existence of the auction and checks its status. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction] diff --git a/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb b/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb index e66c8e8..2c7fcca 100644 --- a/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +++ b/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb @@ -3,13 +3,27 @@ module AuctionFunCore module Contracts module BidContext - # Contract class to create new bids. + # This class validates the creation of new bids for closed-type auctions. + # It ensures the bid is placed by a valid user on a valid auction that is open for bids, and that + # the bid value meets or exceeds the starting bid required by the auction. + # Furthermore, only one bid per participant is allowed. + # + # @example Creating a bid for a closed auction + # contract = AuctionFunCore::Contracts::BidContext::CreateBidClosedContract.new + # attributes = { auction_id: 123, user_id: 2, value_cents: 10000 } + # result = contract.call(attributes) + # if result.success? + # puts "Bid created successfully." + # else + # puts "Failed to create bid: #{result.errors.to_h}" + # end class CreateBidClosedContract < Contracts::ApplicationContract + # Repositories initialized to retrieve data for validation. option :user_repository, default: proc { Repos::UserContext::UserRepository.new } option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new } option :bid_repository, default: proc { Repos::BidContext::BidRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) required(:user_id).filled(:integer) @@ -21,9 +35,7 @@ class CreateBidClosedContract < Contracts::ApplicationContract end end - # Validation for auction. - # validate whether the given auction is valid at the database level. - # validate if the auction is open to receive bids + # Validates the auction's validity and status for receiving bids. rule(:auction_id) do |context:| context[:auction] ||= auction_repository.by_id(value) @@ -42,9 +54,7 @@ class CreateBidClosedContract < Contracts::ApplicationContract end end - # Validation for user. - # Validate whether the given user is valid at the database level. - # Validates if user has already placed a bid + # Validates the user's existence and checks if they have already placed a bid. rule(:user_id) do |context:| context[:user] ||= user_repository.by_id(value) @@ -57,8 +67,7 @@ class CreateBidClosedContract < Contracts::ApplicationContract end end - # Validation for value bid. - # The bid amount must be greater than or equal to the starting bid. + # Validates that the bid amount is greater than or equal to the auction's starting bid. rule(:value_cents) do |context:| unless rule_error?(:user_id) closed_auction_bid_value_is_gteq_initial_bid?(key, value, context[:auction].initial_bid_cents) @@ -67,7 +76,7 @@ class CreateBidClosedContract < Contracts::ApplicationContract private - # Checks if bid amount must be greater than or equal to the starting bid. + # Helper method to check if the bid amount meets the minimum required bid. def closed_auction_bid_value_is_gteq_initial_bid?(key, value_cents, minimal_bid_cents) return unless value_cents < minimal_bid_cents diff --git a/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb b/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb index 6dd6694..460b06f 100644 --- a/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +++ b/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb @@ -3,12 +3,25 @@ module AuctionFunCore module Contracts module BidContext - # Contract class to create new bids. + # This class validates the creation of new bids for penny-type auctions. + # It guarantees that the bid can only be made within the correct status of this type of auction, + # in addition, the participant must have sufficient balance in their wallet to place a new bid. + # + # @example Creating a bid for a penny auction + # contract = AuctionFunCore::Contracts::BidContext::CreateBidPennyContract.new + # attributes = { auction_id: 123, user_id: 2 } + # result = contract.call(attributes) + # if result.success? + # puts "Bid created successfully." + # else + # puts "Failed to create bid: #{result.errors.to_h}" + # end class CreateBidPennyContract < Contracts::ApplicationContract + # Repositories initialized to retrieve data for validation. option :user_repo, default: proc { Repos::UserContext::UserRepository.new } option :auction_repo, default: proc { Repos::AuctionContext::AuctionRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) required(:user_id).filled(:integer) @@ -19,9 +32,7 @@ class CreateBidPennyContract < Contracts::ApplicationContract end end - # Validation for auction. - # validate whether the given auction is valid at the database level. - # validate if the auction is open to receive bids + # Validates the auction's validity, kind, and status for receiving bids. rule(:auction_id) do |context:| context[:auction] ||= auction_repo.by_id(value) @@ -40,9 +51,7 @@ class CreateBidPennyContract < Contracts::ApplicationContract end end - # Validation for user. - # Validate whether the given user is valid at the database level. - # Validates if user has enough balance to bid. + # Validates the user's existence and ensures they have enough balance to bid. rule(:user_id) do |context:| context[:user] ||= user_repo.by_id(value) @@ -59,7 +68,7 @@ class CreateBidPennyContract < Contracts::ApplicationContract private - # Checks if user has enough balance to bid. + # Helper method to check if the user has sufficient balance to place a bid in a penny auction. def penny_auction_check_user_has_balance?(key, auction_bid_cents, balance_cents) key.failure(I18n.t("contracts.errors.custom.bids.insufficient_balance")) if balance_cents < auction_bid_cents end diff --git a/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb b/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb index c9db5f8..bca2c46 100644 --- a/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +++ b/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb @@ -3,12 +3,25 @@ module AuctionFunCore module Contracts module BidContext - # Contract class to create new bids. + # This class validates the creation of new bids for standard-type auctions. + # It ensures the bid is placed by a valid user on a valid auction that is open for bids, + # and that the bid value meets or exceeds the minimum bid required by the auction. + # + # @example Creating a bid for a standard auction + # contract = AuctionFunCore::Contracts::BidContext::CreateBidStandardContract.new + # attributes = { auction_id: 1, user_id: 2, value_cents: 5000 } + # result = contract.call(attributes) + # if result.success? + # puts "Bid created successfully." + # else + # puts "Failed to create bid: #{result.errors.to_h}" + # end class CreateBidStandardContract < Contracts::ApplicationContract + # Repositories initialized to retrieve data for validation. option :user_repo, default: proc { Repos::UserContext::UserRepository.new } option :auction_repo, default: proc { Repos::AuctionContext::AuctionRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Parameters specifying the required input types and fields. params do required(:auction_id).filled(:integer) required(:user_id).filled(:integer) @@ -20,9 +33,7 @@ class CreateBidStandardContract < Contracts::ApplicationContract end end - # Validation for auction. - # validate whether the given auction is valid at the database level. - # validate if the auction is open to receive bids + # Validates the auction's validity, kind, and status for receiving bids. rule(:auction_id) do |context:| context[:auction] ||= auction_repo.by_id(value) @@ -41,22 +52,20 @@ class CreateBidStandardContract < Contracts::ApplicationContract end end - # Validation for user. - # Validate whether the given user is valid at the database level. + # Validates the user's existence in the database. rule(:user_id) do |context:| context[:user] ||= user_repo.by_id(value) key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:user] end - # Validation for value bid. - # must be greater than or equal to the auction's minimal bid. + # Validates that the bid amount is greater than or equal to the auction's minimum bid. rule(:value_cents) do |context:| standard_auction_valid_bid?(key, value, context[:auction].minimal_bid_cents) end private - # Checks if the bid amount is greather than or equal to minimum bid. + # Helper method to check if the bid amount meets the minimum required bid. def standard_auction_valid_bid?(key, value_cents, minimal_bid_cents) return if value_cents >= minimal_bid_cents diff --git a/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb b/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb index e2cc2dd..55d8a68 100644 --- a/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +++ b/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb @@ -3,12 +3,27 @@ module AuctionFunCore module Contracts module StaffContext - # Contract class to authenticate staff. + # This class is designed to authenticate staff members. + # It validates the login and password, checking their format and verifying them against the database records. + # + # @example Authenticating a staff member + # contract = AuctionFunCore::Contracts::StaffContext::AuthenticationContract.new + # attributes = { login: 'staff@example.com', password: 'securePassword123' } + # result = contract.call(attributes) + # if result.success? + # puts "Authentication successful." + # else + # puts "Authentication failed: #{result.errors.to_h}" + # end + # class AuthenticationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :staff_repository, default: proc { Repos::StaffContext::StaffRepository.new } + # Parameters specifying the required input types and fields. params do required(:login) required(:password) @@ -18,12 +33,11 @@ class AuthenticationContract < ApplicationContract end end + # Additional rules for validating the format of login and password. rule(:login).validate(:login_format) rule(:password).validate(:password_format) - # Validation for login. - # Searches for the staff in the database from the login, and, if found, - # compares the entered password. + # Validates the presence of the staff member in the database and checks if the password matches. rule do |context:| next if (rule_error?(:login) || schema_error?(:login)) || (rule_error?(:password) || schema_error?(:password)) diff --git a/lib/auction_fun_core/contracts/staff_context/registration_contract.rb b/lib/auction_fun_core/contracts/staff_context/registration_contract.rb index 200906c..3cb3bb2 100644 --- a/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +++ b/lib/auction_fun_core/contracts/staff_context/registration_contract.rb @@ -3,13 +3,27 @@ module AuctionFunCore module Contracts module StaffContext - # Contract class to create new staff. + # This class is designed to create staff members. + # It validates the parameters, ensuring their format and uniqueness. + # + # @example Registering a new staff member + # contract = AuctionFunCore::Contracts::StaffContext::RegistrationContract.new + # attributes = { name: 'John Doe', email: 'john.doe@example.com', phone: '1234567890' } + # result = contract.call(attributes) + # if result.success? + # puts "Staff member registered successfully." + # else + # puts "Failed to register staff member: #{result.errors.to_h}" + # end + # class RegistrationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :staff_repository, default: proc { Repos::StaffContext::StaffRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Parameters specifying the required input types and fields. params do required(:name) required(:email) @@ -19,27 +33,25 @@ class RegistrationContract < ApplicationContract result.to_h.compact end - # Normalize and add default values + # Normalizes and adds default values after coercion. after(:value_coercer) do |result| result.update(email: result[:email].strip.downcase) if result[:email] result.update(phone: result[:phone].tr_s("^0-9", "")) if result[:phone] end end + # Validates the format of the staff member's name. rule(:name).validate(:name_format) - # Validation for email. - # It must validate the format and uniqueness in the database. + # It ensures email format and checks for uniqueness in the database. rule(:email).validate(:email_format) rule(:email) do - # Email should be unique on database if !rule_error?(:email) && staff_repository.exists?(email: value) key.failure(I18n.t(:taken, scope: I18N_SCOPE)) end end - # Validation for phone. - # It must validate the format and uniqueness in the database. + # It ensures phone format and checks for uniqueness in the database. rule(:phone).validate(:phone_format) rule(:phone) do if !rule_error?(:phone) && staff_repository.exists?(phone: value) diff --git a/lib/auction_fun_core/contracts/user_context/authentication_contract.rb b/lib/auction_fun_core/contracts/user_context/authentication_contract.rb index 91126e9..f379065 100644 --- a/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +++ b/lib/auction_fun_core/contracts/user_context/authentication_contract.rb @@ -3,12 +3,27 @@ module AuctionFunCore module Contracts module UserContext - # Contract class to authenticate users. + # This class is designed to authenticate users. + # It verifies the provided login credentials against stored user data in the system. + # + # @example Authenticating a user + # contract = AuctionFunCore::Contracts::UserContext::AuthenticationContract.new + # attributes = { login: 'example_user', password: 'securePassword123' } + # result = contract.call(attributes) + # if result.success? + # puts "User authenticated successfully." + # else + # puts "Authentication failed: #{result.errors.to_h}" + # end + # class AuthenticationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :user_repository, default: proc { Repos::UserContext::UserRepository.new } + # Parameters specifying the required input types and fields. params do required(:login) required(:password) @@ -18,12 +33,11 @@ class AuthenticationContract < ApplicationContract end end + # Additional rules for validating the format of login and password. rule(:login).validate(:login_format) rule(:password).validate(:password_format) - # Validation for login. - # Searches for the user in the database from the login, and, if found, - # compares the entered password. + # Validates the presence of the user in the database and checks if the password matches. rule do |context:| next if (rule_error?(:login) || schema_error?(:login)) || (rule_error?(:password) || schema_error?(:password)) diff --git a/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb b/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb index 4bcba59..3a8e1cb 100644 --- a/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +++ b/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb @@ -3,12 +3,27 @@ module AuctionFunCore module Contracts module UserContext - # Contract class responsible for validating the confirmation token for email. + # This class provides validation for confirming email addresses. + # It verifies the provided email confirmation token against stored user data in the system. + # + # @example Confirming an email address + # contract = AuctionFunCore::Contracts::UserContext::EmailConfirmationContract.new + # attributes = { email_confirmation_token: 'example_token' } + # result = contract.call(attributes) + # if result.success? + # puts "Email address enabled for confirmation." + # else + # puts "Failed to confirm email address: #{result.errors.to_h}" + # end + # class EmailConfirmationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :user_repository, default: proc { Repos::UserContext::UserRepository.new } + # Parameters specifying the required input types and fields. params do required(:email_confirmation_token) @@ -17,7 +32,6 @@ class EmailConfirmationContract < ApplicationContract end end - # Validation for email_confirmation_token. # Searches for the user in the database from the email_confirmation_token rule do |context:| next if schema_error?(:email_confirmation_token) @@ -29,6 +43,7 @@ class EmailConfirmationContract < ApplicationContract key(:email_confirmation_token).failure(I18n.t("not_found", scope: I18N_SCOPE)) end + # Additional validation to check if the user account associated with the token is active. rule do |context:| next if context[:user].blank? || context[:user].active? diff --git a/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb b/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb index 0e90256..7480be4 100644 --- a/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +++ b/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb @@ -3,12 +3,27 @@ module AuctionFunCore module Contracts module UserContext - # Contract class responsible for validating the confirmation token for phone number. + # This class provides validation for confirming phone numbers. + # It verifies the provided phone confirmation token against stored user data in the system. + # + # @example Confirming a phone number + # contract = AuctionFunCore::Contracts::UserContext::PhoneConfirmationContract.new + # attributes = { phone_confirmation_token: 'example_token' } + # result = contract.call(attributes) + # if result.success? + # puts "Phone number enabled for confirmation." + # else + # puts "Failed to confirm phone number: #{result.errors.to_h}" + # end + # class PhoneConfirmationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :user_repository, default: proc { Repos::UserContext::UserRepository.new } + # Parameters specifying the required input types and fields. params do required(:phone_confirmation_token) @@ -17,7 +32,6 @@ class PhoneConfirmationContract < ApplicationContract end end - # Validation for token_confirmation_token. # Searches for the user in the database from the phone_confirmation_token rule do |context:| next if schema_error?(:phone_confirmation_token) @@ -29,6 +43,7 @@ class PhoneConfirmationContract < ApplicationContract key(:phone_confirmation_token).failure(I18n.t("not_found", scope: I18N_SCOPE)) end + # Additional validation to check if the user account associated with the token is active. rule do |context:| next if context[:user].blank? || context[:user].active? diff --git a/lib/auction_fun_core/contracts/user_context/registration_contract.rb b/lib/auction_fun_core/contracts/user_context/registration_contract.rb index 07b3759..f41b333 100644 --- a/lib/auction_fun_core/contracts/user_context/registration_contract.rb +++ b/lib/auction_fun_core/contracts/user_context/registration_contract.rb @@ -3,13 +3,33 @@ module AuctionFunCore module Contracts module UserContext - # Contract class to create new users. + # This class is designed to create new users. + # It validates the parameters, ensuring their format and uniqueness. + # + # @example Registering a new staff member + # contract = AuctionFunCore::Contracts::StaffContext::RegistrationContract.new + # attributes = { + # name: 'John Doe', + # email: 'john.doe@example.com', + # phone: '1234567890' + # password: 'password', + # password_confirmation: 'password' + # } + # result = contract.call(attributes) + # if result.success? + # puts "New user registered successfully." + # else + # puts "Failed to register new user: #{result.errors.to_h}" + # end + # class RegistrationContract < ApplicationContract + # Scope for internationalization (i18n) entries specific to errors in this contract. I18N_SCOPE = "contracts.errors.custom.default" + # Repositories initialized to retrieve data for validation. option :user_repository, default: proc { Repos::UserContext::UserRepository.new } - # @param [Hash] opts Sets an allowed list of parameters, as well as some initial validations. + # Parameters specifying the required input types and fields. params do required(:name) required(:email) @@ -21,17 +41,17 @@ class RegistrationContract < ApplicationContract result.to_h.compact end - # Normalize and add default values + # Normalizes and adds default values after coercion. after(:value_coercer) do |result| result.update(email: result[:email].strip.downcase) if result[:email] result.update(phone: result[:phone].tr_s("^0-9", "")) if result[:phone] end end + # Validates the format of the user's name. rule(:name).validate(:name_format) - # Validation for email. - # It must validate the format and uniqueness in the database. + # It ensures email format and checks for uniqueness in the database. rule(:email).validate(:email_format) rule(:email) do # Email should be unique on database @@ -40,8 +60,7 @@ class RegistrationContract < ApplicationContract end end - # Validation for phone. - # It must validate the format and uniqueness in the database. + # It ensures phone format and checks for uniqueness in the database. rule(:phone).validate(:phone_format) rule(:phone) do if !rule_error?(:phone) && user_repository.exists?(phone: value) @@ -49,7 +68,6 @@ class RegistrationContract < ApplicationContract end end - # Validation for password. # Check if the confirmation matches the password. rule(:password).validate(:password_format) rule(:password, :password_confirmation) do diff --git a/lib/auction_fun_core/entities/auction.rb b/lib/auction_fun_core/entities/auction.rb index 1278ba5..e90f843 100644 --- a/lib/auction_fun_core/entities/auction.rb +++ b/lib/auction_fun_core/entities/auction.rb @@ -2,11 +2,10 @@ module AuctionFunCore module Entities - # Auction Relations class. This return simple objects with attribute readers - # to represent data in your auction. + ## + # Defines the Auction class as Entity. It appears to be a simple data structure + # class representing auction-related information. class Auction < ROM::Struct - INQUIRER_ATTRIBUTES = Relations::Auctions::STATUSES.values.freeze - # Retrieves the initial bid amount for an auction as a Money object. # # This method creates and returns a new Money object that represents the initial bid diff --git a/lib/auction_fun_core/entities/bid.rb b/lib/auction_fun_core/entities/bid.rb index 9791e0f..680fedb 100644 --- a/lib/auction_fun_core/entities/bid.rb +++ b/lib/auction_fun_core/entities/bid.rb @@ -2,8 +2,9 @@ module AuctionFunCore module Entities - # Bid Relations class. This return simple objects with attribute readers - # to represent data in your bid. + ## + # Defines the Bid class as Entity. It appears to be a simple data structure + # class representing bid-related information. class Bid < ROM::Struct end end diff --git a/lib/auction_fun_core/entities/staff.rb b/lib/auction_fun_core/entities/staff.rb index cc19be2..5364fcc 100644 --- a/lib/auction_fun_core/entities/staff.rb +++ b/lib/auction_fun_core/entities/staff.rb @@ -2,17 +2,30 @@ module AuctionFunCore module Entities - # Staff Relations class. This return simple objects with attribute readers - # to represent data in your staff. + ## + # Defines the Staff class as Entity. It appears to be a simple data structure + # class representing staff-related information. class Staff < ROM::Struct + ## + # Checks if the staff is active. + # + # @return [Boolean] True if the staff is active, otherwise false. def active? active end + ## + # Checks if the staff is inactive. + # + # @return [Boolean] True if the staff is inactive, otherwise false. def inactive? !active end + ## + # Returns staff information excluding password digest. + # + # @return [Hash] Staff information. def info attributes.except(:password_digest) end diff --git a/lib/auction_fun_core/entities/user.rb b/lib/auction_fun_core/entities/user.rb index 2748915..1fff896 100644 --- a/lib/auction_fun_core/entities/user.rb +++ b/lib/auction_fun_core/entities/user.rb @@ -2,33 +2,62 @@ module AuctionFunCore module Entities - # User Relations class. This return simple objects with attribute readers - # to represent data in your user. + ## + # Defines the User class as Entity. It appears to be a simple data structure + # class representing user-related information. class User < ROM::Struct + ## + # Checks if the user is active. + # + # @return [Boolean] True if the user is active, otherwise false. def active? active end + ## + # Checks if the user is inactive. + # + # @return [Boolean] True if the user is inactive, otherwise false. def inactive? !active end + ## + # Checks if the user has been confirmed. + # + # @return [Boolean] True if the user is confirmed, otherwise false. def confirmed? confirmed_at.present? end + ## + # Checks if the user's email has been confirmed. + # + # @return [Boolean] True if the email is confirmed, otherwise false. def email_confirmed? email_confirmation_at.present? end + ## + # Checks if the user's phone has been confirmed. + # + # @return [Boolean] True if the phone is confirmed, otherwise false. def phone_confirmed? phone_confirmation_at.present? end + ## + # Returns user information excluding password digest. + # + # @return [Hash] User information. def info attributes.except(:password_digest) end + ## + # Returns the user's balance as a Money object. + # + # @return [Money] User's balance. def balance Money.new(balance_cents, balance_currency) end diff --git a/lib/auction_fun_core/events/app.rb b/lib/auction_fun_core/events/app.rb index 39941f4..4ae67d1 100644 --- a/lib/auction_fun_core/events/app.rb +++ b/lib/auction_fun_core/events/app.rb @@ -2,23 +2,29 @@ module AuctionFunCore module Events - # Event class to register business events on system. + ## + # Represents the main application class for registering business events in the system. + # + # This class includes Dry::Events::Publisher[:app] to enable event publishing functionality. # @see https://dry-rb.org/gems/dry-events/main/ class App - # @!parser include Dry::Events::Publisher[:app] include Dry::Events::Publisher[:app] + # Registers events related to auctions. register_event("auctions.created") register_event("auctions.started") register_event("auctions.finished") register_event("auctions.paused") register_event("auctions.unpaused") + # Registers events related to bids. register_event("bids.created") + # Registers events related to staffs. register_event("staffs.authentication") register_event("staffs.registration") + # Registers events related to users. register_event("users.authentication") register_event("users.registration") register_event("users.confirmation") diff --git a/lib/auction_fun_core/events/listener.rb b/lib/auction_fun_core/events/listener.rb index d7f981b..b2f67f3 100644 --- a/lib/auction_fun_core/events/listener.rb +++ b/lib/auction_fun_core/events/listener.rb @@ -2,7 +2,10 @@ module AuctionFunCore module Events - # Event class that can listen business events. + ## + # Represents a class that listens to business events and performs actions accordingly. + # + # This class defines methods to handle various events related to auctions, bids, staff, and users. # @see https://dry-rb.org/gems/dry-events/main/#event-listeners class Listener # Listener for to *auctions.created* event. @@ -36,15 +39,15 @@ def on_auctions_unpaused(auction) end # Listener for to *bids.created* event. - # @param event [Integer] Auction ID + # @param event [ROM::Struct::Bid] Auction ID def on_bids_created(bid) logger("Create bid with: #{bid.to_h}") end - # Listener for to *staffs.authentication* event. - # @param attributes [Hash] Authentication attributes - # @option staff_id [Integer] Staff ID - # @option time [DateTime] Authentication time + # Listener for the *staffs.authentication* event. + # @param attributes [Hash] Authentication attributes. + # @option attributes staff_id [Integer] Staff ID. + # @option attributes time [DateTime] Authentication time. def on_staffs_authentication(attributes) logger("Staff #{attributes[:staff_id]} authenticated on: #{attributes[:time].iso8601}") end @@ -61,26 +64,26 @@ def on_users_registration(user) logger("New registered user: #{user.to_h}") end - # Listener for to *users.authentication* event. - # @param attributes [Hash] Authentication attributes - # @option user_id [Integer] User ID - # @option time [DateTime] Authentication time + # Listener for the *users.authentication* event. + # @param attributes [Hash] Authentication attributes. + # @option attributes user_id [Integer] User ID. + # @option attributes time [DateTime] Authentication time. def on_users_authentication(attributes) logger("User #{attributes[:user_id]} authenticated on: #{attributes[:time].iso8601}") end - # Listener for to *users.confirmation* event. - # @param attributes [Hash] Confirmation attributes - # @option user_id [Integer] User ID - # @option time [DateTime] Authentication time + # Listener for the *users.confirmation* event. + # @param attributes [Hash] Confirmation attributes. + # @option user_id [Integer] User ID. + # @option time [DateTime] Authentication time. def on_users_confirmation(attributes) logger("User #{attributes[:user_id]} confirmed at: #{attributes[:time].iso8601}") end private - # Append message to system log. - # @param message [String] the message + # Appends a message to the system log. + # @param message [String] The message. def logger(message) Application[:logger].info(message) end diff --git a/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb b/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb index 533d366..192ff95 100644 --- a/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb @@ -5,13 +5,29 @@ module Operations module AuctionContext module PostAuction ## - # Operation class for finish auctions. + # Operation class for managing participants in auctions. # class ParticipantOperation < AuctionFunCore::Operations::Base include Import["repos.user_context.user_repository"] include Import["contracts.auction_context.post_auction.participant_contract"] include Import["workers.services.mail.auction_context.post_auction.participant_mailer_job"] + ## + # Executes the participant operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the winner operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @option attributes participant_id [Integer] The participating user ID. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123, participant_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::PostAuction::ParticipantOperation.call(attributes) do |result| + # result.success { |auction| puts "Participation operation completed successfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed auction participation operation: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -20,8 +36,12 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end - ## @todo Add more actions - # Send email to participant with auction statistics. + ## + # Executes the participant operation. + # + # @param attributes [Hash] The attributes for the participant operation. + # @return [Dry::Monads::Result] The result of the operation. + # def call(attributes) auction, participant = yield validate_contract(attributes) @@ -34,6 +54,12 @@ def call(attributes) private + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = participant_contract.call(attributes) @@ -42,6 +68,13 @@ def validate_contract(attributes) Success([contract.context[:auction], contract.context[:participant]]) end + ## + # Sends participant email with auction statistics and payment instructions. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @return [Dry::Monads::Result] The result of sending the email. + # def send_participant_email_with_statistics_and_payment_instructions(auction_id, participant_id) Success(participant_mailer_job.class.perform_async(auction_id, participant_id)) end diff --git a/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb b/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb index 731e40d..8bd5589 100644 --- a/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb @@ -5,13 +5,29 @@ module Operations module AuctionContext module PostAuction ## - # Operation class for finish auctions. + # Operation class for managing winners in auctions. # class WinnerOperation < AuctionFunCore::Operations::Base include Import["repos.user_context.user_repository"] include Import["contracts.auction_context.post_auction.winner_contract"] include Import["workers.services.mail.auction_context.post_auction.winner_mailer_job"] + ## + # Executes the winner operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the winner operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @option attributes winner_id [Integer] The winning user ID + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123, winner_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::PostAuction::WinnerOperation.call(attributes) do |result| + # result.success { |auction| puts "Winner operation completed successfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed auction winner operation: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -20,7 +36,12 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end - ## @todo Add doc + ## + # Executes the winner operation. + # + # @param attributes [Hash] The attributes for the winner operation. + # @return [Dry::Monads::Result] The result of the operation. + # def call(attributes) auction, winner = yield validate_contract(attributes) @@ -33,6 +54,12 @@ def call(attributes) private + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = winner_contract.call(attributes) @@ -41,6 +68,13 @@ def validate_contract(attributes) Success([contract.context[:auction], contract.context[:winner]]) end + ## + # Sends winner email with auction statistics and payment instructions. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @return [Dry::Monads::Result] The result of sending the email. + # def send_winner_email_with_statistics_and_payment_instructions(auction_id, winner_id) Success(winner_mailer_job.class.perform_async(auction_id, winner_id)) end diff --git a/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb b/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb index 007f646..da05719 100644 --- a/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb @@ -5,14 +5,20 @@ module Operations module AuctionContext module PreAuction ## - # Operation class for send a reminder email to a participant about the start of an auction. + # Operation class for sending a reminder email to a participant about the start of an auction. # class AuctionStartReminderOperation < AuctionFunCore::Operations::Base include Import["repos.bid_context.bid_repository"] include Import["contracts.auction_context.pre_auction.auction_start_reminder_contract"] include Import["workers.services.mail.auction_context.pre_auction.auction_start_reminder_mailer_job"] - # @todo Add custom doc + ## + # Executes the auction start reminder operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the auction start reminder operation. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # def self.call(attributes, &block) operation = new.call(attributes) @@ -21,6 +27,12 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end + ## + # Executes the auction start reminder operation. + # + # @param attributes [Hash] The attributes for the auction start reminder operation. + # @return [Dry::Monads::Result] The result of the operation. + # def call(attributes) auction = yield validate_contract(attributes) participant_ids = yield collect_current_auction_participants(auction.id) @@ -36,6 +48,13 @@ def call(attributes) private + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @option auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = auction_start_reminder_contract.call(attributes) @@ -44,6 +63,12 @@ def validate_contract(attributes) Success(contract.context[:auction]) end + ## + # Collects the participant IDs for the current auction. + # + # @param auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of collecting the participant IDs. + # def collect_current_auction_participants(auction_id) Success( AuctionFunCore::Application[:container] @@ -54,6 +79,13 @@ def collect_current_auction_participants(auction_id) ) end + ## + # Sends the auction start reminder email to a participant. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @return [Dry::Monads::Result] The result of sending the email. + # def send_auction_start_reminder_mailer_job(auction_id, participant_id) Success(auction_start_reminder_mailer_job.class.perform_async(auction_id, participant_id)) end diff --git a/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb b/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb index fcdc3cd..d4f608f 100644 --- a/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb @@ -7,7 +7,7 @@ module Processor module Finish ## # Operation class for finalizing a closed auction. - # By default, this change auction status from 'running' to 'finished'. + # By default, this changes the auction status from 'running' to 'finished'. # class ClosedOperation < AuctionFunCore::Operations::Base include Import["repos.auction_context.auction_repository"] @@ -15,7 +15,21 @@ class ClosedOperation < AuctionFunCore::Operations::Base include Import["workers.operations.auction_context.post_auction.winner_operation_job"] include Import["workers.operations.auction_context.post_auction.participant_operation_job"] - # @todo Add custom doc + ## + # Executes the closed operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the closed operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::Processor::Finish::ClosedOperation.call(attributes) do |result| + # result.success { |auction| puts "Finished closed auction sucessfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed to finished closed auction: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -24,10 +38,27 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end - # It only performs the basic processing of completing an auction. - # It just changes the status at the database level and triggers the finished event. - # @param auction_id [Integer] Auction ID - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Performs the closing of a closed auction. + # + # @param attributes [Hash] The attributes for the closed operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # operation = AuctionFunCore::Operations::AuctionContext::Processor::Finish::ClosedOperation.call(attributes) + # + # if operation.success? + # auction = operation.success + # puts "Finished closed auction sucessfully! #{auction.to_h}" + # end + # + # if operation.failure? + # failure = operation.failure + # puts "Failed to finished closed auction: #{failure.errors.to_h}" + # end def call(attributes) auction = yield validate_contract(attributes) summary = yield load_closed_auction_winners_and_participants(auction.id) @@ -50,10 +81,13 @@ def call(attributes) private - # Calls the finish contract class to perform the validation - # of the informed attributes. - # @param attributes [Hash] auction attributes - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @option auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = closed_contract.call(attributes) @@ -62,12 +96,25 @@ def validate_contract(attributes) Success(contract.context[:auction]) end + ## + # Loads the winners and participants of the closed auction. + # + # @param auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of loading the winners and participants. + # def load_closed_auction_winners_and_participants(auction_id) summary = relation.load_closed_auction_winners_and_participants(auction_id).first Success(summary) end + ## + # Updates the attributes of the finished auction. + # + # @param auction [Auction] The auction object. + # @param summary [Summary] The summary of winners and participants. + # @return [Dry::Monads::Result] The result of updating the attributes. + # def update_finished_auction(auction, summary) attrs = {status: "finished"} attrs[:winner_id] = summary.winner_id if summary.winner_id.present? @@ -75,20 +122,45 @@ def update_finished_auction(auction, summary) Success(attrs) end + ## + # Retrieves the relation. + # + # @return [ROM::Relation] The relation object. + # def relation AuctionFunCore::Application[:container].relations[:auctions] end + ## + # Executes the winner operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @return [Dry::Monads::Result] The result of executing the operation. + # def winner_operation(auction_id, winner_id) return Success() if winner_id.blank? Success(winner_operation_job.class.perform_async(auction_id, winner_id)) end + ## + # Executes the participant operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @return [Dry::Monads::Result] The result of executing the operation. + # def participant_operation(auction_id, participant_id) Success(participant_operation_job.class.perform_async(auction_id, participant_id)) end + ## + # Publishes the auction finish event. + # + # @param auction [ROM::Struct::Auction] The auction object. + # @return [void] + # def publish_auction_finish_event(auction) Application[:event].publish("auctions.finished", auction.to_h) end diff --git a/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb b/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb index c570f1c..21f5eaf 100644 --- a/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb @@ -7,7 +7,7 @@ module Processor module Finish ## # Operation class for finalizing a penny auction. - # By default, this change auction status from 'running' to 'finished'. + # By default, this changes the auction status from 'running' to 'finished'. # class PennyOperation < AuctionFunCore::Operations::Base include Import["repos.auction_context.auction_repository"] @@ -15,7 +15,21 @@ class PennyOperation < AuctionFunCore::Operations::Base include Import["workers.operations.auction_context.post_auction.winner_operation_job"] include Import["workers.operations.auction_context.post_auction.participant_operation_job"] - # @todo Add custom doc + ## + # Executes the penny operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the penny operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::Processor::Finish::PennyOperation.call(attributes) do |result| + # result.success { |auction| puts "Finished penny auction sucessfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed to finished penny auction: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -24,10 +38,27 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end - # It only performs the basic processing of completing an auction. - # It just changes the status at the database level and triggers the finished event. - # @param auction_id [Integer] Auction ID - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Performs the closing of a penny auction. + # + # @param attributes [Hash] The attributes for the penny operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # operation = AuctionFunCore::Operations::AuctionContext::Processor::Finish::PennyOperation.call(attributes) + # + # if operation.success? + # auction = operation.success + # puts "Finished penny auction sucessfully! #{auction.to_h}" + # end + # + # if operation.failure? + # failure = operation.failure + # puts "Failed to finished penny auction: #{failure.errors.to_h}" + # end def call(attributes) auction = yield validate_contract(attributes) summary = yield load_penny_auction_winners_and_participants(auction.id) @@ -50,10 +81,12 @@ def call(attributes) private - # Calls the finish contract class to perform the validation - # of the informed attributes. - # @param attributes [Hash] auction attributes - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = penny_contract.call(attributes) @@ -62,12 +95,25 @@ def validate_contract(attributes) Success(contract.context[:auction]) end + ## + # Loads the winners and participants of the penny auction. + # + # @param auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of loading the winners and participants. + # def load_penny_auction_winners_and_participants(auction_id) summary = relation.load_penny_auction_winners_and_participants(auction_id).first Success(summary) end + ## + # Updates the attributes of the finished auction. + # + # @param auction [ROM::Struct::Auction] The auction object. + # @param summary [ROM::OpenStruct] The summary of winners and participants. + # @return [Dry::Monads::Result] The result of updating the attributes. + # def update_finished_auction(auction, summary) attrs = {status: "finished"} attrs[:winner_id] = summary.winner_id if summary.winner_id.present? @@ -75,20 +121,45 @@ def update_finished_auction(auction, summary) Success(attrs) end + ## + # Retrieves the relation. + # + # @return [ROM::Relation] The relation object. + # def relation AuctionFunCore::Application[:container].relations[:auctions] end + ## + # Executes the winner operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @return [Dry::Monads::Result] The result of executing the operation. + # def winner_operation(auction_id, winner_id) return Success() if winner_id.blank? Success(winner_operation_job.class.perform_async(auction_id, winner_id)) end + ## + # Executes the participant operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @return [Dry::Monads::Result] The result of executing the operation. + # def participant_operation(auction_id, participant_id) Success(participant_operation_job.class.perform_async(auction_id, participant_id)) end + ## + # Publishes the auction finish event. + # + # @param auction [ROM::Struct::Auction] The auction object. + # @return [void] + # def publish_auction_finish_event(auction) Application[:event].publish("auctions.finished", auction.to_h) end diff --git a/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb b/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb index cc17252..a553b09 100644 --- a/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb @@ -7,7 +7,7 @@ module Processor module Finish ## # Operation class for finalizing a standard auction. - # By default, this change auction status from 'running' to 'finished'. + # By default, this changes the auction status from 'running' to 'finished'. # class StandardOperation < AuctionFunCore::Operations::Base include Import["repos.auction_context.auction_repository"] @@ -15,7 +15,21 @@ class StandardOperation < AuctionFunCore::Operations::Base include Import["workers.operations.auction_context.post_auction.winner_operation_job"] include Import["workers.operations.auction_context.post_auction.participant_operation_job"] - # @todo Add custom doc + ## + # Executes the standard operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the standard operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::Processor::Finish::StandardOperation.call(attributes) do |result| + # result.success { |auction| puts "Finished standard auction sucessfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed to finished standard auction: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -24,12 +38,27 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end - # TODO: update doc - # It only performs the basic processing of completing an auction. - # It just changes the status at the database level and triggers the finished event. - # @param attrs [Hash] auction attributes - # @option auction_id [Integer] Auction ID - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Performs the closing of a standard auction. + # + # @param attributes [Hash] The attributes for the standard operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # operation = AuctionFunCore::Operations::AuctionContext::Processor::Finish::StandardOperation.call(attributes) + # + # if operation.success? + # auction = operation.success + # puts "Finished standard auction sucessfully! #{auction.to_h}" + # end + # + # if operation.failure? + # failure = operation.failure + # puts "Failed to finished standard auction: #{failure.errors.to_h}" + # end def call(attributes) auction = yield validate_contract(attributes) summary = yield load_standard_auction_winners_and_participants(auction.id) @@ -52,10 +81,12 @@ def call(attributes) private - # Calls the finish standard contract class to perform the validation - # of the informed attributes. - # @param attributes [Hash] auction attributes - # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] + ## + # Validates the contract with the provided attributes. + # + # @param attributes [Hash] The attributes to validate. + # @return [Dry::Monads::Result] The result of the validation. + # def validate_contract(attributes) contract = standard_contract.call(attributes) @@ -64,12 +95,25 @@ def validate_contract(attributes) Success(contract.context[:auction]) end + ## + # Loads the winners and participants of the standard auction. + # + # @param auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result] The result of loading the winners and participants. + # def load_standard_auction_winners_and_participants(auction_id) summary = relation.load_standard_auction_winners_and_participants(auction_id).first Success(summary) end + ## + # Updates the attributes of the finished auction. + # + # @param auction [Auction] The auction object. + # @param summary [Summary] The summary of winners and participants. + # @return [Dry::Monads::Result] The result of updating the attributes. + # def update_finished_auction(auction, summary) attrs = {status: "finished"} attrs[:winner_id] = summary.winner_id if summary.winner_id.present? @@ -77,20 +121,45 @@ def update_finished_auction(auction, summary) Success(attrs) end + ## + # Retrieves the relation. + # + # @return [ROM::Relation] The relation object. + # def relation AuctionFunCore::Application[:container].relations[:auctions] end + ## + # Executes the winner operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @return [Dry::Monads::Result] The result of executing the operation. + # def winner_operation(auction_id, winner_id) return Success() if winner_id.blank? Success(winner_operation_job.class.perform_async(auction_id, winner_id)) end + ## + # Executes the participant operation asynchronously. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @return [Dry::Monads::Result] The result of executing the operation. + # def participant_operation(auction_id, participant_id) Success(participant_operation_job.class.perform_async(auction_id, participant_id)) end + ## + # Publishes the auction finish event. + # + # @param auction [ROM::Struct::Auction] The auction object. + # @return [void] + # def publish_auction_finish_event(auction) Application[:event].publish("auctions.finished", auction.to_h) end diff --git a/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb b/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb index 960fd7f..86abe16 100644 --- a/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb @@ -12,7 +12,21 @@ class PauseOperation < AuctionFunCore::Operations::Base include Import["repos.auction_context.auction_repository"] include Import["contracts.auction_context.processor.pause_contract"] - # @todo Add custom doc + ## + # Executes the pause operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the pause operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::Processor::PauseOperation.call(attributes) do |result| + # result.success { |auction| puts "Paused auction sucessfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed to pause auction: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -21,6 +35,27 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end + ## + # Performing an auction pause + # + # @param attributes [Hash] The attributes for the pause operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # operation = AuctionFunCore::Operations::AuctionContext::Processor::PauseOperation.call(attributes) + # + # if operation.success? + # auction = operation.success + # puts "Paused auction sucessfully! #{auction.to_h}" + # end + # + # if operation.failure? + # failure = operation.failure + # puts "Failed to pause auction: #{failure.errors.to_h}" + # end def call(attributes) attrs = yield validate(attributes) diff --git a/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb b/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb index 313c53a..09b45e1 100644 --- a/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +++ b/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb @@ -12,7 +12,21 @@ class UnpauseOperation < AuctionFunCore::Operations::Base include Import["repos.auction_context.auction_repository"] include Import["contracts.auction_context.processor.unpause_contract"] - # @todo Add custom doc + ## + # Executes the unpause operation with the provided attributes. + # + # @param attributes [Hash] The attributes for the unpause operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation. + # @return [Dry::Matcher::Evaluator] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # AuctionFunCore::Operations::AuctionContext::Processor::UnpauseOperation.call(attributes) do |result| + # result.success { |auction| puts "Unpaused auction sucessfully! #{auction.to_h}" } + # result.failure { |failure| puts "Failed to unpause auction: #{failure.errors.to_h}"} + # end def self.call(attributes, &block) operation = new.call(attributes) @@ -21,6 +35,27 @@ def self.call(attributes, &block) Dry::Matcher::ResultMatcher.call(operation, &block) end + ## + # Performs the unpause of an auction. + # + # @param attributes [Hash] The attributes for the unpause operation. + # @option attributes auction_id [Integer] The ID of the auction. + # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] The result of the operation. + # + # @example + # attributes = { auction_id: 123 } + # + # operation = AuctionFunCore::Operations::AuctionContext::Processor::UnpauseOperation.call(attributes) + # + # if operation.success? + # auction = operation.success + # puts "Unpaused auction sucessfully! #{auction.to_h}" + # end + # + # if operation.failure? + # failure = operation.failure + # puts "Failed to unpause auction: #{failure.errors.to_h}" + # end def call(attributes) attrs = yield validate(attributes) diff --git a/lib/auction_fun_core/relations/auctions.rb b/lib/auction_fun_core/relations/auctions.rb index 0c90549..87e860e 100644 --- a/lib/auction_fun_core/relations/auctions.rb +++ b/lib/auction_fun_core/relations/auctions.rb @@ -40,12 +40,30 @@ class Auctions < ROM::Relation[:sql] struct_namespace Entities auto_struct(true) + # Retrieves a paginated list of auctions along with related information. + # By default, it retrieves the first page with 10 auctions per page and includes information for the top 3 bidders. + # + # @param page [Integer] The page number to retrieve (default is 1). + # @param per_page [Integer] The number of auctions per page (default is 10). + # @param options [Hash] Additional options for customization (default is {bidders_count: 3}). + # @option options [Integer] :bidders_count The number of top bidders to include in the result (default is 3). + # @return [Array] An array of hashes representing the auctions and related information. + # @example Retrieve the first page of auctions with 10 per page and include information for the top 3 bidders + # all_auctions = all + # + # @example Retrieve the second page of auctions with 5 per page and include information for the top 5 bidders + # all_auctions = all(2, 5, { bidders_count: 5 }) + # + # @example Retrieve the third page of auctions with 15 per page and include information for the top 2 bidders + # all_auctions = all(3, 15, { bidders_count: 2 }) + # + # @raise [RuntimeError] if either `page` or `per_page` argument is not an integer. def all(page = 1, per_page = 10, options = {bidders_count: 3}) raise "Invalid argument" unless page.is_a?(Integer) && per_page.is_a?(Integer) offset = ((page - 1) * per_page) - read(" + sql = <<-SQL SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents, (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = a.id) dt) AS total_bids, CASE @@ -69,17 +87,37 @@ def all(page = 1, per_page = 10, options = {bidders_count: 3}) WHEN a.kind = 'closed' THEN json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int) END as bids - FROM auctions as a - LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id - LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id - GROUP BY a.id - LIMIT #{per_page} OFFSET #{offset}") + FROM auctions as a + LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id + LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id + GROUP BY a.id + LIMIT #{per_page} OFFSET #{offset} + SQL + + read(sql) end + # Retrieves detailed information about a specific auction. + # + # @param auction_id [Integer] The ID of the auction to retrieve information for. + # @param options [Hash] Additional options for customization (default is {bidders_count: 3}). + # @option options [Integer] :bidders_count The number of top bidders to include in the result (default is 3). + # @return [Hash] A hash representing the auction and related information. + # + # @example Retrieve information for auction with ID 123 + # auction_info = info(123) + # + # @example Retrieve information for auction with ID 456 and include information for the top 5 bidders + # auction_info = info(456, { bidders_count: 5 }) + # + # @example Retrieve information for auction with ID 789 and include information for the top 2 bidders + # auction_info = info(789, { bidders_count: 2 }) + # + # @raise [RuntimeError] if `auction_id` argument is not an integer. def info(auction_id, options = {bidders_count: 3}) raise "Invalid argument" unless auction_id.is_a?(Integer) - read(" + sql = <<-SQL SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents, (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = #{auction_id}) dt) AS total_bids, CASE @@ -103,11 +141,14 @@ def info(auction_id, options = {bidders_count: 3}) WHEN a.kind = 'closed' THEN json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int) END as bids - FROM auctions as a - LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id AND a.id = #{auction_id} - LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id - WHERE a.id = #{auction_id} - GROUP BY a.id") + FROM auctions as a + LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id AND a.id = #{auction_id} + LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id + WHERE a.id = #{auction_id} + GROUP BY a.id + SQL + + read(sql) end # Retrieves the standard auction winner and other participating bidders for a specified auction. @@ -125,22 +166,26 @@ def info(auction_id, options = {bidders_count: 3}) def load_standard_auction_winners_and_participants(auction_id) raise "Invalid argument" unless auction_id.is_a?(Integer) - read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, - COALESCE( - ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] - ) AS participant_ids - FROM auctions a - LEFT JOIN bids b ON a.id = b.auction_id - LEFT JOIN ( - SELECT auction_id, user_id, MAX(value_cents) AS value_cents - FROM bids - WHERE auction_id = #{auction_id} - GROUP BY auction_id, user_id - ORDER BY value_cents DESC - LIMIT 1 - ) AS w ON a.id = w.auction_id - WHERE a.id = #{auction_id} - GROUP BY a.id, w.user_id") + sql = <<-SQL + SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, + COALESCE( + ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] + ) AS participant_ids + FROM auctions a + LEFT JOIN bids b ON a.id = b.auction_id + LEFT JOIN ( + SELECT auction_id, user_id, MAX(value_cents) AS value_cents + FROM bids + WHERE auction_id = #{auction_id} + GROUP BY auction_id, user_id + ORDER BY value_cents DESC + LIMIT 1 + ) AS w ON a.id = w.auction_id + WHERE a.id = #{auction_id} + GROUP BY a.id, w.user_id + SQL + + read(sql) end # Retrieves the penny auction winner and other participating bidders for a specified auction. @@ -158,21 +203,25 @@ def load_standard_auction_winners_and_participants(auction_id) def load_penny_auction_winners_and_participants(auction_id) raise "Invalid argument" unless auction_id.is_a?(Integer) - read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, - COALESCE( - ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] - ) AS participant_ids - FROM auctions a - LEFT JOIN bids b ON a.id = b.auction_id - LEFT JOIN ( - SELECT auction_id, user_id - FROM bids - WHERE auction_id = #{auction_id} - ORDER BY bids.created_at DESC - LIMIT 1 - ) AS w ON a.id = w.auction_id - WHERE a.id = #{auction_id} - GROUP BY a.id, w.user_id") + sql = <<-SQL + SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, + COALESCE( + ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] + ) AS participant_ids + FROM auctions a + LEFT JOIN bids b ON a.id = b.auction_id + LEFT JOIN ( + SELECT auction_id, user_id + FROM bids + WHERE auction_id = #{auction_id} + ORDER BY bids.created_at DESC + LIMIT 1 + ) AS w ON a.id = w.auction_id + WHERE a.id = #{auction_id} + GROUP BY a.id, w.user_id + SQL + + read(sql) end # Retrieves the closed auction winner and other participating bidders for a specified auction. @@ -190,70 +239,102 @@ def load_penny_auction_winners_and_participants(auction_id) def load_closed_auction_winners_and_participants(auction_id) raise "Invalid argument" unless auction_id.is_a?(Integer) - read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, - COALESCE( - ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] - ) AS participant_ids - FROM auctions a - LEFT JOIN bids b ON a.id = b.auction_id - LEFT JOIN ( - SELECT auction_id, user_id, MAX(value_cents) AS value_cents - FROM bids - WHERE auction_id = #{auction_id} - GROUP BY auction_id, user_id - ORDER BY value_cents DESC - LIMIT 1 - ) AS w ON a.id = w.auction_id - WHERE a.id = #{auction_id} - GROUP BY a.id, w.user_id") + sql = <<-SQL + SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids, + COALESCE( + ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[] + ) AS participant_ids + FROM auctions a + LEFT JOIN bids b ON a.id = b.auction_id + LEFT JOIN ( + SELECT auction_id, user_id, MAX(value_cents) AS value_cents + FROM bids + WHERE auction_id = #{auction_id} + GROUP BY auction_id, user_id + ORDER BY value_cents DESC + LIMIT 1 + ) AS w ON a.id = w.auction_id + WHERE a.id = #{auction_id} + GROUP BY a.id, w.user_id + SQL + + read(sql) end + # Loads statistics for the winner of a specific auction. + # + # @param auction_id [Integer] The ID of the auction to load statistics for. + # @param winner_id [Integer] The ID of the winner to load statistics for. + # @return [Hash] A hash representing the statistics for the winner of the auction. + # + # @example Load statistics for the winner of auction with ID 123 and winner with ID 456 + # winner_stats = load_winner_statistics(123, 456) + # + # @raise [RuntimeError] if either `auction_id` or `winner_id` arguments are not integers. def load_winner_statistics(auction_id, winner_id) raise "Invalid argument" unless auction_id.is_a?(Integer) && winner_id.is_a?(Integer) - read("SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid, - date(a.finished_at) as auction_date, - (SELECT COUNT(*) FROM bids b2 - WHERE b2.auction_id = #{auction_id} - AND b2.user_id = #{winner_id} - ) AS winner_total_bids - FROM auctions a - LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id} - LEFT JOIN users u ON u.id = b.user_id AND u.id = #{winner_id} - LEFT JOIN ( - SELECT auction_id, user_id, MAX(value_cents) AS value_cents - FROM bids - WHERE auction_id = #{auction_id} - GROUP BY auction_id, user_id - ORDER BY value_cents DESC - LIMIT 1 - ) AS w ON a.id = w.auction_id - WHERE a.id = #{auction_id} - GROUP BY a.id") + sql = <<-SQL + SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid, + date(a.finished_at) as auction_date, + (SELECT COUNT(*) FROM bids b2 + WHERE b2.auction_id = #{auction_id} + AND b2.user_id = #{winner_id} + ) AS winner_total_bids + FROM auctions a + LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id} + LEFT JOIN users u ON u.id = b.user_id AND u.id = #{winner_id} + LEFT JOIN ( + SELECT auction_id, user_id, MAX(value_cents) AS value_cents + FROM bids + WHERE auction_id = #{auction_id} + GROUP BY auction_id, user_id + ORDER BY value_cents DESC + LIMIT 1 + ) AS w ON a.id = w.auction_id + WHERE a.id = #{auction_id} + GROUP BY a.id + SQL + + read(sql) end + # Loads statistics for a participant in a specific auction. + # + # @param auction_id [Integer] The ID of the auction to load statistics for. + # @param participant_id [Integer] The ID of the participant to load statistics for. + # @return [Hash] A hash representing the statistics for the participant in the auction. + # + # @example Load statistics for the participant with ID 456 in auction with ID 123 + # participant_stats = load_participant_statistics(123, 456) + # + # @raise [RuntimeError] if either `auction_id` or `participant_id` arguments are not integers. def load_participant_statistics(auction_id, participant_id) raise "Invalid argument" unless auction_id.is_a?(Integer) && participant_id.is_a?(Integer) - read("SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid, - date(a.finished_at) as auction_date, - (SELECT COUNT(*) FROM bids b2 - WHERE b2.auction_id = #{auction_id} - AND b2.user_id = #{participant_id} - ) AS winner_total_bids - FROM auctions a - LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id} - LEFT JOIN users u ON u.id = b.user_id AND u.id = #{participant_id} - LEFT JOIN ( - SELECT auction_id, user_id, MAX(value_cents) AS value_cents - FROM bids - WHERE auction_id = #{auction_id} - GROUP BY auction_id, user_id - ORDER BY value_cents DESC - LIMIT 1 - ) AS w ON a.id = w.auction_id - WHERE a.id = #{auction_id} - GROUP BY a.id") + sql = <<-SQL + SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid, + date(a.finished_at) as auction_date, + (SELECT COUNT(*) FROM bids b2 + WHERE b2.auction_id = #{auction_id} + AND b2.user_id = #{participant_id} + ) AS winner_total_bids + FROM auctions a + LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id} + LEFT JOIN users u ON u.id = b.user_id AND u.id = #{participant_id} + LEFT JOIN ( + SELECT auction_id, user_id, MAX(value_cents) AS value_cents + FROM bids + WHERE auction_id = #{auction_id} + GROUP BY auction_id, user_id + ORDER BY value_cents DESC + LIMIT 1 + ) AS w ON a.id = w.auction_id + WHERE a.id = #{auction_id} + GROUP BY a.id + SQL + + read(sql) end end end diff --git a/lib/auction_fun_core/repos/auction_context/auction_repository.rb b/lib/auction_fun_core/repos/auction_context/auction_repository.rb index 5b48004..fc569f1 100644 --- a/lib/auction_fun_core/repos/auction_context/auction_repository.rb +++ b/lib/auction_fun_core/repos/auction_context/auction_repository.rb @@ -3,7 +3,30 @@ module AuctionFunCore module Repos module AuctionContext - # SQL repository for auctions. + # Repository for handling repository operations related to auctions. + # + # This repository provides methods to interact with auction data in the database, + # including creating, updating, deleting, and retrieving auctions. + # + # @example + # auction_repo = AuctionFunCore::Repos::AuctionContext::AuctionRepository.new + # + # # Retrieve all auctions + # all_auctions = auction_repo.all + # + # # Get the total number of auctions + # total_auctions = auction_repo.count + # + # # Find an auction by its ID + # auction = auction_repo.by_id(123) + # + # # Find an auction by its ID and raise an error if not found + # auction = auction_repo.by_id!(123) + # + # @see AuctionFunCore::Entities::Auction Struct representing auction data + # @see https://rom-rb.org/learn/sql/3.3/queries/ + # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading + # class AuctionRepository < ROM::Repository[:auctions] include Import["container"] @@ -11,28 +34,34 @@ class AuctionRepository < ROM::Repository[:auctions] commands :create, update: :by_pk, delete: :by_pk # Returns all auctions in the database. - # @return [Array, []] + # @return [Array] def all auctions.to_a end - # Returns the total number of auctions in database. - # @return [Integer] + # Returns the total number of auctions in the database. + # + # @return [Integer] Total number of auctions. + # def count auctions.count end - # Search auction in database by primary key. - # @param id [Integer] Auction ID - # @return [ROM::Struct::Auction, nil] + # Retrieves an auction from the database by its primary key. + # + # @param id [Integer] The ID of the auction to retrieve. + # @return [ROM::Struct::Auction, nil] The retrieved auction, or nil if not found. + # def by_id(id) auctions.by_pk(id).one end - # Search auction in database by primary key. - # @param id [Integer] Auction ID - # @raise [ROM::TupleCountMismatchError] if not found on database - # @return [ROM::Struct::Auction] + # Retrieves an auction from the database by its primary key, raising an error if not found. + # + # @param id [Integer] The ID of the auction to retrieve. + # @raise [ROM::TupleCountMismatchError] if the auction is not found. + # @return [ROM::Struct::Auction] The retrieved auction. + # def by_id!(id) auctions.by_pk(id).one! end diff --git a/lib/auction_fun_core/repos/bid_context/bid_repository.rb b/lib/auction_fun_core/repos/bid_context/bid_repository.rb index 08227a0..07dd8cf 100644 --- a/lib/auction_fun_core/repos/bid_context/bid_repository.rb +++ b/lib/auction_fun_core/repos/bid_context/bid_repository.rb @@ -3,21 +3,43 @@ module AuctionFunCore module Repos module BidContext - # SQL repository for bids. + # Repository for handling repository operations related to bids. + # + # This repository provides methods to interact with bid data in the database, + # including creating, updating, deleting, and retrieving bids. + # + # @example + # bid_repo = AuctionFunCore::Repos::BidContext::BidRepository.new + # + # # Get the total number of bids + # total_bids = bid_repo.count + # + # # Checks if a bid exists based on the provided conditions. + # bid_repo.exists?(id: 123) + # + # @see AuctionFunCore::Entities::Bid Struct representing bid data + # @see https://rom-rb.org/learn/sql/3.3/queries/ + # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading + # class BidRepository < ROM::Repository[:bids] include Import["container"] struct_namespace Entities commands :create, update: :by_pk, delete: :by_pk - # Returns the total number of bids in database. - # @return [Integer] + # Returns the total number of bids in the database. + # + # @return [Integer] Total number of bids. + # def count bids.count end - # @param conditions [Hash] DSL Dataset - # @return [Boolean] + # Checks if a bid exists based on the provided conditions. + # + # @param conditions [Hash] The conditions to check (DSL Dataset). + # @return [Boolean] true if a bid exists that matches the conditions, otherwise false. + # def exists?(conditions) bids.exist?(conditions) end diff --git a/lib/auction_fun_core/repos/staff_context/staff_repository.rb b/lib/auction_fun_core/repos/staff_context/staff_repository.rb index 6e76713..31056cb 100644 --- a/lib/auction_fun_core/repos/staff_context/staff_repository.rb +++ b/lib/auction_fun_core/repos/staff_context/staff_repository.rb @@ -3,7 +3,41 @@ module AuctionFunCore module Repos module StaffContext - # SQL repository for staffs. + # Repository for handling repository operations related to staffs. + # + # This repository provides methods to interact with staff data in the database, + # including creating, updating, deleting, and retrieving staffs. + # + # @example + # staff_repo = AuctionFunCore::Repos::StaffContext::StaffRepository.new + # + # # Retrieve all staffs + # all_staffs = staff_repo.all + # + # # Get the total number of staffs + # total_staffs = staff_repo.count + # + # # Search staffs based on certain conditions + # conditions = {name: 'Staff'} + # search = staff_repo.query(conditions) + # + # # Find an staff by its ID + # staff = staff_repo.by_id(123) + # + # # Find an staff by its ID and raise an error if not found + # staff = staff_repo.by_id!(123) + # + # # Search for a staff by email or phone + # staff_by_login = staff_repo.by_login('example@example.com') + # + # # Check if a staff exists based on certain conditions + # conditions = { name: 'John Doe' } + # staff_exists = staff_repo.exists?(conditions) + # + # @see AuctionFunCore::Entities::Staff Struct representing staff data + # @see https://rom-rb.org/learn/sql/3.3/queries/ + # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading + # class StaffRepository < ROM::Repository[:staffs] include Import["container"] @@ -11,50 +45,58 @@ class StaffRepository < ROM::Repository[:staffs] commands :create, update: :by_pk, delete: :by_pk # Returns all staffs in database. - # @return [Array, []] + # @return [Array] def all staffs.to_a end - # Returns the total number of staffs in database. - # @return [Integer] + # Returns the total number of staffs in the database. + # + # @return [Integer] Total number of staffs. def count staffs.count end - # Mount SQL conditions in query for search in database. - # @param conditions [Hash] DSL Dataset - # @return [AuctionFunCore::Relations::Staffs] + # Constructs SQL conditions for querying staffs in the database. + # + # @param conditions [Hash] The conditions to be used in the query (DSL Dataset). + # @return [AuctionFunCore::Relations::Staff] The relation containing the staffs that match the given conditions. def query(conditions) staffs.where(conditions) end - # Search staff in database by primary key. - # @param id [Integer] Staff ID - # @return [ROM::Struct::Staff, nil] + # Retrieves an staff from the database by its primary key. + # + # @param id [Integer] The ID of the staff to retrieve. + # @return [ROM::Struct::Staff, nil] The retrieved staff, or nil if not found. + # def by_id(id) staffs.by_pk(id).one end - # Search staffs in database by primary key. - # @param id [Integer] Staff ID - # @raise [ROM::TupleCountMismatchError] if not found on database - # @return [ROM::Struct::Auction] + # Retrieves an staff from the database by its primary key, raising an error if not found. + # + # @param id [Integer] The ID of the staff to retrieve. + # @raise [ROM::TupleCountMismatchError] if the staff is not found. + # @return [ROM::Struct::Staff] The retrieved staff. + # def by_id!(id) staffs.by_pk(id).one! end - # Search staff in database by email of phone keys. - # @param login [String] Staff email or phone - # @return [ROM::Struct::Staff, nil] + # Searches for a staff in the database by email or phone keys. + # + # @param login [String] The email or phone of the staff. + # @return [ROM::Struct::Staff, nil] The staff found with the provided email or phone, + # or nil if not found. def by_login(login) staffs.where(Sequel[email: login] | Sequel[phone: login]).one end - # Checks if it returns any staff given one or more conditions. - # @param conditions [Hash] DSL Dataset - # @return [true] when some staff is returned from the given condition. - # @return [false] when no staff is returned from the given condition. + # Checks if a bid exists based on the provided conditions. + # + # @param conditions [Hash] The conditions to check (DSL Dataset). + # @return [Boolean] true if a staff exists that matches the conditions, otherwise false. def exists?(conditions) staffs.exist?(conditions) end diff --git a/lib/auction_fun_core/repos/user_context/user_repository.rb b/lib/auction_fun_core/repos/user_context/user_repository.rb index 9eca117..b6fecac 100644 --- a/lib/auction_fun_core/repos/user_context/user_repository.rb +++ b/lib/auction_fun_core/repos/user_context/user_repository.rb @@ -3,7 +3,40 @@ module AuctionFunCore module Repos module UserContext - # SQL repository for users. + # Repository for handling repository operations related to users. + # + # This repository provides methods to interact with user data in the database, + # including creating, updating, deleting, and retrieving users. + # + # @example + # user_repo = AuctionFunCore::Repos::UserContext::UserRepository.new + # + # # Retrieve all users + # all_users = user_repo.all + # + # # Get the total number of users + # total_users = user_repo.count + # + # # Find a user by its ID + # user = user_repo.by_id(123) + # + # # Find a user by its ID and raise an error if not found + # user = user_repo.by_id!(123) + # + # # Search for a user by email or phone + # user = user_repo.by_login('example@example.com') + # user = user_repo.by_login('1234567890') + # + # # Search for a user by email confirmation token + # user = user_repo.by_email_confirmation_token('email_confirmation_token') + # + # # Search for a user by phone confirmation token + # user = user_repo.by_phone_confirmation_token('phone_confirmation_token') + # + # @see AuctionFunCore::Entities::User Struct representing user data + # @see https://rom-rb.org/learn/sql/3.3/queries/ + # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading + # class UserRepository < ROM::Repository[:users] include Import["container"] @@ -11,7 +44,7 @@ class UserRepository < ROM::Repository[:users] commands :create, update: :by_pk, delete: :by_pk # Returns all users in database. - # @return [Array, []] + # @return [Array] def all users.to_a end @@ -22,53 +55,64 @@ def count users.count end - # Mount SQL conditions in query for search in database. - # @param conditions [Hash] DSL Dataset - # @return [AuctionFunCore::Relations::Users] + # Constructs SQL conditions for querying users in the database. + # + # @param conditions [Hash] The conditions to be used in the query (DSL Dataset). + # @return [AuctionFunCore::Relations::Users] The relation containing the users that match the given conditions. def query(conditions) users.where(conditions) end - # Search user in database by primary key. - # @param id [Integer] User ID - # @return [ROM::Struct::User, nil] + # Retrieves a user from the database by its primary key. + # + # @param id [Integer] The ID of the user to retrieve. + # @return [ROM::Struct::User, nil] The retrieved user, or nil if not found. + # def by_id(id) users.by_pk(id).one end - # Search user in database by primary key. - # @param id [Integer] User ID - # @raise [ROM::TupleCountMismatchError] if not found on database - # @return [ROM::Struct::Auction] + # Retrieves a user from the database by its primary key, raising an error if not found. + # + # @param id [Integer] The ID of the user to retrieve. + # @raise [ROM::TupleCountMismatchError] if the user is not found. + # @return [ROM::Struct::User] The retrieved user. + # def by_id!(id) users.by_pk(id).one! end - # Search user in database by email of phone keys. - # @param login [String] User email or phone - # @return [ROM::Struct::User, nil] + # Searches for a user in the database by email or phone keys. + # + # @param login [String] The email or phone of the user. + # @return [ROM::Struct::User, nil] The user found with the provided email or phone, + # or nil if not found. def by_login(login) users.where(Sequel[email: login] | Sequel[phone: login]).one end - # Search user in database by email_confirmation_token key. - # @param email_confirmation_token [String] User email confirmation token - # @return [ROM::Struct::User, nil] + # Searches for a user in the database by email confirmation token. + # + # @param email_confirmation_token [String] The email confirmation token of the user. + # @return [ROM::Struct::User, nil] The user found with the provided email confirmation token, + # or nil if not found. def by_email_confirmation_token(email_confirmation_token) users.where(Sequel[email_confirmation_token: email_confirmation_token]).one end - # Search user in database by phone_confirmation_token of phone keys. - # @param phone [String] User phone confirmation token - # @return [ROM::Struct::User, nil] + # Searches for a user in the database by phone confirmation token. + # + # @param phone_confirmation_token [String] The phone confirmation token of the user. + # @return [ROM::Struct::User, nil] The user found with the provided phone confirmation token, + # or nil if not found. def by_phone_confirmation_token(phone_confirmation_token) users.where(Sequel[phone_confirmation_token: phone_confirmation_token]).one end - # Checks if it returns any user given one or more conditions. - # @param conditions [Hash] DSL Dataset - # @return [true] when some user is returned from the given condition. - # @return [false] when no user is returned from the given condition. + # Checks if a user exists based on the provided conditions. + # + # @param conditions [Hash] The conditions to check (DSL Dataset). + # @return [Boolean] true if a user exists that matches the conditions, otherwise false. def exists?(conditions) users.exist?(conditions) end diff --git a/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb b/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb index b83243f..c680e7f 100644 --- a/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +++ b/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb @@ -5,12 +5,15 @@ module Services module Mail module AuctionContext module PostAuction + # Service class responsible for sending emails to auction participants. class ParticipantMailer include IdleMailer::Mailer include IdleMailer::TemplateManager + # Initializes a new ParticipantMailer instance. + # # @param auction [ROM::Struct::Auction] The auction object - # @param participant [ROM::Struct::User] The user object + # @param participant [ROM::Struct::User] The participant object # @param statistics [OpenStruct] Statistics object def initialize(auction, participant, statistics) @auction = auction @@ -20,6 +23,9 @@ def initialize(auction, participant, statistics) mail.subject = I18n.t("mail.auction_context.post_auction.participant_mailer.subject", title: @auction.title) end + # Returns the template name for the ParticipantMailer. + # + # @return [String] The template name. def self.template_name IdleMailer.config.templates.join("auction_context/post_auction/participant") end diff --git a/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb b/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb index 83dd8bb..4285125 100644 --- a/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +++ b/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb @@ -5,12 +5,15 @@ module Services module Mail module AuctionContext module PostAuction + # Service class responsible for sending emails to auction winners. class WinnerMailer include IdleMailer::Mailer include IdleMailer::TemplateManager + # Initializes a new WinnerMailer instance. + # # @param auction [ROM::Struct::Auction] The auction object - # @param winner [ROM::Struct::User] The user object + # @param winner [ROM::Struct::User] The winner object # @param statistics [OpenStruct] Statistics object def initialize(auction, winner, statistics) @auction = auction @@ -20,6 +23,9 @@ def initialize(auction, winner, statistics) mail.subject = I18n.t("mail.auction_context.post_auction.winner_mailer.subject", title: @auction.title) end + # Returns the template name for the WinnerMailer. + # + # @return [String] The template name. def self.template_name IdleMailer.config.templates.join("auction_context/post_auction/winner") end diff --git a/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb b/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb index a111082..765e37a 100644 --- a/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb +++ b/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb @@ -5,10 +5,13 @@ module Services module Mail module AuctionContext module PreAuction + # # Service class responsible for sending auction start reminder emails to participants. class AuctionStartReminderMailer include IdleMailer::Mailer include IdleMailer::TemplateManager + # Initializes a new AuctionStartReminderMailer instance. + # # @param auction [ROM::Struct::Auction] The auction object # @param participant [ROM::Struct::User] The participant object def initialize(auction, participant) @@ -18,6 +21,9 @@ def initialize(auction, participant) mail.subject = I18n.t("mail.auction_context.pre_auction.auction_start_reminder_mailer.subject", title: @auction.title) end + # Returns the template name for the AuctionStartReminderMailer. + # + # @return [String] The template name. def self.template_name IdleMailer.config.templates.join("auction_context/pre_auction/auction_start_reminder") end diff --git a/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb b/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb index 065b289..4936c13 100644 --- a/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +++ b/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb @@ -4,10 +4,13 @@ module AuctionFunCore module Services module Mail module UserContext + # Service class responsible for sending registration emails to users. class RegistrationMailer include IdleMailer::Mailer include IdleMailer::TemplateManager + # Initializes a new RegistrationMailer instance. + # # @param user [ROM::Struct::User] The user object def initialize(user) @user = user @@ -15,6 +18,9 @@ def initialize(user) mail.subject = I18n.t("mail.user_context.registration.subject") end + # Returns the template name for the RegistrationMailer. + # + # @return [String] The template name. def self.template_name IdleMailer.config.templates.join("user_context/registration") end diff --git a/lib/auction_fun_core/version.rb b/lib/auction_fun_core/version.rb index 98a073b..8f746b2 100644 --- a/lib/auction_fun_core/version.rb +++ b/lib/auction_fun_core/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module AuctionFunCore - VERSION = "0.8.8" + VERSION = "0.8.9" # Required class module is a gem dependency class Version; end diff --git a/lib/auction_fun_core/workers/application_job.rb b/lib/auction_fun_core/workers/application_job.rb index 1192e57..78f6fc7 100644 --- a/lib/auction_fun_core/workers/application_job.rb +++ b/lib/auction_fun_core/workers/application_job.rb @@ -10,10 +10,20 @@ class ApplicationJob MAX_RETRIES = 15 include Sidekiq::Job + # Captures an exception and logs it along with additional attributes. + # + # @param exception [Exception] The exception to be captured. + # @param attributes [Hash] Additional attributes to be logged. + # @return [void] def capture_exception(exception, attributes = {}) Application[:logger].error("#{exception.message}. Parameters: #{attributes}") end + # Calculates an exponential backoff interval for retrying the job. + # + # @param retry_count [Integer] The current retry count. + # @param measure [String] The unit of time to measure the interval. + # @return [Integer] The backoff interval in the specified measure. def backoff_exponential_job(retry_count, measure = "seconds") max_retries = Float(2**retry_count) diff --git a/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb index 4847927..b0cae21 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb @@ -6,13 +6,18 @@ module Operations module AuctionContext module PostAuction ## - # BackgroundJob class for call finish auction operation. + # Background job class responsible for performing participant operations after an finished auction. class ParticipantOperationJob < Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] include Import["operations.auction_context.post_auction.participant_operation"] - # @todo Add detailed documentation + # Executes the participant operation for the specified auction and participant. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, participant_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) participant = user_repository.by_id!(participant_id) diff --git a/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb index 12b61a8..989f8b3 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb @@ -6,13 +6,17 @@ module Operations module AuctionContext module PostAuction ## - # BackgroundJob class for call finish auction operation. + # Background job class responsible for performing winner operations after an finished auction. class WinnerOperationJob < Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] include Import["operations.auction_context.post_auction.winner_operation"] - # @todo Add detailed documentation + # Executes the winner operation for the specified auction and winner. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @param retry_count [Integer] The current retry count for the job. def perform(auction_id, winner_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) winner = user_repository.by_id!(winner_id) diff --git a/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb index e1c2b4b..e61a643 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb @@ -6,12 +6,16 @@ module Operations module AuctionContext module PreAuction ## - # BackgroundJob class for call auction start reminder operation. + # Background job class responsible for sending auction start reminders class AuctionStartReminderOperationJob < Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] - # @todo Add detailed documentation + # Executes the auction start reminder operation for the specified auction. + # + # @param auction_id [Integer] The ID of the auction. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) @@ -26,9 +30,9 @@ def perform(auction_id, retry_count = 0) private - # Since the shipping code structure does not follow project conventions, - # making the default injection dependency would be more complicated. - # Therefore, here I directly explain the class to be called. + # Retrieves the auction start reminder operation. + # + # @return [Class] The auction start reminder operation class. def auction_start_reminder_operation AuctionFunCore::Operations::AuctionContext::PreAuction::AuctionStartReminderOperation end diff --git a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb index f7c905b..6895931 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb @@ -7,13 +7,16 @@ module AuctionContext module Processor module Finish ## - # BackgroundJob class for call finish closed auction operation. - # + # Background job class responsible for call finish closed auction operation. class ClosedOperationJob < Workers::ApplicationJob include Import["repos.auction_context.auction_repository"] include Import["operations.auction_context.processor.finish.closed_operation"] - # @todo Add detailed documentation + # Executes the operation to finish a closed auction. + # + # @param auction_id [Integer] The ID of the closed auction. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) diff --git a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb index d7ae8a0..b4cdf59 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb @@ -7,8 +7,7 @@ module AuctionContext module Processor module Finish ## - # BackgroundJob class for call finish penny auction operation. - # + # Background job class responsible for call finish penny auction operation. class PennyOperationJob < Workers::ApplicationJob include Sidekiq::Worker include Import["repos.auction_context.auction_repository"] @@ -16,7 +15,11 @@ class PennyOperationJob < Workers::ApplicationJob sidekiq_options queue: "default", lock: :until_executed, on_conflict: :replace - # @todo Add detailed documentation + # Executes the operation to finish a penny auction. + # + # @param auction_id [Integer] The ID of the penny auction. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) diff --git a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb index 1fd44cd..7fd911e 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb @@ -7,13 +7,17 @@ module AuctionContext module Processor module Finish ## - # BackgroundJob class for call finish standard auction operation. + # Background job class responsible for call finish standard auction operation. # class StandardOperationJob < Workers::ApplicationJob include Import["repos.auction_context.auction_repository"] include Import["operations.auction_context.processor.finish.standard_operation"] - # @todo Add detailed documentation + # Executes the operation to finish a standard auction. + # + # @param auction_id [Integer] The ID of the standard auction. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) diff --git a/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb b/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb index 72a2f16..441ccff 100644 --- a/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +++ b/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb @@ -6,13 +6,16 @@ module Operations module AuctionContext module Processor ## - # BackgroundJob class for call start auction operation. - # + # Background job class responsible for call start auction operation. class StartOperationJob < AuctionFunCore::Workers::ApplicationJob include Import["repos.auction_context.auction_repository"] include Import["operations.auction_context.processor.start_operation"] - # @todo Add detailed documentation + # Executes the operation to start an auction. + # + # @param auction_id [Integer] The ID of the auction to start. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) diff --git a/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb b/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb index 5a24fcd..e8545b9 100644 --- a/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +++ b/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb @@ -7,14 +7,17 @@ module Mail module AuctionContext module PostAuction ## - # Background job class responsible for adding emails to the queue. - # + # Background job class responsible for queuing participant emails. class ParticipantMailerJob < AuctionFunCore::Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] - # @param auction_id [Integer] auction ID - # @param participant_id [Integer] user ID + # Reads the statistics of a participant in an auction and sends it by email. + # + # @param auction_id [Integer] The ID of the auction. + # @param participant_id [Integer] The ID of the participant. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, participant_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) participant = user_repository.by_id!(participant_id) @@ -32,13 +35,15 @@ def perform(auction_id, participant_id, retry_count = 0) private - # Since the shipping code structure does not follow project conventions, - # making the default injection dependency would be more complicated. - # Therefore, here I directly explain the class to be called. + # Directly specifies the class to be called due to non-standard dependency injection. + # @return [Class] The participant mailer class. def participant_mailer AuctionFunCore::Services::Mail::AuctionContext::PostAuction::ParticipantMailer end + # Retrieves the relation for loading participant statistics. + # + # @return [ROM::Relation] The relation object. def relation AuctionFunCore::Application[:container].relations[:auctions] end diff --git a/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb b/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb index 47e1865..1a7fb20 100644 --- a/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +++ b/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb @@ -13,8 +13,12 @@ class WinnerMailerJob < AuctionFunCore::Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] - # @param auction_id [Integer] auction ID - # @param winner_id [Integer] user ID + # Reads the statistics of a winner in an auction and sends it by email. + # + # @param auction_id [Integer] The ID of the auction. + # @param winner_id [Integer] The ID of the winner. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, winner_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) winner = user_repository.by_id!(winner_id) @@ -32,13 +36,15 @@ def perform(auction_id, winner_id, retry_count = 0) private - # Since the shipping code structure does not follow project conventions, - # making the default injection dependency would be more complicated. - # Therefore, here I directly explain the class to be called. + # Directly specifies the class to be called due to non-standard dependency injection. + # @return [Class] The winner mailer class. def winner_mailer AuctionFunCore::Services::Mail::AuctionContext::PostAuction::WinnerMailer end + # Retrieves the relation for loading winner statistics. + # + # @return [ROM::Relation] The relation object. def relation AuctionFunCore::Application[:container].relations[:auctions] end diff --git a/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb b/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb index 0d349ac..c50dbfa 100644 --- a/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb +++ b/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb @@ -7,14 +7,18 @@ module Mail module AuctionContext module PreAuction ## - # Background job class responsible for adding emails to the queue. - # + # Background job class responsible for adding auction start emails to the queue. class AuctionStartReminderMailerJob < AuctionFunCore::Workers::ApplicationJob include Import["repos.user_context.user_repository"] include Import["repos.auction_context.auction_repository"] - # @param auction_id [Integer] auction ID - # @param participant_id [Integer] user ID + # Executes the operation of sending an email to the participant notifying + # them of the start of the auction. + # + # @param auction_id [Integer] The ID of the standard auction. + # @param participant_id [Integer] The ID of the participant + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(auction_id, participant_id, retry_count = 0) auction = auction_repository.by_id!(auction_id) participant = user_repository.by_id!(participant_id) @@ -30,9 +34,8 @@ def perform(auction_id, participant_id, retry_count = 0) private - # Since the shipping code structure does not follow project conventions, - # making the default injection dependency would be more complicated. - # Therefore, here I directly explain the class to be called. + # Directly specifies the class to be called due to non-standard dependency injection. + # @return [Class] The auction start reminder mailer class. def auction_start_reminder_mailer AuctionFunCore::Services::Mail::AuctionContext::PreAuction::AuctionStartReminderMailer end diff --git a/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb b/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb index 2a2990a..8c2a7a6 100644 --- a/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +++ b/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb @@ -6,12 +6,15 @@ module Services module Mail module UserContext ## - # Background job class responsible for adding emails to the queue. - # + # Background job class responsible for queuing registration emails. class RegistrationMailerJob < AuctionFunCore::Workers::ApplicationJob include Import["repos.user_context.user_repository"] - # @param user_id [Integer] user ID + # Initializes a new RegistrationMailerJob instance. + # + # @param user_id [Integer] The ID of the user. + # @param retry_count [Integer] The current retry count for the job. + # @return [void] def perform(user_id, retry_count = 0) user = user_repository.by_id!(user_id) @@ -26,9 +29,8 @@ def perform(user_id, retry_count = 0) private - # Since the shipping code structure does not follow project conventions, - # making the default injection dependency would be more complicated. - # Therefore, here I directly explain the class to be called. + # Directly specifies the class to be called due to non-standard dependency injection. + # @return [Class] The registration mailer class. def registration_mailer AuctionFunCore::Services::Mail::UserContext::RegistrationMailer end diff --git a/spec/auction_fun_core_spec.rb b/spec/auction_fun_core_spec.rb index d66ab81..b93735b 100644 --- a/spec/auction_fun_core_spec.rb +++ b/spec/auction_fun_core_spec.rb @@ -2,6 +2,6 @@ RSpec.describe AuctionFunCore do it "has a version number" do - expect(AuctionFunCore::VERSION).to eq("0.8.8") + expect(AuctionFunCore::VERSION).to eq("0.8.9") end end diff --git a/system/providers/background_job.rb b/system/providers/background_job.rb index be4b104..81e0983 100644 --- a/system/providers/background_job.rb +++ b/system/providers/background_job.rb @@ -8,22 +8,28 @@ start do Sidekiq.configure_server do |config| + # Set up Sidekiq server configuration config.redis = {url: target[:settings].redis_url} config.logger = target[:settings].logger config.average_scheduled_poll_interval = 3 + # Configure client middleware for uniqueness config.client_middleware do |chain| chain.add SidekiqUniqueJobs::Middleware::Client end + # Configure server middleware for uniqueness config.server_middleware do |chain| chain.add SidekiqUniqueJobs::Middleware::Server end + # Configure Sidekiq Unique Jobs for the server SidekiqUniqueJobs::Server.configure(config) end + # Configure client middleware for uniqueness Sidekiq.configure_client do |config| + # Set up Sidekiq client configuration config.redis = {url: target[:settings].redis_url} config.client_middleware do |chain|