Move too-many-tries guard into the repo

Stephen Paul Weber created

Change summary

lib/invites_repo.rb       | 23 ++++++++++++++++++++---
lib/registration.rb       | 19 +++----------------
test/test_registration.rb | 27 +++++++++++++--------------
3 files changed, 36 insertions(+), 33 deletions(-)

Detailed changes

lib/invites_repo.rb 🔗

@@ -3,8 +3,9 @@
 class InvitesRepo
 	class Invalid < StandardError; end
 
-	def initialize(db=DB)
+	def initialize(db=DB, redis=REDIS)
 		@db = db
+		@redis = redis
 	end
 
 	def unused_invites(customer_id)
@@ -15,13 +16,13 @@ class InvitesRepo
 	end
 
 	def claim_code(customer_id, code, &blk)
-		EMPromise.resolve(nil).then do
+		guard_too_many_tries(customer_id).then do
 			@db.transaction do
 				valid = @db.exec(<<~SQL, [customer_id, code]).cmd_tuples.positive?
 					UPDATE invites SET used_by_id=$1, used_at=LOCALTIMESTAMP
 					WHERE code=$2 AND used_by_id IS NULL
 				SQL
-				raise Invalid, "Not a valid invite code: #{code}" unless valid
+				invalid_code(customer_id, code).sync unless valid
 
 				blk.call
 			end
@@ -76,4 +77,20 @@ class InvitesRepo
 			SQL
 		}
 	end
+
+protected
+
+	def guard_too_many_tries(customer_id)
+		@redis.get("jmp_invite_tries-#{customer_id}").then do |t|
+			raise Invalid, "Too many wrong attempts" if t.to_i > 10
+		end
+	end
+
+	def invalid_code(customer_id, code)
+		@redis.incr("jmp_invite_tries-#{customer_id}").then {
+			@redis.expire("jmp_invite_tries-#{customer_id}", 60 * 60)
+		}.then do
+			raise Invalid, "Not a valid invite code: #{code}"
+		end
+	end
 end

lib/registration.rb 🔗

@@ -434,28 +434,15 @@ class Registration
 			def parse(iq)
 				return Activation.for(@customer, nil, @tel).then(&:write) if iq.prev?
 
-				guard_too_many_tries.then {
-					verify(iq.form.field("code")&.value&.to_s)
-				}.then {
+				verify(iq.form.field("code")&.value&.to_s).then {
 					Finish.new(@customer, @tel)
 				}.catch_only(InvitesRepo::Invalid, &method(:invalid_code)).then(&:write)
 			end
 
 		protected
 
-			def guard_too_many_tries
-				REDIS.get("jmp_invite_tries-#{customer_id}").then do |t|
-					raise InvitesRepo::Invalid, "Too many wrong attempts" if t.to_i > 10
-				end
-			end
-
 			def invalid_code(e)
-				EMPromise.all([
-					REDIS.incr("jmp_invite_tries-#{customer_id}").then do
-						REDIS.expire("jmp_invite_tries-#{customer_id}", 60 * 60)
-					end,
-					InviteCode.new(@customer, @tel, error: e.message)
-				]).then(&:last)
+				InviteCode.new(@customer, @tel, error: e.message)
 			end
 
 			def customer_id
@@ -463,7 +450,7 @@ class Registration
 			end
 
 			def verify(code)
-				InvitesRepo.new(DB).claim_code(customer_id, code) do
+				InvitesRepo.new(DB, REDIS).claim_code(customer_id, code) do
 					@customer.activate_plan_starting_now
 				end
 			end

test/test_registration.rb 🔗

@@ -628,9 +628,15 @@ class RegistrationTest < Minitest::Test
 						EMPromise.resolve(0),
 						["jmp_invite_tries-test"]
 					)
-					Registration::Payment::InviteCode::DB.expect(:transaction, []) do
-						raise InvitesRepo::Invalid, "wut"
-					end
+					Registration::Payment::InviteCode::DB.expect(
+						:transaction,
+						[]
+					) { |&blk| blk.call }
+					Registration::Payment::InviteCode::DB.expect(
+						:exec,
+						OpenStruct.new(cmd_tuples: 0),
+						[String, ["test", "abc"]]
+					)
 					Registration::Payment::InviteCode::REDIS.expect(
 						:incr,
 						EMPromise.resolve(nil),
@@ -658,7 +664,10 @@ class RegistrationTest < Minitest::Test
 						EMPromise.reject(:test_result),
 						[Matching.new do |reply|
 							assert_equal :form, reply.form.type
-							assert_equal "wut", reply.form.instructions
+							assert_equal(
+								"Not a valid invite code: abc",
+								reply.form.instructions
+							)
 						end]
 					)
 
@@ -694,16 +703,6 @@ class RegistrationTest < Minitest::Test
 							assert_nil reply.form.instructions
 						end]
 					)
-					Registration::Payment::InviteCode::REDIS.expect(
-						:incr,
-						EMPromise.resolve(nil),
-						["jmp_invite_tries-test"]
-					)
-					Registration::Payment::InviteCode::REDIS.expect(
-						:expire,
-						EMPromise.resolve(nil),
-						["jmp_invite_tries-test", 60 * 60]
-					)
 					Command::COMMAND_MANAGER.expect(
 						:write,
 						EMPromise.reject(:test_result),