From 67609fee446efdbf8875997407d432d304d8e79a Mon Sep 17 00:00:00 2001 From: Christopher Vollick <0@psycoti.ca> Date: Tue, 7 Jun 2022 11:19:57 -0400 Subject: [PATCH] Undo and Undoable Command Harness It's a little weird to start with Undo when there's nothing to Undo yet, but it's laying the groundwork for what's to come. This gives me a harness I can use here that gets the action, performs it, gets the result of that performed action, and then persists that to the log and reports success or failure. And the first such action I have just grabs the most recent item and undoes it. --- forms/admin_menu.rb | 3 +- lib/admin_command.rb | 76 ++++++++++++++++++++++++++++++++++---- test/test_admin_command.rb | 1 + 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/forms/admin_menu.rb b/forms/admin_menu.rb index aeb8b7ddc1b36ef9b7b9fc7dc5fed41e985dcf21..650642e6c101f4c1687ccf2077a06c8c5a777203 100644 --- a/forms/admin_menu.rb +++ b/forms/admin_menu.rb @@ -11,6 +11,7 @@ field( { value: "info", label: "Customer Info" }, { value: "financial", label: "Customer Billing Information" }, { value: "bill_plan", label: "Bill Customer" }, - { value: "cancel_account", label: "Cancel Customer" } + { value: "cancel_account", label: "Cancel Customer" }, + { value: "undo", label: "Undo" } ] ) diff --git a/lib/admin_command.rb b/lib/admin_command.rb index 84378e9d4b16bcff840ec8ca2e086080f12551a6..955db83831aa223822c37e95a5fcb29fe6b6c482 100644 --- a/lib/admin_command.rb +++ b/lib/admin_command.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative "admin_action_repo" require_relative "admin_actions/cancel" require_relative "admin_actions/financial" require_relative "bill_plan_command" @@ -8,21 +9,26 @@ require_relative "financial_info" require_relative "form_template" class AdminCommand - def self.for(target_customer, customer_repo) + def self.for( + target_customer, + customer_repo, + admin_action_repo=AdminActionRepo.new + ) if target_customer - new(target_customer, customer_repo) + new(target_customer, customer_repo, admin_action_repo) else Command.reply { |reply| reply.allowed_actions = [:next, :complete] reply.note_type = :error reply.note_text = "Customer Not Found" - }.then { NoUser.new(customer_repo) } + }.then { NoUser.new(customer_repo, admin_action_repo) } end end class NoUser - def initialize(customer_repo) + def initialize(customer_repo, admin_action_repo=AdminActionRepo.new) @customer_repo = customer_repo + @admin_action_repo = admin_action_repo end def start @@ -32,14 +38,20 @@ class AdminCommand }.then { |response| CustomerInfoForm.new(@customer_repo).find_customer(response) }.then { |customer| - AdminCommand.for(customer, @customer_repo).then(&:start) + AdminCommand.for(customer, @customer_repo, @admin_action_repo) + .then(&:start) } end end - def initialize(target_customer, customer_repo) + def initialize( + target_customer, + customer_repo, + admin_action_repo=AdminActionRepo.new + ) @target_customer = target_customer @customer_repo = customer_repo + @admin_action_repo = admin_action_repo end def start @@ -76,7 +88,8 @@ class AdminCommand def new_context(q) CustomerInfoForm.new(@customer_repo) .parse_something(q).then do |new_customer| - AdminCommand.for(new_customer, @customer_repo).then(&:start) + AdminCommand.for(new_customer, @customer_repo, @admin_action_repo) + .then(&:start) end end @@ -89,6 +102,40 @@ class AdminCommand BillPlanCommand.for(@target_customer).call end + class Undoable + def initialize(klass) + @klass = klass + end + + def call(customer, admin_action_repo:, **) + @klass.for(customer, reply: method(:reply)).then { |action| + Command.customer.then { |actor| + action.with(actor_id: actor.customer_id).perform.then do |performed| + admin_action_repo.create(performed) + end + } + }.then(method(:success), method(:failure)) + end + + def reply(form=nil, note_type: nil, note_text: nil) + Command.reply { |reply| + reply.allowed_actions = [:next, :complete] + reply.command << form if form + reply.note_type = note_type if note_type + reply.note_text = note_text if note_text + } + end + + def success(action) + reply(note_type: :info, note_text: "Action #{action.id}: #{action}") + end + + def failure(err) + LOG.error "Action Failure", err + reply(note_type: :error, note_text: "Action Failed: #{err}") + end + end + class Simple def initialize(klass) @klass = klass @@ -112,9 +159,22 @@ class AdminCommand end end + class Undo + def self.for(target_customer, **) + AdminActionRepo.new + .find(1, customer_id: target_customer.customer_id) + .then { |actions| + raise "No actions found" if actions.empty? + + actions.first.undo + } + end + end + [ [:cancel_account, Simple.new(AdminAction::CancelCustomer)], - [:financial, Simple.new(AdminAction::Financial)] + [:financial, Simple.new(AdminAction::Financial)], + [:undo, Undoable.new(Undo)] ].each do |action, handler| define_method("action_#{action}") do handler.call( diff --git a/test/test_admin_command.rb b/test/test_admin_command.rb index 1b31f3dc530cfe91f1079e0335eb683ac16d76ad..506cc3a1b5fe1dc2a1f8ad1f9dc4791de2abf734 100644 --- a/test/test_admin_command.rb +++ b/test/test_admin_command.rb @@ -4,6 +4,7 @@ require "admin_command" BackendSgx::IQ_MANAGER = Minitest::Mock.new Customer::BLATHER = Minitest::Mock.new +AdminActionRepo::REDIS = Minitest::Mock.new class AdminCommandTest < Minitest::Test def admin_command(tel="+15556667777")