From 5a1e3cb26c27cae749b6a9de579aa254ec2ee9c8 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 10:45:34 -0500 Subject: [PATCH 1/6] s/WebRegisterManager/TelSelections --- lib/registration.rb | 6 +++--- lib/{web_register_manager.rb => tel_selections.rb} | 2 +- sgx_jmp.rb | 8 ++++---- test/test_registration.rb | 4 ++-- ..._web_register_manager.rb => test_tel_selections.rb} | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) rename lib/{web_register_manager.rb => tel_selections.rb} (96%) rename test/{test_web_register_manager.rb => test_tel_selections.rb} (55%) diff --git a/lib/registration.rb b/lib/registration.rb index 30c65a5688f9a47632b4d6b2937732a99515e836..a4189dc91550a052fb858ad89a816e26aacc7bca 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -9,15 +9,15 @@ require_relative "./command" require_relative "./bandwidth_tn_order" require_relative "./em" require_relative "./oob" -require_relative "./web_register_manager" +require_relative "./tel_selections" class Registration - def self.for(customer, web_register_manager) + def self.for(customer, tel_selections) customer.registered?.then do |registered| if registered Registered.new(registered.phone) else - web_register_manager[customer.jid].then(&:choose_tel).then do |tel| + tel_selections[customer.jid].then(&:choose_tel).then do |tel| Activation.for(customer, tel) end end diff --git a/lib/web_register_manager.rb b/lib/tel_selections.rb similarity index 96% rename from lib/web_register_manager.rb rename to lib/tel_selections.rb index 87be1db90dfbbb9ae739dd3e83f78fda4548030c..769980aa6018b56cc38adb226f1125ce5fc3633c 100644 --- a/lib/web_register_manager.rb +++ b/lib/tel_selections.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class WebRegisterManager +class TelSelections THIRTY_DAYS = 60 * 60 * 24 * 30 def initialize(redis: REDIS) diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 1c71375ee72be3d2e77304165ac4489989bcfe68..90efd568108a24fe3fa789a723be21f84769b46d 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -77,7 +77,7 @@ require_relative "lib/low_balance" require_relative "lib/payment_methods" require_relative "lib/registration" require_relative "lib/transaction" -require_relative "lib/web_register_manager" +require_relative "lib/tel_selections" require_relative "lib/session_manager" require_relative "lib/statsd" @@ -169,7 +169,7 @@ when_ready do LOG.info "Ready" BLATHER = self REDIS = EM::Hiredis.connect - WEB_REGISTER_MANAGER = WebRegisterManager.new + TEL_SELECTIONS = TelSelections.new BTC_SELL_PRICES = BTCSellPrices.new(REDIS, CONFIG[:oxr_app_id]) DB = PG::EM::ConnectionPool.new(dbname: "jmp") do |conn| conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn) @@ -392,7 +392,7 @@ Command.new( Command.execution.customer_repo.create(Command.execution.iq.from.stripped) }.then { |customer| Sentry.add_breadcrumb(Sentry::Breadcrumb.new(message: "Registration.for")) - Registration.for(customer, WEB_REGISTER_MANAGER).then(&:write) + Registration.for(customer, TEL_SELECTIONS).then(&:write) }.then { StatsD.increment("registration.completed") }.catch_only(Command::Execution::FinalStanza) do |e| @@ -547,7 +547,7 @@ command :execute?, node: "web-register", sessionid: nil do |iq| cmd.form.fields = [var: "to", value: jid] cmd.form.type = "submit" }).then { |result| - WEB_REGISTER_MANAGER.set(result.form.field("from")&.value.to_s.strip, tel) + TEL_SELECTIONS.set(result.form.field("from")&.value.to_s.strip, tel) }.then { BLATHER << iq.reply.tap { |reply| reply.status = :completed } }.catch { |e| panic(e, sentry_hub) } diff --git a/test/test_registration.rb b/test/test_registration.rb index f82c9eb2e966ab3f1d6cc055b0a6de8a77fa3d3a..d10da5571d9a0c230abfc3ee944c2cd90fae08fb 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -35,7 +35,7 @@ class RegistrationTest < Minitest::Test em :test_for_registered def test_for_activated - web_manager = WebRegisterManager.new(redis: FakeRedis.new) + web_manager = TelSelections.new(redis: FakeRedis.new) web_manager.set("test@example.net", "+15555550000") result = execute_command do sgx = OpenStruct.new(registered?: EMPromise.resolve(nil)) @@ -54,7 +54,7 @@ class RegistrationTest < Minitest::Test def test_for_not_activated_with_customer_id sgx = OpenStruct.new(registered?: EMPromise.resolve(nil)) - web_manager = WebRegisterManager.new(redis: FakeRedis.new) + web_manager = TelSelections.new(redis: FakeRedis.new) web_manager.set("test@example.net", "+15555550000") iq = Blather::Stanza::Iq::Command.new iq.from = "test@example.com" diff --git a/test/test_web_register_manager.rb b/test/test_tel_selections.rb similarity index 55% rename from test/test_web_register_manager.rb rename to test/test_tel_selections.rb index 3abac88834dafe85ca5790b52e08d3bdaf009040..dc029a09b022fb1bab89248f4e288f91368b6ca4 100644 --- a/test/test_web_register_manager.rb +++ b/test/test_tel_selections.rb @@ -1,17 +1,17 @@ # frozen_string_literal: true require "test_helper" -require "web_register_manager" +require "tel_selections" -class WebRegisterManagerTest < Minitest::Test +class TelSelectionsTest < Minitest::Test def setup - @manager = WebRegisterManager.new(redis: FakeRedis.new) + @manager = TelSelections.new(redis: FakeRedis.new) end def test_set_get - assert_kind_of WebRegisterManager::ChooseTel, @manager["jid@example.com"].sync + assert_kind_of TelSelections::ChooseTel, @manager["jid@example.com"].sync @manager.set("jid@example.com", "+15555550000").sync - assert_kind_of WebRegisterManager::HaveTel, @manager["jid@example.com"].sync + assert_kind_of TelSelections::HaveTel, @manager["jid@example.com"].sync end em :test_set_get From 5d2a8e6daab8a06f14a5554e85c8a2a90d994006 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 13:21:31 -0500 Subject: [PATCH 2/6] Allow user to search for numbers over XMPP --- .rubocop.yml | 7 ++ forms/tn_list.rb | 14 ++++ forms/tn_search.rb | 15 ++++ lib/form_template.rb | 64 ++++++++++++++++ lib/tel_selections.rb | 148 ++++++++++++++++++++++++++++++++++-- test/test_form_template.rb | 65 ++++++++++++++++ test/test_tel_selections.rb | 95 +++++++++++++++++++++++ 7 files changed, 402 insertions(+), 6 deletions(-) create mode 100644 forms/tn_list.rb create mode 100644 forms/tn_search.rb create mode 100644 lib/form_template.rb create mode 100644 test/test_form_template.rb diff --git a/.rubocop.yml b/.rubocop.yml index d9efb21dfb8e36b6ea04f75f28d30fdad3b0246c..17be246f2e8e90d956918240381dee95f886d51f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -54,6 +54,9 @@ Style/DoubleNegation: Style/PerlBackrefs: Enabled: false +Style/SpecialGlobalVars: + EnforcedStyle: use_perl_names + Style/RegexpLiteral: EnforcedStyle: slashes AllowInnerSlashes: true @@ -82,5 +85,9 @@ Style/FormatString: Style/FormatStringToken: EnforcedStyle: unannotated +Style/FrozenStringLiteralComment: + Exclude: + - forms/* + Naming/AccessorMethodName: Enabled: false diff --git a/forms/tn_list.rb b/forms/tn_list.rb new file mode 100644 index 0000000000000000000000000000000000000000..8295c67dcb5aaf7a785e25311f18d413b528b687 --- /dev/null +++ b/forms/tn_list.rb @@ -0,0 +1,14 @@ +form! +title "Choose Telephone Number" +instructions "Please choose one of the following numbers" +field( + var: "tel", + required: true, + type: "list-single", + label: "Telephone Number", + options: @tns.map(&:option) +) + +xml.set(xmlns: "http://jabber.org/protocol/rsm") do |xml| + xml.count @tns.length.to_s +end diff --git a/forms/tn_search.rb b/forms/tn_search.rb new file mode 100644 index 0000000000000000000000000000000000000000..d03bb368456e5678ae600bd4e2a51a46e5f6eb2c --- /dev/null +++ b/forms/tn_search.rb @@ -0,0 +1,15 @@ +form! +title "Search Telephone Numbers" +instructions @error if @error +field( + var: "q", + required: true, + type: "text-single", + label: "Search Telephone Numbers", + description: + "Enter one of: Area code; six or seven digit " \ + "number prefix; zip code; city, state/province; " \ + "or indicate a vanity pattern with ~" +) + +xml.set(xmlns: "http://jabber.org/protocol/rsm") diff --git a/lib/form_template.rb b/lib/form_template.rb new file mode 100644 index 0000000000000000000000000000000000000000..ffe7ccdd968bdb4143740bd00b48d62bfa8114a0 --- /dev/null +++ b/lib/form_template.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require "blather" + +class FormTemplate + def initialize(template, filename="template", **kwargs) + @args = kwargs + @template = template + @filename = filename + freeze + end + + def self.render(path, **kwargs) + full_path = File.dirname(__dir__) + "/forms/#{path}.rb" + new(File.read(full_path), full_path, **kwargs).render + end + + def render(**kwargs) + one = OneRender.new(**@args.merge(kwargs)) + one.instance_eval(@template, @filename) + one.form + end + + class OneRender + def initialize(**kwargs) + kwargs.each do |k, v| + instance_variable_set("@#{k}", v) + end + @__form = Blather::Stanza::X.new + @__builder = Nokogiri::XML::Builder.with(@__form) + end + + def form! + @__type_set = true + @__form.type = :form + end + + def result! + @__type_set = true + @__form.type = :result + end + + def title(s) + @__form.title = s + end + + def instructions(s) + @__form.instructions = s + end + + def field(**kwargs) + @__form.fields = @__form.fields + [kwargs] + end + + def xml + @__builder + end + + def form + raise "Type never set" unless @__type_set + @__form + end + end +end diff --git a/lib/tel_selections.rb b/lib/tel_selections.rb index 769980aa6018b56cc38adb226f1125ce5fc3633c..4e9eaf9f1df5074ce019cdae57cfb80ee03f97bd 100644 --- a/lib/tel_selections.rb +++ b/lib/tel_selections.rb @@ -1,5 +1,10 @@ # frozen_string_literal: true +require "ruby-bandwidth-iris" +Faraday.default_adapter = :em_synchrony + +require_relative "form_template" + class TelSelections THIRTY_DAYS = 60 * 60 * 24 * 30 @@ -28,12 +33,143 @@ class TelSelections end class ChooseTel - def choose_tel - Command.finish( - "You have not chosen a phone number yet, please return to " \ - "https://jmp.chat and choose one now.", - type: :error - ) + def choose_tel(error: nil) + Command.reply { |reply| + reply.allowed_actions = [:next] + reply.command << FormTemplate.render("tn_search", error: error) + }.then { |iq| choose_from_list(AvailableNumber.for(iq.form).tns) } + end + + def choose_from_list(tns) + if tns.empty? + choose_tel(error: "No numbers found, try another search.") + else + Command.reply { |reply| + reply.allowed_actions = [:next] + reply.command << FormTemplate.render("tn_list", tns: tns) + }.then { |iq| iq.form.field("tel").value.to_s.strip } + end + end + + class AvailableNumber + def self.for(form) + new( + Q + .for(form.field("q").value.to_s.strip).iris_query + .merge(enableTNDetail: true) + .merge(Quantity.for(form).iris_query) + ) + end + + def initialize(iris_query) + @iris_query = iris_query + end + + def tns + Command.log.debug("BandwidthIris::AvailableNumber.list", @iris_query) + BandwidthIris::AvailableNumber.list(@iris_query).map(&Tn.method(:new)) + end + + class Quantity + def self.for(form) + rsm_max = form.find( + "ns:set/ns:max", + ns: "http://jabber.org/protocol/rsm" + ).first + if rsm_max + new(rsm_max.content.to_i) + else + Default.new + end + end + + def initialize(quantity) + @quantity = quantity + end + + def iris_query + { quantity: @quantity } + end + + # NOTE: Gajim sends back the whole list on submit, so big + # lists can cause issues + class Default + def iris_query + { quantity: 10 } + end + end + end + end + + class Tn + attr_reader :tel + + def initialize(full_number:, city:, state:, **) + @tel = "+1#{full_number}" + @locality = city + @region = state + end + + def option + { value: tel, label: to_s } + end + + def to_s + "#{@tel} (#{@locality}, #{@region})" + end + end + + class Q + def self.register(regex, &block) + @queries ||= [] + @queries << [regex, block] + end + + def self.for(q) + @queries.each do |(regex, block)| + match_data = (q =~ regex) + return block.call($1 || $&, *$~.to_a[2..-1]) if match_data + end + + raise "Format not recognized: #{q}" + end + + def initialize(q) + @q = q + end + + { + areaCode: [:AreaCode, /\A[2-9][0-9]{2}\Z/], + npaNxx: [:NpaNxx, /\A(?:[2-9][0-9]{2}){2}\Z/], + npaNxxx: [:NpaNxxx, /\A(?:[2-9][0-9]{2}){2}[0-9]\Z/], + zip: [:PostalCode, /\A\d{5}(?:-\d{4})?\Z/], + localVanity: [:LocalVanity, /\A~(.+)\Z/] + }.each do |k, args| + klass = const_set( + args[0], + Class.new(Q) do + define_method(:iris_query) do + { k => @q } + end + end + ) + + args[1..-1].each do |regex| + register(regex) { |q| klass.new(q) } + end + end + + class CityState + Q.register(/\A([^,]+)\s*,\s*([A-Z]{2})\Z/, &method(:new)) + def initialize(city, state) + @city = city + @state = state + end + + def iris_query + { city: @city, state: @state } + end + end end end end diff --git a/test/test_form_template.rb b/test/test_form_template.rb new file mode 100644 index 0000000000000000000000000000000000000000..78c4e0e0071fd2a8addd6eabf11578b010b349e1 --- /dev/null +++ b/test/test_form_template.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require "test_helper" +require "form_template" + +class FormTemplateTest < Minitest::Test + def test_form_one_field + template = FormTemplate.new(<<~TEMPLATE) + form! + title "TITLE" + instructions "INSTRUCTIONS" + field(var: "thevar", label: "thelabel") + TEMPLATE + form = template.render + assert_equal :form, form.type + assert_equal "TITLE", form.title + assert_equal "INSTRUCTIONS", form.instructions + assert_equal 1, form.fields.length + assert_equal "thevar", form.fields[0].var + assert_equal "thelabel", form.fields[0].label + end + + def test_form_two_fields + template = FormTemplate.new(<<~TEMPLATE) + form! + field(var: "thevar", label: "thelabel") + field(var: "thevar2", label: "thelabel2") + TEMPLATE + form = template.render + assert_equal 2, form.fields.length + assert_equal "thevar", form.fields[0].var + assert_equal "thelabel", form.fields[0].label + assert_equal "thevar2", form.fields[1].var + assert_equal "thelabel2", form.fields[1].label + end + + def test_result_no_fields + template = FormTemplate.new(<<~TEMPLATE) + result! + title "TITLE" + instructions "INSTRUCTIONS" + TEMPLATE + form = template.render + assert_equal :result, form.type + assert_equal "TITLE", form.title + assert_equal "INSTRUCTIONS", form.instructions + end + + def test_no_type + template = FormTemplate.new(<<~TEMPLATE) + title "TITLE" + instructions "INSTRUCTIONS" + TEMPLATE + assert_raises { template.render } + end + + def test_custom_xml + template = FormTemplate.new(<<~TEMPLATE) + form! + xml.whoever @arg + TEMPLATE + form = template.render(arg: "abc") + assert_equal "abc", form.at("whoever").content + end +end diff --git a/test/test_tel_selections.rb b/test/test_tel_selections.rb index dc029a09b022fb1bab89248f4e288f91368b6ca4..cc80cd2835521c7d97d60c5208007332c1685f0f 100644 --- a/test/test_tel_selections.rb +++ b/test/test_tel_selections.rb @@ -21,4 +21,99 @@ class TelSelectionsTest < Minitest::Test assert_equal "+15555550000", @manager[jid].then(&:choose_tel).sync end em :test_choose_tel_have_tel + + class AvailableNumberTest < Minitest::Test + def test_for_no_rsm + form = Blather::Stanza::X.new + form.fields = [{ var: "q", value: "226" }] + iris_query = + TelSelections::ChooseTel::AvailableNumber + .for(form) + .instance_variable_get(:@iris_query) + assert_equal( + { areaCode: "226", enableTNDetail: true, quantity: 10 }, + iris_query + ) + end + + def test_for_rsm + form = Blather::Stanza::X.new + form.fields = [{ var: "q", value: "226" }] + Nokogiri::XML::Builder.with(form) do + set(xmlns: "http://jabber.org/protocol/rsm") do + max 500 + end + end + iris_query = + TelSelections::ChooseTel::AvailableNumber + .for(form) + .instance_variable_get(:@iris_query) + assert_equal( + { areaCode: "226", enableTNDetail: true, quantity: 500 }, + iris_query + ) + end + end + + class TnTest < Minitest::Test + def setup + @tn = TelSelections::ChooseTel::Tn.new( + full_number: "5551234567", + city: "Toronto", + state: "ON", + garbage: "stuff" + ) + end + + def test_to_s + assert_equal "+15551234567 (Toronto, ON)", @tn.to_s + end + + def test_tel + assert_equal "+15551234567", @tn.tel + end + + def test_option + assert_equal( + { label: "+15551234567 (Toronto, ON)", value: "+15551234567" }, + @tn.option + ) + end + end + + class QTest < Minitest::Test + def test_for_area_code + q = TelSelections::ChooseTel::Q.for("226") + assert_equal({ areaCode: "226" }, q.iris_query) + end + + def test_for_npanxx + q = TelSelections::ChooseTel::Q.for("226666") + assert_equal({ npaNxx: "226666" }, q.iris_query) + end + + def test_for_npanxxx + q = TelSelections::ChooseTel::Q.for("2266667") + assert_equal({ npaNxxx: "2266667" }, q.iris_query) + end + + def test_for_zip + q = TelSelections::ChooseTel::Q.for("90210") + assert_equal({ zip: "90210" }, q.iris_query) + end + + def test_for_localvanity + q = TelSelections::ChooseTel::Q.for("~mboa") + assert_equal({ localVanity: "mboa" }, q.iris_query) + end + + def test_for_citystate + q = TelSelections::ChooseTel::Q.for("Toronto, ON") + assert_equal({ city: "Toronto", state: "ON" }, q.iris_query) + end + + def test_for_garbage + assert_raises { TelSelections::ChooseTel::Q.for("garbage") } + end + end end From 15ca96c2eaa988507053edc401a06f0dfad7e6da Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 13:24:41 -0500 Subject: [PATCH 3/6] Format tel for human reader --- lib/tel_selections.rb | 3 ++- test/test_tel_selections.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/tel_selections.rb b/lib/tel_selections.rb index 4e9eaf9f1df5074ce019cdae57cfb80ee03f97bd..8cc558c7273987bf70de6521837fd8a4bcc33493 100644 --- a/lib/tel_selections.rb +++ b/lib/tel_selections.rb @@ -115,7 +115,8 @@ class TelSelections end def to_s - "#{@tel} (#{@locality}, #{@region})" + @tel =~ /\A\+1(\d{3})(\d{3})(\d+)\Z/ + "(#{$1}) #{$2}-#{$3} (#{@locality}, #{@region})" end end diff --git a/test/test_tel_selections.rb b/test/test_tel_selections.rb index cc80cd2835521c7d97d60c5208007332c1685f0f..78cae2ea58a372beafd1192e4a1edba15cb7a7c4 100644 --- a/test/test_tel_selections.rb +++ b/test/test_tel_selections.rb @@ -66,7 +66,7 @@ class TelSelectionsTest < Minitest::Test end def test_to_s - assert_equal "+15551234567 (Toronto, ON)", @tn.to_s + assert_equal "(555) 123-4567 (Toronto, ON)", @tn.to_s end def test_tel @@ -75,7 +75,7 @@ class TelSelectionsTest < Minitest::Test def test_option assert_equal( - { label: "+15551234567 (Toronto, ON)", value: "+15551234567" }, + { label: "(555) 123-4567 (Toronto, ON)", value: "+15551234567" }, @tn.option ) end From e8c2919d77d49b35b3f0ac8bd1ca1a5c0305cef9 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 14:09:40 -0500 Subject: [PATCH 4/6] Add reference to option to show where the tel is --- lib/tel_selections.rb | 24 +++++++++++++++++++++--- test/test_tel_selections.rb | 14 +++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/tel_selections.rb b/lib/tel_selections.rb index 8cc558c7273987bf70de6521837fd8a4bcc33493..d297c0a8c7be0b2f4a2512754ae98c697b9f2eac 100644 --- a/lib/tel_selections.rb +++ b/lib/tel_selections.rb @@ -110,13 +110,31 @@ class TelSelections @region = state end + def formatted_tel + @tel =~ /\A\+1(\d{3})(\d{3})(\d+)\Z/ + "(#{$1}) #{$2}-#{$3}" + end + def option - { value: tel, label: to_s } + op = Blather::Stanza::X::Field::Option.new(value: tel, label: to_s) + op << reference + op + end + + def reference + Nokogiri::XML::Builder.new { |xml| + xml.reference( + xmlns: "urn:xmpp:reference:0", + begin: 0, + end: formatted_tel.length - 1, + type: "data", + uri: "tel:#{tel}" + ) + }.doc.root end def to_s - @tel =~ /\A\+1(\d{3})(\d{3})(\d+)\Z/ - "(#{$1}) #{$2}-#{$3} (#{@locality}, #{@region})" + "#{formatted_tel} (#{@locality}, #{@region})" end end diff --git a/test/test_tel_selections.rb b/test/test_tel_selections.rb index 78cae2ea58a372beafd1192e4a1edba15cb7a7c4..69e6ecc310e8731e89d7d5c6e0492d54419ad6de 100644 --- a/test/test_tel_selections.rb +++ b/test/test_tel_selections.rb @@ -75,10 +75,22 @@ class TelSelectionsTest < Minitest::Test def test_option assert_equal( - { label: "(555) 123-4567 (Toronto, ON)", value: "+15551234567" }, + Blather::Stanza::X::Field::Option.new( + label: "(555) 123-4567 (Toronto, ON)", + value: "+15551234567" + ), @tn.option ) end + + def test_option_reference + ref = @tn.option.find("ns:reference", ns: "urn:xmpp:reference:0").first + assert_equal( + @tn.formatted_tel, + @tn.option.label[ref["begin"].to_i..ref["end"].to_i] + ) + assert_equal "tel:+15551234567", ref["uri"] + end end class QTest < Minitest::Test From 23379ab675fe840f251474bb1e5bd3d622fa430b Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 14:10:00 -0500 Subject: [PATCH 5/6] Run rubocop after tests --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index e88645fa6eff90b35af35a85a30503a2efca24c2..bc3f56eb06c40da715680e61d4be842693fc443d 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,7 @@ end RuboCop::RakeTask.new(:lint) task :entr do - sh "sh", "-c", "git ls-files | entr -s 'rubocop && rake test'" + sh "sh", "-c", "git ls-files | entr -s 'rake test && rubocop'" end task default: :test From a16fd0d068ef810854d365490268bdd381830a27 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 31 Aug 2021 18:54:21 -0500 Subject: [PATCH 6/6] Do not direct back to website to pick new number Instead, if number is no longer available keep them in flow and use the number search tool. --- lib/registration.rb | 16 +++++++++------- lib/tel_selections.rb | 4 ++++ test/test_helper.rb | 22 ++++++++++++++++++++++ test/test_registration.rb | 32 ++++++++++++++++++++------------ 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/lib/registration.rb b/lib/registration.rb index a4189dc91550a052fb858ad89a816e26aacc7bca..ffc2f76a047c4f88c325ec4244c98ef83408ceaf 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -425,18 +425,20 @@ class Registration def write BandwidthTNOrder.create(@tel).then(&:poll).then( ->(_) { customer_active_tel_purchased }, - lambda do |_| - Command.finish( - "The JMP number #{@tel} is no longer available, " \ - "please visit https://jmp.chat and choose another.", - type: :error - ) - end + ->(_) { number_purchase_error } ) end protected + def number_purchase_error + TEL_SELECTIONS.delete(@customer.jid).then { + TelSelections::ChooseTel.new.choose_tel( + error: "The JMP number #{@tel} is no longer available." + ) + }.then { |tel| Finish.new(@customer, tel).write } + end + def cheogram_sip_addr "sip:#{ERB::Util.url_encode(@customer.jid)}@sip.cheogram.com" end diff --git a/lib/tel_selections.rb b/lib/tel_selections.rb index d297c0a8c7be0b2f4a2512754ae98c697b9f2eac..3c9592cbc850a1e181dd56472037ad3ae4436535 100644 --- a/lib/tel_selections.rb +++ b/lib/tel_selections.rb @@ -16,6 +16,10 @@ class TelSelections @redis.setex("pending_tel_for-#{jid}", THIRTY_DAYS, tel) end + def delete(jid) + @redis.del("pending_tel_for-#{jid}") + end + def [](jid) @redis.get("pending_tel_for-#{jid}").then do |tel| tel ? HaveTel.new(tel) : ChooseTel.new diff --git a/test/test_helper.rb b/test/test_helper.rb index c546f701720f7b5c8bac882d73b3016997e5575c..bcd869537e4b0745516554c99222b7e2de4fc174 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -34,6 +34,7 @@ rescue LoadError end require "backend_sgx" +require "tel_selections" $VERBOSE = nil Sentry.init @@ -132,6 +133,27 @@ class PromiseMock < Minitest::Mock end end +class FakeTelSelections + def initialize + @selections = {} + end + + def set(jid, tel) + @selections[jid] = EMPromise.resolve(TelSelections::HaveTel.new(tel)) + end + + def delete(jid) + @selections.delete(jid) + EMPromise.resolve("OK") + end + + def [](jid) + @selections.fetch(jid) do + TelSelections::ChooseTel.new + end + end +end + class FakeRedis def initialize(values={}) @values = values diff --git a/test/test_registration.rb b/test/test_registration.rb index d10da5571d9a0c230abfc3ee944c2cd90fae08fb..04c66a0e9d716bf1a933f9d01d7a0eb7cefd603b 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -514,6 +514,8 @@ class RegistrationTest < Minitest::Test end class FinishTest < Minitest::Test + Command::COMMAND_MANAGER = Minitest::Mock.new + Registration::Finish::TEL_SELECTIONS = FakeTelSelections.new Registration::Finish::REDIS = Minitest::Mock.new BackendSgx::REDIS = Minitest::Mock.new @@ -628,23 +630,29 @@ class RegistrationTest < Minitest::Test FAILED RESPONSE - blather = Minitest::Mock.new - blather.expect( - :<<, - nil, - [Matching.new do |reply| - assert_equal :completed, reply.status - assert_equal :error, reply.note_type + + Command::COMMAND_MANAGER.expect( + :write, + EMPromise.reject(:test_result), + [Matching.new do |iq| + assert_equal :form, iq.form.type assert_equal( - "The JMP number +15555550000 is no longer available, " \ - "please visit https://jmp.chat and choose another.", - reply.note.content + "The JMP number +15555550000 is no longer available.", + iq.form.instructions ) end] ) - execute_command(blather: blather) { @finish.write } + + assert_equal( + :test_result, + execute_command { @finish.write.catch { |e| e } } + ) + assert_mock Command::COMMAND_MANAGER + assert_instance_of( + TelSelections::ChooseTel, + Registration::Finish::TEL_SELECTIONS["test@example.com"] + ) assert_requested create_order - assert_mock blather end em :test_write_tn_fail end