~singpolyma/sgx-jmp

ref: 8dd92b96258d14d431e9966d0534631c7fdc0214 sgx-jmp/lib/admin_command.rb -rw-r--r-- 4.7 KiB
8dd92b96Stephen Paul Weber Merge branch 'admin-actions' 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# frozen_string_literal: true

require_relative "admin_action_repo"
require_relative "admin_actions/add_invites"
require_relative "admin_actions/cancel"
require_relative "admin_actions/financial"
require_relative "admin_actions/reset_declines"
require_relative "admin_actions/set_trust_level"
require_relative "bill_plan_command"
require_relative "customer_info_form"
require_relative "financial_info"
require_relative "form_template"

class AdminCommand
	def self.for(
		target_customer,
		customer_repo,
		admin_action_repo=AdminActionRepo.new
	)
		if target_customer
			new(target_customer, customer_repo, admin_action_repo)
		else
			NoUser.new(customer_repo, admin_action_repo, notice: "Customer Not Found")
		end
	end

	class NoUser < AdminCommand
		def initialize(
			customer_repo,
			admin_action_repo=AdminActionRepo.new,
			notice: nil
		)
			@customer_repo = customer_repo
			@admin_action_repo = admin_action_repo
			@notice = notice
		end

		def start(command_action=:execute)
			return Command.finish(@notice || "Done") if command_action == :complete

			reply(
				FormTemplate.render("customer_picker", notice: @notice)
			).then { |response|
				new_context(response.form.field("q").value, response.action)
			}
		end
	end

	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(command_action=:execute)
		@target_customer.admin_info.then { |info|
			if command_action == :complete
				Command.finish { |iq| iq.command << info.form }
			else
				reply(info.form)
			end
		}.then { |response| menu_or_done(response.action) }
	end

	def reply(form)
		Command.reply { |reply|
			reply.allowed_actions = [:next, :complete]
			reply.command << form
		}
	end

	def menu_or_done(command_action=:execute, notice: nil)
		return Command.finish("Done") if command_action == :complete

		reply(FormTemplate.render("admin_menu", notice: notice)).then do |response|
			if response.form.field("action")
				handle(response.form.field("action").value, response.action)
			end
		end
	end

	def handle(action, command_action)
		if respond_to?("action_#{action}")
			send("action_#{action}").then do |notice|
				menu_or_done(command_action, notice: notice)
			end
		else
			new_context(action)
		end
	end

	def new_context(q, command_action=:execute)
		CustomerInfoForm.new(@customer_repo)
			.parse_something(q).then do |new_customer|
				AdminCommand.for(new_customer, @customer_repo, @admin_action_repo)
					.then { |ac| ac.start(command_action) }
			end
	end

	def action_info
		# Refresh the data
		new_context(@target_customer.customer_id)
	end

	def action_bill_plan
		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 { |action| "Action #{action.id}: #{action}" }
		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
	end

	class Simple
		def initialize(klass)
			@klass = klass
		end

		def call(customer_id, customer_repo:, **)
			@klass.call(
				customer_id,
				reply: method(:reply),
				customer_repo: customer_repo
			).then { nil }
		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
	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)],
		[:undo, Undoable.new(Undo)],
		[:reset_declines, Undoable.new(AdminAction::ResetDeclines::Command)],
		[:set_trust_level, Undoable.new(AdminAction::SetTrustLevel::Command)],
		[:add_invites, Undoable.new(AdminAction::AddInvites::Command)]
	].each do |action, handler|
		define_method("action_#{action}") do
			handler.call(
				@target_customer,
				admin_action_repo: @admin_action_repo,
				customer_repo: @customer_repo
			)
		end
	end
end