Beispiel #1
0
    def avatar(self, event, user=None):
        if user is None:
            user = event.author

        user_id = 0
        if isinstance(user, (int, long)):
            user_id = user
            user = self.state.users.get(user)

        if user and not user_id:
            user = self.state.users.get(user.id)

        if not user:
            if user_id:
                try:
                    user = self.client.api.users_get(user_id)
                except APIException:
                    raise CommandFail('unknown user')
                User.from_disco_user(user)
            else:
                raise CommandFail('unknown user')

        ext = 'gif' if user.avatar.startswith('a_') else 'png'
        url = user.get_avatar_url()
        r = requests.get(url)
        r.raise_for_status()
        event.msg.reply('', attachments=[('{}.{}'.format(user.id, ext), r.content)])
Beispiel #2
0
    def infraction_duration(self, event, infraction, duration):
        try:
            inf = Infraction.get(id=infraction)
        except Infraction.DoesNotExist:
            raise CommandFail('invalid infraction (try `!infractions recent`)')

        if inf.actor_id != event.author.id and event.user_level < CommandLevels.ADMIN:
            raise CommandFail('only administrators can modify the duration of infractions created by other moderators')

        if not inf.active:
            raise CommandFail('that infraction is not active and cannot be updated')

        expires_dt = parse_duration(duration, inf.created_at)

        converted = False
        if inf.type_ in [Infraction.Types.MUTE.index, Infraction.Types.BAN.index]:
            inf.type_ = Infraction.Types.TEMPMUTE if inf.type_ == Infraction.Types.MUTE.index else Infraction.Types.TEMPBAN
            converted = True
        elif inf.type_ not in [Infraction.Types.TEMPMUTE.index, Infraction.Types.TEMPBAN.index, Infraction.Types.TEMPROLE.index]:
            raise CommandFail('cannot set the duration for that type of infraction')

        inf.expires_at = expires_dt
        inf.save()
        self.queue_infractions()

        if converted:
            raise CommandSuccess('ok, I\'ve made that infraction temporary, it will now expire on {}'.format(
                inf.expires_at.isoformat()
            ))
        else:
            raise CommandSuccess('ok, I\'ve updated that infractions duration, it will now expire on {}'.format(
                inf.expires_at.isoformat()
            ))
Beispiel #3
0
    def clean(self, event, user=None, size=25, typ=None, mode='all'):
        """
        Removes messages
        """
        if 0 > size >= 10000:
            raise CommandFail('too many messages must be between 1-10000')

        lock = rdb.lock('clean-{}'.format(event.channel.id))
        if not lock.acquire(blocking=False):
            raise CommandFail('already running a clean on this channel')

        try:
            query = Message.select().where(
                (Message.deleted >> False)
                & (Message.channel_id == event.channel.id)
                & (Message.timestamp > (datetime.utcnow() - timedelta(days=13))
                   )).join(User).order_by(Message.timestamp.desc()).limit(size)

            if mode == 'bots':
                query = query.where((User.bot >> True))
            elif mode == 'user':
                query = query.where((User.user_id == user.id))

            msgs = list(reversed(query))
            event.channel.delete_messages(msgs)
            event.msg.reply(':wastebasket: Ok, deleted {} messages'.format(
                len(msgs))).after(5).delete()
        finally:
            lock.release()
Beispiel #4
0
    def tempmute(self, event, user, duration, reason=None):
        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)
            if not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            if event.config.mute_role in member.roles:
                raise CommandFail(u'{} is already muted'.format(member.user))

            expire_dt = parse_duration(duration)

            # Reset the infraction task so we make sure it runs after this new infraction
            self.inf_task.set_next_schedule(expire_dt)

            # Create the infraction
            Infraction.tempmute(self, event, member, reason, expire_dt)

            if event.config.confirm_actions:
                event.msg.reply(
                    maybe_string(
                        reason,
                        u':ok_hand: {u} is now muted for {t} (`{o}`)',
                        u':ok_hand: {u} is now muted for {t}',
                        u=member.user,
                        t=humanize.naturaldelta(expire_dt - datetime.utcnow()),
                    ))
        else:
            raise CommandFail('invalid user')
Beispiel #5
0
    def temprole(self, event, user, role, duration, reason=None):
        member = event.guild.get_member(user)
        if not member:
            raise CommandFail('invalid user')

        self.can_act_on(event, member.id)
        role_id = role if isinstance(role, (int, long)) else event.config.role_aliases.get(role.lower())
        if not role_id or role_id not in event.guild.roles:
            raise CommandFail('invalid or unknown role')

        if role_id in member.roles:
            raise CommandFail(u'{} is already in that role'.format(member.user))

        expire_dt = parse_duration(duration)
        Infraction.temprole(self, event, member, role_id, reason, expire_dt)
        self.queue_infractions()

        self.confirm_action(event, maybe_string(
            reason,
            u':ok_hand: {u} is now in the {r} role for {t} (`{o}`)',
            u':ok_hand: {u} is now in the {r} role for {t}',
            r=event.guild.roles[role_id].name,
            u=member.user,
            t=humanize.naturaldelta(expire_dt - datetime.utcnow()),
        ))
Beispiel #6
0
    def unmute(self, event, user, reason=None):
        # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server
        member = event.guild.get_member(user)

        if member:
            self.can_act_on(event, member.id)
            if not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            if event.config.mute_role not in member.roles:
                raise CommandFail(u'{} is not muted'.format(member.user))

            Infraction.clear_active(
                event, member.id,
                [Infraction.Types.MUTE, Infraction.Types.TEMPMUTE])

            self.bot.plugins.get('ModLogPlugin').create_debounce(
                event,
                member.user.id,
                'unmuted',
                actor=unicode(event.author),
                roles=[event.config.mute_role])

            member.remove_role(event.config.mute_role)

            if event.config.confirm_actions:
                event.msg.reply(u':ok_hand: {} is now unmuted'.format(
                    member.user))
        else:
            raise CommandFail('invalid user')
Beispiel #7
0
    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())
Beispiel #8
0
    def unmute(self, event, user, reason=None):
        # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server
        member = event.guild.get_member(user)

        if member:
            if not event.config.temp_mute_role and not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            roles = {event.config.temp_mute_role, event.config.mute_role
                     } & set(member.roles)
            if not len(roles):
                raise CommandFail('{} is not muted'.format(member.user))

            Infraction.update(active=False).where(
                (Infraction.guild_id == event.guild.id)
                & (Infraction.user_id == member.user.id)
                & (Infraction.type_ == Infraction.Types.TEMPMUTE)
                & (Infraction.active == 1)).execute()

            self.bot.plugins.get('ModLogPlugin').create_debounce(
                event,
                member.user.id,
                'unmuted',
                actor=unicode(event.author),
                roles=roles)

            for role in roles:
                member.remove_role(role)

            if event.config.confirm_actions:
                event.msg.reply(u':ok_hand: {} is now unmuted'.format(
                    member.user))
        else:
            raise CommandFail('invalid user')
Beispiel #9
0
    def unmute(self, event, user, reason=None):
        # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server
        member = event.guild.get_member(user)

        if member:
            self.can_act_on(event, member.id)
            if not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            if event.config.mute_role not in member.roles:
                raise CommandFail(u'{} is not muted'.format(member.user))

            Infraction.clear_active(event, member.id, [Infraction.Types.MUTE, Infraction.Types.TEMPMUTE])

            self.call(
                'ModLogPlugin.create_debounce',
                event,
                ['GuildMemberUpdate'],
                role_id=event.config.mute_role,
            )

            member.remove_role(event.config.mute_role)

            self.call(
                'ModLogPlugin.log_action_ext',
                Actions.MEMBER_UNMUTED,
                event.guild.id,
                member=member,
                actor=unicode(event.author) if event.author.id != member.id else 'Automatic',
            )

            self.confirm_action(event, u':ok_hand: {} is now unmuted'.format(member.user))
        else:
            raise CommandFail('invalid user')
Beispiel #10
0
    def clean(self, event, user=None, size=25, typ=None, mode='all'):
        """
        Removes messages
        """
        if 0 > size >= 10000:
            raise CommandFail('too many messages must be between 1-10000')

        if event.channel.id in self.cleans:
            raise CommandFail('a clean is already running on this channel')

        query = Message.select(Message.id).where(
            (Message.deleted >> False)
            & (Message.channel_id == event.channel.id)
            & (Message.timestamp >
               (datetime.utcnow() - timedelta(days=13)))).join(User).order_by(
                   Message.timestamp.desc()).limit(size)

        if mode == 'bots':
            query = query.where((User.bot >> True))
        elif mode == 'user':
            query = query.where((User.user_id == user.id))

        messages = [i[0] for i in query.tuples()]

        if len(messages) > 100:
            msg = event.msg.reply(
                'Woah there, that will delete a total of {} messages, please confirm.'
                .format(len(messages)))

            msg.chain(False).\
                add_reaction(GREEN_TICK_EMOJI).\
                add_reaction(RED_TICK_EMOJI)

            try:
                mra_event = self.wait_for_event(
                    'MessageReactionAdd',
                    message_id=msg.id,
                    conditional=lambda e:
                    (e.emoji.id in (GREEN_TICK_EMOJI_ID, RED_TICK_EMOJI_ID) and
                     e.user_id == event.author.id)).get(timeout=10)
            except gevent.Timeout:
                return
            finally:
                msg.delete()

            if mra_event.emoji.id != GREEN_TICK_EMOJI_ID:
                return

            event.msg.reply(
                ':wastebasket: Ok please hold on while I delete those messages...'
            ).after(5).delete()

        def run_clean():
            for chunk in chunks(messages, 100):
                self.client.api.channels_messages_delete_bulk(
                    event.channel.id, chunk)

        self.cleans[event.channel.id] = gevent.spawn(run_clean)
        self.cleans[event.channel.id].join()
        del self.cleans[event.channel.id]
Beispiel #11
0
 def on_play(self, event, url):
     g = Guild.select(Guild).where((Guild.guild_id == event.guild.id)).get()
     
     if g.premium == False:
       raise CommandFail('This guild does not have premium enabled, please contact an Airplane global administrator.')
     
     # item = YoutubeDLInput(url, command='ffmpeg').pipe(BufferedOpusEncoderPlayable)
     # self.get_player(event.guild.id).queue.append(item)
     item = YoutubeDLInput(url)
     song = item.info
     if song['extractor'] is 'youtube':
         if song['is_live']:
             raise CommandFail('Sorry, live streams are not supported.')
     if song['duration'] > 7200:
         raise CommandFail('Sorry you are not allowed to play songs over 2 hours.')
     if song['duration'] > event.config.max_song_length:
         raise CommandFail('Sorry, you may not go over the server time limit.')
     item2 = item.pipe(BufferedOpusEncoderPlayable)
     self.get_player(event.guild.id).queue.append(item2)
     song = item.info
     if song['extractor'] is 'youtube':
         if song['artist']:
             return event.msg.reply('Now playing **{songname}** by **{author}**. Song length is `{duration}`'.format(songname=song['alt_title'], author=song['artist'], duration=timedelta(seconds=song['duration'])))
         else:
             return event.msg.reply('Now playing **{songname}** uploaded by **{author}**. Song length is `{duration}`'.format(songname=song['title'], author=song['uploader'], duration=timedelta(seconds=song['duration'])))
     else:
         return CommandSuccess('You\'re playing a song :D')
Beispiel #12
0
    def archive(self, event, size=50, mode=None, user=None, channel=None):
        if 0 > size >= 15000:
            raise CommandFail('too many messages must be between 1-15000')

        q = Message.select(Message.id).join(User).order_by(Message.id.desc()).limit(size)

        if mode in ('all', 'channel'):
            cid = event.channel.id
            if channel:
                cid = channel if isinstance(channel, (int, long)) else channel.id
            channel = event.guild.channels.get(cid)
            if not channel:
                raise CommandFail('channel not found')
            perms = channel.get_permissions(event.author)
            if not (perms.administrator or perms.read_messages):
                raise CommandFail('invalid permissions')
            q = q.where(Message.channel_id == cid)
        else:
            user_id = user if isinstance(user, (int, long)) else user.id
            if event.author.id != user_id:
                self.can_act_on(event, user_id)
            q = q.where(
                (Message.author_id == user_id) &
                (Message.guild_id == event.guild.id)
            )

        archive = MessageArchive.create_from_message_ids([i.id for i in q])
        event.msg.reply('OK, archived {} messages at {}'.format(len(archive.message_ids), archive.url))
Beispiel #13
0
    def cmd_remind(self, event, duration, content=None):
        if Reminder.count_for_user(event.author.id) > 15:
            raise CommandFail('You can only have 15 reminders going at once!')

        remind_at = parse_duration(duration)
        if remind_at > (datetime.utcnow() +
                        timedelta(seconds=5 * YEAR_IN_SEC)):
            raise CommandFail('That\'s too far in the future... I\'ll forget!')

        if event.msg.message_reference.message_id:
            referenced_msg: MessageReference = event.channel.get_message(
                event.msg.message_reference.message_id)
            content = 'https://discord.com/channels/{}/{}/{}'.format(
                self.state.channels.get(referenced_msg.channel_id).guild_id,
                referenced_msg.channel_id, referenced_msg.id)
        elif not content:
            raise CommandFail(
                'You need to provide content for the reminder, or reply to a message!'
            )

        r = Reminder.create(message_id=event.msg.id,
                            remind_at=remind_at,
                            content=content)
        self.reminder_task.set_next_schedule(r.remind_at)
        raise CommandSuccess(
            'I\'ll remind you at <t:{0}:f> (<t:{0}:R>)'.format(
                int(r.remind_at.replace(tzinfo=pytz.UTC).timestamp())))
Beispiel #14
0
    def mute(self, event, user, reason=None):
        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)
            if not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            existed = False
            # If the user is already muted check if we can take this from a temp
            #  to perma mute.
            if event.config.mute_role in member.roles:
                existed = Infraction.clear_active(event, member.id,
                                                  [Infraction.Types.TEMPMUTE])

                # The user is 100% muted and not tempmuted at this point, so lets bail
                if not existed:
                    raise CommandFail(u'{} is already muted'.format(
                        member.user))

            Infraction.mute(self, event, member, reason)

            if event.config.confirm_actions:
                existed = u' [was temp-muted]' if existed else ''
                event.msg.reply(
                    maybe_string(
                        reason,
                        u':ok_hand: {u} is now muted (`{o}`)' + existed,
                        u':ok_hand: {u} is now muted' + existed,
                        u=member.user,
                    ))
        else:
            raise CommandFail('invalid user')
Beispiel #15
0
 def manager_info(self, event, user, mode, item):
     user = self.state.users.get(user)
     if mode == 'add':
         special_list = rdb.hget('ServerManagers', '{}'.format(user.id))
         temp_list = []
         temp_list.append(item)
         final_list = str(temp_list).strip('[]')
         new = str('{}, {}'.format(special_list, final_list))
         rdb.hset('ServerManagers', '{}'.format(user.id), new)
         raise CommandSuccess('{} has been added to the list of server managers'.format(user))
     if mode == 'remove':
         special_list = rdb.hget('ServerManagers', '{}'.format(user.id))
         if special_list == None:
             raise CommandFail('User is not a manager on any Airplane protected servers.')
         temp_list = special_list.split(', ')
         found = False
         for x in temp_list:
             if x == item:
                 found = True
                 temp_list.remove(item)
         if found == False:
             raise CommandFail('something went wrong, please try again later')
         else:
             new = str(temp_list).strip('[]')
             rdb.hset('ServerManagers', '{}'.format(user.id), new)
             raise CommandSuccess('The server has been removed from the list of servers the user manages.')
Beispiel #16
0
    def jumbo(self, event, emojis):
        emojis = emojis.split(' ')
        if len(emojis) == 1:
            url = ext = ''
            emoji = emojis[0]
            if EMOJI_RE.match(emoji):
                _, eid = EMOJI_RE.findall(emoji)[0]
                ext = 'gif' if emoji.startswith('<a:') else 'png'
                url = 'https://cdn.discordapp.com/emojis/{}.{}?v=1'.format(eid, ext)
            else:
                ext = 'png'
                url = self.get_emoji_url(emoji)

            if not url:
                raise CommandFail('provided emoji is invalid')

            r = requests.get(url)
            try:
                r.raise_for_status()
            except requests.HTTPError:
                raise CommandFail('provided emoji is invalid')
            return event.msg.reply('', attachments=[('emoji.'+ext, r.content)])

        else:
            urls = []
            for emoji in emojis[:5]:
                if EMOJI_RE.match(emoji):
                    _, eid = EMOJI_RE.findall(emoji)[0]
                    urls.append('https://cdn.discordapp.com/emojis/{}.png?v=1'.format(eid))
                else:
                    url = self.get_emoji_url(emoji)
                    urls.append(url) if url else None

            width, height, images = 0, 0, []

            for r in Pool(6).imap(requests.get, urls):
                try:
                    r.raise_for_status()
                except requests.HTTPError:
                    continue

                img = Image.open(BytesIO(r.content))
                height = img.height if img.height > height else height
                width += img.width + 10
                images.append(img)

            if not images:
                raise CommandFail('provided emojis are invalid')

            image = Image.new('RGBA', (width, height))
            width_offset = 0
            for img in images:
                image.paste(img, (width_offset, 0))
                width_offset += img.width + 10

            combined = BytesIO()
            image.save(combined, 'png', quality=55)
            combined.seek(0)
            return event.msg.reply('', attachments=[('emoji.png', combined)])
Beispiel #17
0
    def command_markov_many(self, event, entity, count=5):
        if entity.id not in self.models:
            raise CommandFail('No model created yet for {}'.format(entity))

        for _ in range(int(count)):
            sentence = self.models[entity.id].make_sentence(max_overlap_total=500)
            if not sentence:
                raise CommandFail('Not enough data :(')
            event.msg.reply('{}: {}'.format(entity, sentence))
Beispiel #18
0
    def command_markov_one(self, event, entity):
        if entity.id not in self.models:
            raise CommandFail('No model created yet for {}'.format(entity))

        sentence = self.models[entity.id].make_sentence(max_overlap_ratio=1, max_overlap_total=500)
        if not sentence:
            raise CommandFail('Not enough data :(')

        event.msg.reply('{}: {}'.format(entity, sentence))
Beispiel #19
0
    def unlock_role(self, event, role_id):
        if role_id not in event.config.locked_roles:
            raise CommandFail('role %s is not locked' % role_id)

        if role_id in self.unlocked_roles and self.unlocked_roles[role_id] > time.time():
            raise CommandFail('role %s is already unlocked' % role_id)

        self.unlocked_roles[role_id] = time.time() + 300
        raise CommandSuccess('role is unlocked for 5 minutes')
Beispiel #20
0
    def reactions_clean(self, event, user, count=10, emoji=None):
        if isinstance(user, DiscoUser):
            user = user.id

        if count > 50:
            raise CommandFail('cannot clean more than 50 reactions')

        lock = rdb.lock('clean-reactions-{}'.format(user))
        if not lock.acquire(blocking=False):
            raise CommandFail('already running a clean on user')

        query = [
            (Reaction.user_id == user),
            (Message.guild_id == event.guild.id),
            (Message.deleted == 0),
        ]

        if emoji:
            emoji_id = EMOJI_RE.findall(emoji)
            if emoji_id:
                query.append((Reaction.emoji_id == emoji_id[0]))
            else:
                # TODO: validation?
                query.append((Reaction.emoji_name == emoji))

        try:
            reactions = list(
                Reaction.select(
                    Reaction.message_id,
                    Reaction.emoji_id,
                    Reaction.emoji_name,
                    Message.channel_id,
                ).join(
                    Message,
                    on=(Message.id == Reaction.message_id),
                ).where(reduce(operator.and_, query)).order_by(
                    Reaction.message_id.desc()).limit(count).tuples())

            if not reactions:
                raise CommandFail('no reactions to purge')

            msg = event.msg.reply('Hold on while I clean {} reactions'.format(
                len(reactions)))

            for message_id, emoji_id, emoji_name, channel_id in reactions:
                if emoji_id:
                    emoji = '{}:{}'.format(emoji_name, emoji_id)
                else:
                    emoji = emoji_name

                self.client.api.channels_messages_reactions_delete(
                    channel_id, message_id, emoji, user)

            msg.edit('Ok, I cleaned {} reactions'.format(len(reactions), ))
        finally:
            lock.release()
Beispiel #21
0
    def tempmute(self, event, user, duration=None, reason=None):
        if not duration and reason:
            duration = parse_duration(reason.split(' ')[0], safe=True)
            if duration:
                if ' ' in reason:
                    reason = reason.split(' ', 1)[-1]
                else:
                    reason = None
        elif duration:
            duration = parse_duration(duration)

        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)
            if not event.config.mute_role:
                raise CommandFail('mute is not setup on this server')

            if event.config.mute_role in member.roles:
                raise CommandFail(u'{} is already muted'.format(member.user))

            # If we have a duration set, this is a tempmute
            if duration:
                # Create the infraction
                Infraction.tempmute(self, event, member, reason, duration)
                self.queue_infractions()

                self.confirm_action(event, maybe_string(
                    reason,
                    u':ok_hand: {u} is now muted for {t} (`{o}`)',
                    u':ok_hand: {u} is now muted for {t}',
                    u=member.user,
                    t=humanize.naturaldelta(duration - datetime.utcnow()),
                ))
            else:
                existed = False
                # If the user is already muted check if we can take this from a temp
                #  to perma mute.
                if event.config.mute_role in member.roles:
                    existed = Infraction.clear_active(event, member.id, [Infraction.Types.TEMPMUTE])

                    # The user is 100% muted and not tempmuted at this point, so lets bail
                    if not existed:
                        raise CommandFail(u'{} is already muted'.format(member.user))

                Infraction.mute(self, event, member, reason)

                existed = u' [was temp-muted]' if existed else ''
                self.confirm_action(event, maybe_string(
                    reason,
                    u':ok_hand: {u} is now muted (`{o}`)' + existed,
                    u':ok_hand: {u} is now muted' + existed,
                    u=member.user,
                ))
        else:
            raise CommandFail('invalid user')
Beispiel #22
0
    def leave_role(self, event, name):
        role_id = event.config.group_roles.get(name.lower())
        if not role_id or role_id not in event.guild.roles:
            raise CommandFail('invalid or unknown group')

        member = event.guild.get_member(event.author)
        if role_id not in member.roles:
            raise CommandFail('you are not a member of that group')

        member.remove_role(role_id)
        raise CommandSuccess(u'you have left the {} group'.format(name))
Beispiel #23
0
    def role_add(self, event, user, role, reason=None, mode=None):
        role_obj = None

        if role.isdigit() and int(role) in event.guild.roles.keys():
            role_obj = event.guild.roles[int(role)]
        elif role.lower() in event.config.role_aliases:
            role_obj = event.guild.roles.get(event.config.role_aliases[role.lower()])
        else:
            # First try exact match
            exact_matches = [i for i in event.guild.roles.values() if i.name.lower().replace(' ', '') == role.lower()]
            if len(exact_matches) == 1:
                role_obj = exact_matches[0]
            else:
                # Otherwise we fuzz it up
                rated = sorted([
                    (fuzz.partial_ratio(role, r.name.replace(' ', '')), r) for r in event.guild.roles.values()
                ], key=lambda i: i[0], reverse=True)

                if rated[0][0] > 40:
                    if len(rated) == 1:
                        role_obj = rated[0][1]
                    elif rated[0][0] - rated[1][0] > 20:
                        role_obj = rated[0][1]

        if not role_obj:
            raise CommandFail('too many matches for that role, try something more exact or the role ID')

        author_member = event.guild.get_member(event.author)
        highest_role = sorted([event.guild.roles.get(r) for r in author_member.roles], key=lambda i: i.position, reverse=True)
        if not author_member.owner and (not highest_role or highest_role[0].position < role_obj.position):
            raise CommandFail('you can only {} roles that are ranked lower than your highest role'.format(mode))

        member = event.guild.get_member(user)
        if not member:
            raise CommandFail('invalid member')

        self.can_act_on(event, member.id)

        if mode == 'add' and role_obj.id in member.roles:
            raise CommandFail(u'{} already has the {} role'.format(member, role_obj.name))
        elif mode == 'remove' and role_obj.id not in member.roles:
            return CommandFail(u'{} doesn\'t have the {} role'.format(member, role_obj.name))

        self.bot.plugins.get('ModLogPlugin').create_debounce(
            event, member.user.id, mode + '_role', actor=event.author, reason=reason or 'no reason')

        if mode == 'add':
            member.add_role(role_obj.id)
        else:
            member.remove_role(role_obj.id)

        event.msg.reply(u':ok_hand: {} role {} to {}'.format('added' if mode == 'add' else 'removed',
            role_obj.name,
            member))
Beispiel #24
0
    def can_act_on(self, event, victim_id, throw=True):
        if event.author.id == victim_id:
            if not throw:
                return False
            raise CommandFail('cannot execute that action on yourself')

        victim_level = self.bot.plugins.get('CorePlugin').get_level(event.guild, victim_id)

        if event.user_level <= victim_level:
            if not throw:
                return False
            raise CommandFail('invalid permissions')

        return True
Beispiel #25
0
    def xp_unblock(self, event, user):
        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)
            success = XPBlock.delete().where(
                (XPBlock.guild_id == event.guild.id)
                & (XPBlock.user_id == user.id)).execute()

            if not success:
                raise CommandFail('{} was not blocked from gaining XP'.format(
                    user, ))
        else:
            raise CommandFail('Invalid user')

        raise CommandSuccess('Unblocked {} from gaining XP.'.format(member))
Beispiel #26
0
    def kick(self, event, user, reason=None):
        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)

            if event.config.notify_action_on and event.config.notify_action_on.kicks:
                try:
                    event.guild.get_member(user.id).user.open_dm(
                    ).send_message(
                        'You have been **Kicked** from the guild **{}** for `{}`'
                        .format(event.guild.name, reason or 'no reason'))
                except:
                    pass
            else:
                pass

            Infraction.kick(self, event, member, reason)
            self.confirm_action(
                event,
                maybe_string(
                    reason,
                    u':ok_hand: kicked {u} (`{o}`)',
                    u':ok_hand: kicked {u}',
                    u=member.user,
                ))
        else:
            raise CommandFail('invalid user')
Beispiel #27
0
    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)))
Beispiel #28
0
    def ban(self, event, user, reason=None):
        member = None

        if isinstance(user, (int, long)):
            self.can_act_on(event, user)
            Infraction.ban(self, event, user, reason, guild=event.guild)
        else:
            member = event.guild.get_member(user)
            if member:
                self.can_act_on(event, member.id)

                if event.config.notify_action_on and event.config.notify_action_on.bans:
                    try:
                        event.guild.get_member(user.id).user.open_dm(
                        ).send_message(
                            'You have been **Permanently Banned** from the guild **{}** for `{}`.'
                            .format(event.guild.name, reason
                                    or 'no reason specified.'))
                    except:
                        pass
                else:
                    pass

                Infraction.ban(self, event, member, reason, guild=event.guild)
            else:
                raise CommandFail('invalid user')

        self.confirm_action(
            event,
            maybe_string(
                reason,
                u':ok_hand: banned {u} (`{o}`)',
                u':ok_hand: banned {u}',
                u=member.user if member else user,
            ))
Beispiel #29
0
    def softban(self, event, user, reason=None):
        """
        Ban then unban a user from the server (with an optional reason for the modlog)
        """
        member = event.guild.get_member(user)
        if member:
            self.can_act_on(event, member.id)

            if event.config.notify_action_on and event.config.notify_action_on.bans:
                try:
                    event.guild.get_member(user.id).user.open_dm(
                    ).send_message(
                        'You have been **Kicked** from the guild **{}** for `{}`.'
                        .format(event.guild.name, reason
                                or 'no reason specified.'))
                except:
                    pass
            else:
                pass

            Infraction.softban(self, event, member, reason)
            self.confirm_action(
                event,
                maybe_string(
                    reason,
                    u':ok_hand: soft-banned {u} (`{o}`)',
                    u':ok_hand: soft-banned {u}',
                    u=member.user,
                ))
        else:
            raise CommandFail('invald user')
Beispiel #30
0
    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]
                ])))