Skip to content

Commit

Permalink
[AF-43] Add documentation (#44)
Browse files Browse the repository at this point in the history
* Add documentation

* Using the heredoc standard to build SQL queries
  • Loading branch information
ricardopacheco committed Apr 29, 2024
1 parent 6fdf60c commit 80fa3ec
Show file tree
Hide file tree
Showing 68 changed files with 1,503 additions and 432 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions .standard.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# For available configuration options, see:
# https://github.com/standardrb/standard
format: progress
parallel: true
ruby_version: 3.0
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
66 changes: 34 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -13,24 +13,24 @@ 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

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.
Expand All @@ -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
Expand All @@ -52,58 +52,58 @@ 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.

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
Expand All @@ -117,20 +117,22 @@ 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

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

Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -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"

Expand Down
31 changes: 31 additions & 0 deletions lib/auction_fun_core/business/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>] 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<String>] 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
Expand Down
20 changes: 19 additions & 1 deletion lib/auction_fun_core/business/token_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion lib/auction_fun_core/contracts/application_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)

Expand All @@ -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)

Expand Down

0 comments on commit 80fa3ec

Please sign in to comment.