-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add authentication resource for users * Refactoring return monads in operation classes - Update lib version * Allow only active users can authenticate * Fix method documentation
- Loading branch information
1 parent
bb8adfe
commit 346f64c
Showing
18 changed files
with
329 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
PATH | ||
remote: . | ||
specs: | ||
auction_fun_core (0.2.0) | ||
auction_fun_core (0.3.1) | ||
|
||
GEM | ||
remote: https://rubygems.org/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
lib/auction_fun_core/contracts/user_context/authentication_contract.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# frozen_string_literal: true | ||
|
||
module AuctionFunCore | ||
module Contracts | ||
module UserContext | ||
# Contract class to authenticate users. | ||
class AuthenticationContract < ApplicationContract | ||
I18N_SCOPE = "contracts.errors.custom.default" | ||
|
||
option :user_repository, default: proc { Repos::UserContext::UserRepository.new } | ||
|
||
params do | ||
required(:login) | ||
required(:password) | ||
|
||
before(:value_coercer) do |result| | ||
result.to_h.compact | ||
end | ||
end | ||
|
||
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. | ||
rule do |context:| | ||
next if (rule_error?(:login) || schema_error?(:login)) || (rule_error?(:password) || schema_error?(:password)) | ||
|
||
context[:user] ||= user_repository.by_login(values[:login]) | ||
|
||
next if context[:user].present? && context[:user].active? && (BCrypt::Password.new(context[:user].password_digest) == values[:password]) | ||
|
||
if context[:user].blank? || (BCrypt::Password.new(context[:user].password_digest) != values[:password]) | ||
key(:base).failure(I18n.t("login_not_found", scope: I18N_SCOPE)) | ||
end | ||
|
||
if context[:user].present? && context[:user].inactive? | ||
key(:base).failure(I18n.t("inactive_account", scope: I18N_SCOPE)) | ||
end | ||
|
||
key(:base).failure(I18n.t("login_not_found", scope: I18N_SCOPE)) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
lib/auction_fun_core/operations/user_context/authentication_operation.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# frozen_string_literal: true | ||
|
||
module AuctionFunCore | ||
module Operations | ||
module UserContext | ||
## | ||
# Operation class for authenticate users. | ||
# | ||
class AuthenticationOperation < AuctionFunCore::Operations::Base | ||
include Import["contracts.user_context.authentication_contract"] | ||
# include Import["repos.user_context.user_repository"] | ||
|
||
def self.call(attributes, &block) | ||
operation = new.call(attributes) | ||
|
||
return operation unless block | ||
|
||
Dry::Matcher::ResultMatcher.call(operation, &block) | ||
end | ||
|
||
# @todo Add custom doc | ||
def call(attributes) | ||
user = yield validate_contract(attributes) | ||
|
||
yield publish_user_authentication(user.id) | ||
|
||
Success(user) | ||
end | ||
|
||
# Calls the authentication contract class to perform the validation | ||
# and authentication of the informed attributes. | ||
# @param attrs [Hash] user attributes | ||
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] | ||
def validate_contract(attrs) | ||
contract = authentication_contract.call(attrs) | ||
|
||
return Failure(contract.errors.to_h) if contract.failure? | ||
|
||
Success(contract.context[:user]) | ||
end | ||
|
||
# Triggers the publication of event *users.registration*. | ||
# @param user_id [Integer] User ID | ||
# @return [Dry::Monads::Result::Success] | ||
def publish_user_authentication(user_id, time = Time.current) | ||
Success( | ||
Application[:event].publish("users.authentication", {user_id: user_id, time: time}) | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
spec/auction_fun_core/contracts/user_context/authentication_contract_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
|
||
RSpec.describe AuctionFunCore::Contracts::UserContext::AuthenticationContract, type: :contract do | ||
describe "#call" do | ||
subject(:contract) { described_class.new.call(attributes) } | ||
|
||
context "when params are blank" do | ||
let(:attributes) { {} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:login]).to include(I18n.t("contracts.errors.key?")) | ||
expect(contract.errors[:password]).to include(I18n.t("contracts.errors.key?")) | ||
end | ||
end | ||
|
||
context "when login params are invalid" do | ||
context "when email is invalid" do | ||
let(:attributes) { {login: "invalid_email"} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:login]).to include( | ||
I18n.t("contracts.errors.custom.macro.login_format") | ||
) | ||
end | ||
end | ||
|
||
context "when phone is invalid" do | ||
let(:attributes) { {login: "12345"} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:login]).to include( | ||
I18n.t("contracts.errors.custom.macro.login_format") | ||
) | ||
end | ||
end | ||
end | ||
|
||
context "with database" do | ||
context "when login is not found on database" do | ||
let(:attributes) { {login: "[email protected]", password: "example"} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:base]).to include( | ||
I18n.t("contracts.errors.custom.default.login_not_found") | ||
) | ||
end | ||
end | ||
|
||
context "when password doesn't match with storage password on database" do | ||
let(:user) { Factory[:user] } | ||
let(:attributes) { {login: user.email, password: "invalid"} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:base]).to include( | ||
I18n.t("contracts.errors.custom.default.login_not_found") | ||
) | ||
end | ||
end | ||
|
||
context "when credentials are valid but user is inactive" do | ||
let(:user) { Factory[:user, :inactive] } | ||
let(:attributes) { {login: user.email, password: "password"} } | ||
|
||
it "expect failure with error messages" do | ||
expect(contract).to be_failure | ||
expect(contract.errors[:base]).to include( | ||
I18n.t("contracts.errors.custom.default.inactive_account") | ||
) | ||
end | ||
end | ||
end | ||
|
||
context "when credentials are valid" do | ||
let(:user) { Factory[:user] } | ||
let(:attributes) { {login: user.email, password: "password"} } | ||
|
||
it "expect return success" do | ||
expect(contract).to be_success | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.