async def dmpartner(self, ctx: commands.Context, *, message: str): ''' DM your Secret Santa partner anonymously (the person you have) via the bot ''' if (self.SecretSantaHelper.channel_is_guild(ctx.channel)): await ctx.message.delete( ) # delete the message before people can see (curr_idx, curr_user) = self.SecretSantaHelper.get_participant_object( ctx.author.id, self.usr_list) if ((curr_idx != -1) and self.exchange_started ): # user has joined and the exchange has started partner = self.bot.get_user(int(curr_user.partnerid)) try: msg = "You have a message from your secret santa\n" msg += f"```{message}```" await partner.send(msg) BOT_ERROR.output_info( f"{ctx.author.name}#{ctx.author.discriminator} DMd {partner.name}#{partner.discriminator}: {message}", self.logger) return except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.author.send( f"Failed to send message to {partner.name}#{partner.discriminator} about their partner. Harass them to turn on server DMs for Secret Santa stuff." ) elif (curr_idx == -1): # user has not joined msg = BOT_ERROR.UNJOINED await ctx.author.send(msg) elif (not self.exchange_started ): # exchange hasn't started (there are no partners) msg = BOT_ERROR.NOT_STARTED await ctx.author.send(msg) else: await ctx.send(BOT_ERROR.UNDETERMINED_CONTACT_CODE_OWNER) return
async def dm_error(self, ctx: commands.Context, error): if (isinstance(error, commands.NoPrivateMessage)): await ctx.send(BOT_ERROR.DM_ERROR) else: BOT_ERROR.output_exception(error, self.logger) await ctx.send(BOT_ERROR.UNDETERMINED_CONTACT_CODE_OWNER) return
def __countdown_cmd_change(self, ctx: commands.Context, cd_name: str, cd_time: str): result_str = "" try: pend_test_convert = pendulum.from_format( cd_time, self.pend_format) # check that the format is correct except ValueError as error: expected = "ERROR: inputted time does not match expected format `month/day/year @ hour:minute AM/PM UTC_offset`\n" result_str = expected + " ex. `5/17/20 @ 1:00 PM -06:00`" BOT_ERROR.output_debug(result_str, self.logger) return result_str query_get_timer_by_name = f"SELECT * FROM {self.__get_cd_table_name(ctx.guild.id)} WHERE name=\'{cd_name}\';" query_result = self.sqlhelp.execute_read_query(query_get_timer_by_name) if (query_result != None): if (len(query_result) > 0): (query_id, query_name, query_time, query_user_id) = query_result[0] if (ctx.author.id == query_user_id): if (self.sqlhelp.execute_update_query( self.__get_cd_table_name(ctx.guild.id), f"time=\'{cd_time}\'", f"id={query_id}")): diff_str = self.__find_pend_diff_str(pend_test_convert) result_str = f"Updated countdown for {cd_name}. Now set for {diff_str}" else: result_str = BOT_ERROR.INVALID_COUNTDOWN_NAME(cd_name) else: cd_owner = ctx.guild.get_member(query_user_id) result_str = BOT_ERROR.CANNOT_CHANGE_COUNTDOWN( cd_owner.name) else: result_str = BOT_ERROR.INVALID_COUNTDOWN_NAME(cd_name) return result_str
async def partnerinfo(self, ctx: commands.Context): ''' Get your partner information via DM (partner name, wishlist, gift preference) ''' currAuthor = ctx.author authorIsParticipant = self.SecretSantaHelper.user_is_participant( currAuthor.id, self.usr_list) if (self.exchange_started and authorIsParticipant): (usr_index, user) = self.SecretSantaHelper.get_participant_object( currAuthor.id, self.usr_list) (partner_index, partnerobj) = self.SecretSantaHelper.get_participant_object( user.partnerid, self.usr_list) msg = "Your partner is " + partnerobj.name + "#" + partnerobj.discriminator + "\n" msg = msg + "Their wishlist(s) can be found here: " + partnerobj.wishlisturl + "\n" msg = msg + "And their gift preferences can be found here: " + partnerobj.preferences + "\n" msg = msg + "If you have trouble accessing your partner's wishlist, please contact an admin to get in touch with your partner. This is a *Secret* Santa, after all!" try: await currAuthor.send(msg) await ctx.send("The information has been sent to your DMs.") except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) elif ((not self.exchange_started) and authorIsParticipant): await ctx.send(BOT_ERROR.NOT_STARTED) elif (self.exchange_started and (not authorIsParticipant)): await ctx.send(BOT_ERROR.EXCHANGE_STARTED_UNJOINED) elif ((not self.exchange_started) and (not authorIsParticipant)): await ctx.send(BOT_ERROR.UNJOINED) else: await ctx.send(BOT_ERROR.UNREACHABLE) return
async def setwishlisturl(self, ctx: commands.Context, *destination: str): ''' [Any number of wishlist URLs or mailing addresses] = set wishlist destinations or mailing address. Surround mailing address with quotation marks and separate EACH wishlist destination with a space (eg. amazonurl/123 "Sesame Street" http://rightstufanime.com/). ''' currAuthor = ctx.author if self.SecretSantaHelper.user_is_participant(currAuthor.id, self.usr_list): if (self.SecretSantaHelper.channel_is_guild(ctx.channel)): await ctx.message.delete( ) # delete the message before people can see (index, user) = self.SecretSantaHelper.get_participant_object( currAuthor.id, self.usr_list) new_wishlist = "None" if (len(destination) == 0): pass else: new_wishlist = " | ".join(destination) try: # save to config file self.config['members'][str(user.usrnum)][ SecretSantaConstants.WISHLISTURL] = new_wishlist self.config.write() # add the input to the value in the user's class instance user.wishlisturl = new_wishlist try: await currAuthor.send( f"New wishlist URL(s): {new_wishlist}") if (not user.pref_is_set()): userPrompt = f"Great! Now please specify what your preferences for your wishlist might be. Use `{CONFIG.prefix}setprefs [preferences separated by a space]` (e.g. `{CONFIG.prefix}setprefs hippopotamus \"stuffed rabbit\" dog`). Defaults to N/A if not entered." await currAuthor.send(userPrompt) if (user.wishlisturl_is_set() and user.pref_is_set()): signup_complete_msg = f"Congrats, you're now officially enrolled in the Secret Santa! You may change your wishlist URL or preferences with `{CONFIG.prefix}setwishlisturl` or `{CONFIG.prefix}setprefs` any time before the admin begins the Secret Santa." await currAuthor.send(signup_complete_msg) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) except Exception as e: BOT_ERROR.output_exception(e, self.logger) try: await currAuthor.send(BOT_ERROR.INVALID_INPUT) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) else: await ctx.send(BOT_ERROR.UNJOINED) return
async def setprefs(self, ctx: commands.Context, *preferences: str): ''' Set new preferences ''' currAuthor = ctx.author if self.SecretSantaHelper.user_is_participant(currAuthor.id, self.usr_list): if (self.SecretSantaHelper.channel_is_guild(ctx.channel)): await ctx.message.delete( ) # delete the message before people can see (index, user) = self.SecretSantaHelper.get_participant_object( currAuthor.id, self.usr_list) new_prefs = "None" if (len(preferences) == 0): pass else: new_prefs = " | ".join(preferences) try: #save to config file self.config['members'][str(user.usrnum)][ SecretSantaConstants.PREFERENCES] = str(new_prefs) self.config.write() #add the input to the value in the user's class instance user.preferences = new_prefs try: await currAuthor.send(f"New preferences: {new_prefs}") if (not user.wishlisturl_is_set()): userPrompt = f"Great! Now please specify what your wishlist URL or mailing address. Use `{CONFIG.prefix}setwishlisturl [wishlist urls separated by a space]` (e.g. `{CONFIG.prefix}setwishlisturl amazonurl/123 \"sesame street\"`) to set your wishlist URL." await currAuthor.send(userPrompt) if (user.wishlisturl_is_set() and user.pref_is_set()): signup_complete_msg = f"Congrats, you're now officially enrolled in the Secret Santa! You may change your wishlist URL or preferences with `{CONFIG.prefix}setwishlisturl` or `{CONFIG.prefix}setprefs` any time before the admin begins the Secret Santa." await currAuthor.send(signup_complete_msg) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) except Exception as e: BOT_ERROR.output_exception(e, self.logger) try: await currAuthor.send(BOT_ERROR.INVALID_INPUT) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) else: await ctx.send(BOT_ERROR.UNJOINED) return
async def emote(self, ctx: commands.Context, *emotes: discord.PartialEmoji): ''' Get the URL to emotes without needing to open the link. Custom emotes only. ''' for passed_emote in emotes: emote_url = str(passed_emote.url) emote_name = passed_emote.name emote_id = passed_emote.id img_type = "gif" if passed_emote.animated else "png" BOT_ERROR.output_info( f"Name={emote_name}, ID={emote_id}, IMG_TYPE={img_type}, url={emote_url}", self.logger) await ctx.send(content=emote_url) return
def run_countdown_command(self, ctx: commands.Context, cd_command: str, cd_name: str, cd_time: str): output = self.__find_countdown_hints(cd_command, cd_name, cd_time) if (output == ""): # no hints were needed if (not self.sqlhelp.if_table_exists( self.__get_cd_table_name(ctx.guild.id)) ): # make sure table exists before executing the CD command self.sqlhelp.create_table( self.__get_cd_table_name(ctx.guild.id), "(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, time TEXT NOT NULL, user_id INTEGER NOT NULL, UNIQUE(name))" ) if (cd_command == "set"): output = self.__countdown_cmd_set(ctx, cd_name, cd_time) elif (cd_command == "change"): output = self.__countdown_cmd_change(ctx, cd_name, cd_time) elif (cd_command == "check"): output = self.__countdown_cmd_check(ctx, cd_name) elif (cd_command == "remove"): output = self.__countdown_cmd_remove(ctx, cd_name) elif (cd_command == "list"): output = self.__countdown_cmd_list(ctx) elif (cd_command == "clean"): output = self.__countdown_cmd_clean(ctx) else: output = BOT_ERROR.INVALID_COUNTDOWN_COMMAND(cd_command) output += "\nCountdown options/sub-commands: `set`, `change`, `check` , `remove`, `list`, `clean`." return output
async def manage_reactions(self, payload: discord.RawReactionActionEvent): if (self.role_channel == None): # if no role channel assigned, self.role_channel = self.bot.get_channel(CONFIG.role_channel) if ( CONFIG.role_channel != -1 ) else None # attempt to get role channel if ( self.role_channel == None ): # if that fails (CONFIG.role_channel == -1 or get_channel fails) BOT_ERROR.output_error(BOT_ERROR.REACTION_ROLE_UNASSIGNED, self.logger) return # end command else: pass # reassignment of role_channel worked else: pass # role_channel is assigned message_id = payload.message_id channel_id = payload.channel_id emoji = payload.emoji guild = self.bot.get_guild(payload.guild_id) user = guild.get_member(payload.user_id) if channel_id == self.role_channel.id: message = None async for message in self.role_channel.history(limit=200): if message.id == message_id: break if message != None: content = message.content.split("\n") for line in content: line_tokens = line.split(" ") line_tokens = [ i for i in line_tokens if i ] # remove empty strings for quality of life (doesn't break with extra spaces) for (idx, token) in enumerate(line_tokens): if token == "for" and idx > 0 and line_tokens[ idx - 1] == str(emoji): role_id = line_tokens[idx + 1][3:-1] role = guild.get_role(int(role_id)) if payload.event_type == "REACTION_ADD": await user.add_roles(role) else: await user.remove_roles(role) return
async def pin_archive_error(self, error, ctx): if isinstance(error, MissingPermissions): text = BOT_ERROR.NO_PERMISSION("mod") await ctx.send(content=text) elif isinstance(error, MissingRequiredArgument): await ctx.send(content=BOT_ERROR.MISSING_ARGUMENTS) elif isinstance(error, commands.CommandError): await ctx.send(content=error) else: await ctx.send(content=BOT_ERROR.UNDETERMINED_CONTACT_CODE_OWNER)
def __countdown_cmd_remove(self, ctx: commands.Context, cd_name: str): result_str = "" query_get_timer_by_name = f"SELECT * FROM {self.__get_cd_table_name(ctx.guild.id)} WHERE name=\'{cd_name}\';" query_result = self.sqlhelp.execute_read_query(query_get_timer_by_name) if (query_result != None): (query_id, query_name, query_time, query_user_id) = query_result[0] if (query_user_id == ctx.author.id): if (self.sqlhelp.execute_delete_query( self.__get_cd_table_name(ctx.guild.id), f"id={query_id}")): result_str = f"Countdown timer `{query_name}` removed." else: result_str = BOT_ERROR.INVALID_COUNTDOWN_NAME(cd_name) else: cd_owner = ctx.guild.get_member(query_user_id) result_str = BOT_ERROR.CANNOT_CHANGE_COUNTDOWN(cd_owner.name) else: result_str = BOT_ERROR.INVALID_COUNTDOWN_NAME(cd_name) return result_str
async def getprefs(self, ctx: commands.Context): ''' Get current preferences ''' currAuthor = ctx.author if self.SecretSantaHelper.user_is_participant(ctx.author.id, self.usr_list): (index, user) = self.SecretSantaHelper.get_participant_object( ctx.author.id, self.usr_list) try: await currAuthor.send( f"Current preference(s): {user.preferences}") except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) else: await ctx.send(BOT_ERROR.UNJOINED) return
def __countdown_cmd_set(self, ctx: commands.Context, cd_name: str, cd_time: str): result_str = "" try: pend_test_convert = pendulum.from_format( cd_time, self.pend_format) # check that the format is correct if (self.sqlhelp.insert_records( self.__get_cd_table_name(ctx.guild.id), "(name, time, user_id)", [f"('{cd_name}', '{cd_time}', {ctx.author.id})"])): diff_str = self.__find_pend_diff_str(pend_test_convert) result_str = f"{cd_name} countdown set for {cd_time} ({diff_str})" else: result_str = BOT_ERROR.COUNTDOWN_NAME_TAKEN except ValueError as error: expected = "ERROR: inputted time does not match expected format `month/day/year @ hour:minute AM/PM UTC_offset`\n" result_str = expected + "ex. `5/17/20 @ 1:00 PM -06:00`" BOT_ERROR.output_debug(result_str, self.logger) finally: return result_str
def __countdown_cmd_check(self, ctx: commands.Context, cd_name: str): result_str = "" query_get_timer_by_name = f"SELECT * FROM {self.__get_cd_table_name(ctx.guild.id)} WHERE name=\'{cd_name}\';" query_result = self.sqlhelp.execute_read_query(query_get_timer_by_name) if (query_result != None): (query_id, query_name, query_time, query_user_id) = query_result[0] cd_pend = pendulum.from_format(query_time, self.pend_format) diff_str = self.__find_pend_diff_str(cd_pend) result_str = f"Time until {cd_name}: {diff_str}" else: result_str = BOT_ERROR.INVALID_COUNTDOWN_NAME(cd_name) return result_str
async def join(self, ctx: commands.Context): ''' Join Secret Santa if it has not started. Contact the Secret Santa admin if you wish to join. ''' currAuthor = ctx.author # check if the exchange has already started if self.SecretSantaHelper.user_is_participant(currAuthor.id, self.usr_list): await ctx.send(BOT_ERROR.ALREADY_JOINED) else: # initialize instance of Participant for the author self.highest_key = self.highest_key + 1 self.usr_list.append( SecretSantaParticipant(currAuthor.name, currAuthor.discriminator, currAuthor.id, self.highest_key)) # write details of the class instance to config and increment total_users self.config['members'][str(self.highest_key)] = [ currAuthor.name, currAuthor.discriminator, currAuthor.id, self.highest_key, "", "N/A", "" ] self.config.write() # prompt user about inputting info await ctx.send( currAuthor.mention + f" has been added to the {str(ctx.guild)} Secret Santa exchange!" + "\nMore instructions have been DMd to you.") try: userPrompt = f"Welcome to the __{str(ctx.guild)}__ Secret Santa! To complete your enrollment you'll need to input your wishlist URL and preferences (by DMing this bot) so your Secret Santa can send you something\n" await currAuthor.send(userPrompt) userPrompt = f".\nFirst we need your wishlist (or the destination for sending gifts). Please use `{CONFIG.prefix}setwishlisturl [wishlist urls separated by a space]` (e.g. `{CONFIG.prefix}setwishlisturl amazonurl/123 \"sesame street\"`) to set your wishlist URL (you may also add your mailing address)." await currAuthor.send(userPrompt) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) return
async def dmsanta(self, ctx: commands.Context, *, message: str): ''' DM your Secret Santa (the person that has you) via the bot ''' if (self.SecretSantaHelper.channel_is_guild(ctx.channel)): await ctx.message.delete( ) # delete the message before people can see (santa_idx, santa_user) = self.SecretSantaHelper.get_participant_object( ctx.author.id, self.usr_list, id_is_partner=True) if ((santa_idx != -1) and self.exchange_started ): # user has joined and the exchange has started santa = self.bot.get_user(int(santa_user.idstr)) try: msg = "You have a message from your secret santa partner\n" msg += f"```{message}```" await santa.send(msg) BOT_ERROR.output_info( f"{ctx.author.name}#{ctx.author.discriminator} DMd {santa.name}#{santa.discriminator}: {message}", self.logger) author_msg = "Message sent to your Secret Santa\n" author_msg += f"```{message}```" await ctx.author.send(author_msg) return except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.author.send( f"Failed to send the message to your secret santa. Their DMs may be off. Please ask your Secret Santa admin." ) elif (santa_idx == -1): # user has not joined msg = BOT_ERROR.UNJOINED await ctx.author.send(msg) elif (not self.exchange_started ): # exchange hasn't started (there are no partners) msg = BOT_ERROR.NOT_STARTED await ctx.author.send(msg) else: await ctx.send(BOT_ERROR.UNDETERMINED_CONTACT_CODE_OWNER) return
async def pause(self, ctx: commands.Context): ''' Pause for people that want to join last-minute (reshuffles and matches upon restart) ''' if (ctx.author.top_role == ctx.guild.roles[-1]): self.exchange_started = False self.config['programData']['exchange_started'] = False self.config.write() self.is_paused = True await ctx.send( "Secret Santa has been paused. New people may now join.") else: await ctx.send(BOT_ERROR.NO_PERMISSION(ctx.guild.roles[-1])) return
async def emote(self, ctx: commands.Context, *emotes: str): ''' Get the URL to emotes without needing to open the link. ''' http = urllib3.PoolManager() for passed_emote in emotes: # Create the base URL of the emote emote_parts = passed_emote.split(sep=":") (emote_name, emote_id) = (emote_parts[1], (emote_parts[2])[:-1]) base_url = f"https://cdn.discordapp.com/emojis/{str(emote_id)}" # http request to find the appropriate extension response = http.urlopen('GET', url=base_url) img_type = response.info()['Content-Type'] img_ext = img_type.split(sep="/")[1] http.clear() # output emote_url = f"{base_url}.{img_ext}" BOT_ERROR.output_info( f"Name={emote_name}, ID={emote_id}, IMG_TYPE={img_type}, url={emote_url}", self.logger) await ctx.send(content=emote_url) return
async def end(self, ctx: commands.Context): ''' End the Secret Santa ''' if (ctx.author.top_role == ctx.guild.roles[-1]): self.exchange_started = False self.is_paused = False self.config['programData']['exchange_started'] = False self.highest_key = 0 del self.usr_list[:] self.config['members'].clear() self.config.write() await ctx.send("Secret Santa ended") else: await ctx.send(BOT_ERROR.NO_PERMISSION(ctx.guild.roles[-1])) return
async def restart(self, ctx: commands.Context): ''' Restart the Secret Santa after pause ''' currAuthor = ctx.author is_paused = True if ((currAuthor.top_role == ctx.guild.roles[-1]) and is_paused): # ensure all users have all info submitted all_fields_complete = True for user in self.usr_list: if (user.wishlisturl_is_set() and user.pref_is_set()): pass else: all_fields_complete = False try: await currAuthor.send( BOT_ERROR.HAS_NOT_SUBMITTED(user.name)) await ctx.send( "`Partner assignment cancelled: participant info incomplete.`" ) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) list_changed = self.SecretSantaHelper.usr_list_changed_during_pause( self.usr_list, self.user_left_during_pause) if (list_changed): ctx.send( f"User list changed during the pause. Partners must be picked again with `{CONFIG.prefix}start`." ) else: self.exchange_started = True is_paused = False self.config['programData']['exchange_started'] = True self.config.write() await ctx.send( "No change was made during the pause. Secret Santa resumed with the same partners." ) elif (currAuthor.top_role != ctx.guild.roles[-1]): await ctx.send(BOT_ERROR.NO_PERMISSION(ctx.guild.roles[-1])) elif (not is_paused): await ctx.send(BOT_ERROR.NOT_PAUSED) else: await ctx.send(BOT_ERROR.UNREACHABLE) return
async def archive_pins(self, ctx: commands.Context, channel_to_archive: discord.TextChannel, channel_to_message: discord.TextChannel): ''' Archive the pins in one channel to another channel as messages ex. `s!archive_pins #general #archive` ''' start_message = f"Attempting to archive pinned messages from {channel_to_archive.mention} to {channel_to_message.mention}" await ctx.send(content=start_message) pins_to_archive = await channel_to_archive.pins() pins_to_archive.reverse() for pin in pins_to_archive: attachments = pin.attachments attachment_str = "" for attachment in attachments: attachment_str += f"{attachment.url}\n" # add link to attachments pin_author = pin.author.name pin_pendulum = pendulum.instance(pin.created_at) pin_dt_str = pin_pendulum.format("MMMM DD, YYYY") pin_url = pin.jump_url pin_content = pin.content output_str = f"-**(from `{pin_author}` on {pin_dt_str})** {pin_content}\n" output_str += f"Message link: <{pin_url}>\n" output_str += f"Attachment links: {attachment_str}" if len(output_str) > 2000: await ctx.send(content=BOT_ERROR.ARCHIVE_ERROR_LENGTH(pin_url)) else: await channel_to_message.send(content=output_str) end_message = f"Pinned message are archived in {channel_to_message.mention}. If the archive messages look good, use **{CONFIG.prefix}unpin_all** to remove the pins in {channel_to_archive.mention}" await ctx.send(content=end_message)
async def leave(self, ctx: commands.Context): ''' Leave the Secret Santa ''' if (self.exchange_started): await ctx.send(BOT_ERROR.EXCHANGE_IN_PROGRESS_LEAVE("a mod")) return currAuthor = ctx.author if (self.SecretSantaHelper.user_is_participant(currAuthor.id, self.usr_list)): (index, user) = self.SecretSantaHelper.get_participant_object( currAuthor.id, self.usr_list) self.usr_list.remove(user) popped_user = self.config['members'].pop(str(user.usrnum)) self.config.write() if (self.is_paused): self.user_left_during_pause = True await ctx.send( currAuthor.mention + f" has left the {str(ctx.guild)} Secret Santa exchange") else: await ctx.send(BOT_ERROR.UNJOINED) return
async def echo(self, ctx: commands.Context, *, content: str): ''' [content] = echos back the [content] ''' BOT_ERROR.output_info(content, self.logger) await ctx.send(content)
async def manage_reactions(self, payload: discord.RawReactionActionEvent): if (self.role_channel == None): # if no role channel assigned, self.role_channel = self.bot.get_channel(CONFIG.role_channel) if ( CONFIG.role_channel != -1 ) else None # attempt to get role channel if ( self.role_channel == None ): # if that fails (CONFIG.role_channel == -1 or get_channel fails) BOT_ERROR.output_error(BOT_ERROR.REACTION_ROLE_UNASSIGNED, self.logger) return # end command else: pass # reassignment of role_channel worked else: pass # role_channel is assigned message_id = payload.message_id channel_id = payload.channel_id emoji = payload.emoji emoji_str = str(payload.emoji) guild = self.bot.get_guild(payload.guild_id) user = guild.get_member(payload.user_id) if channel_id == self.role_channel.id: message = None async for message in self.role_channel.history(limit=200): if message.id == message_id: break if message != None: content = message.content.split("\n") for line in content: if ((line[0:2] == "~~") and (line[-1] == "~") ): # don't pay attention to lines that are crossed out continue line_tokens = [ i for i in line.split(" ") if i ] # remove empty strings for quality of life (doesn't break with extra spaces) test_emote_idx = for_idx = test_role_id_idx = -1 try: for_idx = line_tokens.index("for") test_emote_idx, test_role_id_idx = for_idx - 1, for_idx + 1 except: for_idx = -1 if (for_idx != -1): # no 'for' or 'for' is in the wrong place test_emote = line_tokens[test_emote_idx] test_role_id = int(line_tokens[test_role_id_idx][3:-1]) BOT_ERROR.output_info( f"Test emote={test_emote.encode('raw_unicode_escape')}, Input emote={emoji_str.encode('raw_unicode_escape')}", self.logger) found_emoji = False if emoji.is_unicode_emoji(): found_emoji = (emoji_str == test_emote) else: found_emoji = (emoji_str[1:-1] in test_emote) if found_emoji: role = guild.get_role(test_role_id) BOT_ERROR.output_info( f"Role added/removed=@{role.name}, user={user.name}", self.logger) if payload.event_type == "REACTION_ADD": await user.add_roles(role) else: await user.remove_roles(role) return
async def start(self, ctx: commands.Context): ''' Begin the Secret Santa ''' currAuthor = ctx.author if (currAuthor.top_role == ctx.guild.roles[-1]): # first ensure all users have all info submitted all_fields_complete = True for user in self.usr_list: if (user.wishlisturl_is_set() and user.pref_is_set()): pass else: all_fields_complete = False try: await currAuthor.send( BOT_ERROR.HAS_NOT_SUBMITTED(user.name)) await ctx.send( "`Partner assignment cancelled: participant info incomplete.`" ) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await ctx.send(currAuthor.mention + BOT_ERROR.DM_FAILED) BOT_ERROR.output_error( currAuthor.mention + BOT_ERROR.DM_FAILED, self.logger) # select a random partner for each participant if all information is complete and there are enough people to do it if (all_fields_complete and (len(self.usr_list) > 1)): BOT_ERROR.output_info("Proposing a partner list", self.logger) potential_list = self.SecretSantaHelper.propose_partner_list( self.usr_list) while (not self.SecretSantaHelper.partners_are_valid( potential_list)): BOT_ERROR.output_info("Proposing a partner list", self.logger) potential_list = self.SecretSantaHelper.propose_partner_list( self.usr_list) # save to config file BOT_ERROR.output_info("Partner assignment successful", self.logger) for user in potential_list: (temp_index, temp_user ) = self.SecretSantaHelper.get_participant_object( int(user.idstr), self.usr_list) # get the user's object in usr_list (index, partner) = self.SecretSantaHelper.get_participant_object( int(user.partnerid), self.usr_list) # get their partner temp_user.partnerid = user.partnerid self.config['members'][str(user.usrnum)][ SecretSantaConstants.PARTNERID] = user.partnerid self.config.write() # tell participants who their partner is this_user = ctx.guild.get_member(int(user.idstr)) message_pt1 = f"{str(partner.name)}#{str(partner.discriminator)} is your Secret Santa partner! Mosey on over to their wishlist URL(s) and pick out a gift! Remember to keep it in the ${CONFIG.min_budget}-{CONFIG.max_budget} range.\n" message_pt2 = f"Their wishlist(s) can be found here: {partner.wishlisturl}\n" message_pt3 = f"And their gift preferences can be found here: {partner.preferences}\n" message_pt4 = f"If you have trouble accessing your partner's wishlist, try `{CONFIG.prefix}dmpartner` or contact an admin to get in touch with them. This is a *secret* santa, after all!" santa_message = message_pt1 + message_pt2 + message_pt3 + message_pt4 try: await this_user.send(santa_message) except Exception as e: BOT_ERROR.output_exception(e, self.logger) await currAuthor.send( f"Failed to send message to {this_user.name}#{this_user.discriminator} about their partner. Ask them to turn on server DMs for Secret Santa stuff." ) # mark the exchange as in-progress self.exchange_started = True self.is_paused = False self.config['programData']['exchange_started'] = True self.config.write() usr_list = copy.deepcopy(potential_list) await ctx.send( "Secret Santa pairs have been picked! Check your PMs and remember not to let your partner know. Have fun!" ) elif not all_fields_complete: await ctx.send(currAuthor.mention + BOT_ERROR.SIGNUPS_INCOMPLETE) elif not (len(self.usr_list) > 1): await ctx.send(BOT_ERROR.NOT_ENOUGH_SIGNUPS) else: await ctx.send(BOT_ERROR.UNREACHABLE) else: await ctx.send(BOT_ERROR.NO_PERMISSION(ctx.guild.roles[-1])) return