diff --git a/lib/command_list.rb b/lib/command_list.rb new file mode 100644 index 0000000000000000000000000000000000000000..2621b86c6046edba43ef43abc1f3b02e30d77423 --- /dev/null +++ b/lib/command_list.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +class CommandList + include Enumerable + + def self.for(jid) + Customer.for_jid(jid).catch { nil }.then do |customer| + EMPromise.resolve(customer&.registered?).catch { nil }.then do |reg| + next Registered.for(customer, reg.phone) if reg + CommandList.new + end + end + end + + def each + yield node: "jabber:iq:register", name: "Register" + end + + class Registered < CommandList + def self.for(customer, tel) + EMPromise.all([ + REDIS.get("catapult_fwd-#{tel}"), + customer.plan_name ? customer.payment_methods : [] + ]).then do |(fwd, payment_methods)| + klass = Class.new(Registered) + klass.include(HasBilling) unless payment_methods.empty? + klass.include(HasForwarding) if fwd + klass.new + end + end + + def each + super + yield node: "number-display", name: "Display JMP Number" + yield node: "configure-calls", name: "Configure Calls" + yield node: "usage", name: "Show Monthly Usage" + yield node: "reset sip account", name: "Create or Reset SIP Account" + end + end + + module HasForwarding + def each + super + yield( + node: "record-voicemail-greeting", + name: "Record Voicemail Greeting" + ) + end + end + + module HasBilling + def each + super + yield node: "buy-credit", name: "Buy account credit" + end + end +end diff --git a/lib/payment_methods.rb b/lib/payment_methods.rb index 1375d5d39a6036c6ab0d199cdc911df95ce1fa5a..33d4f33c54f1447e10abf4652de017c7c72d43c6 100644 --- a/lib/payment_methods.rb +++ b/lib/payment_methods.rb @@ -46,11 +46,19 @@ class PaymentMethods }.merge(kwargs) end + def empty? + false + end + class Empty def default_payment_method; end def to_list_single(*) raise "No payment methods available" end + + def empty? + true + end end end diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 4012b0f217c113f8dcd46d357e5dd22d9b596895..53dfb2f64134318eb7624cc17c3582e8065dd429 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -28,6 +28,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| @@ -298,7 +294,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 0000000000000000000000000000000000000000..7741a3f08d9bd99e598833ce8ffc57ae41c62281 --- /dev/null +++ b/test/test_command_list.rb @@ -0,0 +1,115 @@ +# 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"), + payment_methods: EMPromise.resolve([]) + )), + ["registered"] + ) + assert_equal( + ["CommandList::Registered"], + CommandList.for("registered").sync + .class.ancestors.map(&:name).grep(/\ACommandList::/) + ) + 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"), + payment_methods: EMPromise.resolve([]) + )), + ["registered"] + ) + assert_kind_of( + CommandList::HasForwarding, + CommandList.for("registered").sync + ) + end + em :test_for_registered_with_fwd + + def test_for_registered_with_billing + CommandList::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["catapult_fwd-1"] + ) + CommandList::Customer.expect( + :for_jid, + EMPromise.resolve(OpenStruct.new( + registered?: OpenStruct.new(phone: "1"), + plan_name: "test", + payment_methods: EMPromise.resolve([:boop]) + )), + ["registered"] + ) + assert_kind_of( + CommandList::HasBilling, + CommandList.for("registered").sync + ) + end + em :test_for_registered_with_billing + + def test_for_registered_with_forwarding_and_billing + 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"), + plan_name: "test", + payment_methods: EMPromise.resolve([:boop]) + )), + ["registered"] + ) + result = CommandList.for("registered").sync + assert_kind_of CommandList::HasForwarding, result + assert_kind_of CommandList::HasBilling, result + end + em :test_for_registered_with_forwarding_and_billing +end