Ejemplo n.º 1
0
    async def on_message(self, message: discord.Message):
        if not message.guild:
            return
        try:
            if message.guild.id != self.system.config.getint("general", "server_id", fallback=None):
                return
        except:pass

        prefixes = await self.bot.get_prefix(message)
        view = StringView(message.content)
        if isinstance(prefixes, list):
            for prefix in prefixes:
                if view.skip_string(prefix):
                    cmd = view.get_word()
                    command = await self.system.get_command(cmd)
                    if command is not None:
                        user = await self.system.get_user_discord_id(message.author.id)
                        if command.can_run_discord(message, user):
                            return await self.process_commands(message, command, view)

        else:
            if view.skip_string(prefixes):
                cmd = view.get_word()
                command = await self.system.get_command(cmd)
                if command is not None:
                    user = await self.system.get_user_discord_id(message.author.id)
                    if command.can_run_discord(message, user):
                        return await self.process_commands(message, command, view)
Ejemplo n.º 2
0
    async def on_message(self, message):
        if message.author.bot or not self.bot.is_running():
            return
        if message.content.startswith(self.bot.command_prefix):
            name = message.content.lower().lstrip(self.bot.command_prefix).split(" ")[0]
            if command := config.Commands.fetch(name):
                attachment = None
                if command["attachment"]:
                    async with aiohttp.ClientSession() as session:
                        async with session.get(command["attachment"]) as resp:
                            buff = io.BytesIO(await resp.read())
                            attachment = discord.File(filename=command["attachment"].split("/")[-1], fp=buff)
                args = []
                view = StringView(message.content.lstrip(self.bot.command_prefix))
                view.get_word()  # command name
                while not view.eof:
                    view.skip_ws()
                    args.append(view.get_quoted_word())

                text = re.sub(
                    r'{(\d+)}',
                    lambda match: args[int(match.group(1))]
                    if int(match.group(1)) < len(args)
                    else '(missing argument)',
                    command["content"]
                ).replace('{...}', ' '.join(args))

                await self.bot.reply_to_msg(message, text, file=attachment)
                return
Ejemplo n.º 3
0
    async def event_message(self, message: twitchio.Message):
        if not message.channel:
            return

        if message.channel.name != self.bot._ws.nick:
            return

        prefixes = await self.bot._get_prefixes(message)
        view = StringView(message.content)
        if isinstance(prefixes, list):
            for prefix in prefixes:
                if view.skip_string(prefix):
                    cmd = view.get_word()
                    command = await self.system.get_command(cmd)
                    if command is not None:
                        user = await self.system.get_user_twitch_name(
                            message.author.name, id=message.author.id)
                        if command.can_run_twitch(message, user):
                            return await self.process_commands(
                                message, command, view)

        else:
            if view.skip_string(prefixes):
                cmd = view.get_word()
                command = await self.system.get_command(cmd)
                if command is not None:
                    user = await self.system.get_user_twitch_name(
                        message.author.name, id=message.author.id)
                    if command.can_run_twitch(message, user):
                        return await self.process_commands(
                            message, command, view)
Ejemplo n.º 4
0
    async def get_context(self, message, *, cls=Context):
        view = StringView(message.content)
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        prefix = await self.get_prefix(message)
        invoked_prefix = prefix

        if isinstance(prefix, str):
            if not view.skip_string(prefix):
                return ctx
        elif isinstance(prefix, list) \
                and any([isinstance(p, list) for p in prefix]):
            # Regex time
            for p in prefix:
                if isinstance(p, list):
                    if p[1]:
                        # regex prefix parsing
                        reg = re.match(p[0], message.content)
                        if reg:

                            if message.content == reg.groups()[0]:
                                # ignore * prefixes
                                continue

                            # Matches, this is the prefix
                            invoked_prefix = p

                            # redo the string view with the capture group
                            view = StringView(reg.groups()[0])

                            invoker = view.get_word()
                            ctx.invoked_with = invoker
                            ctx.prefix = invoked_prefix
                            ctx.command = self.all_commands.get(invoker)
                            ctx.view = view
                            return ctx
                    else:
                        # regex has highest priority or something idk
                        # what I'm doing help
                        continue

            # No prefix found, use the branch below
            prefix = [p[0] for p in prefix if not p[1]]
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return ctx
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return ctx

        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.prefix = invoked_prefix
        ctx.command = self.all_commands.get(invoker)
        return ctx
Ejemplo n.º 5
0
    async def get_contexts(self, message, *, cls=commands.Context):
        """
        Returns all invocation contexts from the message.
        Supports getting the prefix from database as well as command aliases.
        """

        view = StringView(message.content)
        ctx = cls(prefix=self.prefix, view=view, bot=self, message=message)
        ctx.thread = await self.threads.find(channel=ctx.channel)

        if self._skip_check(message.author.id, self.user.id):
            return [ctx]

        prefixes = await self.get_prefix()

        invoked_prefix = discord.utils.find(view.skip_string, prefixes)
        if invoked_prefix is None:
            return [ctx]

        invoker = view.get_word().lower()

        # Check if there is any aliases being called.
        alias = self.aliases.get(invoker)
        if alias is not None:
            aliases = parse_alias(alias)
            if not aliases:
                logger.warning("Alias %s is invalid, removing.", invoker)
                self.aliases.pop(invoker)
            else:
                len_ = len(f"{invoked_prefix}{invoker}")
                contents = parse_alias(message.content[len_:])
                if not contents:
                    contents = [message.content[len_:]]

                ctxs = []
                for alias, content in zip_longest(aliases, contents):
                    if alias is None:
                        break
                    ctx = cls(prefix=self.prefix,
                              view=view,
                              bot=self,
                              message=message)
                    ctx.thread = await self.threads.find(channel=ctx.channel)

                    if content is not None:
                        view = StringView(f"{alias} {content.strip()}")
                    else:
                        view = StringView(alias)
                    ctx.view = view
                    ctx.invoked_with = view.get_word()
                    ctx.command = self.all_commands.get(ctx.invoked_with)
                    ctxs += [ctx]
                return ctxs

        ctx.invoked_with = invoker
        ctx.command = self.all_commands.get(invoker)
        return [ctx]
Ejemplo n.º 6
0
    async def get_contexts(self, message, *, cls=commands.Context):
        """
        Returns all invocation contexts from the message.
        Supports getting the prefix from database as well as command aliases.
        """

        view = StringView(message.content)
        ctx = cls(prefix=self.prefix, view=view, bot=self, message=message)
        thread = await self.threads.find(channel=ctx.channel)

        if self._skip_check(message.author.id, self.user.id):
            return [ctx]

        prefixes = await self.get_prefix()

        invoked_prefix = discord.utils.find(view.skip_string, prefixes)
        if invoked_prefix is None:
            return [ctx]

        invoker = view.get_word().lower()

        # Check if there is any aliases being called.
        alias = self.aliases.get(invoker)
        if alias is not None:
            ctxs = []
            aliases = normalize_alias(
                alias, message.content[len(f"{invoked_prefix}{invoker}"):])
            if not aliases:
                logger.warning("Alias %s is invalid, removing.", invoker)
                self.aliases.pop(invoker)

            for alias in aliases:
                view = StringView(invoked_prefix + alias)
                ctx_ = cls(prefix=self.prefix,
                           view=view,
                           bot=self,
                           message=message)
                ctx_.thread = thread
                discord.utils.find(view.skip_string, prefixes)
                ctx_.invoked_with = view.get_word().lower()
                ctx_.command = self.all_commands.get(ctx_.invoked_with)
                ctxs += [ctx_]
            return ctxs

        ctx.thread = thread
        ctx.invoked_with = invoker
        ctx.command = self.all_commands.get(invoker)
        return [ctx]
Ejemplo n.º 7
0
    async def get_context(self, message, *, cls=commands.Context):
        """
        Returns the invocation context from the message.
        Supports getting the prefix from database.
        """

        view = StringView(message.content)
        ctx = cls(prefix=self.prefix, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        ctx.thread = await self.threads.find(channel=ctx.channel)

        prefixes = await self.get_prefix()

        invoked_prefix = discord.utils.find(view.skip_string, prefixes)
        if invoked_prefix is None:
            return ctx

        invoker = view.get_word().lower()

        ctx.invoked_with = invoker
        ctx.command = self.all_commands.get(invoker)

        return ctx
Ejemplo n.º 8
0
    async def on_message(self, message):
        # If no prefix is found discard the message
        if not message.content.startswith(settings.PREFIX):
            return

        # If the message has a prefix but no known command we
        # convert the message to an !i command before passing it
        view = StringView(message.content)
        view.skip_string(settings.PREFIX)
        invoker = view.get_word()

        for command in self.commands:
            if invoker == command.name:
                break
        else:
            message.content = message.content[:1] + "i " + message.content[1:]

        # if invoker not in self.commands.name:
        #     message.content = message.content[:1] + "i " + message.content[1:]

        # Allow for the command to be processed by discord.py
        await self.process_commands(message)

        # Put the message in the database queue to be stored
        self.db.add_message_to_queue(message)
Ejemplo n.º 9
0
    async def get_context(self, message, *, cls=cmd.Context):
        # This function is called internally by discord.py.
        # We have to fiddle with it because we are using a dynamic prefix (our mention string),
        # as well as no prefix inside of DMs.
        # The included prefix matching functions could not deal with this case.
        # If it ever becomes possible, we should probably switch to that.

        # Frankly, I don't really remember what I did here, but it might be good
        # to periodically check the get_context method on the base class and
        # port over any changes that happened there. ~hmry (2019-08-14, 02:25)

        if self.command_regex is None:
            return cls(prefix=None, view=None, bot=self, message=message)

        cmd_regex = self.command_dms_regex if message.guild is None else self.command_regex
        match = cmd_regex.match(message.content)

        if not match:
            return cls(prefix=None, view=None, bot=self, message=message)

        view = StringView(match.group(1).strip())
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.command = self.all_commands.get(invoker)
        return ctx
Ejemplo n.º 10
0
            async def parse_line(line):
                '''
                Parses a macro line
                '''
                if line.split()[0].lower() == "wait":
                    if print_queue:
                        # We have run into a wait, send ze messages
                        await message.channel.send("\n".join(print_queue))
                        print_queue.clear()
                    await asyncio.sleep(float(line.split()[1]))
                else:
                    # Trick discord.py into parsing this command as a bot
                    view = StringView(line)
                    ctx = commands.Context(prefix=bot_prefix,
                                           view=view,
                                           bot=bot,
                                           message=message)
                    invoker = view.get_word()
                    ctx.invoked_with = invoker

                    if (command := bot.all_commands.get(invoker)
                        ) and not command.qualified_name == "macro":
                        if print_queue:
                            # We have run into a command, send ze messages
                            await ctx.send("\n".join(print_queue))
                            print_queue.clear()

                        # invoke a command
                        ctx.command = command
                        await bot.invoke(ctx)
                    else:
Ejemplo n.º 11
0
    async def on_thread_ready(self, thread, creator, category,
                              initial_message):
        """Sends out menu to user"""
        menu_config = await self.db.find_one({'_id': 'config'})
        if menu_config:
            message = DummyMessage(copy.copy(initial_message))
            message.author = self.bot.modmail_guild.me
            message.content = menu_config['content']
            #genesis = thread.recipient_genesis_message
            #await genesis.delete()
            msg, _ = await thread.reply(message, anonymous=True)
            for r in menu_config['options']:
                await msg.add_reaction(r)
                await asyncio.sleep(0.3)

            try:
                reaction, _ = await self.bot.wait_for(
                    'reaction_add',
                    check=lambda r, u: r.message == msg and u == thread.
                    recipient and str(r.emoji) in menu_config['options'],
                    timeout=120)
            except asyncio.TimeoutError:
                message.content = 'No reaction recieved in menu... timing out'
                await thread.reply(message)
            else:
                alias = menu_config['options'][str(reaction.emoji)]

                ctxs = []
                if alias is not None:
                    ctxs = []
                    aliases = normalize_alias(alias)
                    for alias in aliases:
                        view = StringView(self.bot.prefix + alias)
                        ctx_ = commands.Context(prefix=self.bot.prefix,
                                                view=view,
                                                bot=self.bot,
                                                message=message)
                        ctx_.thread = thread
                        discord.utils.find(view.skip_string, await
                                           self.bot.get_prefix())
                        ctx_.invoked_with = view.get_word().lower()
                        ctx_.command = self.bot.all_commands.get(
                            ctx_.invoked_with)
                        ctxs += [ctx_]

                for ctx in ctxs:
                    if ctx.command:
                        old_checks = copy.copy(ctx.command.checks)
                        ctx.command.checks = [
                            checks.has_permissions(PermissionLevel.INVALID)
                        ]

                        await self.bot.invoke(ctx)

                        ctx.command.checks = old_checks
                        continue
Ejemplo n.º 12
0
    async def get_context(self, message, *, cls=commands.Context):
        """
        Returns the invocation context from the message.
        Supports getting the prefix from database as well as command aliases.
        """

        view = StringView(message.content)
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        ctx.thread = await self.threads.find(channel=ctx.channel)

        prefixes = await self.get_prefix()

        invoked_prefix = discord.utils.find(view.skip_string, prefixes)
        if invoked_prefix is None:
            return ctx

        invoker = view.get_word().lower()

        # Check if there is any aliases being called.
        alias = self.config.get('aliases', {}).get(invoker)
        if alias is not None:
            ctx._alias_invoked = True
            len_ = len(f'{invoked_prefix}{invoker}')
            view = StringView(f'{alias}{ctx.message.content[len_:]}')
            ctx.view = view
            invoker = view.get_word()

        ctx.invoked_with = invoker
        ctx.prefix = self.prefix  # Sane prefix (No mentions)
        ctx.command = self.all_commands.get(invoker)

        has_ai = hasattr(ctx, '_alias_invoked')
        if ctx.command is self.get_command('eval') and has_ai:
            # ctx.command.checks = None # Let anyone use the command.
            pass

        return ctx
Ejemplo n.º 13
0
    async def invoke(self, ctx: SlashContext, command):
        view = StringView(command)
        m = await ctx.send(f"Invoking command `{command}`...")
        ctx = commands.Context(
            prefix=bot_prefix, view=view, bot=self.bot, message=m)
        invoker = view.get_word()
        ctx.invoked_with = invoker

        if command := self.bot.all_commands.get(invoker):
            # invoke a command
            ctx.command = command
            await self.bot.invoke(ctx)
Ejemplo n.º 14
0
    async def get_context(self, message, prefixes=None):
        prefixes = prefixes or await get_prefix(self.bot, message)
        for prefix in prefixes:
            message_regex = re.compile(
                rf"^({re.escape(prefix)})[\s]*(\w+)(.*)", re.I | re.X | re.S)
            match = message_regex.findall(message.content)
            if match:
                break
        if not match:
            return
        match = match[0]
        invoked_prefix = match[0].lower()
        message.content = f"{invoked_prefix}{match[1].lower()}{match[2]}"
        #piping operator
        pop = self.pop
        piped = pop in message.content
        if self.piping_enabled:
            if piped:
                #edge case for prefix being piping operator
                if invoked_prefix == pop:
                    split = message.content.rsplit(
                        pop,
                        message.content.count(pop) - 1)
                else:
                    split = message.content.split(pop)

                #modify message content to first command invoked
                if not split[-1].strip():
                    piped = False
                else:
                    piped = await self.process_piping(split, message.author,
                                                      invoked_prefix)
                    if piped:
                        message.content = split[0]

        view = StringView(message.content)
        ctx = NotSoContext(prefix=None,
                           view=view,
                           bot=self.bot,
                           message=message)
        view.skip_string(invoked_prefix)
        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.prefix = invoked_prefix
        command = self.bot.all_commands.get(invoker)
        if command is None:
            return
        ctx.command = command
        if piped:
            ctx.piped = piped
            ctx.cached = []
        return ctx, piped
Ejemplo n.º 15
0
    def process_commands(self, message):

        _internal_channel = message.channel
        _internal_author = message.author

        view = StringView(message.content)
        if message.author == self.user:
            return

        prefix = self._get_prefix(message)
        invoked_prefix = prefix
        
        if not isinstance(prefix, (tuple, list)):
            if not view.skip_string(prefix):
                
                ## procesar emoticons
                yield from self.process_emotes(message, view)
                return
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return

        invoker = view.get_word()
        tmp = {
            'bot': self,
            'invoked_with': invoker,
            'message': message,
            'view': view,
            'prefix': invoked_prefix
        }
        ctx = Context(**tmp)
        del tmp

        if invoker in self.commands:
            command = self.commands[invoker]
            self.dispatch('command', command, ctx)
            ctx.command = command
            yield from command.invoke(ctx)
            self.dispatch('command_completion', command, ctx)
        else:
            exc = CommandNotFound('Command "{}" is not found'.format(invoker))
            self.dispatch('command_error', exc, ctx)

            ## Invocar Kaomojis si existen
            key = invoker
            if(key not in kaomoji.keys()):
                key = random.sample(kaomoji.keys(), 1)[0]
            kao = random.sample(kaomoji[key],1)[0]
            yield from self.say(kao)
Ejemplo n.º 16
0
    async def get_context(self, message, *, cls=commands.Context):
        """
        Returns the invocation context from the message.
        Supports getting the prefix from database as well as command aliases.
        """

        view = StringView(message.content)
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        prefixes = [self.prefix, f'<@{bot.user.id}> ', f'<@!{bot.user.id}>']

        invoked_prefix = discord.utils.find(view.skip_string, prefixes)
        if invoked_prefix is None:
            return ctx

        invoker = view.get_word().lower()

        # Check if there is any aliases being called.
        alias = self.config.get('aliases', {}).get(invoker)
        if alias is not None:
            ctx._alias_invoked = True
            _len = len(f'{invoked_prefix}{invoker}')
            ctx.view = view = StringView(
                f'{alias}{ctx.message.content[_len:]}')
            invoker = view.get_word()

        ctx.invoked_with = invoker
        ctx.prefix = self.prefix  # Sane prefix (No mentions)
        ctx.command = self.all_commands.get(invoker)

        # if hasattr(ctx, '_alias_invoked'):
        #     ctx.command.checks = None # Let anyone use the command.

        return ctx
Ejemplo n.º 17
0
async def special_get_context(bot, message, cmdtext, *, cls=Context):
    # similar to bot's get_context method but use cmdtext rather than message.content to build the context
    # notice that if any command uses context.message.content be behavior may not be as expected
    # the documentation can be viewed in discord.ext.commands -> bot.get_context

    view = StringView(cmdtext)
    ctx = cls(prefix=None, view=view, bot=bot, message=message)

    if bot._skip_check(message.author.id, bot.user.id):
        return ctx

    prefix = await bot.get_prefix(message)
    invoked_prefix = prefix

    if isinstance(prefix, str):
        if not view.skip_string(prefix):
            return ctx
    else:
        try:
            # if the context class' __init__ consumes something from the view this
            # will be wrong.  That seems unreasonable though.
            if cmdtext.startswith(tuple(prefix)):
                invoked_prefix = discord.utils.find(view.skip_string, prefix)
            else:
                return ctx

        except TypeError:
            if not isinstance(prefix, list):
                raise TypeError(
                    "get_prefix must return either a string or a list of string, "
                    "not {}".format(prefix.__class__.__name__))

            # It's possible a bad command_prefix got us here.
            for value in prefix:
                if not isinstance(value, str):
                    raise TypeError(
                        "Iterable command_prefix or list returned from get_prefix must "
                        "contain only strings, not {}".format(
                            value.__class__.__name__))

            # Getting here shouldn't happen
            raise

    invoker = view.get_word()
    ctx.invoked_with = invoker
    ctx.prefix = invoked_prefix
    ctx.command = bot.all_commands.get(invoker)
    return ctx
Ejemplo n.º 18
0
    async def get_context(self,
                          message,
                          *,
                          cls=TwitchContext) -> TwitchContext:
        view = StringView(message.content)
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        prefix = await self._get_prefixes(message)
        invoked_prefix = prefix

        if isinstance(prefix, str):
            if not view.skip_string(prefix):
                return ctx
        else:
            try:
                # if the context class' __init__ consumes something from the view this
                # will be wrong.  That seems unreasonable though.
                if message.content.startswith(tuple(prefix)):
                    invoked_prefix = discord.utils.find(
                        view.skip_string, prefix)
                else:
                    return ctx

            except TypeError:
                if not isinstance(prefix, list):
                    raise TypeError(
                        "get_prefix must return either a string or a list of string, "
                        "not {}".format(prefix.__class__.__name__))

                # It's possible a bad command_prefix got us here.
                for value in prefix:
                    if not isinstance(value, str):
                        raise TypeError(
                            "Iterable command_prefix or list returned from get_prefix must "
                            "contain only strings, not {}".format(
                                value.__class__.__name__))

                # Getting here shouldn't happen
                raise

        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.prefix = invoked_prefix
        ctx.command = self.all_commands.get(invoker)
        return ctx
Ejemplo n.º 19
0
    def add_message(self, message):
        view = StringView(message.content)
        command = view.get_word()

        request_data = {
            "message_id": str(message.id),
            "user_id": str(message.author.id),
            "server_id": str(message.guild.id),
            "command": command,
            "content": view.read_rest(),
            "timestamp": message.created_at
        }

        try:
            self.firestore.collection('requests').add(
                document_data=request_data, document_id=str(message.id))
        except Conflict as e:
            logger.error(e)
Ejemplo n.º 20
0
    async def get_context(self, message, *, cls=Context):
        view = StringView(message.content)
        ctx = cls(prefix=None, view=view, bot=self, message=message)

        if self._skip_check((await message.author()).id, (await
                                                          self.user()).id):
            return ctx

        prefix = await self.get_prefix(message)
        invoked_prefix = prefix

        if isinstance(prefix, str):
            if not view.skip_string(prefix):
                return ctx
        else:
            try:
                if message.content.startswith(tuple(prefix)):
                    invoked_prefix = utils.find(view.skip_string, prefix)
                else:
                    return ctx

            except TypeError:
                if not isinstance(prefix, list):
                    raise TypeError(
                        "get_prefix must return either a string or a list of string, "
                        "not {}".format(prefix.__class__.__name__))

                for value in prefix:
                    if not isinstance(value, str):
                        raise TypeError(
                            "Iterable command_prefix or list returned from get_prefix must "
                            "contain only strings, not {}".format(
                                value.__class__.__name__))

                raise

        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.prefix = invoked_prefix
        ctx.command = self.all_commands.get(invoker)
        return ctx
Ejemplo n.º 21
0
    async def process_commands(self, message):
        """
        Override of process_commands to use our own context.
        """
        _internal_channel = message.channel
        _internal_author = message.author

        view = StringView(message.content)
        if self._skip_check(message.author, self.user):
            return

        prefix = await self._get_prefix(message)
        invoked_prefix = prefix

        if not isinstance(prefix, (tuple, list)):
            if not view.skip_string(prefix):
                return
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return

        invoker = view.get_word()
        tmp = {
            'bot': self,
            'invoked_with': invoker,
            'message': message,
            'view': view,
            'prefix': invoked_prefix
        }
        ctx = Context(**tmp)
        del tmp

        if invoker in self.commands:
            command = self.commands[invoker]
            self.dispatch('command', command, ctx)
            await command.invoke(ctx)
            self.dispatch('command_completion', command, ctx)
        elif invoker:
            exc = CommandNotFound('Command "{}" is not found'.format(invoker))
            self.dispatch('command_error', exc, ctx)
Ejemplo n.º 22
0
    async def get_context(client: Client, msg: Message) -> Context:
        view = StringView(msg.content)
        ctx = Context(prefix=None, view=view, bot=client, message=msg)

        if client._skip_check(msg.author.id, client.user.id):
            return ctx

        prefix = await client._get_prefix(msg)
        invoked_prefix = prefix

        if isinstance(prefix, str):
            if not view.skip_string(prefix):
                return ctx
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return ctx

        invoker = view.get_word()
        ctx.invoked_with = invoker
        ctx.prefix = invoked_prefix
        ctx.command = client.all_commands.get(invoker)
        return ctx
Ejemplo n.º 23
0
 async def process_commands(self, message):
     _internal_channel = message.channel
     _internal_author = message.author
     view = StringView(message.content)
     if self._skip_check(message.author, self.user):
         return
     prefix = await self._get_prefix(message)
     invoked_prefix = prefix
     if not isinstance(prefix, (tuple, list)):
         if not view.skip_string(prefix):
             return
     else:
         invoked_prefix = discord.utils.find(view.skip_string, prefix)
         if invoked_prefix is None:
             return
     invoker = view.get_word().lower()  # case-insensitive commands
     tmp = {
         'bot': self,
         'invoked_with': invoker,
         'message': message,
         'view': view,
         'prefix': invoked_prefix
     }
     ctx = Context(**tmp)
     del tmp
     if invoker in self.commands:
         command = self.commands[invoker]
         self.dispatch('command', command, ctx)
         try:
             await command.invoke(ctx)
         except CommandError as e:
             ctx.command.dispatch_error(e, ctx)
         else:
             self.dispatch('command_completion', command, ctx)
     elif invoker:
         exc = CommandNotFound('Command "{}" is not found'.format(invoker))
         self.dispatch('command_error', exc, ctx)
Ejemplo n.º 24
0
async def on_message(message):
    """
    discord.py on_message

    Processes messages, and if the message is a command, will execute it.
    We do check if the command is in the whitelist - these commands do not require bot terms acceptance to run, as they
    are typically general use commands (e.g. accept).

    If the command is not in the whitelist, we check that the user has accepted the terms of service.  If they have,
    we process the command and move on.  If they have not, we inform them that they must accept the terms before
    they can use commands.
    """
    view = StringView(message.content)
    # invoked_prefix = COMMAND_PREFIX  # Can we remove this? It's reset immediately after

    invoked_prefix = discord.utils.find(view.skip_string, COMMAND_PREFIX)
    discord.utils.find(view.skip_string, COMMAND_PREFIX)

    # This is fairly worthless.  While it can purge the message, everyone will still get a notification that there
    # was a message for them.  That's on Discord themselves to correct if the message is deleted.
    if "@everyone" in message.content:
        await Moderation(CLIENT).purge_everyone_message(message)

    if invoked_prefix is None:
        return

    invoker = view.get_word()

    if invoker in CLIENT.commands:
        # If the message content is a command within the whitelist, run the command; otherwise, they must have accepted
        # the bot terms before the command can be used.
        if message.content in whitelist:
            await CLIENT.process_commands(message)
        else:
            can_use = BotResources().check_accepted(message.author.id)
            message_channel_valid = False
            if not message.channel.is_private:
                message_channel_valid = BotResources().get_tos_channel_valid(message.server.id)
            if can_use:
                await CLIENT.process_commands(message)
            elif not can_use and message_channel_valid:
                if message.author.id != CLIENT.user.id:
                    message_channel_id = ConfigLoader().load_server_int_setting(
                        message.server.id,
                        'ConfigSettings',
                        'not_accepted_channel_id')

                    bot_message = await CLIENT.send_message(
                        discord.Object(id=message_channel_id),
                        NOT_ACCEPTED_MESSAGE.replace(
                            "{user}", message.author.mention).replace(
                                "{prefix}", COMMAND_PREFIX))
                    await asyncio.sleep(20)
                    await CLIENT.delete_message(bot_message)
            else:
                # This is needed to prevent infinite looping message posting
                if message.author.id != CLIENT.user.id:
                    bot_message = await CLIENT.send_message(
                        discord.Object(id=message.channel.id),
                        NOT_ACCEPTED_MESSAGE.replace(
                            "{user}", message.author.mention).replace(
                                "{prefix}", COMMAND_PREFIX))
                    await asyncio.sleep(20)
                    await CLIENT.delete_message(bot_message)
Ejemplo n.º 25
0
    def process_commands(self, message):
        bot = self.bot
        log_channel = bot.get_server("107883969424396288").get_channel("257926036728184832")
        error_channel = bot.get_server("107883969424396288").get_channel("257922447205072897")
        _internal_channel = message.channel
        _internal_author = message.author
        self = bot

        view = StringView(message.content)
        if self._skip_check(message.author, self.user):
            pass

        prefix = yield from self._get_prefix(message)
        invoked_prefix = prefix

        if not isinstance(prefix, (tuple, list)):
            if not view.skip_string(prefix):
                return
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return

        if invoked_prefix is "c." and message.author != message.server.me:
            return


        invoker = view.get_word()
        invoker_orig = invoker
        diff = difflib.get_close_matches(invoker, self.commands, n=1, cutoff=0.8)
        if diff != []:
            invoker = diff[0]
        tmp = {
            'bot': self,
            'invoked_with': invoker,
            'message': message,
            'view': view,
            'prefix': invoked_prefix
        }
        ctx = Context(**tmp)
        del tmp

        if invoker in self.commands:
            command = self.commands[invoker]
            self.dispatch('command', command, ctx)
            try:
                yield from command.invoke(ctx)
            except discord.ext.commands.errors.DisabledCommand as e:
                yield from self.say("*`{}` is disabled*".format(str(e).split(" ")[0]))
            except discord.ext.commands.errors.CheckFailure as e:
                yield from self.say("```You do not have permission for this command!```")
            except discord.ext.commands.errors.CommandOnCooldown as e:
                yield from self.say("```{}```".format(str(e)))
            except discord.ext.commands.errors.BadArgument as e:
                yield from self.say("```{}```".format(str(e)))
            except discord.ext.commands.errors.CommandError as e:
                ctx.command.dispatch_error(e, ctx)
                yield from self.say("An Error Has Occurred: ```py\n{}```".format(traceback.format_exc().replace("/home/seacow/Discord-Bot/","./").split("The above exception was the direct cause of the following exception:")[0]))
                if not message.author == message.server.me:
                    yield from self.send_message(error_channel,"{}```py\n{}```".format("\"{}\" produced an error on \"{}\" / \"{}\" | Invoked by \"{}\"".format(message.content, _internal_channel.name, _internal_channel.server.name, _internal_author.name+"#"+_internal_author.discriminator), traceback.format_exc().replace("/home/seacow/Discord-Bot/","./").replace("\"penny123\"", "********").split("The above exception was the direct cause of the following exception:")[0]))
            except discord.ext.commands.errors.MissingRequiredArgument as e:
                yield from self.say("```{}```".format(str(e)))
            except:
                pass
            else:
                self.dispatch('command_completion', command, ctx)
        elif invoker:
            close_matches = difflib.get_close_matches(invoker, self.commands)
            extra = ""
            if close_matches != []:
                extra = "\nDid you mean?: {}{}".format(invoked_prefix, ", {}".format(invoked_prefix).join(close_matches))
            yield from self.say("```\"{}\" is not a command{}```".format(invoked_prefix+invoker, extra))
            exc = discord.ext.commands.errors.CommandNotFound('Command "{}" is not found'.format(invoker))
            logging.warning('Command "{}" is not found'.format(invoker))
            self.dispatch('command_error', exc, ctx)
Ejemplo n.º 26
0
 def check(prefix):
     view = StringView(message.content)
     return view.skip_string(prefix) and view.get_word().lower() in cmds
Ejemplo n.º 27
0
    async def get_context(self, message, *, cls=Context):
        """Defaults to check for prefix first."""
        view = StringView(message.content)
        ctx = cls(prefix=None, suffix=None, view=view, bot=self, message=message)

        if self._skip_check(message.author.id, self.user.id):
            return ctx

        prefix = await self.get_prefix(message)
        suffix = await self.get_suffix(message)

        if prefix is not None:
            if isinstance(prefix, str):
                if view.skip_string(prefix):
                    invoked_prefix = prefix
            else:
                try:
                    if message.content.startswith(tuple(prefix)):
                        invoked_prefix = discord.utils.find(view.skip_string, prefix)
                except TypeError:
                    if not isinstance(prefix, list):
                        raise TypeError("get_prefix must return either a string or a list of string, "
                                        "not {}".format(prefix.__class__.__name__))

                    for value in prefix:
                        if not isinstance(value, str):
                            raise TypeError("Iterable command_prefix or list returned from get_prefix must "
                                            "contain only strings, not {}".format(value.__class__.__name__))

                    raise
        else:
            if isinstance(suffix, str):
                if _suffix_used(suffix, message.content):
                    invoked_suffix = suffix
                else:
                    return ctx
            else:
                try:
                    invoked_suffixes = [s for s in suffix if _suffix_used(s, message.content)]
                    if not invoked_suffixes:
                        return ctx

                    for suf in invoked_suffixes:
                        invoker = view.get_word()[:-len(suf)]
                        command = self.all_commands.get(invoker)
                        if command is not None:
                            view.undo()
                            invoked_suffix = suf
                            break
                    else:
                        return ctx

                except TypeError:
                    if not isinstance(suffix, list):
                        raise TypeError("get_suffix must return either a string or a list of string, "
                                        "not {}".format(suffix.__class__.__name__))

                    for value in suffix:
                        if not isinstance(value, str):
                            raise TypeError("Iterable command_suffix or list returned from get_suffix must "
                                            "contain only strings, not {}".format(value.__class__.__name__))

                    raise

        invoker = view.get_word()

        try:
            ctx.suffix = invoked_suffix
        except NameError:
            try:
                ctx.prefix = invoked_prefix
            except NameError:
                pass
        else:
            invoker = invoker[:-len(invoked_suffix)]

        ctx.invoked_with = invoker
        ctx.command = self.all_commands.get(invoker)
        return ctx
Ejemplo n.º 28
0
    async def invoke(self, ctx, piped):
        if piped and ctx.piped:
            not_owner = not await self.is_owner(ctx.author)
            if not_owner:
                await self.check_cooldown(
                    1, ctx,
                    "\N{NO ENTRY} **Cooldown** `Cannot pipe for another {:.2f} seconds.`",
                    True)

            lp = len(ctx.piped)
            it = time()
            for idx, p in enumerate(ctx.piped):
                e = discord.Embed(title=p[0][:256])
                if idx != 0:
                    # Re-init StringView
                    view = StringView(
                        f"{p[0]} {' '.join(filter(lambda x: isinstance(x, str), ctx.cached))}"
                    )
                    # Clear the output cache for the next run
                    ctx.cached.clear()
                    ctx.view = view
                    view.skip_string("")
                    view.get_word()
                    ctx.command = p[1]
                else:
                    if not ctx.channel.permissions_for(ctx.me).embed_links:
                        raise CannotPaginate(
                            'Bot does not have `embed_links` permission for piping.'
                        )
                    e.description = f"\N{HOURGLASS WITH FLOWING SAND} Piping {lp} commands"
                    # Don't need NotSoContext.send, can't mention ping in embeds
                    m = await super(ctx.__class__, ctx).send(embed=e)
                    self.bot.command_messages[ctx.message.id][2].append(m.id)

                # Return on cooldown
                if ctx.cached:
                    return await m.edit(content=ctx.cached[0].decode())

                is_last = (idx + 1) == lp
                t = time()
                # 5 min cache for last result, 10s + current index to circumvent discord cache
                ctx.cached.append(300 if is_last else 60 + idx)

                # Wait on ratelimit to prevent cooldown on cooldown messages
                try:
                    await self.bot.invoke(ctx)
                except commands.CommandOnCooldown as e:
                    if not_owner:
                        ra = e.retry_after
                        # Let the user know
                        e.description = f"\N{TIMER CLOCK} Waiting {ra:.2f} seconds for cooldown."
                        await m.edit(embed=e)

                        # Sleep then bypass checks
                        await asyncio.sleep(ra)
                        await ctx.reinvoke()

                # Using embed as a progress "bar" through images
                e.timestamp = datetime.datetime.now()
                if is_last:
                    e.set_footer(
                        text="\N{HOLE} Piping took {:.01f}s".format(time() -
                                                                    it))
                else:
                    e.set_footer(
                        text=f"\N{HOLE} Piping in progress: {idx + 1}/{lp}")

                # Set embed
                for c in ctx.cached[:3]:
                    if isinstance(c, int):
                        continue
                    # Differentiate between imis cache and text content
                    if isinstance(c, str):
                        e.set_image(url=c)
                    else:
                        e.description = c.decode()

                # Don't update the embed too fast
                if (time() - t) < 1:
                    await asyncio.sleep(1.5)
                # Edit with new results or create message and add to cmessages
                await m.edit(embed=e)
        else:
            await self.bot.invoke(ctx)
Ejemplo n.º 29
0
    def process_commands(self, message):
        bot = self.bot
        log_channel = bot.get_server("107883969424396288").get_channel(
            "257926036728184832")
        error_channel = bot.get_server("107883969424396288").get_channel(
            "257922447205072897")
        _internal_channel = message.channel
        _internal_author = message.author
        self = bot

        view = StringView(message.content)
        if self._skip_check(message.author, self.user):
            pass

        prefix = yield from self._get_prefix(message)
        invoked_prefix = prefix

        if not isinstance(prefix, (tuple, list)):
            if not view.skip_string(prefix):
                return
        else:
            invoked_prefix = discord.utils.find(view.skip_string, prefix)
            if invoked_prefix is None:
                return

        if invoked_prefix is "c." and message.author != message.server.me:
            return

        invoker = view.get_word()
        invoker_orig = invoker
        diff = difflib.get_close_matches(invoker,
                                         self.commands,
                                         n=1,
                                         cutoff=0.8)
        if diff != []:
            invoker = diff[0]
        tmp = {
            'bot': self,
            'invoked_with': invoker,
            'message': message,
            'view': view,
            'prefix': invoked_prefix
        }
        ctx = Context(**tmp)
        del tmp

        if invoker in self.commands:
            command = self.commands[invoker]
            self.dispatch('command', command, ctx)
            try:
                yield from command.invoke(ctx)
            except discord.ext.commands.errors.DisabledCommand as e:
                yield from self.say("*`{}` is disabled*".format(
                    str(e).split(" ")[0]))
            except discord.ext.commands.errors.CheckFailure as e:
                yield from self.say(
                    "```You do not have permission for this command!```")
            except discord.ext.commands.errors.CommandOnCooldown as e:
                yield from self.say("```{}```".format(str(e)))
            except discord.ext.commands.errors.BadArgument as e:
                yield from self.say("```{}```".format(str(e)))
            except discord.ext.commands.errors.CommandError as e:
                ctx.command.dispatch_error(e, ctx)
                yield from self.say(
                    "An Error Has Occurred: ```py\n{}```".
                    format(traceback.format_exc(
                    ).replace("/home/seacow/Discord-Bot/", "./").split(
                        "The above exception was the direct cause of the following exception:"
                    )[0]))
                if not message.author == message.server.me:
                    yield from self.send_message(
                        error_channel, "{}```py\n{}```".format(
                            "\"{}\" produced an error on \"{}\" / \"{}\" | Invoked by \"{}\""
                            .format(
                                message.content, _internal_channel.name,
                                _internal_channel.server.name,
                                _internal_author.name + "#" +
                                _internal_author.discriminator),
                            traceback.format_exc().replace(
                                "/home/seacow/Discord-Bot/", "./"
                            ).replace("\"penny123\"", "********").split(
                                "The above exception was the direct cause of the following exception:"
                            )[0]))
            except discord.ext.commands.errors.MissingRequiredArgument as e:
                yield from self.say("```{}```".format(str(e)))
            except:
                pass
            else:
                self.dispatch('command_completion', command, ctx)
        elif invoker:
            close_matches = difflib.get_close_matches(invoker, self.commands)
            extra = ""
            if close_matches != []:
                extra = "\nDid you mean?: {}{}".format(
                    invoked_prefix,
                    ", {}".format(invoked_prefix).join(close_matches))
            yield from self.say("```\"{}\" is not a command{}```".format(
                invoked_prefix + invoker, extra))
            exc = discord.ext.commands.errors.CommandNotFound(
                'Command "{}" is not found'.format(invoker))
            logging.warning('Command "{}" is not found'.format(invoker))
            self.dispatch('command_error', exc, ctx)