async def _report(self, channel, count): announcement_channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) # everyone who filled in feedback for the last 3 tests feedback_providers = set( c.user for test in await NewGameTest.filter().order_by( "-end").limit(count).prefetch_related("completions") for c in test.completions) # all testers testers = set(m.id for m in announcement_channel.guild.get_role( Configuration.get_var("tester_role")).members) # report those who didn't contribute slackers = testers - feedback_providers buffer = StringIO() writer = csv.writer(buffer, delimiter=";", quotechar='"', quoting=csv.QUOTE_MINIMAL) writer.writerow(["User id", "Username"]) # write codes to the writer for s in slackers: writer.writerow([f"\t{s}", str(self.bot.get_user(s))]) buffer.seek(0) file = discord.File(buffer, f"did not participate in last {count} tests.csv") await channel.send(file=file)
async def wrapped(self, *args, **kwargs): channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) role = channel.guild.get_role(Configuration.get_var("tester_role")) await role.edit(mentionable=True) # wrap everything so we always make the role unmentionable in all cases try: await func(self, *args, **kwargs) finally: await role.edit(mentionable=False)
async def on_ready(self): if not self.loaded: Logging.BOT_LOG_CHANNEL = self.get_channel(Configuration.get_var("log_channel")) Emoji.initialize(self) Logging.info("Connected to discord!") Logging.info("Establishing database connections") await Tortoise.init( db_url="sqlite://db.sqlite3", modules={"models": ["Utils.Models"]} ) await Tortoise.generate_schemas() Logging.info("Database connected") if await NewGameTest.filter().first() is None: to_insert = list() for test in await GameTest.all().prefetch_related("game"): to_insert.append(NewGameTest(game=test.game, message=test.message, end=test.end, status=test.status, feedback=test.feedback)) await NewGameTest.bulk_create(to_insert) Logging.info("Loading cogs") for cog in ["GameTesting"]: try: self.load_extension("Cogs." + cog) except Exception as e: await Utils.handle_exception(f"Failed to load cog {cog}", self, e) Logging.info("Cogs loaded") await Logging.bot_log("GameDjinnie ready to go!") self.loaded = True
async def reminder(self, test): channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) await channel.send( f"<@&{Configuration.get_var('tester_role')}> Only 24 hours remaining before this test ends. Please make sure to get your feedback before then if you have not already! https://canary.discordapp.com/channels/{channel.guild.id}/{channel.id}/{test.message}" ) test.status = TestStatus.ENDING await test.save()
async def ender(self, test): # edit message to say this test is completed channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) message = await channel.fetch_message(test.message) await message.edit( content=f"~~{message.content}~~\n**This test has ended**") # mark as completed in the database test.status = TestStatus.ENDED await test.save() if test.feedback is not None: # find all users who filled in the feedback sheet = SheetUtils.get_sheet(test.feedback) user_ids = sheet.col_values(2)[1:] await Completion.bulk_create( [Completion(test=test, user=u) for u in user_ids]) await self._test_report( self.bot.get_user(Configuration.get_var("admin_id")), test)
async def update(self, ctx, test: TestConverter, *, new_content): channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) message = await channel.fetch_message(test.message) # edit message to new content + role ping await message.edit( content=f"{new_content}\n<@&{Configuration.get_var('tester_role')}>" ) await ctx.send("Message updated!")
async def test(self, ctx, game: GameConverter, until: dateConverter, sheet_url: Optional[Sheetconverter] = None, *, announcement): channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) role = channel.guild.get_role(Configuration.get_var("tester_role")) reaction = Configuration.get_var("reaction_emoji") message = await channel.send(f"{announcement}\n{role.mention}") await message.add_reaction(reaction) gt = await NewGameTest.create(game=game, message=message.id, end=until, feedback=sheet_url) await ctx.send( f"Test running until {humanize.naturaldate(gt.end)} has started!")
async def running(self, ctx): channel = self.bot.get_channel( Configuration.get_var("announcement_channel")) active_tests = await NewGameTest.filter( status__not=TestStatus.ENDED ).order_by("-end").limit(20).prefetch_related("game") embed = Embed(description="\n".join( f"[{test.id} - {test.game.name}: ending in {humanize.naturaltime(datetime.now() - test.end)}](https://canary.discordapp.com/channels/{channel.guild.id}/{channel.id}/{test.message})" for test in active_tests)) await ctx.send(embed=embed)
def initialize(bot): for name, eid in Configuration.get_var("emoji").items(): EMOJI[name] = utils.get(bot.emojis, id=eid)
param = list(ctx.command.params.values())[min(len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await ctx.send( f"{Emoji.get_chat_emoji('NO')} You are missing a required command argument: `{param._name}`\n{Emoji.get_chat_emoji('WRENCH')} Command usage: `{bot.help_command.get_command_signature(ctx.command)}`") elif isinstance(error, commands.BadArgument): param = list(ctx.command.params.values())[min(len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await ctx.send( f"{Emoji.get_chat_emoji('NO')} Failed to parse the ``{param._name}`` param: ``{error}``\n{Emoji.get_chat_emoji('WRENCH')} Command usage: `{bot.help_command.get_command_signature(ctx.command)}`") elif isinstance(error, commands.CommandNotFound): return else: await Utils.handle_exception("Command execution failed", bot, error.original if hasattr(error, "original") else error, ctx=ctx) # notify caller e = Emoji.get_chat_emoji('BUG') if ctx.channel.permissions_for(ctx.me).send_messages: await ctx.send(f"{e} Something went wrong while executing that command {e}") if __name__ == '__main__': Logging.init() Configuration.load() Logging.info("Did someone summon the GameDjinnie?") bot = GameJinnie(command_prefix=Configuration.get_var("prefix"), case_insensitive=True) bot.run(Configuration.get_var("token")) Logging.info("GameDjinnie shutdown")
async def cog_check(self, ctx): return ctx.author.id == Configuration.get_var("admin_id")
async def give_code(self, payload): user = self.bot.get_user(payload.user_id) async def message_user(message): try: await user.send(message) except Forbidden: # user has DMs closed, remove their reaction to indicate this message = await self.bot.get_channel( payload.channel_id).fetch_message(payload.message_id) await message.remove_reaction(payload.emoji, Object(payload.user_id)) try: test = await NewGameTest.get(message=payload.message_id) except DoesNotExist: return # not an announcement, nothing to do else: if test.status == TestStatus.ENDED: try: await user.send("This test has already ended") except Forbidden: pass message = await self.bot.get_channel( payload.channel_id).fetch_message(payload.message_id) await message.remove_reaction(payload.emoji, Object(payload.user_id)) return try: await test.fetch_related("game") exising_code = await GameCode.get(game=test.game, claimed_by=payload.user_id) except DoesNotExist: # doesn't have a code, fetch one for claiming code = await GameCode.filter(game=test.game, claimed_by=None).first() if code is None: # no more codes are available! await message_user( f"Sadly there are no more codes available for {test.game} at this time. Please try again later" ) else: # try to claim that code but make sure we don't override races updated = await GameCode.filter( code=code.code, claimed_by=None).update(claimed_by=payload.user_id) # make sure we updated that row if updated == 1: try: await user.send( f"Your code for {test.game} is {code}!") except Forbidden: # failed to send, free up the code again await GameCode.filter(code=code.code ).update(clamied_by=None) # code claimed, make sure we have more codes left available = await GameCode.filter( game=test.game, claimed_by=None, claimed_in=None).count() if available is 0: # this was the last one, inform admin admin = self.bot.get_user( Configuration.get_var('admin_id')) try: await admin.send( f"Someone just claimed the last available code for {test.game}!" ) except Forbidden: # admin has DMs closed, fall back to botlog await Logging.bot_log( f"{admin.mention} Someone just claimed the last available code for {test.game}!" ) else: # we didn't claim, probably someone else won the race, try again await self.give_code(payload) else: # user already has a code, send it to them again user = self.bot.get_user(payload.user_id) await message_user( f"You already claimed a code for {test.game} before: {exising_code}. If this code didn't work please contact <@{Configuration.get_var('admin_id')}>" )