async def remind_action(self): offset = tz.human_timedelta(tz.day_start(tz.get().day + 1), source=tz.get()) mentions = await self.bot.db.fetch("SELECT * FROM reminders") channels = {} # group the channels to bulk send messages for m in mentions: if m['channel_id'] not in channels: channels[m['channel_id']] = [] channels[m['channel_id']].append(m['user_id']) for channel, users in channels.items(): c = self.bot.get_channel(channel) if c is None: continue index = 0 while index < len(users): targets = users[index:index + 4] index += 4 msg = f"Hey, it's {offset} until Advent Of Code day {tz.get().day+1}!\n{''.join([f'<@!{x}>' for x in targets])}" try: await c.send( msg, allowed_mentions=discord.AllowedMentions(users=True)) except: raise break
async def remind_sleeper(self): while True: start = tz.day_start(tz.get().day + 1) if start.day > 25 or start.month != 12 or ( start - tz.get()).total_seconds() < 300: await asyncio.sleep(600) continue await asyncio.sleep((start - tz.get()).total_seconds() - 300) await asyncio.shield(self.remind_action(), loop=self.bot.loop)
async def about(ctx): if not bot.owner_id and not bot.owner_ids: await bot.is_owner(ctx.author) # get the owner owner = bot.owner_ids or [bot.owner_id] fmt = f"Made by IAmTomahawkx#1000 (547861735391100931).\nThis bot is being run by {', '.join(f'<@!{x}>' for x in owner)}\n Just your average discord bot. " now = tz.get() if now.month == 12 and now.day < 26: fmt += f"\nIt is currently day {now.day} of Advent of code" await ctx.send(fmt)
async def guild_cookie(self, ctx): """ sets the given cookie as the guilds cookie. DO NOT SEND YOUR COOKIE IN CHAT, the bot will ask you for it in dms! You can delete your cookie at any time by using the rmcookie command """ today = tz.get() await ctx.send( f"{ctx.author.mention}, please DM me your cookie. This can be found by going to " f"https://adventofcode.com/{today.year}/leaderboard/private while logged in, opening the " "inspector, and grabbing the `cookie` header from the page request. This will overwrite an existing cookie from this server", allowed_mentions=discord.AllowedMentions(users=True)) try: msg = await self.bot.wait_for("message", timeout=60, check=lambda m: m.guild is None and m .author.id == ctx.author.id) except: return await ctx.send("Took too long, aborting") cookie = msg.content.strip() if not cookie.startswith("session="): cookie = f"session={cookie}" async with self.bot.session.get( f"https://adventofcode.com/{today.year}/leaderboard/private", headers={"cookie": cookie}, allow_redirects=False) as resp: if resp.status != 200: return await ctx.send("Invalid cookie") await self.bot.db.execute( "INSERT INTO cookies VALUES ($1, $2) ON CONFLICT (guild_id) DO UPDATE SET cookie = $2", ctx.guild.id, cookie) await ctx.author.send( f"Your cookie will now be used for {ctx.guild.name}")
async def lang(self, ctx, day: Optional[int], language: str, file_link: str = None): """ tells the bot that youve completed todays challenge in the given language """ if language not in self.langs: closest = difflib.get_close_matches(language, self.langs, 3) return await ctx.send( f"That language was not recognized (the closest found were {', '.join(closest)}). Tell the bot owner to add it to the languages.txt file" ) today = tz.get() day = day or today.day if today.month != 12: return await ctx.send("It's not AOC time yet") if day > 25: return await ctx.send("Hmm, that doesnt seem like a valid day") if day > today.day: return await ctx.send("Nice try") try: await self.bot.db.execute( "INSERT INTO langs VALUES ($1, $2, $3, $4)", ctx.author.id, day, language, file_link) except asyncpg.UniqueViolationError: return await ctx.send( "You have already done that language today...") except asyncpg.ForeignKeyViolationError: return await ctx.send("You have not confirmed your AOC id...") else: await ctx.send(f"Marked {language} as completed for day {day}")
async def info(self, ctx, *, user: Union[discord.User, str] = None): """ gives you advent of code info on the given person. if no target is given, will give you your own info """ if isinstance(user, str): user = user.strip() if not user: user = ctx.author user = user or ctx.author if isinstance(user, discord.user.BaseUser): query = """ SELECT * FROM users INNER JOIN guilds g on g.guild_id = $2 INNER JOIN cookies c on c.guild_id = g.guild_id WHERE discord_id = $1 """ # do this in two queries due to variable row amounts data = await self.bot.db.fetchrow(query, user.id, ctx.guild.id) if not data: return await ctx.send( f"Hmm, either {'you havent identified yourself' if user == ctx.author else f'{user.name} hasnt identified themselves'} " f"(use the {ctx.prefix}iam command), the server owner has not set up a leaderboard (use the {ctx.prefix}leaderboard set command), " f"or something screwed up internally. Probably the latter") board = await self.bot.get_board(data['board_id'], data['cookie']) langs = await self.bot.db.fetch( "SELECT * FROM langs WHERE id = $1", user.id) member: _board.Member = discord.utils.get(board.members, id=data['aoc_id']) else: board_id = await self.bot.db.fetchrow( "SELECT board_id, cookie FROM guilds inner join cookies c on c.guild_id = guilds.guild_id where guilds.guild_id = $1", ctx.guild.id) if not board_id: return await ctx.send( "Please ask someone with the manage server permission to set a board id" ) board = await self.bot.get_board(board_id['board_id'], board_id['cookie']) member = discord.utils.get(board.members, name=user) if not member: return await ctx.send( "That user doesnt appear to be in your server's leaderboard. Passing leaderboard names is case-sensitive" ) langs = [] rows = [] for day in range(1, tz.get().day + 1): day_langs = [x['lang'] for x in langs if x['day'] == day] stars = member.completion_stats.get(day) if not stars: star_1 = "Incomplete" star_2 = "Incomplete" else: start = tz.day_start(day) star_1 = time.human_timedelta( stars[1], source=start) if stars[1] else "Incomplete" star_2 = time.human_timedelta( stars[2], source=start) if stars[2] else "Incomplete" rows.append((day, star_1, star_2, ", ".join(day_langs))) boards = [] index = 0 while index < len(rows): boards.append( tabulate.tabulate(rows[index:index + 5], headers=("Day #", "First star", "Second star", "Languages used"), tablefmt="simple", stralign="center").strip()) index += 4 menu = ext_menus.MenuPages(menus.InfoDataSource(boards), clear_reactions_after=True) await menu.start(ctx)