示例#1
0
    async def add(self, ctx, *, string):
        """Adds quotes to a guild-specific list. Ideal formatting: "quote" - author <year>. For guild use only."""
        seperator = string.rfind('-')
        substring = string[:seperator - 1]
        startIndex = substring.find('\"')
        if startIndex != -1:
            endIndex = substring.find('\"', startIndex + 1)
            if endIndex != -1 and len(
                    string[seperator:].rstrip().lstrip()) > 0:
                quote = substring[startIndex:endIndex + 1]
                author = string[seperator:]

                access = sqlite3.connect('quotes.db')
                access.cursor().execute(
                    'INSERT INTO quotes (guild, quote, author) VALUES (?, ?, ?)',
                    (ctx.guild.id, quote, author))
                rowid = access.cursor().execute(
                    'SELECT rowid FROM quotes ORDER BY rowid DESC LIMIT 1'
                ).fetchone()[0]
                access.commit()
                access.close()

                embed = discord.Embed(title='Quote successfully added.',
                                      description=quote,
                                      colour=0x00FF00)
                embed.set_footer(text='{0} [ID: {1}]'.format(author, rowid))
                await ctx.send(embed=embed)
            else:
                raise discord.InvalidArgument("Quote not properly formatted")
        else:
            raise discord.InvalidArgument("Quote not properly formatted")
示例#2
0
 def __init__(self, callback, **kwargs):
     self.guild_id = kwargs.get('guild')
     super().__init__(callback, **kwargs)
     del self.aliases
     del self.usage
     del self.brief
     del self.hidden
     del self.rest_is_raw
     del self.description
     del self.require_var_positional
     del self.ignore_extra
     self._max_concurency = None
     self.type = kwargs.get('type_', 1)
     if self.type != 1 and not isinstance(self.type, CommandsTypes):
         raise discord.InvalidArgument(
             'type_ has to be interactions.CommandsTypes')
     self.type = int(self.type)
     self.default_permission = kwargs.get('default_permission', True)
     self.id = None
     if self.type == 1 and not (1 <= len(self.help) <= 100):
         raise discord.InvalidArgument(
             'Description for a command should have 1-100 characters')
     if re.match(r'^[\w-]{1,32}$', self.name) is None:
         raise discord.InvalidArgument(
             'Command names can contain only [A-Za-z0-9] and dashes or underscores'
             ' and have 1-32 characters')
示例#3
0
    def __init__(self,
                 custom_id,
                 options,
                 placeholder=None,
                 min_values=1,
                 max_values=1,
                 disabled=False,
                 **_):
        if len(options) > 25:
            raise discord.InvalidArgument(
                'options cannot have more than 25 elements')
        if len(options
               ) < max_values or min_values > max_values or min_values < 0:
            raise discord.InvalidArgument(
                'wrong value of min_values/max_values')
        if (placeholder and not isinstance(placeholder, str)) or not isinstance(min_values, int) \
                or not isinstance(max_values, int) or not isinstance(disabled, bool):
            raise TypeError('Wrong types')

        if not all([isinstance(option, SelectOption) for option in options]) and \
                len(set((option.value for option in options))) == len(options):
            raise TypeError(
                'All options have to be SelectOption and have unique value param'
            )

        self.custom_id = str(custom_id)
        self.options = options
        self.placeholder = placeholder
        self.min_values = min_values
        self.max_values = max_values
        self.disabled = disabled
示例#4
0
async def process_args(
    messageable, content, file, files
) -> Tuple[Optional[str], List[discord.File]]:
    if file is not None and files is not None:
        raise discord.InvalidArgument(
            "cannot pass both file and files parameter to send()"
        )
    if file is not None:
        files = [file]
    elif files is None:
        files = []
    if content is None:
        return None, files

    mentions = [match.group(0) for match in MENTIONS_RE.finditer(content)]
    ret_content = None
    if mentions:
        ret_content = ", ".join(mentions)

    if len(files) > 10:
        raise discord.InvalidArgument(
            "files parameter must be a list of up to 10 elements"
        )
    if len(files) == 10:
        await real_send(messageable, file=await get_text_image(content))
    else:
        files.insert(0, await get_text_image(content))
    return ret_content, files
示例#5
0
    async def purgetrash(self, ctx: commands.Context, limit: converters.myint,
                         **flags) -> None:
        """Works similar to a normal purge command,
        but instead of deleting the messages, each
        message is trashed. See sb!help trash for
        info on trashing.

        Can only trash up to 200 messages at once.

        Usage:
            purge <limit> <options>
        Options:
            --by: Only trash messages by this author
            --notby: Do not trash message by this author
            --contains: Only trash messages that contain
                this phrase.
        Examples:
            trash 50 --by @Circuit
            trash 50 --contains bad-word
            trash 50 --notby @Cool Person
            trash 50"""
        if limit > 200:
            raise discord.InvalidArgument(
                "Can only purge up to 200 messages at once")
        elif limit < 1:
            raise discord.InvalidArgument("Must purge at least 1 message")

        purged = {}
        total = 0

        def check(m: discord.Message) -> bool:
            if flags["by"] and m.author.id != flags["by"].id:
                return False
            if flags["notby"] and m.author.id == flags["notby"].id:
                return False
            if flags["contains"] and flags["contains"] not in m.content:
                return False
            return True

        async for m in ctx.channel.history(limit=limit):
            if not check(m):
                continue
            sql_message = await starboard_funcs.orig_message(self.bot, m.id)
            if not sql_message:
                continue
            await utility_funcs.handle_trashing(self.bot, sql_message["id"],
                                                sql_message["guild_id"], True)
            purged.setdefault(m.author, 0)
            purged[m.author] += 1
            total += 1

        embed = discord.Embed(
            title=f"Purged {total} Messages",
            description="\n".join(
                [f"{u.name}: {c}" for u, c in purged.items()]),
            color=self.bot.theme_color,
        )

        await ctx.send(embed=embed)
示例#6
0
    async def rename(self, ctx, scheme='custom', *words):
        size = len(ctx.guild.members)
        if scheme.lower().startswith('cus'):
            if len(words) >= size:
                new_names = words
            else:
                raise discord.InvalidArgument('Too few words provided')
        elif scheme.lower().startswith('num'):
            new_names = []
            for i in range(1, size + 1):
                new_names.append(str(i))
        elif scheme.lower().startswith('res'):
            new_names = []
            for i in range(1, size + 1):
                new_names.append(None)
        elif scheme.lower().startswith('bin'):
            new_names = []
            for i in range(1, size + 1):
                new_names.append(str(bin(i).replace('0b', '')))
        elif scheme.lower().startswith('hex'):
            new_names = []
            for i in range(1, size + 1):
                new_names.append(str(hex(i).replace('0x', '')))
        elif scheme.lower().startswith('fuc'):
            new_names = []
            for i in range(1, size + 1):
                new_names.append(str(words[0] * i))
        else:
            try:
                lib_list = self.alphs[scheme]
            except KeyError:
                raise discord.InvalidArgument('Couldn\'t get Scheme')
            else:
                if len(lib_list) >= size:
                    new_names = lib_list
                else:
                    raise discord.InvalidArgument('Too few words in Library')

        nicks = list(new_names)
        forbidden = []
        for m in ctx.guild.members:
            if m.id == self.bot.user.id:
                pass
            else:
                name = nicks[0]
                try:
                    await m.edit(
                        nick=name,
                        reason=f'{ctx.author} requested rename-madness')
                except:
                    forbidden.append(m.name)
                else:
                    nicks.remove(name)
        await ctx.send(embed=discord.Embed(
            title='New Nicknames!',
            color=(ctx.guild.get_member_named(str(self.bot.user))).color,
            description=
            f'I happily just changed everyones nicknames!\nYou can thank {ctx.author.mention} for this.\nUnfornutaly the following users coudn\'t be renamed:\n{", ".join(forbidden)}'
        ))
示例#7
0
 def from_pair(cls, target: Union[discord.Role, discord.User],
               permission: bool) -> RawCommandPermission:
     if not isinstance(target, (discord.Role, discord.User)):
         raise discord.InvalidArgument("target should be Role or User")
     if not isinstance(permission, bool):
         raise discord.InvalidArgument("permission should be bool")
     return RawCommandPermission(
         id=target.id,
         type=1 if isinstance(target, discord.Role) else 2,
         permission=permission)
示例#8
0
    def __init__(self, *components: Component):
        self._limit = 5
        if len(components) > self._limit:
            raise discord.InvalidArgument(
                f"components must be a list of up to {self._limit} elements")
        if not all(isinstance(comp, Component) for comp in components):
            raise discord.InvalidArgument(
                "components must be a list of Component")

        super().__init__(1)
        self.components = list(components)
示例#9
0
    async def send(self,
                   content=None,
                   *,
                   tts=False,
                   file=None,
                   files=None,
                   embed=None,
                   embeds=None,
                   allowed_mentions=None,
                   ephemeral=False):
        if not self.acked:
            await self.ack(ephemeral)

        payload = {}
        if files is not None and file is not None:
            raise discord.InvalidArgument(
                'Cannot mix file and files keyword arguments.')
        if embeds is not None and embed is not None:
            raise discord.InvalidArgument(
                'Cannot mix embed and embeds keyword arguments.')

        if embeds is not None:
            if len(embeds) > 10:
                raise discord.InvalidArgument(
                    'embeds has a maximum of 10 elements.')
            payload['embeds'] = [e.to_dict() for e in embeds]

        if embed is not None:
            payload['embeds'] = [embed.to_dict()]

        if content is not None:
            payload['content'] = str(content)

        if ephemeral:
            payload['flags'] = 1 << 6

        payload['tts'] = tts

        previous_mentions = getattr(self._state, 'allowed_mentions', None)

        if allowed_mentions:
            if previous_mentions is not None:
                payload['allowed_mentions'] = previous_mentions.merge(
                    allowed_mentions).to_dict()
            else:
                payload['allowed_mentions'] = allowed_mentions.to_dict()
        elif previous_mentions is not None:
            payload['allowed_mentions'] = previous_mentions.to_dict()

        return await self._webhook._adapter.execute_webhook(wait=True,
                                                            file=file,
                                                            files=files,
                                                            payload=payload)
示例#10
0
    async def convert(self, ctx: commands.Context, arg: str) -> None:
        link_pattern = "^https://discord.com/channels/[0-9]+/[0-9]+/[0-9]+"
        special_id_pattern = "^[0-9]+-[0-9]*[0-9]$"
        normal_id_pattern = "^[0-9][0-9]+[0-9]$"

        channel_id: int = None
        message_id: int = None
        message: discord.Message = None

        if arg == "^":
            try:
                message = (await ctx.channel.history(limit=2).flatten())[1]
            except discord.Forbidden:
                raise discord.Forbidden(
                    "I can't read the messae history of this channel, "
                    "so I don't know what message you want me to force.")
        elif re.match(normal_id_pattern, arg):
            channel_id = ctx.channel.id
            message_id = int(arg)
        elif re.match(link_pattern, arg):
            split = arg.split("/")
            channel_id = int(split[-2])
            message_id = int(split[-1])
        elif re.match(special_id_pattern, arg):
            split = arg.split("-")
            channel_id = int(split[0])
            message_id = int(split[1])
        else:
            raise discord.InvalidArgument(
                f"The argument, `{arg}`, does not appear to be "
                "a message link.")

        if not message:
            channel = ctx.guild.get_channel(channel_id)
            if not channel:
                raise discord.InvalidArgument(
                    "I couldn't find a channel with the id "
                    f"`{channel_id}`. Please make sure the message "
                    "link is valid, and is in this server.")
            try:
                message = await channel.fetch_message(message_id)
            except discord.NotFound:
                raise discord.InvalidArgument(
                    "I couldn't find a message that matches "
                    f"the link `{arg}`. Please make sure the "
                    "message link is valid.")
            except discord.Forbidden:
                raise discord.Forbidden(
                    "I don't have permission to read message history "
                    f"in {channel.mention}, so I can't fetch the message "
                    f"`{arg}`")
        return message
示例#11
0
    def icon_url_as(self, *, format='webp', size=1024):
        if not discord.utils.valid_icon_size(size):
            raise discord.InvalidArgument(
                "size must be a power of 2 between 16 and 1024")
        if format not in discord.guild.VALID_ICON_FORMATS:
            raise discord.InvalidArgument("format must be one of {0}".format(
                discord.guild.VALID_ICON_FORMATS))

        if self.icon is None:
            return ''

        return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.{1}?size={2}'.format(
            self, format, size)
示例#12
0
    async def add_prefix(
        self, ctx: commands.Context, prefix: str, **options
    ) -> None:
        """Adds a prefix.

        Usage:
            prefixes add <prefix> <options>
        Options:
            --space: Wether or not to add a space at
                the end of the prefix.
        Examples:
            sb!prefixes add star --space
            sb!prefixes add sb?
        """
        if options["space"] is True:
            prefix += " "
        if len(prefix) > 8:
            raise discord.InvalidArgument(
                f"`{prefix}` is too long (max length is 8 characters)."
            )
        guild = await self.bot.db.get_guild(ctx.guild.id)
        if prefix in guild["prefixes"]:
            raise errors.AlreadyExists(f"`{prefix}` is already a prefix.")
        new_prefixes = guild["prefixes"] + [prefix]
        await self.bot.db.execute(
            """UPDATE guilds
            SET prefixes=$1
            WHERE id=$2""",
            new_prefixes,
            ctx.guild.id,
        )

        await ctx.send(f"Added `{prefix}` to the prefixes.")
示例#13
0
def extract_user_id(input_id: str) -> str:
    """
    Validate and extract a user ID from an input (@mention, raw user ID, etc.).

    This method is intended to validate and sanitise an input provided by a user, e.g., over a
    command. It can accept:

    * Raw ID: '123456789012345678'
    * Mentions:
        * No nickname: '<@123456789012345678>'
        * User has nickname: '<@!123456789012345678>'
    * Attempts to provide a raw ID:
        * '@123456789012345678'
        * '@!123456789012345678'
        * '!123456789012345678'
    * Various errors:
        * <@123456789012345678
        * 123456789012345678>
        * etc.

    User ID parameters from:
    https://github.com/Rapptz/discord.py/blob/1863a1c6636f53592519320a173ec9573c090c0b/discord/ext/commands/converter.py#L83

    :param input_id: The raw input ID.
    :return: The extracted user ID (numerical string).
    :raise discord.InvalidArgument: id is not a recognised user ID format
    """
    try:
        return _re_user_id.fullmatch(input_id).group(1)
    except AttributeError:  # no match - fullmatch() returned None
        raise discord.InvalidArgument(
            'Invalid user ID format {!r}'.format(input_id))
async def test_add_emoji_role_pair_invalid_argument(mocker):
    """Adds a emoji/role pair to the role message creation, but the emoji is an InvalidArgument."""
    cog, mock_bot, _ = init_mocks()
    mock_message = tosurnament_mock.DEFAULT_MESSAGE_MOCK
    mock_message.add_reaction = mocker.AsyncMock(side_effect=discord.InvalidArgument())
    await cog.add_emoji_role_pair(cog, tosurnament_mock.CtxMock(mock_bot, message=mock_message), "🛎️", None)
    cog.send_reply.assert_called_once_with(mocker.ANY, "invalid_emoji", "🛎️")
示例#15
0
def auto_rows(*buttons: Button, max_in_row: int = 5) -> List[ActionRow]:
    """
    Distributes buttons across multiple rows
    and returns the list of rows.
    Example
    -------
    ::

        rows = auto_rows(
            Button(label="Red", custom_id="red", style=4),
            Button(label="Green", custom_id="green", style=3),
            max_in_row=1
        )
        await ctx.send("Buttons", components=rows)

    Parameters
    ----------
    buttons : List[:class:`Button`]
        a list of buttons to distribute
    max_in_row : :class:`int`
        limit of buttons in a single row. Must be between 1 and 5.

    Returns
    -------
    List[:class:`ActionRow`]
        the list of rows with buttons
    """
    if not (1 <= max_in_row <= 5):
        raise discord.InvalidArgument(
            "max_in_row parameter should be between 1 and 5.")
    return [
        ActionRow(*buttons[i:i + max_in_row])
        for i in range(0, len(buttons), max_in_row)
    ]
示例#16
0
    def getEmojiCustom(self, emojiID: str) -> discord.Emoji:
        for emoji in self.bot.get_all_emojis():
            if emoji.id == emojiID:
                return emoji

        raise discord.InvalidArgument(
            f"Argument 'emojiID' ({emojiID}) does not"
            " reference a valid custom emoji.")
示例#17
0
 def __init__(self, custom_id, callback):
     if len(custom_id) > 100:
         raise discord.InvalidArgument(
             'custom_id cannot be longer than 100 characters')
     if not inspect.iscoroutinefunction(callback):
         raise TypeError('component callback has to be a coroutine')
     self.custom_id = str(custom_id)
     self.callback = callback
示例#18
0
    def __init__(self,
                 style,
                 label=None,
                 emoji=None,
                 url=None,
                 disabled=False,
                 custom_id=None,
                 **_):
        if not isinstance(style, ButtonStyle):
            raise TypeError('style has to be one of ButtonStyle')
        if label and len(label) > 80:
            raise discord.InvalidArgument(
                'label cannot be longer than 80 characters')
        if emoji and not isinstance(
                emoji, (discord.PartialEmoji, str, discord.Emoji)):
            raise TypeError('emoji has to be the type of PartialEmoji')
        elif emoji:
            if isinstance(emoji, str):
                emoji = discord.PartialEmoji(name=emoji)
            elif isinstance(emoji, discord.Emoji):
                emoji = discord.PartialEmoji(name=emoji.name,
                                             animated=emoji.animated,
                                             id=emoji.id)
        if not isinstance(disabled, bool):
            raise TypeError('disabled must be boolean')

        if url and style is not ButtonStyle.Link:
            raise discord.InvalidArgument(
                'url cannot be passed when not using Link style')
        elif not url and style is ButtonStyle.Link:
            raise discord.InvalidArgument(
                'url nas to be passed when using Link style')

        if not custom_id and style is not ButtonStyle.Link:
            raise discord.InvalidArgument(
                'custom_id has to be passed when not using Link style')
        if url and custom_id:
            raise discord.InvalidArgument(
                'cannot provide both custom_id and url')

        self.custom_id = str(custom_id)
        self.disabled = disabled
        self.url = url
        self.style = style
        self.label = label
        self.emoji = emoji
示例#19
0
    def team_name_validator(self, team):
        """
        Raises discord.InvalidArgument if team is not one of "instinct", "mystic", or "valor", case-insensitive.

        :param team:
        :return:
        """
        if team.lower() not in ("instinct", "mystic", "valor"):
            raise discord.InvalidArgument('team must be one of "instinct", "mystic", or "valor" (case-insensitive)')
示例#20
0
    async def respond(self,
                      content=None,
                      *,
                      embed=None,
                      embeds=None,
                      tts=False,
                      allowed_mentions=None,
                      ephemeral=False):
        state = self._state
        content = str(content) if content is not None else None

        if embeds is not None and embed is not None:
            raise discord.InvalidArgument(
                'Cannot mix embed and embeds keyword arguments.')

        if embeds is not None:
            if len(embeds) > 10:
                raise discord.InvalidArgument(
                    'embeds has a maximum of 10 elements.')
            embeds = [e.to_dict() for e in embeds]
        if embed is not None:
            embed = embed.to_dict()

        if allowed_mentions is not None:
            if state.allowed_mentions is not None:
                allowed_mentions = state.allowed_mentions.merge(
                    allowed_mentions).to_dict()
            else:
                allowed_mentions = allowed_mentions.to_dict()
        else:
            allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict(
            )
        if self.acked:
            raise discord.ClientException('Response already created')
        self.acked = True
        await state.http.respond_interaction(self.token,
                                             self.id,
                                             content,
                                             tts=tts,
                                             embed=embed,
                                             embeds=embeds,
                                             allowed_mentions=allowed_mentions,
                                             ephemeral=ephemeral)
示例#21
0
    async def reload(self, *, extension: str):
        if extension not in extensions:
            raise discord.InvalidArgument(
                '%s is not a valid extension to reload, the valid ones are: %s'
                % (extension, ', '.join(extensions)))

        package = make_extension_import(extension)
        bot = self.bot
        bot.unload_extension(package)
        bot.load_extension(package)
        await bot.say('Reloaded %s extension' % extension)
示例#22
0
async def add_xp_role(bot: commands.Bot, role: discord.Role,
                      req_xp: int) -> None:
    if not await functions.can_manage_role(bot, role):
        raise discord.InvalidArgument("I can't manage that role, "
                                      "probably because that role "
                                      "is higher than my top role.")
    limit = await functions.get_limit(bot, 'xproles', role.guild.id)
    if limit is False:
        raise errors.NoPremiumError("Non-premium guilds do not have "
                                    "access to XP Roles. See the last "
                                    "page of `sb!tutorial` for more info.")

    conn = bot.db.conn

    async with bot.db.lock:
        async with conn.transaction():
            current_num = await conn.fetchval(
                """SELECT COUNT(*) FROM xproles
                WHERE guild_id=$1""", role.guild.id)

    if current_num + 1 > limit:
        raise errors.NoPremiumError(
            "You have reached your limit for XP Roles.")

    if await is_pr(bot, role.id):
        raise discord.InvalidArgument("A role cannot be both a Position Role "
                                      "and an XP Role.")

    if not 0 <= req_xp < 100000:
        raise discord.errors.InvalidArgument(
            "Required XP must be greater than or "
            "equal to 0 and less than 100,000")
    create_xp_role = \
        """INSERT INTO xproles (id, guild_id, req_xp)
        VALUES ($1, $2, $3)"""

    async with bot.db.lock:
        async with conn.transaction():
            await conn.execute(create_xp_role, role.id, role.guild.id, req_xp)
示例#23
0
async def add_pos_role(bot: commands.Bot, role: discord.Role,
                       max_users: int) -> None:
    add_role = \
        """INSERT INTO posroles (id, guild_id, max_users)
        VALUES ($1, $2, $3)"""

    if not await functions.can_manage_role(bot, role):
        raise discord.InvalidArgument("I can't manage that role, probably "
                                      "because it is above my highest role.")

    limit = await functions.get_limit(bot, 'posroles', role.guild.id)

    if limit is False:
        raise errors.NoPremiumError(
            "Non-premium guilds do not have access "
            "to position-based Role Awards. See the "
            "last page of `sb!tutorial` for more info.")

    conn = bot.db.conn

    async with bot.db.lock:
        async with conn.transaction():
            current_num = await conn.fetchval(
                """SELECT COUNT (*) FROM posroles
                WHERE guild_id=$1""", role.guild.id)

    if current_num + 1 > limit:
        raise errors.NoPremiumError(
            "You have reached your limit for Position Roles")

    if await is_xpr(bot, role.id):
        raise discord.InvalidArgument("A role cannot be both an XP Role and "
                                      "a Position Role.")

    async with bot.db.lock:
        async with conn.transaction():
            await conn.execute(add_role, role.id, role.guild.id, max_users)
示例#24
0
async def edit_role_icon(
    bot,
    role: Role,
    *,
    reason=None,
    icon: bytes = None,
    unicode_emoji: str = None,
    reset: bool = False,
):
    """|coro|

    Changes specified role's icon

    Parameters
    -----------
    role: :class:`discord.Role`
        A role to edit
    icon: :class:`bytes`
        A :term:`py:bytes-like object` representing the image to upload.
    unicode_emoji: :class:`str`
        A unicode emoji to set
    reason: Optional[:class:`str`]
        The reason for editing this role. Shows up on the audit log.

    Raises
    -------
    Forbidden
        You do not have permissions to change the role.
    HTTPException
        Editing the role failed.
    InvalidArgument
        Wrong image format passed for ``icon``.
        :param bot:
    """
    if not icon and not unicode_emoji and not reset:
        raise discord.InvalidArgument("You must specify icon or unicode_emoji")
    if reset:
        fields = {"unicode_emoji": None, "icon": None}
    else:
        fields = {
            "unicode_emoji": unicode_emoji,
            "icon": _bytes_to_base64_data(icon) if icon else None,
        }

    r = Route("PATCH",
              "/guilds/{guild_id}/roles/{role_id}",
              guild_id=role.guild.id,
              role_id=role.id)
    await bot.http.request(r, json=fields, reason=reason)
示例#25
0
    def __init__(
        self,
        *,
        style: ButtonStyle,
        label: Optional[str] = None,
        emoji: Optional[Union[discord.PartialEmoji, str]] = None,
        custom_id: Optional[str] = None,
        url: Optional[str] = None,
        disabled: bool = False,
    ) -> None:
        global ID_SOURCE  # Ugly as hell

        if custom_id is None:
            if url is None:
                custom_id = str(ID_SOURCE)
                ID_SOURCE = (ID_SOURCE + 1) % MAX_ID
            elif style != ButtonStyle.link:
                raise discord.InvalidArgument(
                    "if you specify url, the style must be ButtonStyle.link")
        elif url is not None:
            raise discord.InvalidArgument(
                "you can't specify both url and custom_id")
        elif style == ButtonStyle.link:
            raise discord.InvalidArgument(
                "style 'link' expects url to be specified")

        if isinstance(emoji, str):
            emoji = _partial_emoji_converter(emoji)

        super().__init__(2)
        self.style = style
        self.label = label
        self.emoji = emoji
        self.custom_id = custom_id
        self.url = url
        self.disabled = disabled
示例#26
0
    def set_channel(self, guild, channel: discord.TextChannel, type):
        """
        Set the screenshot or help channel for the guild.

        :param guild:
        :param channel:
        :param type: one of "screenshot", or "help"
        :return:
        """
        if type not in ("screenshot", "help"):
            raise discord.InvalidArgument(
                'channel type must be one of "screenshot", or "help"')
        self.table.update_item(
            Key={"guild_id": guild.id},
            UpdateExpression=f"SET {type}_channel = :channel",
            ExpressionAttributeValues={":channel": channel.id})
示例#27
0
    async def group_add(self, ctx: NabCtx, *, name: str):
        """Creates a new group for members to join.

        The group can be a new role that will be created with this command.  
        If the name matches an existent role, that role will become joinable.

        You need `Manage Roles` permissions to use this command."""
        name = name.replace("\"", "")
        forbidden = ["add", "remove", "delete", "list"]
        converter = InsensitiveRole()
        try:
            role = await converter.convert(ctx, name)
        except commands.BadArgument:
            try:
                if name.lower() in forbidden:
                    raise discord.InvalidArgument()
                role = await ctx.guild.create_role(
                    name=name, reason="Created joinable role")
            except discord.Forbidden:
                await ctx.send(
                    f"{ctx.tick(False)} I need `Manage Roles` permission to create a group."
                )
                return
            except discord.InvalidArgument:
                await ctx.send(f"{ctx.tick(False)} Invalid group name.")
                return
        result = userDatabase.execute(
            "SELECT * FROM joinable_roles WHERE role_id = ?", (role.id, ))
        group = list(result)
        if group:
            await ctx.send(
                f"{ctx.tick(False)} Group `{role.name}` already exists.")
            return

        # Can't make joinable group a role higher than the owner's top role
        top_role: discord.Role = ctx.author.top_role
        if role >= top_role:
            await ctx.send(
                f"{ctx.tick(False)} You can't make a group with a role higher or equals than your highest."
            )
            return

        userDatabase.execute(
            "INSERT INTO joinable_roles(server_id, role_id) VALUES(?,?)",
            (ctx.guild.id, role.id))
        await ctx.send(
            f"{ctx.tick()} Group `{role.name}` created successfully.")
示例#28
0
def _partial_emoji_converter(argument: str) -> discord.PartialEmoji:
    if len(argument) < 5:
        # Sometimes unicode emojis are actually more than 1 symbol
        return discord.PartialEmoji(name=argument)

    match = re.match(r"<(a?):([a-zA-Z0-9\_]+):([0-9]+)>$", argument)
    if match is not None:
        emoji_animated = bool(match.group(1))
        emoji_name = match.group(2)
        emoji_id = int(match.group(3))

        return discord.PartialEmoji(name=emoji_name,
                                    animated=emoji_animated,
                                    id=emoji_id)

    raise discord.InvalidArgument(
        f"Failed to convert {argument} to PartialEmoji")
示例#29
0
def extract_role_id(input_id: str) -> str:
    """
    Similar to :func:`~.extract_user_id` for roles.

    Role mentions are of the form <@&123456789012345678>.

    :param input_id: The raw input ID.
    :return: The extracted user ID (numerical string).
    :raise discord.InvalidArgument: id is not a recognised user ID format
    """
    if 15 <= len(input_id) <= 23 and input_id.isnumeric():
        return input_id

    try:
        return _re_role_id.fullmatch(input_id).group(1)
    except AttributeError:
        raise discord.InvalidArgument(
            'Invalid role ID format {!r}'.format(input_id))
示例#30
0
 async def de(self, ctx, *users):
     member = ctx.message.mentions
     roles = ctx.message.role_mentions
     if len(member) == 0 and len(roles) == 0:
         raise discord.InvalidArgument('No Users provided')
     else:
         for r in roles:
             for u in r.members:
                 member.append(u)
         for m in member:
             if m == None:
                 continue
             elif m.voice.deaf:
                 await m.edit(deafen=False,
                              reason=f'Request for un-deaf by {ctx.author}')
             else:
                 await m.edit(deafen=True,
                              reason=f'Request for deaf by {ctx.author}')