diff --git a/Points.py b/Points.py index f65827e..7292e71 100644 --- a/Points.py +++ b/Points.py @@ -18,6 +18,9 @@ class Points(commands.Cog): self.BANK_ID = 42 self.init() + self.pointsCount = {} + self.reloadPointsCount() + def __check(self, ctx): return True @@ -31,6 +34,8 @@ class Points(commands.Cog): De eerste 10 punten zijn on the house. (Als er genoeg in de bank zit.) """ + self.reloadPointsCount() + if points == 0: yield from ctx.channel.send("0 punten? Gul hoor.") return @@ -58,21 +63,26 @@ class Points(commands.Cog): return # Execute the transaction: - # First, try to give a away (at most 10) bankpoints - areBeingGivenFromBank = min(points, self.getUsersRemainingBankPointsToGiveAwayToday(ctx.author.id)) - areBeingGivenFromBank = min(areBeingGivenFromBank, self.getBankBalance()) - if areBeingGivenFromBank > 0: - self.transferPoints(self.BANK_ID, userObj.id, areBeingGivenFromBank) - self.increaseUsersBankPointGivenAwayToday(ctx.author.id, areBeingGivenFromBank) - remainingPointsToGive = points - areBeingGivenFromBank - else: - remainingPointsToGive = points - # The remaining points come out of your own pocket - if remainingPointsToGive > 0: - self.transferPoints(ctx.author.id, userObj.id, remainingPointsToGive) + self.execute_geefpunten(ctx.author.id, userObj.id, points) + + self.savePointsCount() message = self.getMessageForAwardingPoints(ctx.author.name, userObj.name, points) yield from ctx.channel.send(message) + + def execute_geefpunten(self, giverId, recieverId, points): + # First, try to give away (at most 10) bankpoints + areBeingGivenFromBank = min(points, self.getUsersRemainingBankPointsToGiveAwayToday(giverId)) + areBeingGivenFromBank = min(areBeingGivenFromBank, self.getBankBalance()) + if areBeingGivenFromBank > 0: + self.transferPoints(self.BANK_ID, recieverId, areBeingGivenFromBank) + self.increaseUsersBankPointGivenAwayToday(giverId, areBeingGivenFromBank) + remainingPointsToGive = points - areBeingGivenFromBank + else: + remainingPointsToGive = points + # The remaining points come out of your own pocket + if remainingPointsToGive > 0: + self.transferPoints(giverId, recieverId, remainingPointsToGive) @commands.command(pass_context=True, hidden=False) @@ -85,6 +95,8 @@ class Points(commands.Cog): Let op: je moet iemand taggen om punten weg te nemen. """ + self.reloadPointsCount() + if points < 1: yield from ctx.channel.send("Volgens mij snap je het niet.") return @@ -110,11 +122,16 @@ class Points(commands.Cog): return # Execute the transaction: - self.increaseUsersPointTakenOnDate(ctx.author.id, points) - self.transferPoints(userObj.id, self.BANK_ID, points) + self.execute_neempunten(ctx.author.id, userObj.id, points); + + self.savePointsCount() message = self.getMessageForTakingPoints(userObj.name, ctx.author.name, points) yield from ctx.channel.send(message) + + def execute_neempunten(self, takerId, victimId, points): + self.increaseUsersPointTakenOnDate(takerId, points) + self.transferPoints(victimId, self.BANK_ID, points) @commands.command(pass_context=True, hidden=False) @@ -123,14 +140,14 @@ class Points(commands.Cog): """Hoeveel punten heeft iedereen? """ + self.reloadPointsCount() + message = "**De puntentelling:** \n```" - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - pointsCountSorted = sorted(pointsCount.items(), key=lambda i: i[1]['points'], reverse=True) + pointsCountSorted = sorted(self.pointsCount.items(), key=lambda i: i[1]['points'], reverse=True) for user in pointsCountSorted: if user[0] != self.BANK_ID: message += str(user[1]["points"]).rjust(4) + " " + user[1]["name"] + "\n" - message += str(pointsCount[self.BANK_ID]["points"]).rjust(4) + " " + pointsCount[self.BANK_ID]["name"] + "```" - #message += "```" + message += str(self.pointsCount[self.BANK_ID]["points"]).rjust(4) + " " + self.pointsCount[self.BANK_ID]["name"] + "```" yield from ctx.channel.send(message) @@ -146,40 +163,42 @@ class Points(commands.Cog): except: print("No permission to send DM") + + # Get the points count object from the file + def reloadPointsCount(self): + self.pointsCount = np.load('pointscount.npy', allow_pickle=True).item() + + # Save the points count to the file + def savePointsCount(self): + np.save("pointscount.npy", self.pointsCount) + # Transfer points form one user to another def transferPoints(self, fromUserId, toUserId, points): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - pointsCount[fromUserId]["points"] -= points - pointsCount[toUserId]["points"] += points - np.save("pointscount.npy", pointsCount) + self.pointsCount[fromUserId]["points"] -= points + self.pointsCount[toUserId]["points"] += points # Do we know this user? def isUserOnList(self, user): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - return user.id in pointsCount.keys() + return user.id in self.pointsCount.keys() # Get a user's point balance def getUserBalance(self, user): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - return pointsCount[user.id]["points"] + return self.pointsCount[user.id]["points"] # Get the balance of the bank def getBankBalance(self): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - return pointsCount[self.BANK_ID]["points"] + return self.pointsCount[self.BANK_ID]["points"] # To keep track if a user used some points today, we look at when the last time was he/she used them # If this was in the past: reset # Also, return the updated object. Why not. def refreshDateVarsAndReturnUserVars(self, userId): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() currentDateStr = datetime.now().strftime("%Y%m%d") - if pointsCount[userId]["theDate"] != currentDateStr: - pointsCount[userId]["theDate"] = currentDateStr - pointsCount[userId]["pointTakenOnDate"] = 0 - pointsCount[userId]["bankPointsGivenOnDate"] = 0 - np.save("pointscount.npy", pointsCount) - return pointsCount[userId] + if self.pointsCount[userId]["theDate"] != currentDateStr: + self.pointsCount[userId]["theDate"] = currentDateStr + self.pointsCount[userId]["pointTakenOnDate"] = 0 + self.pointsCount[userId]["bankPointsGivenOnDate"] = 0 + return self.pointsCount[userId] # How many points can this user still take away today? def getUsersRemainingPointsToTakeToday(self, userId): @@ -194,16 +213,12 @@ class Points(commands.Cog): # Increase the number of points this user has taken away today. # Warning: assumes you executed refreshDateVarsAndReturnUserVars() def increaseUsersPointTakenOnDate(self, userId, points): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - pointsCount[userId]["pointTakenOnDate"] += points - np.save("pointscount.npy", pointsCount) + self.pointsCount[userId]["pointTakenOnDate"] += points # Increase the number of bank points this user has given today # Warning: assumes you executed refreshDateVarsAndReturnUserVars() def increaseUsersBankPointGivenAwayToday(self, userId, points): - pointsCount = np.load('pointscount.npy', allow_pickle=True).item() - pointsCount[userId]["bankPointsGivenOnDate"] += points - np.save("pointscount.npy", pointsCount) + self.pointsCount[userId]["bankPointsGivenOnDate"] += points # Generate a semi-random text to tell somebody they got some shiny new points diff --git a/tests/points.py b/tests/points.py index 0d5b7fd..9f79f2a 100644 --- a/tests/points.py +++ b/tests/points.py @@ -8,6 +8,11 @@ from discord.ext import commands import Points +class User: + def __init__(self, id, name): + self.id = id + self.name = name + class TestPoints(unittest.TestCase): def setUp(self): dotenv.load_dotenv() @@ -16,6 +21,137 @@ class TestPoints(unittest.TestCase): intents.members = True bot = commands.Bot(command_prefix=commands.when_mentioned_or('!'), description='Stroopwafel. Shitpost bot extraordinaire.', pm_help=True, intents=intents) self.cog = Points.Points(bot) + + self.user1 = User(10001, "Alice") + self.user2 = User(10002, "Bob") def test_getUserBalance(self): - self.assertEqual(2, 1+1) \ No newline at end of file + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 69} + self.assertEqual(69, self.cog.getUserBalance(self.user1)) + + def test_getBankBalance(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 1} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 999} + self.assertEqual(999, self.cog.getBankBalance()) + + def test_isUserOnList(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 1} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 999} + self.assertTrue(self.cog.isUserOnList(self.user1)) + self.assertFalse(self.cog.isUserOnList(self.user2)) + + def test_transferPoints(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 50} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 30} + self.cog.transferPoints(self.user1.id, self.user2.id, 4) + self.assertEqual(46, self.cog.getUserBalance(self.user1)) + self.assertEqual(34, self.cog.getUserBalance(self.user2)) + + def test_given_bankHasBalanceAndUserHasNotGivenPointsYetToday_when_givingPoints_then_tenPointComeFromBank(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 1000} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 200, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 12) + self.assertEqual(990, self.cog.getBankBalance()) + self.assertEqual(198, self.cog.getUserBalance(self.user1)) + self.assertEqual(112, self.cog.getUserBalance(self.user2)) + + def test_given_bankHasBalanceButUserHasNoBalanceAndUserHasNotGivenPointsYetToday_when_givingPoints_then_pointComeFromBank(self): + currentDateStr = datetime.now().strftime("%Y%m%d") + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 1000} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 0, "pointTakenOnDate":10, "bankPointsGivenOnDate":0, "theDate":currentDateStr} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":10, "bankPointsGivenOnDate":10, "theDate":currentDateStr} + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 5) + self.assertEqual(995, self.cog.getBankBalance()) + self.assertEqual(0, self.cog.getUserBalance(self.user1)) + self.assertEqual(105, self.cog.getUserBalance(self.user2)) + + def test_given_bankIsEmpty_when_givingPoints_then_AllPointsComeFromUser(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 0} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 200, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 15) + self.assertEqual(0, self.cog.getBankBalance()) + self.assertEqual(185, self.cog.getUserBalance(self.user1)) + self.assertEqual(115, self.cog.getUserBalance(self.user2)) + + def test_given_userHasAlreadyGivenSomeBankPointsToday_when_givingPoints_then_NotAllPointsComeFromBank(self): + currentDateStr = datetime.now().strftime("%Y%m%d") + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 1000} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 200, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":currentDateStr} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + # First a normal transaction: + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 5) + self.assertEqual(995, self.cog.getBankBalance()) + self.assertEqual(200, self.cog.getUserBalance(self.user1)) + self.assertEqual(105, self.cog.getUserBalance(self.user2)) + # Then another one: + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 8) + self.assertEqual(990, self.cog.getBankBalance()) # Only the first 5 come from the bank + self.assertEqual(197, self.cog.getUserBalance(self.user1)) + self.assertEqual(113, self.cog.getUserBalance(self.user2)) + # One more: + self.cog.execute_geefpunten(self.user1.id, self.user2.id, 3) + self.assertEqual(990, self.cog.getBankBalance()) # All points come out of the user's pocket now + self.assertEqual(194, self.cog.getUserBalance(self.user1)) + self.assertEqual(116, self.cog.getUserBalance(self.user2)) + + def test_given_usersWithPoints_when_takingPoints_then_pointsGoToTheBank(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 1000} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 200, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.refreshDateVarsAndReturnUserVars(self.user1.id) #usually happens in !neempunten, so this unittest is a bit poor + self.cog.execute_neempunten(self.user1.id, self.user2.id, 2) + self.assertEqual(1002, self.cog.getBankBalance()) + self.assertEqual(200, self.cog.getUserBalance(self.user1)) + self.assertEqual(98, self.cog.getUserBalance(self.user2)) + # The user should only have 8 points left to give away today: + self.assertEqual(8, self.cog.getUsersRemainingPointsToTakeToday(self.user1.id)) + + def test_given_user_when_takingPoints_then_pointsToTakeAreLimited(self): + self.cog.pointsCount = {} + self.cog.pointsCount[self.cog.BANK_ID] = {"name": "DE BANK", "points": 1000} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 200, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.pointsCount[self.user2.id] = {"name": self.user2.name, "points": 100, "pointTakenOnDate":0, "bankPointsGivenOnDate":0, "theDate":"20220101"} + self.cog.refreshDateVarsAndReturnUserVars(self.user1.id) #usually happens in !neempunten, so this unittest is a bit poor + self.cog.execute_neempunten(self.user1.id, self.user2.id, 6) + self.assertEqual(94, self.cog.getUserBalance(self.user2)) + # The user should only have 4 points left to give away today: + self.assertEqual(4, self.cog.getUsersRemainingPointsToTakeToday(self.user1.id)) + self.cog.execute_neempunten(self.user1.id, self.user2.id, 3) + self.assertEqual(91, self.cog.getUserBalance(self.user2)) + # The user should only have 1 point left to give away today: + self.assertEqual(1, self.cog.getUsersRemainingPointsToTakeToday(self.user1.id)) + self.cog.execute_neempunten(self.user1.id, self.user2.id, 1) + self.assertEqual(90, self.cog.getUserBalance(self.user2)) + # The user should have 0 points left to take away: + self.assertEqual(0, self.cog.getUsersRemainingPointsToTakeToday(self.user1.id)) + # The actual check whether or not a user can keep on taking points away happens in !neempunten and is not tested here + + def test_refreshDateVarsAndReturnUserVars(self): + with self.subTest("Should not be updated yet. Update was just today."): + currentDateStr = datetime.now().strftime("%Y%m%d") + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 100, "pointTakenOnDate":2, "bankPointsGivenOnDate":1, "theDate":currentDateStr} + self.cog.refreshDateVarsAndReturnUserVars(self.user1.id) + # Still today. Values should stay the same: + self.assertEqual(2, self.cog.pointsCount[self.user1.id]["pointTakenOnDate"]) + self.assertEqual(1, self.cog.pointsCount[self.user1.id]["bankPointsGivenOnDate"]) + with self.subTest("Should be reset. Update was in the past."): + currentDateStr = datetime.now().strftime("%Y%m%d") + self.cog.pointsCount = {} + self.cog.pointsCount[self.user1.id] = {"name": self.user1.name, "points": 100, "pointTakenOnDate":2, "bankPointsGivenOnDate":1, "theDate":"20150101"} + self.cog.refreshDateVarsAndReturnUserVars(self.user1.id) + # A new day. Values should be set to 0 again: + self.assertEqual(0, self.cog.pointsCount[self.user1.id]["pointTakenOnDate"]) + self.assertEqual(0, self.cog.pointsCount[self.user1.id]["bankPointsGivenOnDate"]) + self.assertNotEqual("20150101", self.cog.pointsCount[self.user1.id]["theDate"])