async def remove_scheduled_events(self, ctx, tag=None): """ Removes a scheduled event. For create channel events the tag is create + the channel's name. For delete channel events the tag is delete + the channel's id. For purge messages from channel the tag is purge + the channel's id. For send message in channel the tag is send + the channel's id. If no tag is provided then all scheduled events will be canceled. Usage: ?remove_scheduled_events createsome_channel_name Usage: ?remove_scheduled_events delete182736519823 Usage: ?remove_scheduled_events purge182736519823 Usage: ?remove_scheduled_events send182736519823 """ schedule.clear(tag) if tag is None: execute_statement(create_delete_query("configure__schedule")) await ctx.send(f"Removed all scheduled events") else: execute_statement( create_delete_query("configure__schedule", "tag", f"'{tag}'")) await ctx.send(f"Removed all scheduled events with tag [{tag}]")
async def purge(self, ctx, channel_id, weekday, at_time, number_of_messages=0): """ Purges the [number_of_messages] latest messages from the specified channel. If no [number_of_messages] is provided the given channel will be emptied. Usage: ?configure schedule purge some_channel_id monday 13:00 2 """ channel_to_purge = self.bot.get_channel(int(channel_id)) number = None if number_of_messages == 0 else int(number_of_messages) await scheduler.schedule_new_task(self.bot, ctx, _schedule_purge, "configure/schedule/purge", weekday, at_time, "purge" + channel_id, channel=channel_to_purge, number=number) if at_time != "0": execute_statement( create_insert_scheduled_event_query(task="purge", weekday=weekday, at_time=at_time, tag="purge" + channel_id, channel_id=int(channel_id), number=number_of_messages))
async def send_message(self, ctx, channel_id, weekday, at_time, *args): """ Sends [message] in the specified channel every [weekday] at [at_time]. Usage: ?configure schedule send_message 8126387123 monday 13:00 some message here """ await scheduler.schedule_new_task(self.bot, ctx, _message_channel, "configure/schedule/send_message", weekday, at_time, "send" + channel_id, channel=self.bot.get_channel( int(channel_id)), message=" ".join(args[:])) if at_time != "0": execute_statement( create_insert_scheduled_event_query(task="send_message", weekday=weekday, at_time=at_time, tag="send" + channel_id, channel_id=int(channel_id), message=" ".join(args[:])))
async def create_channel(self, ctx, channel_name, category_id, weekday, at_time): """ Creates a channel at a specified time every week. Usage: ?configure schedule create_channel some_channel_name 12756371253 monday 13:00 """ await scheduler.schedule_new_task(self.bot, ctx, _create_channel, "configure/schedule/create_channel", weekday, at_time, "create" + channel_name, guild=ctx.message.guild, channel_name=channel_name, category=discord.utils.get( ctx.guild.categories, id=int(category_id))) if at_time != "0": execute_statement( create_insert_scheduled_event_query( task="create_channel", weekday=weekday, at_time=at_time, tag="create" + channel_name, channel_name=channel_name, category_id=int(category_id), guild_id=ctx.message.guild.id))
async def claim(self, ctx): """ Use this command to gain access to the leaderboards. Usage: ?claim """ await message_wrapper.delete_message(bot=self.bot, message=ctx.message, source="Claim") if await _validate_eligibility(ctx): execute_statement( f"INSERT INTO idclaims (name, user_id) VALUES ('{ctx.author.display_name}', {ctx.author.id})" ) role = discord.utils.get(ctx.message.guild.roles, name="claimed") await ctx.message.author.add_roles(role) command_channel = discord.utils.get(ctx.message.guild.channels, name="leaderboards") await message_wrapper.message_user(self.bot, ctx.message.author, _create_introductory_message(), source="Claim") await message_wrapper.message_channel( bot=self.bot, channel=ctx.message.channel, message= f""":white_check_mark: {ctx.message.author.mention} you have claimed the nickname """ f"""{ctx.message.author.display_name}. Type ?help in {command_channel.mention} """ f"""for help on how to get started.""")
async def leaderboard(self, ctx, score): """ Submit your score to a given leaderboard. Usage: ?jogger 507 """ await _validate_user(self.bot, ctx, score) # extract data try: score = float(score.replace(",", ".")) invoked_leaderboard = ctx.invoked_with if invoked_leaderboard == "leaderboard": await ctx.send( "Please submit to a specific leaderboard, such as jogger, type ?help for example usage." ) return if invoked_leaderboard != "jogger": score = int(score) except: return # get previous top 3 previous_top_3 = execute_statement( create_select_top_x_scores_query(table_name=invoked_leaderboard, limit=3)).all(as_dict=True) # insert entry into leaderboard execute_statement( f"INSERT INTO leaderboard__{invoked_leaderboard} (name, score, submit_date) VALUES ('{ctx.author.display_name}', {score}, DATE '{datetime.now().date()}')" ) # select 10 highest ranks descending_score_dict = execute_statement( create_select_top_x_scores_query(table_name=invoked_leaderboard, limit=10)).all(as_dict=True) leaderboard_channel = discord.utils.get(ctx.guild.channels, name=invoked_leaderboard) embed = _create_leaderboard_embed(leaderboard=invoked_leaderboard, score_dict=descending_score_dict, command_channel=discord.utils.get( ctx.guild.channels, name="leaderboards")) if ctx.channel.name != "momos_test_dungeon": await _update_leaderboard_embed(embed, leaderboard_channel) await _congratulate_submitter(ctx, leaderboard_channel, previous_top_3, descending_score_dict[:3])
async def _validate_claimed_user(bot, ctx): """Validates that current nickname matches claimed_id""" author_id = ctx.author.id author_name = ctx.author.display_name statement = create_select_query(table_name="leaderboard__idclaims", where_key="user_id", where_value=author_id) try: rows = execute_statement(statement) user_id = rows.first(as_dict=True).get("user_id") user_name = rows.first(as_dict=True).get("name") if len(rows.all() ) > 1 or user_id != author_id or user_name != author_name: raise AssertionError("Username doesn't match claimed username") except Exception as e: await ctx.send( "Something wrong with your claimed name, did you change your nickname? Contact an admin." ) await pm_dev_error( bot=bot, error_message= f"\nAuthor ID: {author_id}, Author Name: {author_name}\nSQL QUERY: {statement}", source="_validate_claimed_user") raise AssertionError("Username doesn't match claimed username")
async def _validate_eligibility(ctx): """ Checks that the user has not already claimed access to the leaderboards and has a valid nickname. """ error_in_nickname = _check_invalid_nickname( ctx.message.author.display_name) rows = execute_statement( create_select_query(table_name="leaderboard__idclaims", where_key="user_id", where_value=str( ctx.message.author.id))).all(as_dict=True) if len(rows) > 0: await message_wrapper.message_channel( bot=ctx.bot, channel=ctx.message.channel, message= f""":no_entry: You have already claimed access to the leaderboards, """ f"""{ctx.message.author.mention}, if you have recently changed your nickname, """ f"""please contact an admin.""", source="claim") return False elif error_in_nickname: await message_wrapper.message_channel(bot=ctx.bot, channel=ctx.channel, message=error_in_nickname) return False return True
async def add_to_leaderboards_test(bot, ctx): # check that user is not in test leaderboard before assert (len( execute_statement( create_select_query( table_name="leaderboard__test", where_key="name", where_value=f"'{ctx.author.display_name}'")).all( as_dict=True)) == 0) try: await catch_with_channel_message( invoke_wrapper.invoke_event_now, common.TEST_RESULTS_CHANNEL, f":no_entry: Error during leaderboard #test invocation", True, f"integration/leaderboard", bot, ctx, f"leaderboard", f"leaderboard", *["500000000"]) await common.TEST_RESULTS_CHANNEL.send( f":white_check_mark: Leaderboard[Add to leaderboard]: Successfully added " f"a user to the test leaderboard!") # check that user is in test leaderboard after assert (len( execute_statement( create_select_query( table_name="leaderboard__test", where_key="name", where_value=f"'{ctx.author.display_name}'")).all( as_dict=True)) == 1) # remove user from leaderboard table again execute_statement( create_delete_query(table_name="leaderboard__test", where_key="name", where_value=f"'{ctx.author.display_name}'")) # check that user is no longer in leaderboard assert (len( execute_statement( create_select_query( table_name="leaderboard__test", where_key="name", where_value=f"'{ctx.author.display_name}'")).all( as_dict=True)) == 0) except Exception as e: traceback.print_exc() await common.TEST_RESULTS_CHANNEL.send( f":no_entry: Leaderboard: Error during add_to_leaderboard integration-tests: {e}" ) raise ValueError("Error in Leaderboards integration-test")
async def delete_channel(self, ctx, channel_id, weekday, at_time): """ Deletes a channel at a specified time every week. Usage: ?configure schedule delete_channel some_channel_id monday 13:00 """ await scheduler.schedule_new_task(self.bot, ctx, _remove_channel, "configure/schedule/delete_channel", weekday, at_time, "delete" + channel_id, channel=self.bot.get_channel( int(channel_id))) if at_time != "0": execute_statement( create_insert_scheduled_event_query( task="remove_channel", weekday=weekday, at_time=at_time, tag="delete" + channel_id, channel_id=int(channel_id)))
def _rename_user_in_idclaims(new_name, user_id) -> bool: """ :param new_name: The new name to replace the previous name with :param user_to_replace: The string to find in the entry :return: Returns bool if the user was found and the name that was replaced """ previous_entry = execute_statement( create_select_query("leaderboard__idclaims", "user_id", f"'{user_id}'")).all(as_dict=True) execute_statement( create_update_query("leaderboard__idclaims", "name", f"'{new_name}'", "user_id", f"'{user_id}'")) updated_entry = execute_statement( create_select_query("leaderboard__idclaims", "user_id", f"'{user_id}'")).all(as_dict=True) try: if previous_entry[0].get("name") != new_name and updated_entry[0].get( "name") == new_name: return True else: return False except: return False
async def from_leaderboard(self, ctx, leaderboard, user_name): """ [Admin only]: Delete a user from a given leaderboard. Usage: ?delete from_leaderboard jogger McMomo """ if leaderboard in common.LEADERBOARD_LIST: in_leaderboard_before = execute_statement( create_select_query(f"leaderboard__{leaderboard}", "name", f"'{user_name}'")).all(True) execute_statement( create_delete_query(f"leaderboard__{leaderboard}", "name", f"'{user_name}'")) in_leaderboard_after = execute_statement( create_select_query(f"leaderboard__{leaderboard}", "name", f"'{user_name}'")).all(True) if len(in_leaderboard_before) == 1 and len( in_leaderboard_after) == 0: await ctx.send(f"Removed {user_name} from {leaderboard}") else: await ctx.send(f"Could not find {user_name} in {leaderboard}") else: await ctx.send(f"Can't find the {leaderboard} leaderboard")
def _schedule_event(bot: discord.ext.commands.Bot): task_info_list = execute_statement( create_select_query("configure__schedule")).all(as_dict=True) for task_info in task_info_list: local_guild: discord.Guild = bot.get_guild(task_info.get("guild_id")) re_schedule_task( bot, _get_task(task_info.get("task")), task_info.get("weekday"), task_info.get("at_time"), task_info.get("tag"), message=task_info.get("message"), channel=bot.get_channel(int(task_info.get("channel_id"))), number=task_info.get("number"), guild=local_guild, category=None if local_guild is None else discord.utils.get( local_guild.categories, id=int(task_info.get("category_id"))))
async def list(self, ctx, leaderboard): """ List your position in a given leaderboard. This command will list the top 5 of the leaderboard as well as your position and your closest competitors. Usage: ?list jogger """ if leaderboard not in common.LEADERBOARD_LIST: await ctx.send(f"The **{leaderboard}** leaderboard does not exist." ) return rows = execute_statement( create_select_top_x_scores_query(leaderboard)).all(as_dict=True) found = False list_message = f"**---{leaderboard.capitalize()} list:---**\n" for index, entry in enumerate(rows): # if user is top 5 if index < 5: if entry.get("name") == ctx.author.display_name: found = True list_message += f"{index + 1}. {entry.get('name')} {entry.get('score')}\n" elif index == 5: if found: await ctx.send(list_message) return else: list_message += "-----------------\n" elif index > 5 and entry.get("name") == ctx.author.display_name: list_message += f"{index - 1}. {rows[index - 2].get('name')} {entry.get('score')}\n" list_message += f"{index}. {rows[index - 1].get('name')} {entry.get('score')}\n" list_message += f"{index + 1}. {entry.get('name')} {entry.get('score')}\n" await ctx.send(list_message) return if not found: await ctx.send( f"Could not find {ctx.author.display_name} in {discord.utils.get(ctx.guild.channels, name=leaderboard).mention}" ) # Leaderboard had fewer than 5 entries else: await ctx.send(list_message)
async def refresh(self, ctx, leaderboard): """ [Admin only] Refreshes a given leaderboard. Useful after manual intervention. """ if leaderboard not in common.LEADERBOARD_LIST and leaderboard != "test": await ctx.send(f"Could not find the {leaderboard} leaderboard.") return descending_score_dict = execute_statement( create_select_top_x_scores_query(table_name=leaderboard, limit=10)).all(as_dict=True) leaderboard_channel = discord.utils.get(ctx.guild.channels, name=leaderboard) embed = _create_leaderboard_embed(leaderboard=leaderboard, score_dict=descending_score_dict, command_channel=discord.utils.get( ctx.guild.channels, name="leaderboards")) await _update_leaderboard_embed(embed, leaderboard_channel) await ctx.send(f"Refreshed the {leaderboard} leaderboard.")
async def _congratulate_submitter(ctx, leaderboard_channel, previous_top_3: dict, current_top_3: dict): """Sends a congratulations message custom to which ranking the user got""" name = ctx.author.display_name # if submission made top 3 if any(name == entry.get("name") for entry in current_top_3): for index, user in enumerate(current_top_3): # new rank 1 if index == 0 and name == user.get( "name") and not name == previous_top_3[0].get("name"): await ctx.send( f":crown: :first_place: CONGRATULATIONS {ctx.author.mention} on your new #{index + 1} placement in the {leaderboard_channel.mention} leaderboard!" f"\nPlease send an in-game screenshot to any admin for verification." ) # new top 3 elif name == user.get("name") and not any( name == user_entry.get("name") for user_entry in previous_top_3): await ctx.send( f":crown: Congratulations {ctx.author.mention} on your #{index + 1} placement in the {leaderboard_channel.mention} leaderboard!" f"\nPlease send an in-game screenshot to any admin for verification." ) elif name == user.get("name"): await ctx.send( f":crown: Congratulations {ctx.author.mention} on your #{index + 1} position in the {leaderboard_channel.mention} leaderboard!" ) # submission not top 3 else: record_collection = execute_statement( create_select_top_x_scores_query(leaderboard_channel.name)) ranking = get_ranking_of_user(name=name, record_collection=record_collection) await ctx.send( f"Nice work {ctx.author.mention} on your #{ranking} position in the {leaderboard_channel.mention} leaderboard, keep it up!" )