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