def voice_log(self, event, user): if isinstance(user, DiscoUser): user = user.id sessions = GuildVoiceSession.select( GuildVoiceSession.user_id, GuildVoiceSession.channel_id, GuildVoiceSession.started_at, GuildVoiceSession.ended_at ).where( (GuildVoiceSession.user_id == user) & (GuildVoiceSession.guild_id == event.guild.id) ).order_by(GuildVoiceSession.started_at.desc()).limit(10) tbl = MessageTable() tbl.set_header('Channel', 'Joined At', 'Duration') for session in sessions: tbl.add( unicode(self.state.channels.get(session.channel_id) or 'UNKNOWN'), '{} ({} ago)'.format( session.started_at.isoformat(), humanize.naturaldelta(datetime.utcnow() - session.started_at)), humanize.naturaldelta(session.ended_at - session.started_at) if session.ended_at else 'Active') event.msg.reply(tbl.compile())
def words_top(self, event, target): if isinstance(target, DiscoUser): q = 'author_id' elif isinstance(target, DiscoChannel): q = 'channel_id' elif isinstance(target, DiscoGuild): q = 'guild_id' else: raise Exception("You should not be here") sql = """ SELECT word, count(*) FROM ( SELECT regexp_split_to_table(content, '\s') as word FROM messages WHERE {}=%s LIMIT 3000000 ) t GROUP BY word ORDER BY 2 DESC LIMIT 30 """.format(q) t = MessageTable() t.set_header('Word', 'Count') for word, count in Message.raw(sql, target.id).tuples(): if '```' in word: continue t.add(word, count) event.msg.reply(t.compile())
def debug_shards(self, event): msg = event.msg.reply('One moment, collecting shard information...') table = MessageTable() table.set_header('Shard', 'Guilds', 'Channels', 'Users') guilds_uniq = set() channels_uniq = set() users_uniq = set() guilds = self.bot.shards.all(lambda bot: list(bot.client.state.guilds.keys())) channels = self.bot.shards.all(lambda bot: list(bot.client.state.channels.keys())) users = self.bot.shards.all(lambda bot: list(bot.client.state.users.keys())) for shard in self.bot.shards.keys(): table.add(shard, len(guilds[shard]), len(channels[shard]), len(users[shard])) guilds_uniq |= set(guilds[shard]) channels_uniq |= set(channels[shard]) users_uniq |= set(users[shard]) msg.edit(table.compile() + '\n' + 'Unique Guilds: `{}`, Unique Channels: `{}`, Unique Users: `{}`'.format( len(guilds_uniq), len(channels_uniq), len(users_uniq), ))
def command_sql(self, event): conn = database.obj.get_conn() try: tbl = MessageTable(codeblock=False) with conn.cursor() as cur: start = time.time() cur.execute(event.codeblock.format(e=event)) dur = time.time() - start tbl.set_header(*[desc[0] for desc in cur.description]) for row in cur.fetchall(): tbl.add(*row) result = tbl.compile() if len(result) > 1900: return event.msg.reply( '_took {}ms_'.format(int(dur * 1000)), attachments=[('result.txt', result)]) event.msg.reply('```' + result + '```\n_took {}ms_\n'.format(int(dur * 1000))) except psycopg2.Error as e: event.msg.reply('```{}```'.format(e.pgerror))
def emojistats_custom(self, event, mode, sort): if mode not in ('server', 'global'): raise CommandFail( 'invalid emoji mode, must be `server` or `global`') if sort not in ('least', 'most'): raise CommandFail('invalid emoji sort, must be `least` or `most`') order = 'DESC' if sort == 'most' else 'ASC' if mode == 'server': q = CUSTOM_EMOJI_STATS_SERVER_SQL.format(order, guild=event.guild.id) else: q = CUSTOM_EMOJI_STATS_GLOBAL_SQL.format(order, guild=event.guild.id) q = list(GuildEmoji.raw(q).tuples()) tbl = MessageTable() tbl.set_header('Count', 'Name', 'ID') for emoji_id, name, count in q: tbl.add(count, name, emoji_id) event.msg.reply(tbl.compile())
def command_sql(self, event): """ This a Developer command which allows us to run Database commands without having to interact with the actual database directly. """ conn = database.obj.get_conn() try: tbl = MessageTable(codeblock=False) with conn.cursor() as cur: start = time.time() cur.execute(event.codeblock.format(e=event)) dur = time.time() - start if not cur.description: return event.msg.reply('_took {}ms - no result_'.format( int(dur * 1000))) tbl.set_header(*[desc[0] for desc in cur.description]) for row in cur.fetchall(): tbl.add(*row) result = tbl.compile() if len(result) > 1900: return event.msg.reply( '_took {}ms_'.format(int(dur * 1000)), attachments=[('result.txt', result)]) event.msg.reply('```' + result + '```\n_took {}ms_\n'.format(int(dur * 1000))) except psycopg2.Error as e: event.msg.reply('```{}```'.format(e.pgerror))
def infraction_search(self, event, query=None): q = (Infraction.guild_id == event.guild.id) if query and isinstance(query, list) and isinstance( query[0], DiscoUser): query = query[0].id elif query: query = ' '.join(query) if query and (isinstance(query, int) or query.isdigit()): q &= ((Infraction.id == int(query)) | (Infraction.user_id == int(query)) | (Infraction.actor_id == int(query))) elif query: q &= (Infraction.reason**query) user = User.alias() actor = User.alias() infractions = Infraction.select(Infraction, user, actor).join( user, on=((Infraction.user_id == user.user_id).alias('user') )).switch(Infraction).join( actor, on=((Infraction.actor_id == actor.user_id ).alias('actor'))).where(q).order_by( Infraction.created_at.desc()).limit(6) tbl = MessageTable() tbl.set_header('ID', 'Created', 'Type', 'User', 'Moderator', 'Active', 'Reason') last_tbl_str = None for inf in infractions: type_ = {i.index: i for i in Infraction.Types.attrs}[inf.type_] reason = inf.reason or '' if len(reason) > 256: reason = reason[:256] + '...' if inf.active: active = 'yes' if inf.expires_at: active += ' (expires in {})'.format( humanize.naturaldelta(inf.expires_at - datetime.utcnow())) else: active = 'no' tbl.add(inf.id, inf.created_at.isoformat(), str(type_), unicode(inf.user), unicode(inf.actor), active, clamp(reason, 128)) tbl_str = tbl.compile() if len(tbl_str) >= 2000: break last_tbl_str = tbl_str event.msg.reply(last_tbl_str or "No infractions found.")
def roles(self, event): if not event.guild: return tbl = MessageTable() tbl.set_header('ID', 'Role Name', 'Perms') for role in event.guild.roles.values(): tbl.add(role.id, role.name.replace('@', '@' + ZERO_WIDTH_SPACE), role.permissions.value) event.msg.reply(tbl.compile())
def help(self, event): """ Displays this message. """ tbl = MessageTable() tbl.set_header('Command', 'Desc') for command in self.bot.commands: print command.get_docstring().strip() tbl.add(command.triggers[0], command.get_docstring().strip()) event.msg.reply(tbl.compile())
def on_commands_errors(self, event): q = Command.select().join(Message, on=(Command.message_id == Message.id)).where( Command.success == 0).order_by( Message.timestamp.desc()).limit(10) tbl = MessageTable() tbl.set_header('ID', 'Command', 'Error') for err in q: tbl.add(err.message_id, '{}.{}'.format(err.plugin, err.command), err.traceback.split('\n')[-2]) event.msg.reply(tbl.compile())
def on_commands_usage(self, event): q = Command.select( fn.COUNT('*'), Command.plugin, Command.command, ).group_by(Command.plugin, Command.command).order_by(fn.COUNT('*').desc()).limit(25) tbl = MessageTable() tbl.set_header('Plugin', 'Command', 'Usage') for count, plugin, command in q.tuples(): tbl.add(plugin, command, count) event.msg.reply(tbl.compile())
def all_replies(self, event): foundReplies = AutoReply.select() if not len(foundReplies) >= 1: event.msg.reply('No auto replies found') return tbl = MessageTable(codeblock=False) tbl.set_header('word', 'reply') for reply in foundReplies: tbl.add(reply.word, reply.reply) result = tbl.compile() if len(result) > 1900: return event.msg.reply('Result is too big. Take a TXT file!', attachments=[('result.txt', result)]) return event.msg.reply('```' + result + '```')
def debug_events(self, event, size=50): name = self.name def get_event_count(bot): return bot.plugins[name].event_counter obj = sum(map(Counter, self.bot.shards.all(get_event_count).values()), Counter()) table = MessageTable() table.set_header('Event', 'Count', 'Per Minute', 'Per Second') runtime = max(1, int((time.time() - self.startup) / 60)) for name, count in sorted(obj.items(), key=lambda i: i[1], reverse=True)[:size]: table.add(name, count, count / runtime, (count / runtime) / 60) event.msg.reply(table.compile())
def debug_status(self, event): table = MessageTable() table.set_header('Metric', 'Value') table.add('Guilds', len(self.state.guilds)) table.add('Channels', len(self.state.channels)) table.add('Users', len(self.state.users)) try: import psutil memory = psutil.Process().memory_info() table.add('Memory RSS', sizeof_fmt(memory.rss)) table.add('Memory VMS', sizeof_fmt(memory.vms)) except ImportError: pass table.add('Greenlets', gevent.get_hub().loop.activecnt) event.msg.reply(table.compile())
def xp_leaderboard(self, event, places=None, offset=None): places = places if places else 10 offset = offset if offset else 0 user = User.alias() leaderboard = GuildMemberLevel.select(GuildMemberLevel, user).join( user, on=((GuildMemberLevel.user_id == user.user_id).alias('user')) ).where(GuildMemberLevel.guild_id == event.guild.id, GuildMemberLevel.xp > 0).order_by( GuildMemberLevel.xp.desc()).offset(offset).limit(places) tbl = MessageTable() tbl.set_header('Place', 'User', 'Level (XP)') for place, entry in enumerate(leaderboard, start=(offset if offset else 1)): tbl.add(place, str(entry.user), '{} ({})'.format(self.level_from_xp(entry.xp), entry.xp)) event.msg.reply(tbl.compile())