~singpolyma/sgx-jmp

ref: 8dd92b96258d14d431e9966d0534631c7fdc0214 sgx-jmp/lib/admin_actions/add_invites.rb -rw-r--r-- 2.3 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
# frozen_string_literal: true

require "value_semantics/monkey_patched"
require_relative "../admin_action"
require_relative "../form_to_h"

class AdminAction
	class AddInvites < AdminAction
		class Command
			using FormToH

			def self.for(target_customer, reply:)
				EMPromise.resolve(
					new(customer_id: target_customer.customer_id)
				).then { |x|
					reply.call(x.form).then(&x.method(:create))
				}
			end

			def initialize(**bag)
				@bag = bag
			end

			def form
				FormTemplate.render("admin_add_invites")
			end

			def create(result)
				AdminAction::AddInvites.for(
					**@bag,
					**result.form.to_h
						.reject { |_k, v| v == "nil" }.transform_keys(&:to_sym)
				)
			end
		end

		CodesTaken = Struct.new(:codes) do
			def to_s
				"One of these tokens already exists: #{codes.join(', ')}"
			end
		end

		CodesClaimed = Struct.new(:codes) do
			def to_s
				"One of these tokens is already claimed: #{codes.join(', ')}"
			end
		end

		class MustHaveCodes
			def to_s
				"Action must have list of codes to reverse"
			end
		end

		def customer_id
			@attributes[:customer_id]
		end

		def to_add
			@attributes[:to_add].to_i
		end

		def check_forward
			EMPromise.resolve(nil)
				.then { check_noop }
				.then {
					next nil if chosen_invites.empty?

					InvitesRepo.new.any_existing?(chosen_invites).then { |taken|
						EMPromise.reject(CodesTaken.new(chosen_invites)) if taken
					}
				}
		end

		def forward
			if chosen_invites.empty?
				InvitesRepo.new.create_n_codes(customer_id, to_add).then { |codes|
					with(invites: codes.join("\n"))
				}
			else
				InvitesRepo.new.create_codes(customer_id, chosen_invites).then { self }
			end
		end

		def check_reverse
			return EMPromise.reject(MustHaveCodes.new) if chosen_invites.empty?

			InvitesRepo.new.any_claimed?(chosen_invites).then { |claimed|
				EMPromise.reject(CodesClaimed.new(chosen_invites)) if claimed
			}
		end

		def reverse
			InvitesRepo.new.delete_codes(chosen_invites).then { self }
		end

		def to_s
			"add_invites(#{customer_id}): #{chosen_invites.join(', ')}"
		end

	protected

		def check_noop
			EMPromise.reject(NoOp.new) if to_add.zero?
		end

		def check_too_many
			max = split_invites.length
			EMPromise.reject(TooMany.new(to_add, max)) if to_add > max
		end

		def chosen_invites
			@attributes[:invites]&.split("\n") || []
		end
	end
end