async def register(client, user: discord.user, message: discord.Message): db_user = db.get_db_user(user) db_user.registered = False db_user.registration_step = 1 db.user_table.update(db_user) info("User not registered, setting registration step to 1", header=f"[{user}]") return await step1(user)
async def end(client, user: discord.user, message: discord.Message): # ends meeting by setting the meeting code to an empty string db_user = db.get_db_user(user) info("Validating Admin to end meeting") if db_user.discord_id in db.admins: # admin double check info("ending meeting") meeting_code = '' await user.send(templates.meeting_end) return meeting_code, 'm'
async def ctf_clear_solves(client, user: discord.user, message: discord.Message ): # ctf: tool to clear all solves in the system db_user = db.get_db_user(user) info("Iterating over each user to clear all solves") if db_user.discord_id in db.admins: # admin double check for each_user in db.user_table.all(): if each_user.ctf_problem_solves: each_user.ctf_problem_solves = [] db.user_table.update(each_user) return await ctf_scoreboard_update(client, user, message)
async def email(client, user: discord.user, message: discord.Message): # sends all choate email addresses for the purposes of a mailing list db_user = db.get_db_user(user) info("Iterating over each user to get each email") if db_user.discord_id in db.admins: # admin double check emails = [] for each_user in db.user_table.all(): if each_user.choate_email: emails.append(each_user.choate_email) info("Sending email list") return await send(user, "\n".join(emails))
async def get_attendance(client, user: discord.user, message: discord.Message): # sends attendance for each user who has an attendance entry db_user = db.get_db_user(user) info("Iterating over each user to get each attendance") if db_user.discord_id in db.admins: # admin double check attendances = [] for each_user in db.user_table.all(): if each_user.attendance and each_user.choate_email: attendances.append(f'{each_user.choate_email} | {len(each_user.attendance)}') info("Sending Attendances") return await user.send("\n".join(attendances))
async def ctf_flag_submit( client, user: discord.user, message: discord.Message): # validates inputted cpuCTF flags db_user = db.get_db_user(user) info( f"Checking flag for {user} who tried {message.content} who has solved {db_user.ctf_problem_solves}" ) for key in ctf_problems.yaml: try: if secrets.compare_digest(message.content, ctf_flags.yaml[key].strip()): if db_user.ctf_problem_solves is None: db_user.ctf_problem_solves = [] if key not in db_user.ctf_problem_solves: info(f"Flag {message.content} accepted for {user}") db_user.ctf_problem_solves.append(key) db.user_table.update(db_user) return await user.send(templates.ctf_flag_acceptance) else: info(f"Flag {message.content} already accepted for {user}") return await user.send(templates.ctf_flag_already_solved) except KeyError: pass info(f"Flag {message.content} rejected for {user}") return await user.send(templates.ctf_flag_rejection)
async def ctf_get_solves( client, user: discord.user, message: discord.Message ): # ctf: debugging tool to check who solved what problems db_user = db.get_db_user(user) info("Iterating over each user to get all solves") if db_user.discord_id in db.admins: # admin double check solves = [] for each_user in db.user_table.all(): if each_user.ctf_problem_solves and each_user.choate_email: solves.append( f'{each_user.choate_email} | {len(each_user.ctf_problem_solves)}' ) info("Sending Solves") return await user.send("\n".join(solves))
def find(self, client) -> discord.TextChannel: from bot.bot_client import CPUBotClient client: CPUBotClient for channel in client.guild.channels: if isinstance(channel, discord.TextChannel): if self.id == channel.id: info( f"Text channel with id {self.id} has been found", header=f"[{self.name}]", ) return channel error(f"Text channel with id {self.id} not found", header=f"[{self.name}]")
async def handle_dm(client, user: discord.User, message: discord.Message): responses = [] for each_command, function in direct_commands: if bool(re.fullmatch(each_command, message.content)): info(each_command + " command function executed", header=f"[{user}]") responses.append(await function(client, user, message)) if db.check_admin(user): for each_command, function in admin_direct_commands: if bool(re.fullmatch(each_command, message.content)): info(each_command + " command function executed by " + db.get_db_user(user).choate_email + " for " + str(message.content)) responses.append(await function(client, user, message)) return responses
async def step0(client, user: discord.User, db_user: DBUser): from bot.bot_client import CPUBotClient client: CPUBotClient # Create embed info_embed = discord.Embed(title="User Info", color=0x0000FF) info_embed.add_field(name="__First Name__", value=db_user.first_name) info_embed.add_field(name="__Last Name__", value=db_user.last_name) info_embed.add_field(name="__Choate Email__", value=db_user.choate_email) # Send message and add reactions message = await send(user, templates.welcome_back, embed=info_embed) await message.add_reaction("👍") await message.add_reaction("👎") info("Verification message sent, waiting for user reaction...", header=f"[{user}]") # Wait for user reaction def check(r: discord.Reaction, u: discord.User): return ( r.message.id == message.id and r.emoji in ["👍", "👎"] and u.id != client.user.id ) res = await client.wait_for("reaction_add", check=check) reaction: discord.reaction = res[0] info(f"User reacted with emoji '{reaction.emoji}'", header=f"[{user}]") if reaction.emoji == "👍": await message.remove_reaction("👍", client.user) await message.remove_reaction("👎", client.user) db_user.registered = True db_user.registration_step = 5 user_table.update(db_user) await step5(client, user, db_user) elif reaction.emoji == "👎": await message.remove_reaction("👍", client.user) await message.remove_reaction("👎", client.user) db_user.registered = False db_user.registration_step = 1 user_table.update(db_user) await send(user, templates.reset) await step1(user, user)
async def start(client, user: discord.user, message: discord.Message): # begins meeting by generating attendance code and setting it to be active db_user = db.get_db_user(user) info("Validating Admin to Create meeting Code") if db_user.discord_id in db.admins: # admin double check info("Checking for existing code") if not client.meeting_id: info("Creating Code") meeting_code = secrets.token_hex(4) info(f"Code: {meeting_code}") await user.send(templates.attendance_set + meeting_code) return meeting_code, 'm' else: return await user.send(templates.attendance_set_failed)
async def on_message(self, message: discord.Message): if isinstance(message.channel, discord.DMChannel): if isinstance(message.author, discord.User) and not str(message.author) == BOT: responses = await commands.handle_dm(self, message.author, message) if len(responses) == 0: # No commands were executed executed = False if not get_db_user(message.author).registered: # is registered executed = await register.handle_dm(self, message.author, message) if not executed: # Nothing really happened # await message.author.send(templates.help) await commands.send(message.author, templates.help) await message.author.send(templates.help) else: # meeting attendance code if type(responses[0]) is tuple: # ask Spencer what's happening here if len(responses[0]) == 2: if responses[0][1] == 'm': info(f"Meeting Code set to {responses[0][0]}") self.meeting_id = responses[0][0]
async def ctf_scoreboard_update(client, user: discord.user, message: discord.Message): db_user = db.get_db_user(user) if db_user.discord_id in db.admins: # admin double check problem_solves = {} info("Iterating over each problem for setup") for item in ctf_problems.yaml: problem_solves[item] = 0 info("Iterating over each user to get all solves") for each_user in db.user_table.all(): if each_user.ctf_problem_solves: for item in problem_solves: if item in each_user.ctf_problem_solves: problem_solves[item] += 1 info("Iterating over each user to setup scoreboard") client.ctf_scoreboard = [] for each_user in db.user_table.all(): if each_user.ctf_problem_solves and each_user.first_name and each_user.last_name: user_points = 0 for problem in each_user.ctf_problem_solves: if problem_solves[problem]: user_points += round(client.ctf_point_value / problem_solves[problem]) client.ctf_scoreboard.append(( f"{each_user.first_name} {each_user.last_name}: {user_points} points", user_points)) client.ctf_scoreboard = sorted(client.ctf_scoreboard, key=lambda x: x[1], reverse=True) return await ctf_scoreboard_get(client, user, message)
async def finish_registration(client, user: discord.User, db_user: DBUser): from bot.bot_client import CPUBotClient client: CPUBotClient info("Finishing user registration", header=f"[{user}]") db_user.registered = True user_table.update(db_user) member: discord.Member for member in client.guild.members: if member.id == user.id: break else: error(f"User not found in guild, cannot complete registration", header=f"[{user}]") return try: await member.edit(nick=f"{db_user.first_name} {db_user.last_name}") await member.add_roles(client.club_member_role) except discord.Forbidden: error("User registered, but bot lacks permission to edit user, are they the server owner?", header=f"[{user}]") await welcome_user(client, member)
async def attendance(client, user: discord.user, message: discord.Message): #called upon attendance code dm, the attendance code is then added to a list of attended meetings by that user db_user = db.get_db_user(user) info(f"Checking meeting id {client.meeting_id} for {user} who said {message.content}") if secrets.compare_digest(message.content, client.meeting_id): info(f"Approved meeting id for {user}") if db_user.attendance is None: db_user.attendance = [] if client.meeting_id not in db_user.attendance: info(f'Added meeting id to {user}') db_user.attendance.append(client.meeting_id) db.user_table.update(db_user) return await user.send(templates.attendance) return await user.send(templates.attendance_found)
async def handle_join_server(client, user: discord.Member): db_user = get_db_user(user) info("Added user to database", header=f"[{user}]") if db_user.registered: db_user.registration_step = 0 user_table.update(db_user) info("User has already registered, setting registration step to 0", header=f"[{user}]") await step0(client, user, db_user) else: db_user.registration_step = 1 user_table.update(db_user) info("User not registered, setting registration step to 1", header=f"[{user}]") await step1(user)
async def step4(client, user: discord.User, db_user: DBUser): from bot.bot_client import CPUBotClient client: CPUBotClient # Create Embed info_embed = discord.Embed(title="User Info", color=0x0000FF) info_embed.add_field(name="__First Name__", value=db_user.first_name) info_embed.add_field(name="__Last Name__", value=db_user.last_name) info_embed.add_field(name="__Choate Email__", value=db_user.choate_email) # Nothing really happened # Send message and add reactions message = await send(user, f"""Thanks! Is all of this info correct?""", embed=info_embed ) await message.add_reaction("👍") await message.add_reaction("👎") info("Verification message sent", header=f"[{user}]") # Wait for user reaction def check(r: discord.Reaction, u: discord.User): return ( r.message.id == message.id and r.emoji in ["👍", "👎"] and u.id != client.user.id ) res = await client.wait_for("reaction_add", check=check) reaction: discord.reaction = res[0] info(f"User reacted with emoji '{reaction.emoji}'", header=f"[{user}]") if reaction.emoji == "👍": await message.remove_reaction("👍", client.user) await message.remove_reaction("👎", client.user) db_user.registration_step = 5 user_table.update(db_user) await step5(client, user, db_user) elif reaction.emoji == "👎": await message.remove_reaction("👍", client.user) await message.remove_reaction("👎", client.user) await send(user, "Ok, asking for the info again.") info("User rejected the info, restarting at step 1", header=f"[{user}]") db_user.registration_step = 1 user_table.update(db_user) await step1(user, welcome=False)
async def setup(self, client) -> discord.Role: from bot.bot_client import CPUBotClient client: CPUBotClient role = await self._find(client) if role is None: info( f"{self.name} role not found, creating one now...", header=f"[{self.name}]", ) role = await self._create(client) info( f"{self.name} role has been created, you should update its perms", header=f"[{self.name}]", ) else: info(f"{self.name} role found, skipping creation", header=f"[{self.name}]") return role
async def step3_input(client, user: discord.User, db_user: DBUser, choate_email: str): info(f'User provided Choate email "{choate_email}"', header=f"[{user}]") db_user.choate_email = choate_email db_user.registration_step = 4 user_table.update(db_user) await step4(client, user, db_user)
async def on_member_join(self, member: discord.Member): if member.guild.id != self.guild.id: return info(f"{member} has joined the server", header=f"[{member}]") await register.handle_join_server(self, member)
async def on_ready(self): info("Client connected to discord") for guild in self.guilds: if guild.id == DISCORD_GUILD_ID: self.guild = guild break if self.guild is None: error(f"Guild with id {DISCORD_GUILD_ID} not found") exit(-1) info(f"Guild with id {DISCORD_GUILD_ID} found, name={self.guild.name}") await roles.setup_guild_roles(self) await channels.setup_guild_channels(self) info("Checking existing guild members...") for member in self.guild.members: member: discord.Member if db_user := user_table.find_discord_user(member): if db_user.registered: if self.club_member_role in member.roles: info("Existing member found in db, already has Club Member role", header=f"[{member}]") else: try: await member.add_roles(self.club_member_role) except discord.Forbidden: error("Existing member found in db, but bot lacks permission to give " "Club Member role to this user.", header=f"[{member}]") else: info("Existing member found in db, bot gave user Club Member role", header=f"[{member}]") else: if self.club_member_role in member.roles: warning("Unregistered member found in db, has Club Member role for some reason", header=f"[{member}]") else: info("Unregistered member found in db, doesn't has Club Member role", header=f"[{member}]") else: info("User not found in db", header=f"[{member}]")
async def step2_input(user: discord.User, db_user: DBUser, last_name: str): info(f'User provided last name "{last_name}"', header=f"[{user}]") db_user.last_name = last_name db_user.registration_step = 3 user_table.update(db_user) await step3(user, db_user)
async def step1_input(user: discord.User, db_user: DBUser, first_name: str): info(f'User provided first name "{first_name}"', header=f"[{user}]") db_user.first_name = first_name db_user.registration_step = 2 user_table.update(db_user) await step2(user, db_user)