diff --git a/forms/registration/activate.rb b/forms/registration/activate.rb index 95886767e9ebc5ef6d5d57ce7a59a752fa43d813..ff29bcd0085d20965f280b4e4cdd67e75a7f4581 100644 --- a/forms/registration/activate.rb +++ b/forms/registration/activate.rb @@ -5,6 +5,8 @@ instructions <<~I You've selected #{@tel} as your JMP number. To activate your account, you can either deposit $#{'%.2f' % (CONFIG[:activation_amount] + @tel.price)} to your balance or enter your referral code if you have one. (If you'd like to pay in another cryptocurrency, currently we recommend using a service like simpleswap.io, morphtoken.com, changenow.io, or godex.io.) + + After payment is complete, your number will be activated for inbound calls and texts. Calling out, or sending a text, will often be restricted until you receive at least one text from a person or port in a number. I field( diff --git a/lib/invites_repo.rb b/lib/invites_repo.rb index f5713f17333c8e4dc19b497d10b986e571d40315..eb12a77ffd1d37ded2ded5ee1f3ac3b41ee426c1 100644 --- a/lib/invites_repo.rb +++ b/lib/invites_repo.rb @@ -3,19 +3,25 @@ require "multibases" require "securerandom" +require_relative "trust_level_repo" + class InvitesRepo class Invalid < StandardError; end def initialize(db=DB, redis=REDIS) @db = db @redis = redis + @trust_level_repo = TrustLevelRepo.new(db: db, redis: redis) end - def unused_invites(customer_id) - promise = @db.query_defer(<<~SQL, [customer_id]) - SELECT code FROM unused_invites WHERE creator_id=$1 - SQL - promise.then { |result| result.map { |row| row["code"] } } + def unused_invites(customer) + @trust_level_repo.find(customer).then { |tl| + next [] unless tl.invite? + + @db.query_defer(<<~SQL, [customer_id]) + SELECT code FROM unused_invites WHERE creator_id=$1 + SQL + }.then { |result| result.map { |row| row["code"] } } end def find_or_create_group_code(customer_id) @@ -44,7 +50,7 @@ class InvitesRepo ]).then do |(_, credit_to)| next false if credit_to.to_s.strip == "" - create_claimed_code(credit_to, customer_id) + create_claimed_code(credit_to, customer_id, trusted: false) credit_to end end @@ -69,10 +75,10 @@ class InvitesRepo end end - def create_claimed_code(creator_id, used_by_id) - @db.exec(<<~SQL, [creator_id, used_by_id]) - INSERT INTO invites (creator_id, used_by_id, used_at) - VALUES ($1, $2, LOCALTIMESTAMP) + def create_claimed_code(creator_id, used_by_id, trusted: true) + @db.exec(<<~SQL, [creator_id, used_by_id, trusted]) + INSERT INTO invites (creator_id, used_by_id, used_at, trusted) + VALUES ($1, $2, LOCALTIMESTAMP, $3) SQL end diff --git a/lib/registration.rb b/lib/registration.rb index 928442d70bd060bd75b12abd7b48e71612767eda..086bc6094f1d94355d87e671aabc2a3ac9b08db1 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -718,10 +718,17 @@ class Registration class Finish TN_UNAVAILABLE = "The JMP number %s is no longer available." - def initialize(customer, tel) + def initialize( + customer, tel, + trust_level_repo: TrustLevelRepo.new( + db: LazyObject.new { DB }, + redis: LazyObject.new { REDIS } + ) + ) @customer = customer @tel = tel @invites = InvitesRepo.new(DB, REDIS) + @trust_level_repo = trust_level_repo end def write @@ -796,18 +803,27 @@ class Registration @tel.charge(customer) ]) }.then do - FinishOnboarding.for(customer, @tel).then(&:write) + FinishOnboarding.for( + customer, @tel, trust_level_repo: @trust_level_repo + ).then(&:write) end end end module FinishOnboarding - def self.for(customer, tel, db: LazyObject.new { DB }) + def self.for( + customer, tel, + db: LazyObject.new { DB }, + trust_level_repo: TrustLevelRepo.new( + db: LazyObject.new { DB }, + redis: LazyObject.new { REDIS } + ) + ) jid = ProxiedJID.new(customer.jid).unproxied if jid.domain == CONFIG[:onboarding_domain] Snikket.for(customer, tel, db: db) else - NotOnboarding.new(customer, tel) + NotOnboarding.new(customer, tel, trust_level_repo: trust_level_repo) end end @@ -1006,13 +1022,17 @@ class Registration end class NotOnboarding - def initialize(customer, tel) + def initialize(customer, tel, trust_level_repo:) @customer = customer @tel = tel + @trust_level_repo = trust_level_repo end def write - WelcomeMessage.new(@customer, @tel).welcome + WelcomeMessage.for( + @customer, @tel, + trust_level_repo: @trust_level_repo + ).then(&:welcome) Command.finish("Your JMP account has been activated as #{@tel}") end end diff --git a/lib/trust_level.rb b/lib/trust_level.rb index 10668cac7dcc5116b887f91be939dee7488078cf..b54112c1baf67b85108665e370deba6966c9e5b3 100644 --- a/lib/trust_level.rb +++ b/lib/trust_level.rb @@ -3,12 +3,15 @@ require "delegate" module TrustLevel - def self.for(plan_name:, settled_amount: 0, manual: nil) + def self.for( + customer:, settled_amount: 0, manual: nil, + activated: nil, invited: false, activater: nil + ) @levels.each do |level| tl = level.call( - plan_name: plan_name, - settled_amount: settled_amount, - manual: manual + customer: customer, + settled_amount: settled_amount, activated: activated, + manual: manual, invited: invited, activater: activater ) return manual ? Manual.new(tl) : tl if tl end @@ -32,6 +35,10 @@ module TrustLevel new if manual == "Tomb" end + def invite? + false + end + def write_cdr? false end @@ -70,8 +77,13 @@ module TrustLevel end class Cellar - TrustLevel.register do |manual:, **| - new if manual == "Cellar" + TrustLevel.register do |manual:, activated:, invited:, activater:, **| + new if manual == "Cellar" || (!manual && !activater && !invited && \ + (!activated || activated > Time.parse("2026-02-26"))) + end + + def invite? + false end def write_cdr? @@ -117,6 +129,10 @@ module TrustLevel new if manual == "Basement" || (!manual && settled_amount < 10) end + def invite? + true + end + def write_cdr? true end @@ -171,6 +187,10 @@ module TrustLevel new if manual == "Paragon" || (!manual && settled_amount > 60) end + def invite? + true + end + def write_cdr? true end @@ -225,6 +245,10 @@ module TrustLevel new if manual == "Olympias" end + def invite? + true + end + def write_cdr? true end @@ -253,12 +277,12 @@ module TrustLevel end class Customer - TrustLevel.register do |manual:, plan_name:, **| + TrustLevel.register do |manual:, customer:, **| if manual && manual != "Customer" Sentry.capture_message("Unknown TrustLevel: #{manual}") end - new(plan_name) + new(customer.plan_name) end EXPENSIVE_ROUTE = { @@ -272,6 +296,10 @@ module TrustLevel @max_rate = EXPENSIVE_ROUTE.fetch(plan_name, 0.1) end + def invite? + true + end + def write_cdr? true end diff --git a/lib/trust_level_repo.rb b/lib/trust_level_repo.rb index 4cad9ba90cfa4648a71412e748e6056509c2366f..e7b0b30eaac9dc0c72889e44bb4bddd297cb9526 100644 --- a/lib/trust_level_repo.rb +++ b/lib/trust_level_repo.rb @@ -14,11 +14,17 @@ class TrustLevelRepo def find(customer) EMPromise.all([ find_manual(customer.customer_id), + redis.get("jmp_customer_activater-#{customer.customer_id}"), + customer.activation_date, + fetch_was_invited(customer.customer_id), fetch_settled_amount(customer.billing_customer_id) - ]).then do |(manual, row)| + ]).then do |(manual, activater, activated, invited, row)| TrustLevel.for( + customer: customer, manual: manual, - plan_name: customer.plan_name, + activated: activated, + invited: invited[:used_at], + activater: activater, **row ) end @@ -36,6 +42,22 @@ class TrustLevelRepo end end + def incoming_message(customer, stanza) + from = stanza.from.node.to_s + return if from =~ /^$|^[^+]/ # don't count short codes + + body = m.body.to_s + return if body =~ /^$|http|code/i + + redis.sismember("jmp_blocked_activation_source", from).then do |blocked| + next if blocked + + redis.set( + "jmp_customer_activater-#{customer.customer_id}", stanza.from.node, "NX" + ) + end + end + protected def fetch_settled_amount(customer_id) @@ -44,4 +66,10 @@ protected WHERE customer_id=$1 AND settled_after < LOCALTIMESTAMP AND amount > 0 SQL end + + def fetch_was_invited(customer_id) + db.query_one(<<~SQL, customer_id, default: {}) + SELECT used_at FROM invites WHERE used_by_id=$1 AND trusted LIMIT 1 + SQL + end end diff --git a/lib/welcome_message.rb b/lib/welcome_message.rb index 00fbd918509dc0e15db3a8b685f5a3e6d4bade36..ca5690ef5dfd7547b976e4126fa0595dd5e5097d 100644 --- a/lib/welcome_message.rb +++ b/lib/welcome_message.rb @@ -1,9 +1,18 @@ # frozen_string_literal: true +require_relative "trust_level_repo" + class WelcomeMessage - def initialize(customer, tel) + def self.for(customer, tel, trust_level_repo: TrustLevelRepo.new) + trust_level_repo.find(customer).then do |tl| + new(customer, tel, tl) + end + end + + def initialize(customer, tel, trust_level) @customer = customer @tel = tel + @trust_level = trust_level end def welcome @@ -13,15 +22,24 @@ class WelcomeMessage end end + def warning + return if @trust_level.support_call?(0, 0) && @trust_level.send_message?(0) + + "\n\nYour account is activated for inbound calls and texts, but you " \ + "won't be able to call out or send a text until you receive at least " \ + "one text from a person at your new number, or port in a number from " \ + "outside." + end + def message m = Blather::Stanza::Message.new m.from = CONFIG[:notify_from] m.body = - "Welcome to JMP! Your JMP number is #{@tel}. This is an automated " \ - "message, but anything you send here will go direct to real humans " \ - "who will be happy to help you. Such support requests will get a " \ - "reply within 8 business hours.\n\n" \ - "FAQ: https://jmp.chat/faq\n\n" \ + "Welcome to JMP! Your JMP number is #{@tel}.#{warning}\n\nThis is an " \ + "automated message, but anything you send here will go direct to real " \ + "humans who will be happy to help you. Such support requests will " \ + "get a reply within 8 business hours.\n\n" \ + "FAQ: https://jmp.chat/faq\n" \ "Account Settings: xmpp:cheogram.com?command" m end diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 7aaef894ec29d0195356f2e4776aa6294c80cf45..c4acf4f3932b1159a27db536a256f76e633ece62 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -276,6 +276,8 @@ before nil, to: /\Acustomer_/, from: /(\A|@)#{FROM_BACKEND}(\/|\Z)/ do |s| CustomerRepo.new(set_user: Sentry.method(:set_user)).find( s.to.node.delete_prefix("customer_") ).then do |customer| + # Intentionally called outside filter so ported-in numbers activate here + TrustLevelRepo.new.incoming_message(customer, s) ReachabilityRepo::SMS.new .find(customer, s.from.node, stanza: s).then do |reach| reach.filter do @@ -304,6 +306,7 @@ message( CustomerRepo .new(set_user: Sentry.method(:set_user)) .find_by_jid(address["jid"]).then { |customer| + TrustLevelRepo.new.incoming_message(customer, s) m.from = m.from.with(domain: CONFIG[:component][:jid]) m.to = m.to.with(domain: customer.jid.domain) address["jid"] = customer.jid.to_s @@ -716,7 +719,7 @@ Command.new( Command.customer.then { |customer| EMPromise.all([ repo.find_or_create_group_code(customer.customer_id), - repo.unused_invites(customer.customer_id) + repo.unused_invites(customer) ]) }.then do |(group_code, invites)| if invites.empty? @@ -1092,7 +1095,7 @@ Command.new( jid = ProxiedJID.new(customer.jid).unproxied if jid.domain == CONFIG[:onboarding_domain] CustomerRepo.new.find(customer.customer_id).then do |cust| - WelcomeMessage.new(cust, customer.registered?.phone).welcome + WelcomeMessage.for(cust, customer.registered?.phone).then(&:welcome) end end Command.finish { |reply| diff --git a/test/test_admin_command.rb b/test/test_admin_command.rb index 7534c5c5b4c07c3d2f9d869ad76e0b7b99125c0b..040805082ebf0c7f5b0f8a2a772e3aa2acf74984 100644 --- a/test/test_admin_command.rb +++ b/test/test_admin_command.rb @@ -164,6 +164,18 @@ class AdminCommandTest < Minitest::Test ["jmp_customer_trust_level-testuser"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-testuser"] + ) + + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "testuser"], default: {} + ) + TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({ settled_amount: 0 }), diff --git a/test/test_buy_account_credit_form.rb b/test/test_buy_account_credit_form.rb index 8fc84c67a18f800040072b5b8c4b0ac81b7c181b..2573db8ae19d142fc3c267ecd42bc79d9a725580 100644 --- a/test/test_buy_account_credit_form.rb +++ b/test/test_buy_account_credit_form.rb @@ -36,6 +36,19 @@ class BuyAccountCreditFormTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -47,6 +60,7 @@ class BuyAccountCreditFormTest < Minitest::Test BuyAccountCreditForm.for(customer).sync ) + assert_mock CustomerPlan::DB assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB end diff --git a/test/test_credit_card_sale.rb b/test/test_credit_card_sale.rb index 2d460da513e4c39af7c23f5edc2776ec4c8462f8..a39123f9191666b9343852ad3c159fc33373edec 100644 --- a/test/test_credit_card_sale.rb +++ b/test/test_credit_card_sale.rb @@ -32,6 +32,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -72,6 +85,7 @@ class CreditCardSaleTest < Minitest::Test ).sale.sync end assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB @@ -89,6 +103,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -107,6 +134,7 @@ class CreditCardSaleTest < Minitest::Test ).sale.sync end assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB @@ -124,6 +152,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -144,6 +185,7 @@ class CreditCardSaleTest < Minitest::Test end assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB @@ -161,6 +203,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve("Customer"), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -181,6 +236,7 @@ class CreditCardSaleTest < Minitest::Test end assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB @@ -218,6 +274,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -255,6 +324,7 @@ class CreditCardSaleTest < Minitest::Test ).sale.sync assert_equal FAKE_BRAINTREE_TRANSACTION, result assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB @@ -309,6 +379,19 @@ class CreditCardSaleTest < Minitest::Test EMPromise.resolve("Customer"), ["jmp_customer_trust_level-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-test"] + ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test"], default: {} + ) TrustLevelRepo::DB.expect( :query_one, EMPromise.resolve({}), @@ -367,6 +450,7 @@ class CreditCardSaleTest < Minitest::Test assert_mock transaction_class assert_mock transaction assert_mock CustomerFinancials::REDIS + assert_mock CustomerPlan::DB assert_mock CreditCardSale::REDIS assert_mock TrustLevelRepo::REDIS assert_mock TrustLevelRepo::DB diff --git a/test/test_helper.rb b/test/test_helper.rb index ac1946ed4319cf25f95108c611b623f764864a5f..91c9b5b03e15f23de26405803034858e6e1bd934 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -478,6 +478,16 @@ class FakeIBRRepo end end +class FakeTrustLevelRepo + def initialize(levels) + @levels = levels + end + + def find(customer) + TrustLevel.for(customer: customer, manual: @levels[customer.customer_id]) + end +end + module EventMachine class << self # Patch EM.add_timer to be instant in tests diff --git a/test/test_registration.rb b/test/test_registration.rb index 264e1ddfdce3ce4713411812b425426a5e969831..f84c721c75e1b1a82a4b06a276df95bb62cb5acc 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -220,6 +220,7 @@ class RegistrationTest < Minitest::Test "PARENT_TOMB" => "2", "PARENT_MANY_SUBACCOUNTS" => "many_subaccounts" }, + "jmp_customer_trust_level-1" => "Basement", "jmp_customer_trust_level-2" => "Tomb" ) Registration::Activation::Payment = Minitest::Mock.new @@ -436,6 +437,12 @@ class RegistrationTest < Minitest::Test ) end] ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "1"] + ) + Registration::Activation::DB.expect( + :query_one, {}, [String, "1"], default: {} + ) Registration::Activation::DB.expect( :query_one, {}, [String, "1"], default: {} ) @@ -466,6 +473,7 @@ class RegistrationTest < Minitest::Test ) end assert_mock Command::COMMAND_MANAGER + assert_mock CustomerPlan::DB assert_mock @customer assert_mock Registration::Activation::Payment assert_mock Registration::Activation::DB @@ -490,6 +498,12 @@ class RegistrationTest < Minitest::Test ) end] ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "1"] + ) + Registration::Activation::DB.expect( + :query_one, {}, [String, "1"], default: {} + ) Registration::Activation::DB.expect( :query_one, {}, [String, "1"], default: {} ) @@ -531,6 +545,12 @@ class RegistrationTest < Minitest::Test ) end] ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "2"] + ) + Registration::Activation::DB.expect( + :query_one, {}, [String, "2"], default: {} + ) Registration::Activation::DB.expect( :query_one, {}, [String, "2"], default: {} ) @@ -542,6 +562,7 @@ class RegistrationTest < Minitest::Test execute_command { @activation.write.catch(&:to_s) } ) assert_mock Command::COMMAND_MANAGER + assert_mock CustomerPlan::DB assert_mock @customer assert_mock Registration::Activation::Payment assert_mock Registration::Activation::DB @@ -565,6 +586,12 @@ class RegistrationTest < Minitest::Test ) end] ) + CustomerPlan::DB.expect( + :query_one, {}, [String, "many_subaccounts"] + ) + Registration::Activation::DB.expect( + :query_one, {}, [String, "many_subaccounts"], default: {} + ) Registration::Activation::DB.expect( :query_one, {}, [String, "many_subaccounts"], default: {} ) @@ -576,6 +603,7 @@ class RegistrationTest < Minitest::Test execute_command { @activation.write.catch(&:to_s) } ) assert_mock Command::COMMAND_MANAGER + assert_mock CustomerPlan::DB assert_mock @customer assert_mock Registration::Activation::Payment assert_mock Registration::Activation::DB @@ -654,7 +682,7 @@ class RegistrationTest < Minitest::Test Registration::Activation::Allow::DB.expect( :exec, nil, - [String, ["refercust", "test"]] + [String, ["refercust", "test", true]] ) cust.expect(:with_plan, cust, ["test_usd"]) cust.expect(:activate_plan_starting_now, nil) @@ -1039,6 +1067,12 @@ class RegistrationTest < Minitest::Test :new, OpenStruct.new(write: nil) ) { |*| true } + CustomerPlan::DB.expect( + :query_one, {}, [String, "parent_customer"] + ) + Registration::Payment::InviteCode::DB.expect( + :query_one, {}, [String, "parent_customer"], default: {} + ) Registration::Payment::InviteCode::DB.expect( :query_one, {}, [String, "parent_customer"], default: {} ) @@ -1053,9 +1087,14 @@ class RegistrationTest < Minitest::Test ) Registration::Payment::InviteCode::REDIS.expect( :get, - EMPromise.resolve(nil), + EMPromise.resolve("Basement"), ["jmp_customer_trust_level-parent_customer"] ) + Registration::Payment::InviteCode::REDIS.expect( + :get, + EMPromise.resolve(nil), + ["jmp_customer_activater-parent_customer"] + ) CustomerPlan::DB.expect( :query, [{ "plan_name" => "test_usd" }], @@ -1090,6 +1129,7 @@ class RegistrationTest < Minitest::Test ).write end assert_mock Command::COMMAND_MANAGER + assert_mock CustomerPlan::DB assert_mock Registration::Payment::InviteCode::DB assert_mock Registration::Payment::InviteCode::REDIS assert_mock Registration::Payment::MaybeBill::BillPlan @@ -1314,7 +1354,8 @@ class RegistrationTest < Minitest::Test iq.from = "test\\40example.com@cheogram.com" @finish = Registration::Finish.new( customer(sgx: @sgx, plan_name: "test_usd"), - TelSelections::ChooseTel::Tn.for_pending_value("+15555550000") + TelSelections::ChooseTel::Tn.for_pending_value("+15555550000"), + trust_level_repo: FakeTrustLevelRepo.new("test" => "Cellar") ) end @@ -1468,7 +1509,7 @@ class RegistrationTest < Minitest::Test Registration::Finish::DB.expect( :exec, EMPromise.resolve(nil), - [String, ["test-inviter", "test"]] + [String, ["test-inviter", "test", false]] ) Transaction::DB.expect(:transaction, nil) do |&blk| blk.call diff --git a/test/test_trust_level_repo.rb b/test/test_trust_level_repo.rb index b8e7b86063e8118274fcee96f01df3f02d2dc478..9b7bed6e19c631ca81173cbb5361dd7302fa67d7 100644 --- a/test/test_trust_level_repo.rb +++ b/test/test_trust_level_repo.rb @@ -3,6 +3,16 @@ require "trust_level_repo" class TrustLevelRepoTest < Minitest::Test + def setup + CustomerPlan::DB.expect( + :query_one, {}, [String, "test"] + ) + end + + def teardown + assert_mock CustomerPlan::DB + end + def test_manual_tomb trust_level = TrustLevelRepo.new( db: FakeDB.new, @@ -14,6 +24,17 @@ class TrustLevelRepoTest < Minitest::Test end em :test_manual_tomb + def test_manual_cellar + trust_level = TrustLevelRepo.new( + db: FakeDB.new, + redis: FakeRedis.new( + "jmp_customer_trust_level-test" => "Cellar" + ) + ).find(customer(plan_name: "test_usd")).sync + assert_equal "Manual(Cellar)", trust_level.to_s + end + em :test_manual_cellar + def test_manual_basement trust_level = TrustLevelRepo.new( db: FakeDB.new, @@ -63,14 +84,51 @@ class TrustLevelRepoTest < Minitest::Test db: FakeDB.new, redis: FakeRedis.new ).find(customer(plan_name: "test_usd")).sync - assert_kind_of TrustLevel::Basement, trust_level + assert_kind_of TrustLevel::Cellar, trust_level end em :test_new_customer + def test_new_customer_with_activater + trust_level = TrustLevelRepo.new( + db: FakeDB.new, + redis: FakeRedis.new( + "jmp_customer_activater-test" => "+15551234567" + ) + ).find(customer(plan_name: "test_usd")).sync + assert_kind_of TrustLevel::Basement, trust_level + end + em :test_new_customer_with_activater + + def test_invited_customer + trust_level = TrustLevelRepo.new( + db: FakeDB.new( + ["test"] => FakeDB::MultiResult.new([{ used_at: Time.now }], []) + ), + redis: FakeRedis.new + ).find(customer(plan_name: "test_usd")).sync + assert_kind_of TrustLevel::Basement, trust_level + end + em :test_invited_customer + + def test_old_customer + CustomerPlan::DB.query_one("", "test") + CustomerPlan::DB.expect( + :query_one, { start_date: Time.parse("2026-02-25") }, [String, "test"] + ) + trust_level = TrustLevelRepo.new( + db: FakeDB.new, + redis: FakeRedis.new + ).find(customer(plan_name: "test_usd")).sync + assert_kind_of TrustLevel::Basement, trust_level + end + em :test_old_customer + def test_regular_customer trust_level = TrustLevelRepo.new( db: FakeDB.new(["test"] => [{ "settled_amount" => 15 }]), - redis: FakeRedis.new + redis: FakeRedis.new( + "jmp_customer_activater-test" => "+15551234567" + ) ).find(customer(plan_name: "test_usd")).sync assert_kind_of TrustLevel::Customer, trust_level end @@ -79,7 +137,9 @@ class TrustLevelRepoTest < Minitest::Test def test_settled_customer trust_level = TrustLevelRepo.new( db: FakeDB.new(["test"] => [{ "settled_amount" => 61 }]), - redis: FakeRedis.new + redis: FakeRedis.new( + "jmp_customer_activater-test" => "+15551234567" + ) ).find(customer(plan_name: "test_usd")).sync assert_kind_of TrustLevel::Paragon, trust_level end diff --git a/test/test_web.rb b/test/test_web.rb index 8bc2cc36a2a44489fbb0b56437dbb303566b87e3..8677f382159312555b27ef12e1dfd714a9a63deb 100644 --- a/test/test_web.rb +++ b/test/test_web.rb @@ -124,7 +124,13 @@ class WebTest < Minitest::Test ) ) Web.opts[:call_attempt_repo] = CallAttemptRepo.new( - redis: FakeRedis.new, + redis: FakeRedis.new( + "jmp_customer_activater-customerid" => "+15551234567", + "jmp_customer_activater-customerid2" => "+15551234567", + "jmp_customer_activater-customerid_limit" => "+15551234567", + "jmp_customer_activater-customerid_low" => "+15551234567", + "jmp_customer_activater-customerid_topup" => "+15551234567" + ), db: FakeDB.new( ["test_usd", "+15557654321", :outbound] => [{ "rate" => 0.01 }], ["test_usd", "+1911", :outbound] => [{ "rate" => 0.01 }], @@ -134,14 +140,17 @@ class WebTest < Minitest::Test ["test_usd", "+18001234567", :outbound] => [{ "rate" => 0.00 }], ["customerid_limit"] => FakeDB::MultiResult.new( [{ "a" => 1000 }], + [], [{ "settled_amount" => 15 }] ), ["customerid_low"] => FakeDB::MultiResult.new( [{ "a" => 1000 }], + [], [{ "settled_amount" => 15 }] ), ["customerid_topup"] => FakeDB::MultiResult.new( [{ "a" => 1000 }], + [], [{ "settled_amount" => 15 }] ) ) @@ -163,6 +172,10 @@ class WebTest < Minitest::Test end def test_outbound_forwards + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls", { @@ -180,10 +193,15 @@ class WebTest < Minitest::Test "+15557654321", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_forwards def test_outbound_low_balance + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_low"] + ) + ExpiringLock::REDIS.expect( :set, EMPromise.resolve(nil), @@ -208,10 +226,15 @@ class WebTest < Minitest::Test last_response.body ) assert_mock ExpiringLock::REDIS + assert_mock CustomerPlan::DB end em :test_outbound_low_balance def test_outbound_low_balance_top_up + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_topup"] + ) + LowBalance::AutoTopUp::CreditCardSale.expect( :create, EMPromise.resolve( @@ -273,10 +296,15 @@ class WebTest < Minitest::Test assert_mock ExpiringLock::REDIS assert_mock Customer::BLATHER assert_mock LowBalance::AutoTopUp::CreditCardSale + assert_mock CustomerPlan::DB end em :test_outbound_low_balance_top_up def test_outbound_unsupported + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls", { @@ -294,10 +322,15 @@ class WebTest < Minitest::Test "supported on your account.", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_unsupported def test_outbound_unsupported_short_numbers_911 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls", { @@ -315,10 +348,15 @@ class WebTest < Minitest::Test "supported on your account.", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_unsupported_short_numbers_911 def test_outbound_supported_9116 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls", { @@ -336,10 +374,15 @@ class WebTest < Minitest::Test "+19116", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_supported_9116 def test_outbound_atlimit + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_limit"] + ) + post( "/outbound/calls", { @@ -360,6 +403,7 @@ class WebTest < Minitest::Test "charges. You can hang up to cancel.", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_atlimit @@ -385,6 +429,10 @@ class WebTest < Minitest::Test em :test_outbound_no_customer def test_outbound_atlimit_digits + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_limit"] + ) + post( "/outbound/calls", { @@ -403,10 +451,15 @@ class WebTest < Minitest::Test "+15557654321", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_atlimit_digits def test_outbound_toll_free + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls", { @@ -424,10 +477,15 @@ class WebTest < Minitest::Test "+18001234567", last_response.body ) + assert_mock CustomerPlan::DB end em :test_outbound_toll_free def test_outbound_disconnect + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/outbound/calls/status", { @@ -444,10 +502,15 @@ class WebTest < Minitest::Test assert last_response.ok? assert_equal("OK", last_response.body) + assert_mock CustomerPlan::DB end em :test_outbound_disconnect def test_outbound_disconnect_tombed + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_tombed"] + ) + @cdr_repo.stub(:put, ->(*) { raise "put called" }) do post( "/outbound/calls/status", @@ -466,10 +529,14 @@ class WebTest < Minitest::Test assert last_response.ok? assert_equal("OK", last_response.body) + assert_mock CustomerPlan::DB end em :test_outbound_disconnect_tombed def test_inbound + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) CustomerFwd::BANDWIDTH_VOICE.expect( :create_call, OpenStruct.new(data: OpenStruct.new(call_id: "ocall")), @@ -500,10 +567,14 @@ class WebTest < Minitest::Test last_response.body ) assert_mock CustomerFwd::BANDWIDTH_VOICE + assert_mock CustomerPlan::DB end em :test_inbound def test_inbound_from_reachability + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) CustomerFwd::BANDWIDTH_VOICE.expect( :create_call, OpenStruct.new(data: OpenStruct.new(call_id: "ocall")), @@ -541,10 +612,14 @@ class WebTest < Minitest::Test ) assert_mock CustomerFwd::BANDWIDTH_VOICE assert_mock ReachableRedis + assert_mock CustomerPlan::DB end em :test_inbound_from_reachability def test_inbound_no_bwmsgsv2 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid2"] + ) CustomerFwd::BANDWIDTH_VOICE.expect( :create_call, OpenStruct.new(data: OpenStruct.new(call_id: "ocall")), @@ -575,10 +650,15 @@ class WebTest < Minitest::Test last_response.body ) assert_mock CustomerFwd::BANDWIDTH_VOICE + assert_mock CustomerPlan::DB end em :test_inbound_no_bwmsgsv2 def test_inbound_low + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_low"] + ) + ExpiringLock::REDIS.expect( :set, EMPromise.resolve(nil), @@ -604,10 +684,15 @@ class WebTest < Minitest::Test ) assert_mock CustomerFwd::BANDWIDTH_VOICE assert_mock ExpiringLock::REDIS + assert_mock CustomerPlan::DB end em :test_inbound_low def test_inbound_leg2 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid"] + ) + post( "/inbound/calls/acall?customer_id=customerid", { @@ -625,10 +710,15 @@ class WebTest < Minitest::Test "", last_response.body ) + assert_mock CustomerPlan::DB end em :test_inbound_leg2 def test_inbound_limit_leg2 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_limit"] + ) + path = "/inbound/calls/acall?customer_id=customerid_limit" post( @@ -652,10 +742,15 @@ class WebTest < Minitest::Test "", last_response.body ) + assert_mock CustomerPlan::DB end em :test_inbound_limit_leg2 def test_inbound_limit_digits_leg2 + CustomerPlan::DB.expect( + :query_one, {}, [String, "customerid_limit"] + ) + post( "/inbound/calls/acall?customer_id=customerid_limit", { @@ -674,6 +769,7 @@ class WebTest < Minitest::Test "", last_response.body ) + assert_mock CustomerPlan::DB end em :test_inbound_limit_digits_leg2