From 345895de5e28ddf4e57ae13599924149f5d44d5c Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 23 Jun 2021 12:46:43 -0500 Subject: [PATCH] Show commands conditionally (plus add voicemail record command) Refactor to a factory that allows commands to be shown conditionally, so that the voicemail record command can only be shown if the customer has a forwarding target set up. --- lib/command_list.rb | 43 +++++++++++++++++++++++++++ sgx_jmp.rb | 36 +++++++++++------------ test/test_command_list.rb | 62 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 lib/command_list.rb create mode 100644 test/test_command_list.rb diff --git a/lib/command_list.rb b/lib/command_list.rb new file mode 100644 index 0000000..cb3c2d4 --- /dev/null +++ b/lib/command_list.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class CommandList + include Enumerable + + def self.for(jid) + Customer.for_jid(jid).then(&:registered?).catch { nil }.then { |reg| + next [] unless reg + REDIS.get("catapult_fwd-#{reg.phone}").then { |fwd| [reg, fwd] } + }.then do |(reg, fwd)| + next RegisteredAndHasForwarding.new if reg && fwd + next Registered.new if reg + CommandList.new + end + end + + def each + yield node: "jabber:iq:register", name: "Register" + end + + class Registered < CommandList + def each + super + yield node: "number-display", name: "Display JMP Number" + yield node: "configure-calls", name: "Configure Calls" + # TODO: don't show this item if no braintree methods available + # TODO: don't show this item if no plan for this customer + yield node: "buy-credit", name: "Buy account credit" + yield node: "usage", name: "Show Monthly Usage" + yield node: "reset sip account", name: "Create or Reset SIP Account" + end + end + + class RegisteredAndHasForwarding < Registered + def each + super + yield( + node: "record-voicemail-greeting", + name: "Record Voicemail Greeting" + ) + end + end +end diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 5c70c2b..8d460f3 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -29,6 +29,7 @@ require_relative "lib/backend_sgx" require_relative "lib/bandwidth_tn_order" require_relative "lib/btc_sell_prices" require_relative "lib/buy_account_credit_form" +require_relative "lib/command_list" require_relative "lib/customer" require_relative "lib/electrum" require_relative "lib/em" @@ -241,24 +242,19 @@ disco_info to: Blather::JID.new(CONFIG[:component][:jid]) do |iq| end disco_items node: "http://jabber.org/protocol/commands" do |iq| + sentry_hub = new_sentry_hub(iq, name: iq.node) reply = iq.reply - reply.items = [ - { node: "number-display", name: "Display JMP Number" }, - { node: "configure-calls", name: "Configure Calls" }, - # TODO: don't show this item if no braintree methods available - # TODO: don't show this item if no plan for this customer - { node: "buy-credit", name: "Buy account credit" }, - { node: "jabber:iq:register", name: "Register" }, - { node: "usage", name: "Show Monthly Usage" }, - { node: "reset sip account", name: "Create or Reset SIP Account" } - ].map do |item| - Blather::Stanza::DiscoItems::Item.new( - iq.to, - item[:node], - item[:name] - ) - end - self << reply + + CommandList.for(iq.from.stripped).then { |list| + reply.items = list.map do |item| + Blather::Stanza::DiscoItems::Item.new( + iq.to, + item[:node], + item[:name] + ) + end + self << reply + }.catch { |e| panic(e, sentry_hub) } end command :execute?, node: "jabber:iq:register", sessionid: nil do |iq| @@ -296,7 +292,11 @@ def reply_with_note(iq, text, type: :info) end # Commands that just pass through to the SGX -command node: ["number-display", "configure-calls"] do |iq| +command node: [ + "number-display", + "configure-calls", + "record-voicemail-greeting" +] do |iq| sentry_hub = new_sentry_hub(iq, name: iq.node) Customer.for_jid(iq.from.stripped).then { |customer| sentry_hub.current_scope.set_user( diff --git a/test/test_command_list.rb b/test/test_command_list.rb new file mode 100644 index 0000000..4775ed6 --- /dev/null +++ b/test/test_command_list.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require "test_helper" +require "command_list" + +CommandList::Customer = Minitest::Mock.new +CommandList::REDIS = Minitest::Mock.new + +class CommandListTest < Minitest::Test + def test_for_no_customer + CommandList::Customer.expect( + :for_jid, + EMPromise.reject("not found"), + ["none"] + ) + assert_instance_of CommandList, CommandList.for("none").sync + end + em :test_for_no_customer + + def test_for_unregistered + CommandList::Customer.expect( + :for_jid, + EMPromise.resolve(OpenStruct.new(registered?: false)), + ["unregistered"] + ) + assert_instance_of CommandList, CommandList.for("unregistered").sync + end + em :test_for_unregistered + + def test_for_registered + CommandList::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["catapult_fwd-1"] + ) + CommandList::Customer.expect( + :for_jid, + EMPromise.resolve(OpenStruct.new(registered?: OpenStruct.new(phone: "1"))), + ["registered"] + ) + assert_instance_of CommandList::Registered, CommandList.for("registered").sync + end + em :test_for_registered + + def test_for_registered_with_fwd + CommandList::REDIS.expect( + :get, + EMPromise.resolve("tel:1"), + ["catapult_fwd-1"] + ) + CommandList::Customer.expect( + :for_jid, + EMPromise.resolve(OpenStruct.new(registered?: OpenStruct.new(phone: "1"))), + ["registered"] + ) + assert_instance_of( + CommandList::RegisteredAndHasForwarding, + CommandList.for("registered").sync + ) + end + em :test_for_registered_with_fwd +end -- 2.34.5