admin_command.rb

  1# frozen_string_literal: true
  2
  3require_relative "admin_action_repo"
  4require_relative "admin_actions/add_invites"
  5require_relative "admin_actions/cancel"
  6require_relative "admin_actions/financial"
  7require_relative "admin_actions/reset_declines"
  8require_relative "admin_actions/set_trust_level"
  9require_relative "bill_plan_command"
 10require_relative "customer_info_form"
 11require_relative "financial_info"
 12require_relative "form_template"
 13
 14class AdminCommand
 15	def self.for(
 16		target_customer,
 17		customer_repo,
 18		admin_action_repo=AdminActionRepo.new
 19	)
 20		if target_customer
 21			new(target_customer, customer_repo, admin_action_repo)
 22		else
 23			Command.reply { |reply|
 24				reply.allowed_actions = [:next, :complete]
 25				reply.note_type = :error
 26				reply.note_text = "Customer Not Found"
 27			}.then { NoUser.new(customer_repo, admin_action_repo) }
 28		end
 29	end
 30
 31	class NoUser
 32		def initialize(customer_repo, admin_action_repo=AdminActionRepo.new)
 33			@customer_repo = customer_repo
 34			@admin_action_repo = admin_action_repo
 35		end
 36
 37		def start
 38			Command.reply { |reply|
 39				reply.allowed_actions = [:next]
 40				reply.command << FormTemplate.render("customer_picker")
 41			}.then { |response|
 42				CustomerInfoForm.new(@customer_repo).find_customer(response)
 43			}.then { |customer|
 44				AdminCommand.for(customer, @customer_repo, @admin_action_repo)
 45					.then(&:start)
 46			}
 47		end
 48	end
 49
 50	def initialize(
 51		target_customer,
 52		customer_repo,
 53		admin_action_repo=AdminActionRepo.new
 54	)
 55		@target_customer = target_customer
 56		@customer_repo = customer_repo
 57		@admin_action_repo = admin_action_repo
 58	end
 59
 60	def start
 61		@target_customer.admin_info.then { |info|
 62			reply(info.form)
 63		}.then { menu_or_done }
 64	end
 65
 66	def reply(form)
 67		Command.reply { |reply|
 68			reply.allowed_actions = [:next, :complete]
 69			reply.command << form
 70		}
 71	end
 72
 73	def menu_or_done(command_action=:execute)
 74		return Command.finish("Done") if command_action == :complete
 75
 76		reply(FormTemplate.render("admin_menu")).then do |response|
 77			if response.form.field("action")
 78				handle(response.form.field("action").value, response.action)
 79			end
 80		end
 81	end
 82
 83	def handle(action, command_action)
 84		if respond_to?("action_#{action}")
 85			send("action_#{action}")
 86		else
 87			new_context(action)
 88		end.then { menu_or_done(command_action) }
 89	end
 90
 91	def new_context(q)
 92		CustomerInfoForm.new(@customer_repo)
 93			.parse_something(q).then do |new_customer|
 94				AdminCommand.for(new_customer, @customer_repo, @admin_action_repo)
 95					.then(&:start)
 96			end
 97	end
 98
 99	def action_info
100		# Refresh the data
101		new_context(@target_customer.customer_id)
102	end
103
104	def action_bill_plan
105		BillPlanCommand.for(@target_customer).call
106	end
107
108	class Undoable
109		def initialize(klass)
110			@klass = klass
111		end
112
113		def call(customer, admin_action_repo:, **)
114			@klass.for(customer, reply: method(:reply)).then { |action|
115				Command.customer.then { |actor|
116					action.with(actor_id: actor.customer_id).perform.then do |performed|
117						admin_action_repo.create(performed)
118					end
119				}
120			}.then(method(:success), method(:failure))
121		end
122
123		def reply(form=nil, note_type: nil, note_text: nil)
124			Command.reply { |reply|
125				reply.allowed_actions = [:next, :complete]
126				reply.command << form if form
127				reply.note_type = note_type if note_type
128				reply.note_text = note_text if note_text
129			}
130		end
131
132		def success(action)
133			reply(note_type: :info, note_text: "Action #{action.id}: #{action}")
134		end
135
136		def failure(err)
137			LOG.error "Action Failure", err
138			reply(note_type: :error, note_text: "Action Failed: #{err}")
139		end
140	end
141
142	class Simple
143		def initialize(klass)
144			@klass = klass
145		end
146
147		def call(customer_id, customer_repo:, **)
148			@klass.call(
149				customer_id,
150				reply: method(:reply),
151				customer_repo: customer_repo
152			)
153		end
154
155		def reply(form=nil, note_type: nil, note_text: nil)
156			Command.reply { |reply|
157				reply.allowed_actions = [:next, :complete]
158				reply.command << form if form
159				reply.note_type = note_type if note_type
160				reply.note_text = note_text if note_text
161			}
162		end
163	end
164
165	class Undo
166		def self.for(target_customer, **)
167			AdminActionRepo.new
168				.find(1, customer_id: target_customer.customer_id)
169				.then { |actions|
170					raise "No actions found" if actions.empty?
171
172					actions.first.undo
173				}
174		end
175	end
176
177	[
178		[:cancel_account, Simple.new(AdminAction::CancelCustomer)],
179		[:financial, Simple.new(AdminAction::Financial)],
180		[:undo, Undoable.new(Undo)],
181		[:reset_declines, Undoable.new(AdminAction::ResetDeclines::Command)],
182		[:set_trust_level, Undoable.new(AdminAction::SetTrustLevel::Command)],
183		[:add_invites, Undoable.new(AdminAction::AddInvites::Command)]
184	].each do |action, handler|
185		define_method("action_#{action}") do
186			handler.call(
187				@target_customer,
188				admin_action_repo: @admin_action_repo,
189				customer_repo: @customer_repo
190			)
191		end
192	end
193end