async def quote_stats(self, ctx: commands.Context): """!kazhelp description: Get quote statistics. """ em = discord.Embed(title="Quote statistics") em.add_field(name="Total quotes", value=str(c.get_total_quotes())) em.add_field(name="Quoted users", value=str(c.get_total_quoted_users())) most_quoted = c.get_top_quoted() most_quoted_strs = [ '{.name} ({} quotes)'.format(u, total) for u, total in most_quoted ] em.add_field(name="Most quoted", value='{}'.format(format_list(most_quoted_strs))) most_saved = c.get_top_saved() most_saved_strs = [ '{.name} ({} quotes saved)'.format(u, total) for u, total in most_saved ] em.add_field(name="Top quoters", value='{}'.format(format_list(most_saved_strs))) await self.send_message(ctx.message.channel, embed=em)
def format_list(reminders: List[ReminderData]) -> str: """ Format the input list for sending to a user. """ items = [] for reminder in reminders: build_str = [] if reminder.channel_id: build_str.append( "In {channel} at {remind_time} UTC (in {delta})") else: build_str.append("At {remind_time} UTC (in {delta})") if reminder.renew_data: renew_data = reminder.renew_data build_str.append(" and every {interval}") if renew_data.limit_time: build_str.append(" until {limit_time} up to") build_str.append(" {limit} times") build_str.append(": {message}") items.append(''.join(build_str).format( delta=format_timedelta(reminder.remind_time - datetime.utcnow()), **reminder.str_dict(), **(reminder.renew_data.str_dict() if reminder.renew_data else {}))) return format_list(items) if items else 'None'
async def queue_list(self, ctx): """ [MOD ONLY] Lists the current queue of upcoming spotlights. """ logger.debug("queue list: {}".format(message_log_str(ctx.message))) self._load_applications() logger.info("Listing queue for {0.author!s} in {0.channel!s}".format(ctx.message)) app_strings = self._get_queue_list() if app_strings: app_list_string = format_list(app_strings) else: app_list_string = 'Empty' await self.send_embed_list(title=self.QUEUE_HEADING, contents=app_list_string)
async def finduser(self, ctx, search_term: str, page: int = 1): """ [MOD ONLY] User search. This command searches the name and aliases fields. Arguments: * <search_term>: Required. A substring to search for in the user database's name and aliases fields. Example: .notes finduser Indium If there is a user called "IndiumPhosphide", they would be matched. """ search_term_s = search_term[:Limits.NAME] logger.info("notes finduser: {}".format(message_log_str(ctx.message))) # Get results results = c.search_users(search_term_s) # Prepare for display len_results = len(results) total_pages = int(math.ceil(len_results / self.USEARCH_PAGE_SIZE)) page = max(1, min(total_pages, page)) results_lines = [] start_index = (page - 1) * self.USEARCH_PAGE_SIZE end_index = start_index + self.USEARCH_PAGE_SIZE for user in results[start_index:end_index]: matched_alias = self._find_match_field(user, search_term_s) # Format this user for the list display if not matched_alias: results_lines.append("{} - Canonical name: {}".format( self.format_display_user(user), user.name)) else: results_lines.append("{} - Alias: {}".format( self.format_display_user(user), matched_alias.name)) # Output - should always be sub-2000 characters (given length limits + page size) heading = self.USEARCH_HEADING_F.format(page=page, pages=total_pages, total=len_results, query=search_term_s) await self.bot.say("{}\n\n{}".format(heading, format_list(results_lines)))
async def subwatch(self, ctx: commands.Context): """!kazhelp brief: Show Subwatch configuration. description: Show the current subwatch configuration. """ channel_strings = [] for channel, ch_info in self.cog_state.channels.items(): channel_strings.append("{}: {}".format( channel.mention, ', '.join('/r/' + name for name in ch_info.subreddits))) await self.send_message( ctx.message.channel, ctx.message.author.mention + '\n' + (format_list(channel_strings) if channel_strings else 'No subwatch configured'))
async def filter_list(self, ctx, filter_type: str = None): """!kazhelp description: | Lists the current filters. If `filter_type` is not given, lists all filters; otherwise, lists the specified filter. parameters: - name: filter_type optional: True default: both description: "Filter list: `del` or `warn` (shorthand: `d` or `w`)." examples: - command: .filter list description: Shows both auto-warn and auto-delete lists. - command: .filter list warn description: Shows warn filter list. - command: .filter list del description: Shows auto-delete filter list. - command: .filter l w description: "Shorthand version of `.filter list warn`." """ if filter_type is None: # not passed - list both await ctx.invoke(self.filter_list, 'del') await ctx.invoke(self.filter_list, 'warn') else: validated_type = await self.validate_filter_type(filter_type) if validated_type is None: # error messages and logging already managed return logger.info("filter_list: listing '{}' list for {}".format( validated_type, ctx.message.author)) filter_list = self.cog_state.get(validated_type) if filter_list: list_str = format_list(filter_list) else: list_str = 'Empty' heading_str = self.list_headings[validated_type] say_strings = split_code_chunks_on( list_str, MSG_MAX_LEN - len(heading_str) - 2) await self.bot.say("{}\n{}".format(heading_str, say_strings[0])) for say_str in say_strings[1:]: await self.bot.say(say_str)
async def filter_list(self, ctx, filter_type: str = None): """ [MOD ONLY] Lists the current filters. If `filter_type` is not given, lists all filters; otherwise, lists the specified filter. Examples: .filter list - Shows both auto-warn and auto-delete lists. .filter list warn - Shows warn filter list. .filter list del - Shows auto-delete filter list. You can use single-letter mnemonics for convenience: .filter l w - Shows warn filter list. """ logger.info("filter_list: {}".format(message_log_str(ctx.message))) if filter_type is None: # not passed - list both await ctx.invoke(self.filter_list, 'del') await ctx.invoke(self.filter_list, 'warn') else: validated_type = await self.validate_filter_type(filter_type) if validated_type is None: # error messages and logging already managed return logger.info("filter_list: listing '{}' list for {}".format( validated_type, ctx.message.author)) filter_list = self.filter_cfg.get("filter", validated_type) if filter_list: list_str = format_list(filter_list) else: list_str = 'Empty' heading_str = self.list_headings[validated_type] say_strings = split_code_chunks_on( list_str, MSG_MAX_LEN - len(heading_str) - 2) await self.bot.say("{}\n{}".format(heading_str, say_strings[0])) for say_str in say_strings[1:]: await self.bot.say(say_str)
async def list(self, ctx: commands.Context): """ Lists all future reminders you've requested. """ logger.info("reminder list: {}".format(message_log_str(ctx.message))) items = [] filtered = filter(lambda r: r.user_id == ctx.message.author.id, self.reminders) sorted_reminders = sorted(filtered, key=lambda r: r.remind_time) for reminder in sorted_reminders: items.append("At {} UTC (in {}): {}".format( format_datetime(reminder.remind_time), format_timedelta(reminder.remind_time - datetime.utcnow()), reminder.message )) if items: reminder_list = format_list(items) else: reminder_list = 'None' await self.bot.send_message(ctx.message.author, "**Your reminders**\n" + reminder_list) try: await self.bot.delete_message(ctx.message) except discord.Forbidden: pass # no permission or in a PM; oh well, this is not critical
async def queue_showcase(self, ctx, *, month: NaturalDateConverter=None): """ [MOD ONLY] Lists a month's queue in the showcase format. Arguments: * month: Optional. Specify the month to list applications for. Default: next month. Examples: .spotlight q s 2018-03 .spotlight q s March 2018 """ logger.debug("queue showcase: {}".format(message_log_str(ctx.message))) self._load_applications() logger.info("Listing showcase queue for {0.author!s} in {0.channel!s}".format(ctx.message)) month = month # type: datetime # figure out month start/end times if not month: month = get_month_offset(datetime.utcnow(), 1) else: month = truncate(month, 'month') month_end = get_month_offset(month, 1) month_ts, month_end_ts = utctimestamp(month), utctimestamp(month_end) app_strings = self._get_queue_list(showcase=True) # filter by month filt_app_strings = [] for queue_item, app_string in zip(self.queue_data, app_strings): if month_ts <= queue_item['start'] < month_end_ts: filt_app_strings.append(app_string) if filt_app_strings: app_list_string = format_list(filt_app_strings) else: app_list_string = 'Empty' await self.bot.say('{}\n```{}```'.format(self.QUEUE_HEADING, app_list_string))
async def list(self, ctx): """ [MOD ONLY] List all the spotlight applications in summary form. """ logger.debug("list: {}".format(message_log_str(ctx.message))) self._load_applications() logger.info("Listing all spotlight applications for {0.author!s} in {0.channel!s}" .format(ctx.message)) # format each application as a string app_str_list = [] for app in self.applications: if app.is_valid: app_str_list.append(app.discord_str()) else: # deleted entries: blank username/project name or blank user/'DELETED' project app_str_list.append(None) continue # format into a string list for display app_list_string = format_list(app_str_list) if app_str_list else 'Empty' # cleanup for deleted records # We don't have a dedicated column for this, so hacky regex post-numbering it is! app_list_string = re.sub(r'(^|\n)\s*\d+\. None(\n|$)', '\n', app_list_string) await self.send_embed_list(title=self.LIST_HEADING, contents=app_list_string)