1# frozen_string_literal: true
2
3require "erb"
4require "ruby-bandwidth-iris"
5require "securerandom"
6
7require_relative "./alt_top_up_form"
8require_relative "./bandwidth_tn_order"
9require_relative "./bandwidth_tn_reservation_repo"
10require_relative "./command"
11require_relative "./em"
12require_relative "./invites_repo"
13require_relative "./oob"
14require_relative "./parent_code_repo"
15require_relative "./proxied_jid"
16require_relative "./tel_selections"
17require_relative "./welcome_message"
18require_relative "./sim_kind"
19require_relative "./onboarding"
20
21def reload_customer(customer)
22 EMPromise.resolve(nil).then do
23 Command.execution.customer_repo.find(customer.customer_id)
24 end
25end
26
27def handle_prev(customer, googleplay_user_id, product)
28 if product.is_a?(SIMKind)
29 Registration::DataOnly.for(customer, product)
30 else
31 Registration::Activation.for(customer, googleplay_user_id, product)
32 end
33end
34
35class Registration
36 class PayForSim
37 def initialize(customer, sim_kind)
38 @customer = customer
39 @sim_kind = sim_kind
40 end
41
42 def write
43 Command.reply { |reply|
44 reply.command << FormTemplate.render(
45 "registration/pay_without_code",
46 instructions: instructions,
47 currency_required: !@customer.currency,
48 title: "Pay for #{@sim_kind.label}"
49 )
50 }.then(&method(:parse)).then(&:write)
51 end
52
53 def instructions
54 price = @sim_kind.price(@customer)
55 return nil unless price
56
57 <<~I
58 To activate your data SIM, you need to deposit $#{'%.2f' % price} to your balance.
59 (If you'd like to pay in another cryptocurrency, currently we recommend using a service like simpleswap.io, morphtoken.com, changenow.io, or godex.io.)
60 I
61 end
62
63 def parse(iq)
64 unless @customer.currency
65 plan = Plan.for_registration(iq.form.field("plan_name").value.to_s)
66 (@customer = @customer.with_plan(plan.name)).save_plan!
67 end.then { process_payment(iq) }
68 end
69
70 def process_payment(iq)
71 Payment.for(
72 iq, @customer, @sim_kind,
73 price: @sim_kind.price(@customer),
74 maybe_bill: Registration::Payment::JustCharge
75 ).write.then { reload_customer(@customer) }.then { |customer|
76 DataOnly.for(customer, @sim_kind)
77 }
78 end
79 end
80
81 class DataOnly
82 def self.for(customer, sim_kind)
83 price = sim_kind.price(customer)
84 unless price && customer.balance >= price
85 return PayForSim.new(customer, sim_kind)
86 end
87
88 new(customer, sim_kind)
89 end
90
91 def initialize(customer, sim_kind)
92 @customer = customer
93 @sim_kind = sim_kind
94 end
95
96 def write
97 @sim_kind.get_processor(@customer).then { |order|
98 # NOTE: cheogram will swallow any stanza
99 # with available action `complete`
100 order.process(can_complete: false)
101 }
102 end
103 end
104
105 class RegistrationType
106 def self.for(customer, google_play_userid, product)
107 if product.is_a?(SIMKind)
108 return Registration::DataOnly.for(
109 customer, product
110 )
111 end
112
113 reload_customer(customer).then do |reloaded|
114 Registration::FinishOrStartActivation.for(
115 reloaded, google_play_userid, product
116 )
117 end
118 end
119 end
120
121 def self.for(customer, google_play_userid, tel_selections)
122 if (reg = customer.registered?)
123 Registered.for(customer, reg.phone)
124 else
125 tel_selections[customer].then(&:choose_tel_or_data).then do |product|
126 reserve_and_continue(tel_selections, customer, product).then do
127 RegistrationType.for(customer, google_play_userid, product)
128 end
129 end
130 end
131 end
132
133 # @param [TelSelections] tel_selections
134 # @param [Customer] customer
135 # @param [TelSelections::ChooseTel::Tn, SIMKind]
136 def self.reserve_and_continue(tel_selections, customer, product)
137 product.reserve(customer).catch do
138 tel_selections.delete(customer.jid).then {
139 tel_selections[customer]
140 }.then { |choose|
141 choose.choose_tel_or_data(
142 error: "The JMP number #{product} is no longer available."
143 )
144 }.then { |n_tel| reserve_and_continue(tel_selections, customer, n_tel) }
145 end
146 end
147
148 class Registered
149 def self.for(customer, tel)
150 if customer.jid.onboarding?
151 FinishOnboarding.for(customer, tel)
152 else
153 new(tel)
154 end
155 end
156
157 def initialize(tel)
158 @tel = tel
159 end
160
161 def write
162 Command.finish("You are already registered with JMP number #{@tel}")
163 end
164 end
165
166 class FinishOrStartActivation
167 def self.for(customer, google_play_userid, tel)
168 if customer.active?
169 Finish.new(customer, tel)
170 elsif customer.balance >= CONFIG[:activation_amount_accept]
171 BillPlan.new(customer, tel)
172 else
173 new(customer, google_play_userid, tel)
174 end
175 end
176
177 def initialize(customer, google_play_userid, tel)
178 @customer = customer
179 @tel = tel
180 @google_play_userid = google_play_userid
181 end
182
183 def write
184 Command.reply { |reply|
185 reply.allowed_actions = [:next]
186 reply.note_type = :info
187 reply.note_text = File.read("#{__dir__}/../fup.txt")
188 }.then { Activation.for(@customer, @google_play_userid, @tel).write }
189 end
190 end
191
192 class Activation
193 def self.for(customer, google_play_userid, tel)
194 jid = ProxiedJID.new(customer.jid).unproxied
195 if CONFIG[:approved_domains].key?(jid.domain.to_sym)
196 Allow.for(customer, tel, jid)
197 elsif google_play_userid
198 GooglePlay.new(customer, google_play_userid, tel)
199 else
200 new(customer, tel)
201 end
202 end
203
204 def initialize(customer, tel)
205 @customer = customer
206 @tel = tel
207 end
208
209 attr_reader :customer, :tel
210
211 def form
212 FormTemplate.render("registration/activate", tel: tel)
213 end
214
215 def write
216 Command.reply { |reply|
217 reply.allowed_actions = [:next]
218 reply.command << form
219 }.then(&method(:next_step))
220 end
221
222 def next_step(iq)
223 EMPromise.resolve(nil).then do
224 plan = Plan.for_registration(iq.form.field("plan_name").value.to_s)
225 @customer = @customer.with_plan(plan.name)
226 Registration::Payment::InviteCode.new(
227 @customer, @tel, finish: Finish, db: DB, redis: REDIS
228 ).parse(iq, force_save_plan: true)
229 .catch_only(InvitesRepo::Invalid) do
230 Payment.for(iq, @customer, @tel).then(&:write)
231 end
232 end
233 end
234
235 class GooglePlay
236 def initialize(customer, google_play_userid, tel)
237 @customer = customer
238 @google_play_userid = google_play_userid
239 @tel = tel
240 @invites = InvitesRepo.new(DB, REDIS)
241 @parent_code_repo = ParentCodeRepo.new(redis: REDIS, db: DB)
242 end
243
244 def used
245 REDIS.sismember("google_play_userids", @google_play_userid)
246 end
247
248 def form
249 FormTemplate.render(
250 "registration/google_play",
251 tel: @tel
252 )
253 end
254
255 def write
256 used.then do |u|
257 next Activation.for(@customer, nil, @tel).write if u.to_s == "1"
258
259 Command.reply { |reply|
260 reply.allowed_actions = [:next]
261 reply.command << form
262 }.then(&method(:activate)).then do
263 Finish.new(@customer, @tel).write
264 end
265 end
266 end
267
268 def activate(iq)
269 plan = Plan.for_registration(iq.form.field("plan_name").value)
270 code = iq.form.field("code")&.value
271 EMPromise.all([
272 @parent_code_repo.find(code),
273 REDIS.sadd("google_play_userids", @google_play_userid)
274 ]).then { |(parent, _)|
275 save_active_plan(plan, parent)
276 }.then do
277 use_referral_code(code)
278 end
279 end
280
281 protected
282
283 def save_bogus_transaction
284 Transaction.new(
285 customer_id: @customer.customer_id,
286 transaction_id: "google_play_#{@customer.customer_id}",
287 amount: 0,
288 note: "Activated via Google Play",
289 bonus_eligible?: false
290 ).insert
291 end
292
293 def save_active_plan(plan, parent)
294 @customer = @customer.with_plan(plan.name, parent_customer_id: parent)
295 save_bogus_transaction.then do
296 @customer.activate_plan_starting_now
297 end
298 end
299
300 def use_referral_code(code)
301 EMPromise.resolve(nil).then {
302 @invites.claim_code(@customer.customer_id, code) {
303 @customer.extend_plan
304 }
305 }.catch_only(InvitesRepo::Invalid) do
306 @invites.stash_code(@customer.customer_id, code)
307 end
308 end
309 end
310
311 class Allow < Activation
312 def self.for(customer, tel, jid)
313 credit_to = CONFIG[:approved_domains][jid.domain.to_sym]
314 new(customer, tel, credit_to)
315 end
316
317 def initialize(customer, tel, credit_to)
318 super(customer, tel)
319 @credit_to = credit_to
320 end
321
322 def form
323 FormTemplate.render(
324 "registration/allow",
325 tel: tel,
326 domain: customer.jid.domain
327 )
328 end
329
330 def next_step(iq)
331 plan = Plan.for_registration(iq.form.field("plan_name").value.to_s)
332 @customer = customer.with_plan(plan.name)
333 EMPromise.resolve(nil).then { activate }.then do
334 Finish.new(customer, tel).write
335 end
336 end
337
338 protected
339
340 def activate
341 DB.transaction do
342 if @credit_to
343 InvitesRepo.new(DB, REDIS).create_claimed_code(
344 @credit_to,
345 customer.customer_id
346 )
347 end
348 @customer.activate_plan_starting_now
349 end
350 end
351 end
352 end
353
354 module Payment
355 def self.kinds
356 @kinds ||= {}
357 end
358
359 def self.for(
360 iq, customer, product,
361 finish: Finish, maybe_bill: MaybeBill,
362 price: CONFIG[:activation_amount] + product.price
363 )
364 kinds.fetch(iq.form.field("activation_method")&.value&.to_s&.to_sym) {
365 raise "Invalid activation method"
366 }.call(
367 customer, product, finish: finish, maybe_bill: maybe_bill, price: price
368 )
369 end
370
371 class CryptoPaymentMethod
372 def crypto_addrs
373 raise NotImplementedError, "Subclass must implement"
374 end
375
376 def reg_form_name
377 raise NotImplementedError, "Subclass must implement"
378 end
379
380 def sell_prices
381 raise NotImplementedError, "Subclass must implement"
382 end
383
384 def initialize(
385 customer, product,
386 price: CONFIG[:activation_amount] + product.price, **
387 )
388 @customer = customer
389 @customer_id = customer.customer_id
390 @product = product
391 @price = price
392 end
393
394 def save
395 return if product.is_a?(SIMKind)
396
397 TEL_SELECTIONS.set(@customer.jid, @product)
398 end
399
400 attr_reader :customer_id, :product
401
402 def form(rate, addr)
403 FormTemplate.render(
404 reg_form_name,
405 amount: @price / rate,
406 addr: addr
407 )
408 end
409
410 def write
411 EMPromise.all([addr_and_rate, save]).then do |((addr, rate), _)|
412 Command.reply { |reply|
413 reply.allowed_actions = [:prev]
414 reply.status = :canceled
415 reply.command << form(rate, addr)
416 }.then(&method(:handle_possible_prev))
417 end
418 end
419
420 protected
421
422 def handle_possible_prev(iq)
423 raise "Action not allowed" unless iq.prev?
424
425 handle_prev(@customer, nil, @product)
426 end
427
428 def addr_and_rate
429 EMPromise.all([
430 crypto_addrs.then { |addrs|
431 addrs.first || add_crypto_addr
432 },
433
434 sell_prices.public_send(@customer.currency.to_s.downcase)
435 ])
436 end
437 end
438
439 class Bitcoin < CryptoPaymentMethod
440 Payment.kinds[:bitcoin] = method(:new)
441
442 def reg_form_name
443 "registration/btc"
444 end
445
446 def sell_prices
447 BTC_SELL_PRICES
448 end
449
450 def crypto_addrs
451 @customer.btc_addresses
452 end
453
454 def add_crypto_addr
455 @customer.add_btc_address
456 end
457 end
458
459 ## Like Bitcoin
460 class BCH < CryptoPaymentMethod
461 Payment.kinds[:bch] = method(:new)
462
463 def reg_form_name
464 "registration/bch"
465 end
466
467 def sell_prices
468 BCH_SELL_PRICES
469 end
470
471 def crypto_addrs
472 @customer.bch_addresses
473 end
474
475 def add_crypto_addr
476 @customer.add_bch_address
477 end
478 end
479
480 class MaybeBill
481 def initialize(customer, tel, finish: Finish)
482 @customer = customer
483 @tel = tel
484 @finish = finish
485 end
486
487 def call
488 reload_customer(@customer).then do |customer|
489 if customer.balance >= CONFIG[:activation_amount_accept]
490 next BillPlan.new(customer, @tel, finish: @finish)
491 end
492
493 yield customer
494 end
495 end
496 end
497
498 class JustCharge
499 def initialize(customer, *, **)
500 @customer = customer
501 end
502
503 def call; end
504 end
505
506 class CreditCard
507 Payment.kinds[:credit_card] = method(:new)
508
509 def initialize(
510 customer, product,
511 finish: Finish, maybe_bill: MaybeBill,
512 price: CONFIG[:activation_amount] + product.price
513 )
514 @customer = customer
515 @product = product
516 @finish = finish
517 @maybe_bill = maybe_bill.new(customer, product, finish: finish)
518 @price = price
519 end
520
521 def oob(reply)
522 oob = OOB.find_or_create(reply.command)
523 oob.url = CONFIG[:credit_card_url].call(
524 reply.to.stripped.to_s.gsub("\\", "%5C"),
525 @customer.customer_id
526 ) + "&amount=#{@price.ceil}"
527 oob.desc = "Pay by credit card, save, then next here to continue"
528 oob
529 end
530
531 def write
532 Command.reply { |reply|
533 reply.allowed_actions = [:next, :prev]
534 toob = oob(reply)
535 reply.note_type = :info
536 reply.note_text = "#{toob.desc}: #{toob.url}"
537 }.then do |iq|
538 handle_prev(@customer, nil, @product) if iq.prev?
539
540 @maybe_bill.call { self }&.then(&:write)
541 end
542 end
543 end
544
545 class InviteCode
546 Payment.kinds[:code] = method(:new)
547
548 FIELDS = [{
549 var: "code",
550 type: "text-single",
551 label: "Your referral code",
552 required: true
553 }].freeze
554
555 def initialize(
556 customer, tel,
557 error: nil, finish: Finish, db: DB, redis: REDIS, **
558 )
559 @customer = customer
560 @tel = tel
561 @error = error
562 @finish = finish
563 @invites_repo = InvitesRepo.new(db, redis)
564 @parent_code_repo = ParentCodeRepo.new(db: db, redis: redis)
565 end
566
567 def add_form(reply)
568 form = reply.form
569 form.type = :form
570 form.title = "Enter Referral Code"
571 form.instructions = @error if @error
572 form.fields = FIELDS
573 end
574
575 def write
576 Command.reply { |reply|
577 reply.allowed_actions = [:next, :prev]
578 add_form(reply)
579 }.then(&method(:parse)).catch_only(InvitesRepo::Invalid) { |e|
580 invalid_code(e).write
581 }
582 end
583
584 def parse(iq, force_save_plan: false)
585 return Activation.for(@customer, nil, @tel).then(&:write) if iq.prev?
586
587 verify(iq.form.field("code")&.value&.to_s, force_save_plan)
588 .then(&:write)
589 end
590
591 protected
592
593 def invalid_code(e)
594 self.class.new(@customer, @tel, error: e.message, finish: @finish)
595 end
596
597 def customer_id
598 @customer.customer_id
599 end
600
601 def verify(code, force_save_plan)
602 @parent_code_repo.claim_code(@customer, code) {
603 check_parent_balance
604 }.catch_only(ParentCodeRepo::Invalid) {
605 (@customer.save_plan! if force_save_plan).then do
606 @invites_repo.claim_code(customer_id, code) {
607 @customer.activate_plan_starting_now
608 }.then { @finish.new(@customer, @tel) }
609 end
610 }
611 end
612
613 def check_parent_balance
614 MaybeBill.new(@customer, @tel, finish: @finish).call do
615 msg = "Account balance not enough to cover the activation"
616 invalid_code(RuntimeError.new(msg))
617 end
618 end
619 end
620
621 class Mail
622 Payment.kinds[:mail] = method(:new)
623
624 def initialize(
625 customer, tel,
626 price: CONFIG[:activation_amount] + tel.price, **
627 )
628 @customer = customer
629 @tel = tel
630 @price = price
631 end
632
633 def form
634 FormTemplate.render(
635 "registration/mail",
636 currency: @customer.currency,
637 price: @price,
638 **onboarding_extras
639 )
640 end
641
642 def onboarding_extras
643 jid = ProxiedJID.new(@customer.jid).unproxied
644 return {} unless jid.domain == CONFIG[:onboarding_domain]
645
646 {
647 customer_id: @customer.customer_id,
648 in_note: "Customer ID"
649 }
650 end
651
652 def write
653 Command.reply { |reply|
654 reply.allowed_actions = [:prev]
655 reply.status = :canceled
656 reply.command << form
657 }.then { |iq|
658 raise "Action not allowed" unless iq.prev?
659
660 Activation.for(@customer, nil, @tel).then(&:write)
661 }
662 end
663 end
664 end
665
666 class BillPlan
667 def initialize(customer, tel, finish: Finish)
668 @customer = customer
669 @tel = tel
670 @finish = finish
671 end
672
673 def write
674 @customer.bill_plan(note: "Bill #{@tel} for first month").then do
675 updated_customer =
676 @customer.with(balance: @customer.balance - @customer.monthly_price)
677 @finish.new(updated_customer, @tel).write
678 end
679 end
680 end
681
682 class BuyNumber
683 def initialize(customer, tel)
684 @customer = customer
685 @tel = tel
686 end
687
688 def instructions
689 <<~I
690 You've selected #{@tel} as your JMP number.
691 To activate your account, you can either deposit $#{'%.2f' % (CONFIG[:activation_amount] + @tel.price)} to your balance or enter your referral code if you have one.
692 (If you'd like to pay in another cryptocurrency, currently we recommend using a service like simpleswap.io, morphtoken.com, changenow.io, or godex.io.)
693 I
694 end
695
696 def write
697 Command.reply { |reply|
698 reply.command << FormTemplate.render(
699 "registration/pay_without_code",
700 product: @tel,
701 instructions: instructions,
702 title: "Purchase Number"
703 )
704 }.then(&method(:parse)).then(&:write)
705 end
706
707 protected
708
709 def parse(iq)
710 Payment.for(
711 iq, @customer, @tel,
712 maybe_bill: ::Registration::Payment::JustCharge,
713 price: @tel.price
714 )
715 end
716 end
717
718 class Finish
719 TN_UNAVAILABLE = "The JMP number %s is no longer available."
720
721 def initialize(customer, tel)
722 @customer = customer
723 @tel = tel
724 @invites = InvitesRepo.new(DB, REDIS)
725 end
726
727 def write
728 return buy_number if @customer.balance < @tel.price
729
730 @tel.order(DB, @customer).then(
731 method(:customer_active_tel_purchased),
732 method(:number_purchase_error)
733 )
734 end
735
736 protected
737
738 def buy_number
739 BuyNumber.new(@customer, @tel).write.then do
740 reload_customer(@customer).then { |customer|
741 Finish.new(customer, @tel)
742 }.then(&:write)
743 end
744 end
745
746 def number_purchase_error(e)
747 Command.log.error "number_purchase_error", e
748 TEL_SELECTIONS.delete(@customer.jid)
749 .then { TEL_SELECTIONS[@customer] }
750 .then { |c|
751 c.choose_tel_or_data(
752 error: TN_UNAVAILABLE % @tel,
753 allow_data_only: false
754 )
755 }
756 .then { |p| Finish.new(@customer, p) }
757 .then(&:write)
758 end
759
760 def raise_setup_error(e)
761 Command.log.error "@customer.register! failed", e
762 Command.finish(
763 "There was an error setting up your number, " \
764 "please contact JMP support.",
765 type: :error
766 )
767 end
768
769 def put_default_fwd
770 Bwmsgsv2Repo.new.put_fwd(@customer.customer_id, @tel.tel, CustomerFwd.for(
771 uri: "xmpp:#{@customer.jid}",
772 voicemail_enabled: true
773 ))
774 end
775
776 def use_referral_code
777 @invites.use_pending_group_code(@customer.customer_id).then do |credit_to|
778 next unless credit_to
779
780 Transaction.new(
781 customer_id: @customer.customer_id,
782 transaction_id: "referral_#{@customer.customer_id}_#{credit_to}",
783 amount: @customer.monthly_price,
784 note: "Referral Bonus",
785 bonus_eligible?: false
786 ).insert
787 end
788 end
789
790 def customer_active_tel_purchased(customer)
791 customer.register!(@tel.tel).catch(&method(:raise_setup_error)).then {
792 EMPromise.all([
793 TEL_SELECTIONS.delete(customer.jid),
794 put_default_fwd,
795 use_referral_code,
796 @tel.charge(customer)
797 ])
798 }.then do
799 FinishOnboarding.for(customer, @tel).then(&:write)
800 end
801 end
802 end
803
804 module FinishOnboarding
805 def self.for(customer, tel, db: LazyObject.new { DB })
806 jid = ProxiedJID.new(customer.jid).unproxied
807 if jid.domain == CONFIG[:onboarding_domain]
808 Snikket.for(customer, tel, db: db)
809 else
810 NotOnboarding.new(customer, tel)
811 end
812 end
813
814 class Snikket
815 def self.for(customer, tel, db:)
816 ::Snikket::Repo.new(db: db).find_by_customer(customer).then do |is|
817 if is.empty?
818 new(customer, tel, db: db)
819 elsif is[0].bootstrap_token.empty?
820 # This is a need_dns one, try the launch again
821 new(customer, tel, db: db).launch(is[0].domain)
822 else
823 GetInvite.for(customer, is[0], tel, db: db)
824 end
825 end
826 end
827
828 def initialize(customer, tel, db:, error: nil, old: nil)
829 @customer = customer
830 @tel = tel
831 @error = error
832 @db = db
833 @old = old
834 end
835
836 ACTION_VAR = "http://jabber.org/protocol/commands#actions"
837
838 def form
839 FormTemplate.render(
840 "registration/snikket",
841 tel: @tel,
842 error: @error
843 )
844 end
845
846 def write
847 Command.reply { |reply|
848 reply.allowed_actions = [:next]
849 reply.command << form
850 }.then(&method(:next_step))
851 end
852
853 def next_step(iq)
854 subdomain = empty_nil(iq.form.field("subdomain")&.value)
855 domain = "#{subdomain}.snikket.chat"
856 if iq.form.field(ACTION_VAR)&.value == "custom_domain"
857 CustomDomain.new(@customer, @tel, old: @old).write
858 elsif @old && (!subdomain || domain == @old.domain)
859 GetInvite.for(@customer, @old, @tel, db: @db).then(&:write)
860 else
861 launch(domain)
862 end
863 end
864
865 def launch(domain)
866 IQ_MANAGER.write(::Snikket::Launch.new(
867 nil, CONFIG[:snikket_hosting_api], domain: domain
868 )).then { |launched|
869 save_instance_and_wait(domain, launched)
870 }.catch { |e|
871 next EMPromise.reject(e) unless e.respond_to?(:text)
872
873 Snikket.new(@customer, @tel, old: @old, error: e.text, db: @db).write
874 }
875 end
876
877 def save_instance_and_wait(domain, launched)
878 instance = ::Snikket::CustomerInstance.for(@customer, domain, launched)
879 repo = ::Snikket::Repo.new(db: @db)
880 (@old&.domain == domain ? EMPromise.resolve(nil) : repo.del(@old))
881 .then { repo.put(instance) }.then do
882 if launched.status == :needs_dns
883 NeedsDNS.new(@customer, instance, @tel, launched.records).write
884 else
885 GetInvite.for(@customer, instance, @tel, db: @db).then(&:write)
886 end
887 end
888 end
889
890 def empty_nil(s)
891 s.nil? || s.empty? ? nil : s
892 end
893
894 class NeedsDNS < Snikket
895 def initialize(customer, instance, tel, records, db: DB)
896 @customer = customer
897 @instance = instance
898 @tel = tel
899 @records = records
900 @db = db
901 end
902
903 def form
904 FormTemplate.render(
905 "registration/snikket_needs_dns",
906 records: @records
907 )
908 end
909
910 def write
911 Command.reply { |reply|
912 reply.allowed_actions = [:prev, :next]
913 reply.command << form
914 }.then do |iq|
915 if iq.prev?
916 CustomDomain.new(@customer, @tel, old: @instance).write
917 else
918 launch(@instance.domain)
919 end
920 end
921 end
922 end
923
924 class GetInvite
925 def self.for(customer, instance, tel, db: DB)
926 instance.fetch_invite.then do |xmpp_uri|
927 if xmpp_uri
928 GoToInvite.new(xmpp_uri)
929 else
930 new(customer, instance, tel, db: db)
931 end
932 end
933 end
934
935 def initialize(customer, instance, tel, db: DB)
936 @customer = customer
937 @instance = instance
938 @tel = tel
939 @db = db
940 end
941
942 def form
943 FormTemplate.render(
944 "registration/snikket_wait",
945 domain: @instance.domain
946 )
947 end
948
949 def write
950 Command.reply { |reply|
951 reply.allowed_actions = [:prev, :next]
952 reply.command << form
953 }.then do |iq|
954 if iq.prev?
955 Snikket.new(@customer, @tel, old: @instance, db: @db).write
956 else
957 GetInvite.for(@customer, @instance, @tel, db: @db).then(&:write)
958 end
959 end
960 end
961 end
962
963 class GoToInvite
964 def initialize(xmpp_uri)
965 @xmpp_uri = xmpp_uri
966 end
967
968 def write
969 Command.finish do |reply|
970 oob = OOB.find_or_create(reply.command)
971 oob.url = @xmpp_uri
972 end
973 end
974 end
975 end
976
977 class CustomDomain < Snikket
978 def initialize(customer, tel, old: nil, error: nil, db: DB)
979 @customer = customer
980 @tel = tel
981 @error = error
982 @old = old
983 @db = db
984 end
985
986 def form
987 FormTemplate.render(
988 "registration/snikket_custom",
989 tel: @tel,
990 error: @error
991 )
992 end
993
994 def write
995 Command.reply { |reply|
996 reply.allowed_actions = [:prev, :next]
997 reply.command << form
998 }.then do |iq|
999 if iq.prev?
1000 Snikket.new(@customer, @tel, db: @db, old: @old).write
1001 else
1002 launch(empty_nil(iq.form.field("domain")&.value) || @old&.domain)
1003 end
1004 end
1005 end
1006 end
1007
1008 class NotOnboarding
1009 def initialize(customer, tel)
1010 @customer = customer
1011 @tel = tel
1012 end
1013
1014 def write
1015 WelcomeMessage.new(@customer, @tel).welcome
1016 Command.finish("Your JMP account has been activated as #{@tel}")
1017 end
1018 end
1019 end
1020
1021 def self.public_onboarding_invite
1022 Command.finish { |reply|
1023 reply.allowed_actions = [:prev]
1024 oob = OOB.find_or_create(reply.command)
1025 oob.url = CONFIG[:public_onboarding_url]
1026 oob.desc = "Get your XMPP account"
1027 }
1028 end
1029end