Skip to content

Commit

Permalink
[AF-29] Create actions for pause and unpause auctions (#30)
Browse files Browse the repository at this point in the history
* Create actions for pause and unpause auctions

* Upgrade CHANGELOG and lib version
  • Loading branch information
ricardopacheco committed Mar 12, 2024
1 parent 9b1aeac commit a9a595e
Show file tree
Hide file tree
Showing 15 changed files with 449 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## [Unreleased]

## [0.8.3] - 2024-03-12

### Added

- Processing actions to pause and unpause an auction.

## [0.8.1] - 2024-03-06

### Added
Expand Down
2 changes: 1 addition & 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.1)
auction_fun_core (0.8.3)

GEM
remote: https://rubygems.org/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module AuctionFunCore
module Contracts
module AuctionContext
module Processor
##
# Contract class for pause auction.
#
class PauseContract < Contracts::ApplicationContract
option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new }

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.
rule(:auction_id) do |context:|
context[:auction] ||= auction_repository.by_id(value)
key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction]

unless %w[running].include?(context[:auction].status)
key.failure(
I18n.t("contracts.errors.custom.bids.invalid_status", status: context[:auction].status)
)
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module AuctionFunCore
module Contracts
module AuctionContext
module Processor
##
# Contract class for unpause auction.
#
class UnpauseContract < Contracts::ApplicationContract
option :auction_repository, default: proc { Repos::AuctionContext::AuctionRepository.new }

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.
rule(:auction_id) do |context:|
context[:auction] ||= auction_repository.by_id(value)
key.failure(I18n.t("contracts.errors.custom.not_found")) unless context[:auction]

unless %w[paused].include?(context[:auction].status)
key.failure(
I18n.t("contracts.errors.custom.bids.invalid_status", status: context[:auction].status)
)
end
end
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/auction_fun_core/events/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class App
register_event("auctions.created")
register_event("auctions.started")
register_event("auctions.finished")
register_event("auctions.paused")
register_event("auctions.unpaused")

register_event("bids.created")

Expand Down
12 changes: 12 additions & 0 deletions lib/auction_fun_core/events/listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ def on_auctions_finished(auction)
logger("Finished auction: #{auction.to_h}")
end

# Listener for to *auctions.paused* event.
# @param event [ROM::Struct::Auction] the auction object
def on_auctions_paused(auction)
logger("Paused auction with: #{auction.to_h}")
end

# Listener for to *auctions.unpaused* event.
# @param event [ROM::Struct::Auction] the auction object
def on_auctions_unpaused(auction)
logger("Unpaused auction with: #{auction.to_h}")
end

# Listener for to *bids.created* event.
# @param event [Integer] Auction ID
def on_bids_created(bid)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module AuctionFunCore
module Operations
module AuctionContext
module Processor
##
# Operation class for dispatch pause auction.
# By default, this change auction status from 'running' to 'paused'.
#
class PauseOperation < AuctionFunCore::Operations::Base
include Import["repos.auction_context.auction_repository"]
include Import["contracts.auction_context.processor.pause_contract"]

# @todo Add custom doc
def self.call(attributes, &block)
operation = new.call(attributes)

return operation unless block

Dry::Matcher::ResultMatcher.call(operation, &block)
end

def call(attributes)
attrs = yield validate(attributes)

auction_repository.transaction do |_t|
@auction, _ = auction_repository.update(attrs[:auction_id], status: "paused")

publish_auction_pause_event(@auction)
end

Success(attrs[:auction_id])
end

private

# Calls the finish contract class to perform the validation
# of the informed attributes.
# @param attrs [Hash] auction attributes
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
def validate(attributes)
contract = pause_contract.call(attributes)

return Failure(contract.errors.to_h) if contract.failure?

Success(contract.to_h)
end

def publish_auction_pause_event(auction)
Application[:event].publish("auctions.paused", auction.to_h)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module AuctionFunCore
module Operations
module AuctionContext
module Processor
##
# Operation class for dispatch unpause auction.
# By default, this change auction status from 'paused' to 'running'.
#
class UnpauseOperation < AuctionFunCore::Operations::Base
include Import["repos.auction_context.auction_repository"]
include Import["contracts.auction_context.processor.unpause_contract"]

# @todo Add custom doc
def self.call(attributes, &block)
operation = new.call(attributes)

return operation unless block

Dry::Matcher::ResultMatcher.call(operation, &block)
end

def call(attributes)
attrs = yield validate(attributes)

auction_repository.transaction do |_t|
@auction, _ = auction_repository.update(attrs[:auction_id], status: "running")

publish_auction_unpause_event(@auction)
end

Success(attrs[:auction_id])
end

private

# Calls the unpause contract class to perform the validation
# of the informed attributes.
# @param attrs [Hash] auction attributes
# @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
def validate(attributes)
contract = unpause_contract.call(attributes)

return Failure(contract.errors.to_h) if contract.failure?

Success(contract.to_h)
end

def publish_auction_unpause_event(auction)
Application[:event].publish("auctions.unpaused", auction.to_h)
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/auction_fun_core/version.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module AuctionFunCore
VERSION = "0.8.1"
VERSION = "0.8.3"

# Required class module is a gem dependency
class Version; end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

RSpec.describe AuctionFunCore::Contracts::AuctionContext::Processor::PauseContract, type: :contract do
let(:auction) { Factory[:auction, :default_standard] }

describe "#call" do
subject(:contract) { described_class.new.call(attributes) }

context "when attributes are invalid" do
let(:attributes) { Dry::Core::Constants::EMPTY_HASH }

it "expect failure with error messages" do
expect(contract).to be_failure
expect(contract.errors[:auction_id]).to include(I18n.t("contracts.errors.key?"))
end
end

context "when auction status is different to 'running'" do
let(:attributes) { {auction_id: auction.id} }

it "expect failure with error messages" do
expect(contract).to be_failure
expect(contract.errors[:auction_id]).to include(
I18n.t("contracts.errors.custom.bids.invalid_status")
)
end
end

context "when auction status is equal to 'running'" do
let(:auction) { Factory[:auction, :default_running_standard] }
let(:attributes) { {auction_id: auction.id} }

it "expect return success" do
expect(contract).to be_success
expect(contract.context[:auction]).to be_a(AuctionFunCore::Entities::Auction)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

RSpec.describe AuctionFunCore::Contracts::AuctionContext::Processor::UnpauseContract, type: :contract do
let(:auction) { Factory[:auction, :default_standard] }

describe "#call" do
subject(:contract) { described_class.new.call(attributes) }

context "when attributes are invalid" do
let(:attributes) { Dry::Core::Constants::EMPTY_HASH }

it "expect failure with error messages" do
expect(contract).to be_failure
expect(contract.errors[:auction_id]).to include(I18n.t("contracts.errors.key?"))
end
end

context "when auction status is different to 'paused'" do
let(:attributes) { {auction_id: auction.id} }

it "expect failure with error messages" do
expect(contract).to be_failure
expect(contract.errors[:auction_id]).to include(
I18n.t("contracts.errors.custom.bids.invalid_status")
)
end
end

context "when auction status is equal to 'paused'" do
let(:auction) { Factory[:auction, :default_paused_standard] }
let(:attributes) { {auction_id: auction.id} }

it "expect return success" do
expect(contract).to be_success
expect(contract.context[:auction]).to be_a(AuctionFunCore::Entities::Auction)
end
end
end
end

0 comments on commit a9a595e

Please sign in to comment.