diff options
Diffstat (limited to 'bot/exts/halloween')
| -rw-r--r-- | bot/exts/halloween/candy_collection.py | 60 | ||||
| -rw-r--r-- | bot/exts/halloween/hacktoberstats.py | 79 |
2 files changed, 38 insertions, 101 deletions
diff --git a/bot/exts/halloween/candy_collection.py b/bot/exts/halloween/candy_collection.py index bd0b90cc..33e18b24 100644 --- a/bot/exts/halloween/candy_collection.py +++ b/bot/exts/halloween/candy_collection.py @@ -1,18 +1,14 @@ -import json import logging import random -# from pathlib import Path from typing import Union import discord +from async_rediscache import RedisCache from discord.ext import commands from bot.constants import Channels, Month from bot.utils.decorators import in_month -# TODO: Implement substitutes for volume-persistent methods. # noqa: T000 -# from bot.utils.persist import make_persistent - log = logging.getLogger(__name__) # chance is 1 in x range, so 1 in 20 range would give 5% chance (for add candy) @@ -37,18 +33,15 @@ EMOJIS = dict( class CandyCollection(commands.Cog): """Candy collection game Cog.""" - def __init__(self, bot: commands.Bot): - self.bot = bot - # self.json_file = make_persistent(Path("bot", "resources", "halloween", "candy_collection.json")) + # User candy amount records + candy_records = RedisCache() - with self.json_file.open() as fp: - candy_data = json.load(fp) + # Candy and skull messages mapping + candy_messages = RedisCache() + skull_messages = RedisCache() - self.candy_records = candy_data.get("records", dict()) - - # Message ID where bot added the candies/skulls - self.candy_messages = set() - self.skull_messages = set() + def __init__(self, bot: commands.Bot): + self.bot = bot @in_month(Month.OCTOBER) @commands.Cog.listener() @@ -63,11 +56,11 @@ class CandyCollection(commands.Cog): # do random check for skull first as it has the lower chance if random.randint(1, ADD_SKULL_REACTION_CHANCE) == 1: - self.skull_messages.add(message.id) + await self.skull_messages.set(message.id, "skull") return await message.add_reaction(EMOJIS['SKULL']) # check for the candy chance next if random.randint(1, ADD_CANDY_REACTION_CHANCE) == 1: - self.candy_messages.add(message.id) + await self.candy_messages.set(message.id, "candy") return await message.add_reaction(EMOJIS['CANDY']) @in_month(Month.OCTOBER) @@ -94,17 +87,19 @@ class CandyCollection(commands.Cog): await self.reacted_msg_chance(message) return - if message.id in self.candy_messages and str(reaction.emoji) == EMOJIS['CANDY']: - self.candy_messages.remove(message.id) - prev_record = self.candy_records.get(str(user.id), 0) - self.candy_records[str(user.id)] = prev_record + 1 + if await self.candy_messages.get(message.id) == "candy" and str(reaction.emoji) == EMOJIS['CANDY']: + await self.candy_messages.delete(message.id) + if await self.candy_records.contains(user.id): + await self.candy_records.increment(user.id) + else: + await self.candy_records.set(user.id, 1) - elif message.id in self.skull_messages and str(reaction.emoji) == EMOJIS['SKULL']: - self.skull_messages.remove(message.id) + elif await self.skull_messages.get(message.id) == "skull" and str(reaction.emoji) == EMOJIS['SKULL']: + await self.skull_messages.delete(message.id) - if prev_record := self.candy_records.get(str(user.id)): + if prev_record := await self.candy_records.get(user.id): lost = min(random.randint(1, 3), prev_record) - self.candy_records[str(user.id)] = prev_record - lost + await self.candy_records.decrement(user.id, lost) if lost == prev_record: await CandyCollection.send_spook_msg(user, message.channel, 'all of your') @@ -116,7 +111,6 @@ class CandyCollection(commands.Cog): return # Skip saving await reaction.clear() - await self.bot.loop.run_in_executor(None, self.save_to_json) async def reacted_msg_chance(self, message: discord.Message) -> None: """ @@ -126,11 +120,11 @@ class CandyCollection(commands.Cog): existing reaction. """ if random.randint(1, ADD_SKULL_EXISTING_REACTION_CHANCE) == 1: - self.skull_messages.add(message.id) + await self.skull_messages.set(message.id, "skull") return await message.add_reaction(EMOJIS['SKULL']) if random.randint(1, ADD_CANDY_EXISTING_REACTION_CHANCE) == 1: - self.candy_messages.add(message.id) + await self.candy_messages.set(message.id, "candy") return await message.add_reaction(EMOJIS['CANDY']) @property @@ -159,18 +153,15 @@ class CandyCollection(commands.Cog): "I tried to take your candies but you had none to begin with!") await channel.send(embed=embed) - def save_to_json(self) -> None: - """Save JSON to a local file.""" - with self.json_file.open('w') as fp: - json.dump(dict(records=self.candy_records), fp) - @in_month(Month.OCTOBER) @commands.command() async def candy(self, ctx: commands.Context) -> None: """Get the candy leaderboard and save to JSON.""" + records = await self.candy_records.items() + def generate_leaderboard() -> str: top_sorted = sorted( - ((user_id, score) for user_id, score in self.candy_records.items() if score > 0), + ((user_id, score) for user_id, score in records if score > 0), key=lambda x: x[1], reverse=True ) @@ -199,3 +190,4 @@ class CandyCollection(commands.Cog): def setup(bot: commands.Bot) -> None: """Candy Collection game Cog load.""" + bot.add_cog(CandyCollection(bot)) diff --git a/bot/exts/halloween/hacktoberstats.py b/bot/exts/halloween/hacktoberstats.py index 4fd5c324..26d75565 100644 --- a/bot/exts/halloween/hacktoberstats.py +++ b/bot/exts/halloween/hacktoberstats.py @@ -1,21 +1,17 @@ -import json import logging import re from collections import Counter from datetime import datetime, timedelta -# from pathlib import Path from typing import List, Tuple, Union import aiohttp import discord +from async_rediscache import RedisCache from discord.ext import commands from bot.constants import Channels, Month, Tokens, WHITELISTED_CHANNELS from bot.utils.decorators import in_month, override_in_channel -# TODO: Implement substitutes for volume-persistent methods. # noqa: T000 -# from bot.utils.persist import make_persistent - log = logging.getLogger(__name__) CURRENT_YEAR = datetime.now().year # Used to construct GH API query @@ -39,10 +35,11 @@ GITHUB_NONEXISTENT_USER_MESSAGE = ( class HacktoberStats(commands.Cog): """Hacktoberfest statistics Cog.""" + # Stores mapping of user IDs and GitHub usernames + linked_accounts = RedisCache() + def __init__(self, bot: commands.Bot): self.bot = bot - # self.link_json = make_persistent(Path("bot", "resources", "halloween", "github_links.json")) - self.linked_accounts = self.load_linked_users() @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER) @commands.group(name="hacktoberstats", aliases=("hackstats",), invoke_without_command=True) @@ -58,8 +55,8 @@ class HacktoberStats(commands.Cog): if not github_username: author_id, author_mention = self._author_mention_from_context(ctx) - if str(author_id) in self.linked_accounts.keys(): - github_username = self.linked_accounts[author_id]["github_username"] + if await self.linked_accounts.contains(author_id): + github_username = await self.linked_accounts.get(author_id) logging.info(f"Getting stats for {author_id} linked GitHub account '{github_username}'") else: msg = ( @@ -79,30 +76,19 @@ class HacktoberStats(commands.Cog): """ Link the invoking user's Github github_username to their Discord ID. - Linked users are stored as a nested dict: - { - Discord_ID: { - "github_username": str - "date_added": datetime - } - } + Linked users are stored in Redis: User ID => GitHub Username. """ author_id, author_mention = self._author_mention_from_context(ctx) if github_username: - if str(author_id) in self.linked_accounts.keys(): - old_username = self.linked_accounts[author_id]["github_username"] + if await self.linked_accounts.contains(author_id): + old_username = await self.linked_accounts.get(author_id) logging.info(f"{author_id} has changed their github link from '{old_username}' to '{github_username}'") await ctx.send(f"{author_mention}, your GitHub username has been updated to: '{github_username}'") else: logging.info(f"{author_id} has added a github link to '{github_username}'") await ctx.send(f"{author_mention}, your GitHub username has been added") - self.linked_accounts[author_id] = { - "github_username": github_username, - "date_added": datetime.now() - } - - self.save_linked_users() + await self.linked_accounts.set(author_id, github_username) else: logging.info(f"{author_id} tried to link a GitHub account but didn't provide a username") await ctx.send(f"{author_mention}, a GitHub username is required to link your account") @@ -114,7 +100,7 @@ class HacktoberStats(commands.Cog): """Remove the invoking user's account link from the log.""" author_id, author_mention = self._author_mention_from_context(ctx) - stored_user = self.linked_accounts.pop(author_id, None) + stored_user = await self.linked_accounts.pop(author_id, None) if stored_user: await ctx.send(f"{author_mention}, your GitHub profile has been unlinked") logging.info(f"{author_id} has unlinked their GitHub account") @@ -122,48 +108,6 @@ class HacktoberStats(commands.Cog): await ctx.send(f"{author_mention}, you do not currently have a linked GitHub account") logging.info(f"{author_id} tried to unlink their GitHub account but no account was linked") - self.save_linked_users() - - def load_linked_users(self) -> dict: - """ - Load list of linked users from local JSON file. - - Linked users are stored as a nested dict: - { - Discord_ID: { - "github_username": str - "date_added": datetime - } - } - """ - if self.link_json.exists(): - logging.info(f"Loading linked GitHub accounts from '{self.link_json}'") - with open(self.link_json, 'r', encoding="utf8") as file: - linked_accounts = json.load(file) - - logging.info(f"Loaded {len(linked_accounts)} linked GitHub accounts from '{self.link_json}'") - return linked_accounts - else: - logging.info(f"Linked account log: '{self.link_json}' does not exist") - return {} - - def save_linked_users(self) -> None: - """ - Save list of linked users to local JSON file. - - Linked users are stored as a nested dict: - { - Discord_ID: { - "github_username": str - "date_added": datetime - } - } - """ - logging.info(f"Saving linked_accounts to '{self.link_json}'") - with open(self.link_json, 'w', encoding="utf8") as file: - json.dump(self.linked_accounts, file, default=str) - logging.info(f"linked_accounts saved to '{self.link_json}'") - async def get_stats(self, ctx: commands.Context, github_username: str) -> None: """ Query GitHub's API for PRs created by a GitHub user during the month of October. @@ -491,3 +435,4 @@ class HacktoberStats(commands.Cog): def setup(bot: commands.Bot) -> None: """Hacktoberstats Cog load.""" + bot.add_cog(HacktoberStats(bot)) |