Ejemplo n.º 1
0
    async def _limited(self, ctx):
        '''
        Manages settings for limited role requests
        '''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        channel = doc['requests_opts']['channel']
        hidejoins = doc['requests_opts']['hidejoins']
        ratelimit = doc['requests_opts']['ratelimit']

        embed = discord.Embed(
            title=f'Limited Role Request Options for: {ctx.guild}')
        embed.set_footer(
            text=
            f'Use the "{ctx.prefix}help limited" command for help on changing these settings.'
        )

        if channel == None:
            embed.description = 'Requests are currently disabled for this guild.'
            return await ctx.send(embed=embed)

        embed.add_field(name='Posting Channel', value=f'<#{channel}>')
        embed.add_field(name='Join Command Hiding',
                        value='Enabled' if hidejoins else 'Disabled')
        embed.add_field(name='Join Command Ratelimiting',
                        value='Enabled' if ratelimit else 'Disabled')

        return await ctx.send(embed=embed)
Ejemplo n.º 2
0
    async def _list_send_embed(self, ctx, title, roles, *, footer=None):
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)
        roles = list(
            filter(lambda r: not r.is_default(),
                   reversed(roles)))  # Reversed without @everyone role

        role_list = []
        raw_list = []

        for role in roles:
            typeStr = doc['roles'][str(role.id)]['type'].title() if (
                doc and str(role.id) in doc['roles']) else None
            colorStr = '' if role.color == discord.Colour.default(
            ) else f' [{role.color}]'

            role_list.append(f'<@&{role.id}> (`{role.id}`)' +
                             (f' **{typeStr}**' if typeStr else ''))
            raw_list.append(f'{role.name}{colorStr} ({role.id})' +
                            f' {typeStr}' if typeStr else '')

        await utils.sendListEmbed(ctx,
                                  title,
                                  role_list,
                                  raw_override='\r\n'.join(raw_list),
                                  footer=footer)
Ejemplo n.º 3
0
    async def _limited_disable(self, ctx):
        '''Disables limited role requests for the guild'''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        if doc['requests_opts']['channel'] == None:
            return await utils.cmdFail(
                ctx, f'Requests are already disabled for this guild.')

        utils.guildKeySet(ctx.bot, ctx.guild, 'requests_opts.channel', None)
        return await utils.cmdSuccess(
            ctx, f'Requests are now disabled for this guild.')
Ejemplo n.º 4
0
    async def _limited_channel(self, ctx, channel: discord.TextChannel):
        '''Sets the channel that limited role requests will be posted in'''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        if doc['requests_opts']['channel'] == channel.id:
            return await utils.cmdFail(
                ctx, f'The requests channel is already {channel}.')

        utils.guildKeySet(ctx.bot, ctx.guild, 'requests_opts.channel',
                          channel.id)
        return await utils.cmdSuccess(
            ctx, f'The requests channel is now {channel}.')
Ejemplo n.º 5
0
    async def on_raw_reaction_add(self, payload):
        if not payload.member: return
        if payload.member.bot: return

        doc = utils.getGuildDoc(self.bot, payload.member.guild)
        if not doc: return

        request = doc['requests'][str(payload.message_id)]
        if not request: return

        if str(payload.emoji) == config.greenTick:
            await self.request_update(payload.member.guild, payload.message_id,
                                      request, 'approved', payload.member)
        elif str(payload.emoji) == config.redTick:
            await self.request_update(payload.member.guild, payload.message_id,
                                      request, 'denied', payload.member)

        return
Ejemplo n.º 6
0
    async def _leave(self, ctx, role: discord.Role):
        '''Leaves or cancels a request for a requestable role'''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        if not (doc and str(role.id) in doc['roles']):
            return await utils.cmdFail(
                ctx, f'"{role.name}" is not a requestable role.')

        if not role in ctx.author.roles:
            if doc['roles'][str(role.id)]['type'] == 'limited':
                return await self.bot.get_cog('LimitedRequests'
                                              ).request_cancel(ctx, role)

            return await utils.cmdFail(
                ctx, f'You do not have the role "{role.name}".')

        await ctx.author.remove_roles(role,
                                      reason='User left role via command')
        return await utils.cmdSuccess(ctx, f'You left the role "{role.name}".')
Ejemplo n.º 7
0
    async def request_cancel(self, ctx, role):
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        requests = list(
            filter(
                lambda e: e[1]['user'] == ctx.author.id and e[1]['role'] ==
                role.id, doc['requests'].items()))
        request = requests[-1] if requests else (None, None)

        if not request[1] or request[1]['status'] != 'pending':
            return await utils.cmdFail(
                ctx,
                f'You do not have a request pending for the role "{role.name}".'
            )

        await self.request_update(ctx.guild, request[0], request[1],
                                  'cancelled')
        return await utils.cmdSuccess(
            ctx, f'Your request for "{role.name}" has been cancelled.')
Ejemplo n.º 8
0
    async def _limited_option_toggle(self, ctx, user_setting, setting_key,
                                     setting_string):
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)
        current = doc['requests_opts'][setting_key]

        if user_setting is None:
            user_setting = not current

        human = 'enabled' if user_setting else 'disabled'

        if user_setting == current:
            return await utils.cmdFail(
                ctx,
                f'Limited role join command {setting_string} is already **{human}**.'
            )

        utils.guildKeySet(ctx.bot, ctx.guild, f'requests_opts.{setting_key}',
                          user_setting)
        return await utils.cmdSuccess(
            ctx,
            f'Limited role join command {setting_string} is now **{human}**.')
Ejemplo n.º 9
0
    async def _list(self, ctx):
        '''Lists all requestable roles'''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)
        has_manage_roles = commands.has_permissions(manage_roles=True)(ctx)

        if not (doc and len(doc['roles'])):
            return await utils.cmdFail(
                ctx, f'This server does not have any requestable roles.' +
                f' (Use the `{ctx.prefix}list all` command to list all server roles.)'
                if has_manage_roles else '')

        roles = list(
            filter(lambda r: str(r.id) in doc['roles'],
                   ctx.guild.roles))  # Roles in requestable roles

        await self._list_send_embed(
            ctx,
            'Requestable Roles',
            roles,
            footer=
            f'Use the "{ctx.prefix}list all" command to list all server roles.'
            if has_manage_roles else None)
Ejemplo n.º 10
0
    async def _join(self, ctx, role: discord.Role):
        '''
        Joins or requests a requestable role
        
        If the role is a open role, it will be joined. If the role is a limited role, a request is submitted.
        '''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        if not (doc and str(role.id) in doc['roles']):
            return await utils.cmdFail(
                ctx, f'"{role.name}" is not a requestable role.')

        if role in ctx.author.roles:
            return await utils.cmdFail(
                ctx, f'You already have the role "{role.name}".')

        if doc['roles'][str(role.id)]['type'] == 'limited':
            return await self.bot.get_cog('LimitedRequests').request_create(
                ctx, role)

        await ctx.author.add_roles(role, reason='User joined role via command')
        return await utils.cmdSuccess(
            ctx, f'You have joined the role "{role.name}".')
Ejemplo n.º 11
0
    async def _role(self, ctx, role: discord.Role,
                    option: typing.Optional[str]):
        '''Adds, modifies, or removes a requestable role
        
        Adds or removes a role from the server's requestable roles or modifies an existing requestable roles type.'''
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        options = {
            'open': ['open', 'o'],
            'limited': ['limited', 'limit', 'l'],
            'remove': ['delete', 'del', 'd', 'remove', 'rem', 'r'],
            'add': ['add',
                    'a']  # Option resolves to 'open' but only for new roles.
        }

        resolved_option = None
        for key, val in options.items():
            if option in val:
                resolved_option = key

        if option and not resolved_option:
            return await utils.cmdFail(ctx,
                                       f'"{option}" is not a valid option.')

        # @everyone role or managed
        if role.is_default() or role.managed:
            return await utils.cmdFail(ctx,
                                       f'"{role.name}" is not a valid role.')

        role_request_type = None if not (doc and str(
            role.id) in doc['roles']) else doc['roles'][str(role.id)]['type']

        # Role info
        if resolved_option is None:
            embed = discord.Embed(
                title='Role Info',
                description=f'<@&{role.id}> (`{role.id}`)\n' +
                f'**Color:** {"None" if role.color == discord.Colour.default() else role.color}\n'
                + f'**Hoisted:** {"Yes" if role.hoist else "No"}\n' +
                f'**Mentionable:** {"Yes" if role.mentionable else "No"}\n' +
                '**Requestable:** ' + ('No' if not role_request_type else
                                       f'Yes, {role_request_type.title()}'),
                color=discord.Embed.Empty
                if role.color == discord.Colour.default() else role.colour)

            if commands.has_permissions(manage_roles=True)(ctx):
                embed.set_footer(
                    text=f'See "{ctx.prefix}help role" for valid subcommands.')

            return await ctx.send(embed=embed)

        # Remove role
        if resolved_option == 'remove':
            if not role_request_type:
                return await utils.cmdFail(
                    ctx, f'"{role.name}" is not a requestable role.')

            utils.guildKeyDel(ctx.bot, ctx.guild, f'roles.{role.id}')
            return await utils.cmdSuccess(
                ctx, f'"{role.name}" has been removed as a requestable role.')

        # Modify role type
        if role_request_type:
            if resolved_option == 'add':
                return await utils.cmdFail(
                    ctx, f'"{role.name}" is already a requestable role.')

            if role_request_type == resolved_option:
                return await utils.cmdFail(
                    ctx,
                    f'"{role.name}" is already a {resolved_option} requestable role.'
                )

            utils.guildKeySet(ctx.bot, ctx.guild, f'roles.{role.id}.type',
                              resolved_option)
            return await utils.cmdSuccess(
                ctx,
                f'"{role.name}" is now a {resolved_option} requestable role.')

        # Add role
        else:
            if resolved_option == 'add':
                resolved_option = 'open'

            utils.guildKeySet(ctx.bot, ctx.guild, f'roles.{role.id}',
                              {'type': resolved_option})
            return await utils.cmdSuccess(
                ctx,
                f'"{role.name}" has been added as a requestable {resolved_option} role.'
            )
Ejemplo n.º 12
0
    async def request_create(self, ctx, role):
        doc = utils.getGuildDoc(ctx.bot, ctx.guild)

        channel = doc['requests_opts']['channel']
        users_requests = list(
            filter(lambda e: e['user'] == ctx.author.id,
                   doc['requests'].values()))

        if doc['requests_opts']['hidejoins']:
            try:
                await ctx.message.delete(delay=5)
            except:
                pass
            delete = 15
        else:
            delete = None

        if not channel:
            return await utils.cmdFail(
                ctx,
                f'Limited role requests are currently disabled for this guild.',
                delete_after=delete)

        existing_request = list(
            filter(lambda e: e['role'] == role.id, users_requests))
        if existing_request and existing_request[-1]['status'] == 'pending':
            return await utils.cmdFail(
                ctx,
                f'You already have a request pending for the role "{role.name}".',
                delete_after=delete)

        # Ratelimit if enabled & ratelimit score above maximum; score calculated from status of requests in last 24h
        if doc['requests_opts']['ratelimit']:
            rl_score = 0
            for r in users_requests:
                rl_score += 0 if not r[
                    "status"] in LIMITED_RATELIMIT_SCORES else LIMITED_RATELIMIT_SCORES[
                        r["status"]]

            if rl_score > LIMITED_RATELIMIT_SCORE_MAX:
                return await utils.cmdFail(
                    ctx,
                    'You have too many recent requests. Please try again later.',
                    delete_after=delete)

        embed = discord.Embed(
            title='Limited Role Request',
            description=
            f'<@{ctx.message.author.id}> requested the <@&{role.id}> role.',
            color=discord.Colour.blurple(),
            timestamp=datetime.datetime.utcnow() +
            datetime.timedelta(hours=24))
        embed.set_author(
            name=f'{ctx.message.author} ({ctx.message.author.id})',
            icon_url=ctx.message.author.avatar_url)
        embed.add_field(name='Status',
                        value='Pending. React to approve or deny the request.')
        embed.set_footer(text='Request expires')

        embed_message = await ctx.guild.get_channel(channel).send(embed=embed)
        await embed_message.add_reaction(config.greenTick)
        await embed_message.add_reaction(config.redTick)

        utils.guildKeySet(
            ctx.bot, ctx.guild, f'requests.{embed_message.id}', {
                'channel': embed_message.channel.id,
                'created': datetime.datetime.utcnow().timestamp(),
                'role': role.id,
                'status': 'pending',
                'user': ctx.author.id,
            })

        return await utils.cmdSuccess(
            ctx,
            f'Your request for "{role.name}" has been submitted.',
            delete_after=delete)