Command to show details (currently just remaining data) for account SIMs

Stephen Paul Weber created

Change summary

config-schema.dhall   |  1 +
config.dhall.sample   |  3 ++-
forms/sim_details.rb  |  4 ++++
lib/sim.rb            | 24 ++++++++++++++++++++++++
lib/sim_repo.rb       | 35 +++++++++++++++++++++++++++++++++++
schemas               |  2 +-
sgx_jmp.rb            | 22 ++++++++++++++++++++++
test/test_helper.rb   |  3 ++-
test/test_sim_repo.rb | 39 +++++++++++++++++++++++++++++++++++++++
9 files changed, 130 insertions(+), 3 deletions(-)

Detailed changes

config-schema.dhall 🔗

@@ -21,6 +21,7 @@
 , interac : Text
 , keep_area_codes : List Text
 , keep_area_codes_in : { account : Text, sip_peer_id : Text, site_id : Text }
+, keepgo : Optional { access_token : Text, api_key : Text }
 , notify_admin : Text
 , notify_from : Text
 , ogm_path : Text

config.dhall.sample 🔗

@@ -82,5 +82,6 @@ in
 	snikket_hosting_api = "",
 	rev_ai_token = "",
 	upstream_domain = "example.net",
-	approved_domains = toMap { `example.com` = Some "customer_id" }
+	approved_domains = toMap { `example.com` = Some "customer_id" },
+	keepgo = Some { api_key = "", access_token = "" }
 }

forms/sim_details.rb 🔗

@@ -0,0 +1,4 @@
+result!
+title "(e)SIM Details"
+
+table(@sims, iccid: "ICCID", remaining_usage_mb: "MB Remaining")

lib/sim.rb 🔗

@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require "value_semantics/monkey_patched"
+
+class SIM
+	value_semantics do
+		iccid(/\A\d+\Z/)
+		lpa_code(/\ALPA:/)
+		remaining_usage_kb Integer
+		remaining_days Integer
+		notes String
+	end
+
+	def self.extract(**kwargs)
+		kwargs = kwargs.transform_keys(&:to_sym)
+		new(kwargs.slice(
+			:iccid, :lpa_code, :remaining_usage_kb, :remaining_days, :notes
+		))
+	end
+
+	def remaining_usage_mb
+		(remaining_usage_kb / 1024.0).round(2)
+	end
+end

lib/sim_repo.rb 🔗

@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require "lazy_object"
+require "value_semantics/monkey_patched"
+
+require_relative "sim"
+
+class SIMRepo
+	value_semantics do
+		db Anything(), default: LazyObject.new { DB }
+	end
+
+	def find(iccid)
+		EM::HttpRequest.new(
+			"https://myaccount.keepgo.com/api/v2/line/#{iccid}/get_details",
+			tls: { verify_peer: true }
+		).aget(
+			head: {
+				"Accept" => "application/json",
+				"apiKey" => CONFIG[:keepgo][:api_key],
+				"accessToken" => CONFIG[:keepgo][:access_token]
+			}
+		).then { |req| SIM.extract(**JSON.parse(req.response)["sim_card"]) }
+	end
+
+	def owned_by(customer)
+		customer = customer.customer_id if customer.respond_to?(:customer_id)
+		promise = db.query_defer(<<~SQL, [customer])
+			SELECT iccid FROM sims WHERE customer_id=$1
+		SQL
+		promise.then { |result|
+			EMPromise.all(result.map { |row| find(row["iccid"]) })
+		}
+	end
+end

schemas 🔗

@@ -1 +1 @@
-Subproject commit 2aef72250750b85e344d3d87d789f002db0a7579
+Subproject commit a449672f5cad37e63e6339e4577ed27ff8289df9

sgx_jmp.rb 🔗

@@ -100,6 +100,7 @@ require_relative "lib/postgres"
 require_relative "lib/registration"
 require_relative "lib/transaction"
 require_relative "lib/tel_selections"
+require_relative "lib/sim_repo"
 require_relative "lib/snikket"
 require_relative "web"
 require_relative "lib/statsd"
@@ -672,6 +673,27 @@ Command.new(
 	end
 }.register(self).then(&CommandList.method(:register))
 
+Command.new(
+	"sims",
+	"(e)SIM Details",
+	list_for: ->(customer:, **) { CONFIG[:keepgo] && !!customer&.currency }
+) {
+	Command.customer.then(&SIMRepo.new.method(:owned_by)).then do |sims|
+		if sims.empty?
+			next Command.finish(
+				"You have no (e)SIMs, you can get on the waitlist at https://jmp.chat/sim"
+			)
+		end
+
+		Command.finish do |reply|
+			reply.command << FormTemplate.render(
+				"sim_details",
+				sims: sims
+			)
+		end
+	end
+}.register(self).then(&CommandList.method(:register))
+
 Command.new(
 	"reset sip account",
 	"Create or Reset SIP Account",

test/test_helper.rb 🔗

@@ -111,7 +111,8 @@ CONFIG = {
 		"refer.example.com": "refer_to"
 	},
 	bandwidth_site: "test_site",
-	bandwidth_peer: "test_peer"
+	bandwidth_peer: "test_peer",
+	keepgo: { api_key: "keepgokey", access_token: "keepgotoken" }
 }.freeze
 
 def panic(e)

test/test_sim_repo.rb 🔗

@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "sim_repo"
+
+class SIMRepoTest < Minitest::Test
+	def setup
+		@repo = SIMRepo.new(
+			db: FakeDB.new(
+				["test"] => [{ "iccid" => "1234" }]
+			)
+		)
+	end
+
+	def test_owned_by
+		req = stub_request(
+			:get,
+			"https://myaccount.keepgo.com/api/v2/line/1234/get_details"
+		).with(
+			headers: {
+				"Accept" => "application/json",
+				"Accesstoken" => "keepgotoken",
+				"Apikey" => "keepgokey"
+			}
+		).to_return(status: 200, body: { sim_card: {
+			iccid: "1234",
+			lpa_code: "LPA:dummy",
+			remaining_usage_kb: 1024,
+			remaining_days: 365,
+			notes: ""
+		} }.to_json)
+
+		sims = @repo.owned_by("test").sync
+		assert_equal 1, sims.length
+		assert_equal "1234", sims[0].iccid
+		assert_requested req
+	end
+	em :test_owned_by
+end