1# frozen_string_literal: true
2
3require "value_semantics/monkey_patched"
4require_relative "../admin_action"
5require_relative "../form_to_h"
6
7class AdminAction
8 class NumberChange < AdminAction
9 include Isomorphic
10 class Command
11 using FormToH
12
13 def self.for(target_customer, reply:)
14 EMPromise.resolve(
15 new(
16 customer_id: target_customer.customer_id,
17 old_tel: target_customer.registered?.phone
18 )
19 ).then { |x|
20 reply.call(x.form).then(&x.method(:change))
21 }
22 end
23
24 def initialize(**bag)
25 @bag = bag
26 end
27
28 def form
29 FormTemplate.render("admin_number_change")
30 end
31
32 def change(result)
33 AdminAction::NumberChange.for(
34 **@bag,
35 **result.form.to_h
36 .reject { |_k, v| v == "nil" }.transform_keys(&:to_sym)
37 )
38 end
39 end
40
41 NilKey = Struct.new(:key) {
42 def to_s
43 "Expected a key with a value, but #{key} has no value."
44 end
45 }
46
47 def customer_id
48 @attributes[:customer_id]
49 end
50
51 def old_tel
52 @attributes[:old_tel]
53 end
54
55 def new_tel
56 @attributes[:new_tel]
57 end
58
59 def should_delete?
60 ["1", "true"].include?(@attributes[:should_delete])
61 end
62
63 def check_forward
64 EMPromise.all([
65 check_noop,
66 check_exist
67 ])
68 end
69
70 def forward
71 TrivialBackendSgxRepo.new(redis: REDIS).get(customer_id).then do |sgx|
72 EMPromise.all([
73 REDIS.rename("catapult_fwd-#{old_tel}", "catapult_fwd-#{new_tel}"),
74 sgx.register!(new_tel),
75 should_delete? && first_time? ? disconnect_number : nil
76 ]).then { self }
77 end
78 end
79
80 def to_reverse
81 with(
82 old_tel: new_tel,
83 new_tel: old_tel
84 )
85 end
86
87 def to_s
88 "number_change(#{customer_id}): #{old_tel} -> #{new_tel}#{delete_warning}"
89 end
90
91 protected
92
93 def disconnect_number
94 # Order name is limited to 40 characters
95 # Assuming 12 chars for new_tel and 12 for customer_id, this is tight
96 # but ok
97 BandwidthTnRepo.new.disconnect(
98 old_tel,
99 "cust #{customer_id} swap to #{new_tel}"
100 )
101 end
102
103 def delete_warning
104 return "" unless should_delete? && !first_time?
105
106 " * NOT DELETING"
107 end
108
109 def check_noop
110 EMPromise.reject(NoOp.new) if new_tel == old_tel
111 end
112
113 def check_exist
114 cat_jid = "catapult_jid-#{old_tel}"
115 REDIS.exists(cat_jid).then { |v|
116 EMPromise.reject(NilKey.new(cat_jid)) unless v == 1
117 }
118 end
119 end
120end