From 051be0a9b22a7f2aba7e62f4b104ed6a9f7094c8 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 11 May 2022 14:11:10 -0500 Subject: [PATCH] Admin command to cancel customer Notify customer Deregister from SGX Deregister from Cheogram Disconnect from Bandwidth If on special list, move intead of disconnect --- Gemfile | 2 +- config-schema.dhall | 2 + config.dhall.sample | 2 + forms/admin_menu.rb | 3 +- lib/admin_command.rb | 13 +++++ lib/backend_sgx.rb | 7 +++ lib/bandwidth_tn_repo.rb | 22 +++++++ lib/customer.rb | 3 +- lib/customer_repo.rb | 5 ++ lib/ibr.rb | 11 ++++ test/test_admin_command.rb | 115 +++++++++++++++++++++++++++++++++++++ test/test_helper.rb | 2 + 12 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 test/test_admin_command.rb diff --git a/Gemfile b/Gemfile index 43e0692..e1424ee 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ gem "multihashes" gem "ougai" gem "relative_time" gem "roda" -gem "ruby-bandwidth-iris", git: "https://github.com/singpolyma/ruby-bandwidth-iris", branch: "sip_credential" +gem "ruby-bandwidth-iris", git: "https://github.com/singpolyma/ruby-bandwidth-iris", branch: "tn_move" gem "sentry-ruby", "<= 4.3.1" gem "slim" gem "statsd-instrument", git: "https://github.com/singpolyma/statsd-instrument.git", branch: "graphite" diff --git a/config-schema.dhall b/config-schema.dhall index 9878775..fa5754d 100644 --- a/config-schema.dhall +++ b/config-schema.dhall @@ -19,6 +19,8 @@ , electrum_notify_url : forall (address : Text) -> forall (customer_id : Text) -> Text , interac : Text +, keep_area_codes : List Text +, keep_area_codes_in : { account : Text, site : Text } , notify_admin : Text , notify_from : Text , ogm_path : Text diff --git a/config.dhall.sample b/config.dhall.sample index cedfc1b..72323b4 100644 --- a/config.dhall.sample +++ b/config.dhall.sample @@ -77,6 +77,8 @@ in notify_from = "+15551234567@example.net", admins = ["test\\40example.com@example.net"], unbilled_targets = ["+14169938000"], + keep_area_codes = ["555"], + keep_area_codes_in = { account = "", site = "" }, upstream_domain = "example.net", approved_domains = toMap { `example.com` = Some "customer_id" } } diff --git a/forms/admin_menu.rb b/forms/admin_menu.rb index 4d5fa49..aeb8b7d 100644 --- a/forms/admin_menu.rb +++ b/forms/admin_menu.rb @@ -10,6 +10,7 @@ field( options: [ { value: "info", label: "Customer Info" }, { value: "financial", label: "Customer Billing Information" }, - { value: "bill_plan", label: "Bill Customer" } + { value: "bill_plan", label: "Bill Customer" }, + { value: "cancel_account", label: "Cancel Customer" } ] ) diff --git a/lib/admin_command.rb b/lib/admin_command.rb index 7d8a47a..f19eb4a 100644 --- a/lib/admin_command.rb +++ b/lib/admin_command.rb @@ -75,6 +75,19 @@ class AdminCommand BillPlanCommand.for(@target_customer).call end + def action_cancel_account + m = Blather::Stanza::Message.new + m.from = CONFIG[:notify_from] + m.body = "Your JMP account has been cancelled." + @target_customer.stanza_to(m).then { + EMPromise.all([ + @target_customer.stanza_to(IBR.new(:set).tap(&:remove!)), + @target_customer.deregister!, + @customer_repo.disconnect_tel(@target_customer) + ]) + } + end + def pay_methods(financial_info) reply(FormTemplate.render( "admin_payment_methods", diff --git a/lib/backend_sgx.rb b/lib/backend_sgx.rb index 41de484..496814f 100644 --- a/lib/backend_sgx.rb +++ b/lib/backend_sgx.rb @@ -27,6 +27,13 @@ class BackendSgx IQ_MANAGER.write(ibr) end + def deregister! + ibr = IBR.new(:set, @jid) + ibr.from = from_jid + ibr.remove! + IQ_MANAGER.write(ibr) + end + def stanza(s) s.dup.tap do |stanza| stanza.to = stanza.to.with(domain: jid.domain) diff --git a/lib/bandwidth_tn_repo.rb b/lib/bandwidth_tn_repo.rb index daf76a4..35ef4d7 100644 --- a/lib/bandwidth_tn_repo.rb +++ b/lib/bandwidth_tn_repo.rb @@ -3,6 +3,15 @@ require "ruby-bandwidth-iris" class BandwidthTnRepo + def initialize + @move_client = + BandwidthIris::Client.new( + account_id: CONFIG[:keep_area_codes_in][:account], + username: CONFIG[:creds][:username], + password: CONFIG[:creds][:password] + ) + end + def find(tel) BandwidthIris::Tn.new(telephone_number: tel).get_details end @@ -18,4 +27,17 @@ class BandwidthTnRepo rescue BandwidthIris::Errors::GenericError raise "Could not set CNAM, please contact support" end + + def disconnect(tel, order_name) + tn = tel.sub(/\A\+1/, "") + if CONFIG[:keep_area_codes].find { |area| tn.start_with?(area) } + BandwidthIris::Tn.new({ telephone_number: tn }, @move_client).move( + site_id: CONFIG[:keep_area_codes_in][:site], + customer_order_id: order_name, + source_account_id: CONFIG[:creds][:account] + ) + else + BandwidthIris::Disconnect.create(order_name, tn) + end + end end diff --git a/lib/customer.rb b/lib/customer.rb index e309ddb..9ce9e7f 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -26,7 +26,7 @@ class Customer :currency, :merchant_account, :plan_name, :minute_limit, :message_limit, :auto_top_up_amount, :monthly_overage_limit, :monthly_price, :save_plan! - def_delegators :@sgx, :register!, :registered?, :set_ogm_url, + def_delegators :@sgx, :deregister!, :register!, :registered?, :set_ogm_url, :fwd, :transcription_enabled def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage def_delegators :@financials, :payment_methods, :btc_addresses, @@ -85,6 +85,7 @@ class Customer def stanza_to(stanza) stanza = stanza.dup stanza.to = jid.with(resource: stanza.to&.resource) + stanza.from ||= Blather::JID.new("") stanza.from = stanza.from.with(domain: CONFIG[:component][:jid]) block_given? ? yield(stanza) : (BLATHER << stanza) end diff --git a/lib/customer_repo.rb b/lib/customer_repo.rb index 35a3ec3..56e243b 100644 --- a/lib/customer_repo.rb +++ b/lib/customer_repo.rb @@ -107,6 +107,11 @@ class CustomerRepo end end + def disconnect_tel(customer) + tel = customer.registered?.phone + @bandwidth_tn_repo.disconnect(tel, customer.customer_id) + end + def put_lidb_name(customer, lidb_name) @bandwidth_tn_repo.put_lidb_name(customer.registered?.phone, lidb_name) end diff --git a/lib/ibr.rb b/lib/ibr.rb index 29faf6a..f8fe33a 100644 --- a/lib/ibr.rb +++ b/lib/ibr.rb @@ -16,6 +16,17 @@ class IBR < Blather::Stanza::Iq::Query !!query.at_xpath("./ns:registered", ns: self.class.registered_ns) end + def remove! + query.children.remove + node = Nokogiri::XML::Node.new("remove", document) + node.default_namespace = self.class.registered_ns + query << node + end + + def remove? + !!query.at_xpath("./ns:remove", ns: self.class.registered_ns) + end + [ "instructions", "username", diff --git a/test/test_admin_command.rb b/test/test_admin_command.rb new file mode 100644 index 0000000..4866f88 --- /dev/null +++ b/test/test_admin_command.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require "admin_command" + +BackendSgx::IQ_MANAGER = Minitest::Mock.new +Customer::BLATHER = Minitest::Mock.new + +class AdminCommandTest < Minitest::Test + def admin_command(tel="+15556667777") + sgx = Minitest::Mock.new(OpenStruct.new( + registered?: OpenStruct.new(phone: tel) + )) + [sgx, AdminCommand.new(customer(sgx: sgx), CustomerRepo.new)] + end + + def test_action_cancel_account + sgx, admin = admin_command + + Customer::BLATHER.expect( + :<<, + EMPromise.resolve(nil), + [ + Matching.new do |m| + assert_equal "Your JMP account has been cancelled.", m.body + assert_equal "test@example.net", m.to.to_s + assert_equal "notify_from@component", m.from.to_s + end + ] + ) + + Customer::BLATHER.expect( + :<<, + EMPromise.resolve(nil), + [ + Matching.new do |iq| + assert iq.remove? + assert_equal "test@example.net", iq.to.to_s + assert_equal "component", iq.from.to_s + end + ] + ) + + sgx.expect(:deregister!, EMPromise.resolve(nil)) + + stub_request( + :post, + "https://dashboard.bandwidth.com/v1.0/accounts//disconnects" + ).with( + body: { + name: "test", + DisconnectTelephoneNumberOrderType: { + TelephoneNumberList: { + TelephoneNumber: "5556667777" + } + } + }.to_xml(indent: 0, root: "DisconnectTelephoneNumberOrder") + ).to_return(status: 200, body: "") + + admin.action_cancel_account.sync + + assert_mock sgx + assert_mock BackendSgx::IQ_MANAGER + assert_mock Customer::BLATHER + end + em :test_action_cancel_account + + def test_action_cancel_account_keep_number + sgx, admin = admin_command("+15566667777") + + Customer::BLATHER.expect( + :<<, + EMPromise.resolve(nil), + [ + Matching.new do |m| + assert_equal "Your JMP account has been cancelled.", m.body + assert_equal "test@example.net", m.to.to_s + assert_equal "notify_from@component", m.from.to_s + end + ] + ) + + Customer::BLATHER.expect( + :<<, + EMPromise.resolve(nil), + [ + Matching.new do |iq| + assert iq.remove? + assert_equal "test@example.net", iq.to.to_s + assert_equal "component", iq.from.to_s + end + ] + ) + + sgx.expect(:deregister!, EMPromise.resolve(nil)) + + stub_request( + :post, + "https://dashboard.bandwidth.com/v1.0/accounts/moveto/moveTns" + ).with( + body: { + SiteId: "movetosite", + CustomerOrderId: "test", + SourceAccountId: "test_bw_account", + TelephoneNumbers: { TelephoneNumber: "5566667777" } + }.to_xml(indent: 0, root: "MoveTnsOrder") + ).to_return(status: 200, body: "") + + admin.action_cancel_account.sync + + assert_mock sgx + assert_mock BackendSgx::IQ_MANAGER + assert_mock Customer::BLATHER + end + em :test_action_cancel_account_keep_number +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 5b34d26..d721f84 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -98,6 +98,8 @@ CONFIG = { }, credit_card_url: ->(*) { "http://creditcard.example.com" }, electrum_notify_url: ->(*) { "http://notify.example.com" }, + keep_area_codes: ["556"], + keep_area_codes_in: { account: "moveto", site: "movetosite" }, upstream_domain: "example.net", approved_domains: { "approved.example.com": nil, -- 2.38.4