def details(self): if self.reason is CensorReason.INVITE: if self.ctx['guild']: return 'invite `{}` to {}'.format( self.ctx['invite'], S(self.ctx['guild']['name'], escape_codeblocks=True) ) else: return 'invite `{}`'.format(self.ctx['invite']) elif self.reason is CensorReason.DOMAIN: if self.ctx['hit'] == 'whitelist': return 'domain `{}` is not in whitelist'.format(S(self.ctx['domain'], escape_codeblocks=True)) elif self.ctx['hit'] == 'blacklist': return 'domain `{}` is in blacklist'.format(S(self.ctx['domain'], escape_codeblocks=True)) else: return 'because links are not allowed here' elif self.reason is CensorReason.WORD: return 'found blacklisted words `{}`'.format( ', '.join([S(i, escape_codeblocks=True) for i in self.ctx['words']])) elif self.reason is CensorReason.ZALGO: return 'found zalgo at position `{}` in text'.format( self.ctx['position'] ) else: return '...unsure why this message was censored. Please notify my developer.'
def command_tags_update(self, event, args): updated = Tag.update(value=S(' '.join(args.value))).where( (Tag.name == S(args.name.lower()))).execute() if not updated: event.msg.reply('no tag by that name exists') else: event.msg.reply('ok updated that tag for you')
def on_tags_raw(self, event, name): tag = self.fetch_tag(name, event.guild.id) if not tag: raise CommandFail('no tag exists by that name') content = tag.content source = self.source_re.search(content) if source: source = source.group(1).lower() url = self.remote_url.format(source) r = requests.get(url) r = self.import_parser.search(r.content) r = r.group(1).decode('utf8').strip('`\n') if r else '' data = {'here': '@here', 'everyone': '@everyone'} r = self.replace_variables(r, data) if r and content == r: return event.msg.reply(( 'This tag was imported from `{source}`: <https://github.com/ThaTiemsz' '/RawgoatTags/blob/master/tags/{source}.md>').format( source=source)) content = self.source_re.sub('', content) Tag.update(content=content).where((Tag.name == tag.name) & ( Tag.guild_id == tag.guild_id)).execute() if len(S(content, False, True)) > 1990: return event.msg.reply( 'This tag is too long. See attached file for the source.', attachments=[('tag_raw_{}.txt'.format(event.msg.id), content)]) event.msg.reply(u'```\n{}\n```'.format(S(content, False, True)))
def convert_field(self, value, conversion): if conversion in ('z', 's'): return S(unicode(value), escape_codeblocks=True) if conversion == 'e': return E(unicode(value)) if conversion == 'c': return S(E(unicode(value)), escape_codeblocks=True) return unicode(value)
def command_tags_create(self, event, args): _, created = Tag.get_or_create(name=S(args.name.lower()), defaults={ 'value': S(' '.join(args.value)), 'author_id': event.author.id, }) if not created: event.msg.reply('a tag by that name already exists') return event.msg.reply('ok created that tag for you')
def on_tag(self, event, name, value=None): # Plugins can easily store data locally using Disco's built in storage tags = self.storage.guild.ensure('tags') if value: tags[name] = value event.msg.reply(u':ok_hand: created tag `{}`'.format(S(name))) else: if name in tags: return event.msg.reply(tags[name]) else: return event.msg.reply(u'Unknown tag: `{}`'.format(S(name)))
def urban(self, event, term): r = requests.get('http://api.urbandictionary.com/v0/define', params={ 'term': term, }) r.raise_for_status() data = r.json() if not len(data['list']): return event.msg.reply(':warning: no matches') event.msg.reply(u'{} - {}'.format( S(data['list'][0]['word']), S(data['list'][0]['definition']), ))
def roles(self, event, pattern=None): buff = '' g = event.guild total = {} members = g.members.values() for member in members: for role_id in member.roles: total[role_id] = total.get(role_id, 0) + 1 roles = g.roles.values() roles = sorted(roles, key=lambda r: r.position, reverse=True) for role in roles: if pattern and role.name.lower().find(pattern.lower()) == -1: continue role_members = total.get(role.id, 0) if role.id != g.id else len( g.members) role = S(u'{} - {} ({} member{})\n'.format( role.id, role.name, role_members, 's' if role_members != 1 else ''), escape_codeblocks=True) if len(role) + len(buff) > 1980: event.msg.reply(u'```{}```'.format(buff)) buff = '' buff += role if not buff: return return event.msg.reply(u'```dns\n{}\n```'.format(buff))
def search(self, event, query: str): queries = [] if query.isdigit(): queries.append((User.user_id == query)) q = USER_MENTION_RE.findall(query) if len(q) and q[0].isdigit(): queries.append((User.user_id == q[0])) else: queries.append( (User.username**'%{}%'.format(query.replace('%', '')))) if '#' in query: username, discrim = query.rsplit('#', 1) if discrim is not None: queries.append(((User.username == username) & (User.discriminator == discrim))) users = User.select().where(reduce(operator.or_, queries)).limit(10) if len(users) == 0: raise CommandFail('No users found for query `{}`'.format( S(query, escape_codeblocks=True))) if len(users) == 1: if users[0].user_id in self.state.users: return self.info(event, self.state.users.get(users[0].user_id)) raise CommandSuccess( 'Found the following users for your query: ```{}```'.format( '\n'.join([ '{} ({})'.format(str(i), i.user_id) for i in users[:25] ])))
def trigger_reminders(self): reminders = Reminder.with_message_join().where( (Reminder.remind_at < (datetime.utcnow() + timedelta(seconds=1)))) for reminder in reminders: message = reminder.message_id channel = self.state.channels.get(message.channel_id) if not channel: self.log.warning( 'Not triggering reminder, channel %s was not found!', message.channel_id) reminder.delete_instance() continue channel.send_message( u'<@{}> you asked me at {} ({} ago) to remind you about: {}'. format( message.author_id, reminder.created_at, humanize.naturaldelta(reminder.created_at - datetime.utcnow()), S(reminder.content))) reminder.delete_instance() self.queue_reminders()
def on_dm_message(self, event): if event.channel.type != 1 or event.author.id == self.client.state.me.id: # Not in DM or self return if event.author.id in self.preping: return if list( self.bot.get_commands_for_message( self.bot.config.commands_require_mention, self.bot.config.commands_mention_rules, self.bot.config.commands_prefix, event)): return try: room = MailRoom.find_one(event.channel_id) except IndexError: self.create_room(event) else: if room.channel in self.room_greenlets: # I shouldn't need to do this, but it doesn't hurt... self.room_greenlets[room.channel].kill() self.room_greenlets[room.channel] = self.spawn_later( self.config['expiration'], self.expire_room, room) self.client.api.channels_messages_create( room.channel, S(event.content) or "<No message>") if event.attachments: self.client.api.channels_messages_create( room.channel, """__**Attachments:**__ {}""".format("\n".join( [f" - {a.url}" for a in event.attachments.values()])))
def command_locate(self, event, user): if isinstance(user, (int, long)): uid = user user = self.state.users.get(uid) if not user: return event.msg.reply('User {} not found.'.format(uid)) buff = '' count = 0 guilds = self.state.guilds.values() guilds = sorted(guilds, key=lambda g: g.name) for guild in guilds: member = guild.members.get(user.id) if not member: continue guild = S(u'{} - {} (level: {})\n'.format( guild.id, guild.name, self.get_level(guild, user.id)), escape_codeblocks=True) if len(guild) + len(buff) > 1920: event.msg.reply(u'```{}```'.format(buff)) buff = '' buff += guild count += 1 user = u'{} ({} - {})'.format(user, user.mention, user.id) if not count: return event.msg.reply(u'User {} not found.'.format(user)) event.msg.reply(u'```{}```*User {} found in {} server{}.*'.format( buff, user, count, 's' if count > 1 else ''))
def command_tags_delete(self, event, args): deleted = Tag.delete().where( (Tag.name == S(args.name.lower()))).execute() if deleted: event.msg.reply('ok deleted that tag for you') else: event.msg.reply('no tag exists by that name')
def help_command(self, event, name: str = None): # TODO: Fix issue with commands with same name different group """ ***The Help Command*** This command will provide information on a certain command, or list all commands if no command is specified. ***Optional Values*** > __name__ **The name of the target command** """ if name is None: collections = [plugin.command_list for plugin in self.bot.plugins.values()] complete = [] for collection in collections: complete.extend(collection) embed = MessageEmbed() embed.title = 'List of Commands' embed.color = 0x6832E3 embed.description = ', '.join(complete) else: for plugin in self.bot.plugins.values(): desc = plugin.get_help(name.lower()) if desc: break else: return event.msg.reply("Could not find command '{}'".format(S(name))) embed = MessageEmbed() embed.title = '**{}**'.format(name) embed.color = 0x6832E3 embed.description = desc event.msg.reply(" ", embed=embed)
def fetch_tag(self, name, guild_id): try: tag = Tag.select(Tag).where((Tag.name == S(name)) & (Tag.guild_id == guild_id)).get() except Tag.DoesNotExist: return return tag
def search(self, event, query): queries = [] if query.isdigit(): queries.append((User.user_id == query)) q = USER_MENTION_RE.findall(query) if len(q) and q[0].isdigit(): queries.append((User.user_id == q[0])) else: queries.append((User.username ** u'%{}%'.format(query.replace('%', '')))) if '#' in query: username, discrim = query.rsplit('#', 1) if discrim.isdigit(): queries.append(( (User.username == username) & (User.discriminator == int(discrim)))) users = User.select().where(reduce(operator.or_, queries)) if len(users) == 0: return event.msg.reply(u'No users found for query `{}`'.format(S(query, escape_codeblocks=True))) if len(users) == 1: if users[0].user_id in self.state.users: return self.info(event, self.state.users.get(users[0].user_id)) return event.msg.reply(u'Found the following users for your query: ```{}```'.format( u'\n'.join(map(lambda i: u'{} ({})'.format(unicode(i), i.user_id), users[:25])) ))
def generate_simple(chan_config): info = self.action_simple.get(action) if config._custom: if action in config._custom: info = config._custom[action] contents = self.fmt.format(six.text_type(info['format']), e=event, **details) msg = u':{}: {}'.format( info['emoji'], S(contents), ) if chan_config.timestamps: ts = pytz.utc.localize(datetime.utcnow()).astimezone( chan_config.tz) msg = '`[{}]` '.format(ts.strftime('%H:%M:%S')) + msg if len(msg) > 2000: msg = msg[0:1997] + '...' return msg
def emoji(self, event, emoji): if not EMOJI_RE.match(emoji): return event.msg.reply(u'Unknown emoji: `{}`'.format(emoji)) fields = [] name, eid = EMOJI_RE.findall(emoji)[0] fields.append('**ID:** {}'.format(eid)) fields.append('**Name:** {}'.format(S(name))) guild = self.state.guilds.find_one(lambda v: eid in v.emojis) if guild: fields.append('**Guild:** {} ({})'.format(S(guild.name), guild.id)) url = 'https://discordapp.com/api/emojis/{}.png'.format(eid) r = requests.get(url) r.raise_for_status() return event.msg.reply('\n'.join(fields), attachments=[('emoji.png', r.content)])
def roles(self, event): buff = '' for role in event.guild.roles.values(): role = S(u'{} - {}\n'.format(role.id, role.name), escape_codeblocks=True) if len(role) + len(buff) > 1990: event.msg.reply(u'```{}```'.format(buff)) buff = '' buff += role return event.msg.reply(u'```{}```'.format(buff))
def details(self): if self.reason is CensorReason.INVITE: if self.ctx['guild']: return u'invite `{}` to {}'.format(self.ctx['invite'], S(self.ctx['guild']['name'], escape_codeblocks=True)) else: return u'invite `{}`'.format(self.ctx['invite']) elif self.reason is CensorReason.DOMAIN: if self.ctx['hit'] == 'whitelist': return u'domain `{}` is not in whitelist'.format(S(self.ctx['domain'], escape_codeblocks=True)) else: return u'domain `{}` is in blacklist'.format(S(self.ctx['domain'], escape_codeblocks=True)) elif self.reason is CensorReason.WORD: return u'found blacklisted words `{}`'.format( u', '.join([S(i, escape_codeblocks=True) for i in self.ctx['words']])) elif self.reason is CensorReason.ZALGO: return u'found zalgo at position `{}` in text'.format( self.ctx['position'] )
def on_tags_create(self, event, name, content): name = S(name) content = S(content) if len(content) > event.config.max_tag_length: raise CommandFail('tag content is too long (max {} characters)'.format(event.config.max_tag_length)) _, created = Tag.get_or_create( guild_id=event.guild.id, author_id=event.author.id, name=name, content=content ) if not created: raise CommandFail('a tag by that name already exists') raise CommandSuccess('ok, your tag named `{}` has been created'.format(name))
def S(self, text, restore=False): if not text: return '' chars = [('{', '['), ('}', ']'), ('|', '&')] for t in chars: a, b = t[0], t[1] if not restore: text = text.replace(a, '%{}%'.format(b)) continue text = text.replace('%{}%'.format(b), a) text = text.replace('%{}%'.format(a), b) return S(text, False, not restore)
def cmd_remind_list(self, event, limit=None, mode='server'): user = event.msg.author count = Reminder.count_for_user(user.id, event.guild.id) total_count = Reminder.count_for_user(user.id) embed = MessageEmbed() embed.title = '{} reminder{} ({} total)'.format( count if mode == 'server' else total_count, 's' if (count != 1 and mode == 'server') or (total_count != 1 and mode == 'global') else '', total_count) embed.set_author(name=u'{}#{}'.format( user.username, user.discriminator, ), icon_url=user.avatar_url) embed.color = get_dominant_colors_user(user, user.get_avatar_url('png')) embed.set_footer(text='You can cancel reminders with !r clear [ID]') if (count == 0 and mode == 'server') or total_count == 0: embed.description = 'You have no upcoming reminders{}.'.format( ' in this server. Use `!r list global` to list all your upcoming reminders' if total_count > 0 else '') else: query = Reminder.select(Reminder).where( (Reminder.message_id << Reminder.with_message_join( (Message.id, )).where( (Message.author_id == event.author.id) & (Message.guild_id == event.guild.id if mode == 'server' else True))) & (Reminder.remind_at > (datetime.utcnow() + timedelta(seconds=1)))).order_by( Reminder.remind_at).limit(limit) for reminder in query: time = humanize_duration(reminder.remind_at - datetime.utcnow()) channel = Message.select().where( Message.id == reminder.message_id).get().channel_id channel = self.state.channels.get(channel) embed.add_field( name=u'#{} in {}'.format(reminder.id, time), value=u'[`#{}`](https://discordapp.com/channels/{}/{}/{}) {}' .format( channel.name if channel.type != ChannelType.DM else 'Jetski', channel.guild_id if channel.type != ChannelType.DM else '@me', channel.id, reminder.message_id, S(reminder.content))) return event.msg.reply(embed=embed)
def channels_messages_create(self, channel, content=None, nonce=None, tts=False, attachment=None, attachments=[], embed=None, sanitize=False): payload = { 'nonce': nonce, 'tts': tts, } if attachment: attachments = [attachment] warnings.warn( 'attachment kwarg has been deprecated, switch to using attachments with a list', DeprecationWarning) if content: if sanitize: content = S(content) payload['content'] = content if embed: payload['embed'] = embed.to_dict() if attachments: if len(attachments) > 1: files = { 'file{}'.format(idx): tuple(i) for idx, i in enumerate(attachments) } else: files = { 'file': tuple(attachments[0]), } r = self.http( Routes.CHANNELS_MESSAGES_CREATE, dict(channel=channel), data={'payload_json': json.dumps(payload)}, files=files, ) else: r = self.http(Routes.CHANNELS_MESSAGES_CREATE, dict(channel=channel), json=payload) return Message.create(self.client, r.json())
def emoji(self, event, emoji): if not EMOJI_RE.match(emoji): return event.msg.reply(u'Unknown emoji: `{}`'.format(S(emoji))) fields = [] name, eid = EMOJI_RE.findall(emoji)[0] fields.append('**ID:** {}'.format(eid)) fields.append('**Name:** {}'.format(S(name))) guild = self.state.guilds.find_one(lambda v: eid in v.emojis) if guild: fields.append('**Guild:** {} ({})'.format(S(guild.name), guild.id)) anim = emoji.startswith('<a:') fields.append('**Animated:** {}'.format('Yes' if anim else 'No')) ext = 'gif' if anim else 'png' url = 'https://discordapp.com/api/emojis/{}.{}'.format(eid, ext) r = requests.get(url) r.raise_for_status() return event.msg.reply('\n'.join(fields), attachments=[('emoji.'+ext, r.content)])
def parse(self, rawargs, ctx=None): """ Parse a string of raw arguments into this argument specification. """ parsed = {} flags = {i.name: i for i in self.args if i.flag} if flags: new_rawargs = [] for offset, raw in enumerate(rawargs): if raw.startswith('-'): raw = raw.lstrip('-') if raw in flags: parsed[raw] = True continue new_rawargs.append(raw) rawargs = new_rawargs for index, arg in enumerate( (arg for arg in self.args if not arg.flag)): if not arg.required and index + arg.true_count > len(rawargs): continue if arg.count == 0: raw = rawargs[index:] else: raw = rawargs[index:index + arg.true_count] if arg.types: for idx, r in enumerate(raw): try: raw[idx] = self.convert(ctx, arg.types, r) except Exception: raise ArgumentError( u'cannot convert `{}` to `{}`'.format( S(r), ', '.join(arg.types), )) if arg.count == 1: raw = raw[0] if (not arg.types or arg.types == ['str']) and isinstance( raw, list): raw = ' '.join(raw) parsed[arg.name] = raw return parsed
def trigger_reminder(self, reminder: Reminder): message = Message.get(reminder.message_id) channel = self.state.channels.get(message.channel_id) if not channel: self.log.warning( 'Not triggering reminder, channel %s was not found!', message.channel_id) reminder.delete_instance() return msg = channel.send_message( '<@{}> you asked me on <t:{reminder_time}:f> (<t:{reminder_time}:R>) to remind you about: {}' .format( message.author_id, S(reminder.content), reminder_time=int( reminder.created_at.replace(tzinfo=pytz.UTC).timestamp()), ), allowed_mentions={'users': [str(message.author_id)]}) # Add the emoji options msg.add_reaction(SNOOZE_EMOJI) msg.add_reaction(GREEN_TICK_EMOJI) try: mra_event = self.wait_for_event( 'MessageReactionAdd', message_id=msg.id, conditional=lambda e: ((e.emoji.name == SNOOZE_EMOJI or e.emoji.id == GREEN_TICK_EMOJI_ID) and e.user_id == message.author_id )).get(timeout=30) except gevent.Timeout: reminder.delete_instance() return finally: # Cleanup try: msg.delete_all_reactions() except APIException: # We don't have permission to remove reactions, but, we don't want to fail the reminder. pass if mra_event.emoji.name == SNOOZE_EMOJI: reminder.remind_at = datetime.utcnow() + timedelta(minutes=20) reminder.save() msg.edit( 'Ok, I\'ve snoozed that reminder. You\'ll get another notification in 20 minutes.' ) return reminder.delete_instance()
def command_tags_search(self, event, args): query = Tag.select() if args.name: query = query.where(Tag.name**'%{}%'.format(S(args.name.lower()))) if args.value: query = query.where(Tag.value**'%{}%'.format(S( args.value.lower()))) if args.author: if args.author.isdigit(): query = query.where(Tag.author_id == int(args.author)) else: matches = USER_MENTION_RE.findall(args.author) if not matches: return event.msg.reply('invalid author argument') query = query.where(Tag.author_id == int(matches[0])) query = query.limit(50) event.msg.reply('Results: {}'.format(', '.join(i.name for i in query)))
def try_levelup(self, event, level): if event.config.actions.message: event.channel.send_message( ':ok_hand: You are now level {} in {}!'.format( level, event.guild.name)) if event.config.actions.chat: event.channel.send_message( S(':ok_hand: {} is now level {}!'.format(event.author, level))) if event.config.rewards: if event.config.rewards[level]: event.member.add_role(event.config.rewards[level], reason="Leveled Up!")
def on_tags(self, event, name): try: tag = Tag.select(Tag, User).join( User, on=(User.user_id == Tag.author_id )).where((Tag.guild_id == event.guild.id) & (Tag.name == S(name))).get() except Tag.DoesNotExist: raise CommandFail('no tag by that name exists') # Track the usage of the tag Tag.update(times_used=Tag.times_used + 1).where((Tag.guild_id == tag.guild_id) & (Tag.name == tag.name)).execute() event.msg.reply(':information_source: {}'.format(tag.content))