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