예제 #1
0
    async def quote_add(self, ctx: commands.Context, user: str, *,
                        message: str):
        """!kazhelp
        description: |
            Add a new quote manually.

            TIP: To automatically find and add a recent message, use {{!quote grab}}.
        parameters:
            - name: user
              type: "@user"
              description: >
                The user being quoted. Should be an @mention or a discord ID.
            - name: message
              type: string
              description: The quote text to add.
        examples:
            - command: .quote add @JaneDoe#0921 Ready for the mosh pit, shaka brah.
        """
        if len(message) > Quote.MAX_MESSAGE_LEN:
            raise commands.UserInputError(
                "That quote is too long! Maximum length {:d} characters.".
                format(Quote.MAX_MESSAGE_LEN))
        quote = c.store_quote(user=c.query_user(self.server, user),
                              saved_by=c.query_user(self.server,
                                                    ctx.message.author.id),
                              channel_id=ctx.message.channel.id,
                              message=message,
                              timestamp=ctx.message.timestamp)

        message = "Added quote: {}".format(self.format_quote(quote))
        logger.info(message)
        await self.bot.say(
            embed=self.make_single_embed(quote, title="Added quote."))
        await self.send_output(message)
예제 #2
0
    async def quote_add(self, ctx: commands.Context, user: str, *,
                        message: str):
        """
        Add a new quote manually.

        You can use `.quote grab` instead to automatically grab a recent message.

        Arguments:
        * user: Required. The user to find a quote for. See `.help quote` for valid formats.
        * message: Required. The quote text to add.

        Examples:
            .quote add @JaneDoe Ready for the mosh pit, shaka brah.
        """
        logger.info("quote add: {}".format(message_log_str(ctx.message)))
        if len(message) > Quote.MAX_MESSAGE_LEN:
            raise ValueError(
                "That quote is too long! Maximum length {:d} characters.".
                format(Quote.MAX_MESSAGE_LEN))
        quote = c.store_quote(user=c.query_user(self.server, user),
                              saved_by=c.query_user(self.server,
                                                    ctx.message.author.id),
                              channel_id=ctx.message.channel.id,
                              message=message,
                              timestamp=ctx.message.timestamp)

        message = "Added quote: {}".format(self.format_quote(quote))
        logger.info(message)
        await self.bot.say(
            embed=self.make_single_embed(quote, title="Added quote."))
        await self.send_output(message)
예제 #3
0
 async def quote_list(self,
                      ctx: commands.Context,
                      user: str,
                      page: int = None):
     """!kazhelp
     description: Retrieve a list of quotes. Always PMed.
     parameters:
         - name: user
           type: "@user"
           description: >
             The user to find a quote for. Should be an @mention or a discord ID.
         - name: page
           type: number
           optional: true
           default: last page (most recent)
           description: The page number to show, if there are more than 1 page of quotes.
     examples:
         - command: .quote list @JaneDoe#0921
           description: List all quotes by JaneDoe.
         - command: .quote list @JaneDoe#0921 4
           description: List the 4th page of quotes by JaneDoe.
     """
     db_user = c.query_user(self.server, user)
     if len(db_user.quotes) == 0:
         logger.warning("User has no quotes.")
         await self.bot.say("Sorry, {} has no quotes!".format(db_user.name))
         return
     paginator = Pagination(db_user.quotes,
                            self.QUOTES_PER_PAGE,
                            align_end=True)
     if page is not None:
         paginator.page = max(0, min(paginator.total_pages - 1, page - 1))
     await self.send_quotes_list(ctx.message.author, paginator, db_user)
예제 #4
0
    async def quote_list(self,
                         ctx: commands.Context,
                         user: str,
                         page: int = None):
        """
        Retrieve a list of quotes. Reply is always PMed.

        Arguments:
        * user: Required. The user to find a quote for. See `.help quote` for valid formats.
        * page: Optional. The page number to access, if there are more than 1 pages of notes.
          Default: last page.

        Examples:
            .quote list @JaneDoe - List all quotes by JaneDoe (page 1 if multiple pages)..
            .quote list @JaneDoe 4 - List the 4th page of quotes by JaneDoe.
        """
        logger.info("quote list: {}".format(message_log_str(ctx.message)))
        db_user = c.query_user(self.server, user)
        db_records = c.query_author_quotes(db_user)
        paginator = Pagination(db_records,
                               self.QUOTES_PER_PAGE,
                               align_end=True)
        if page is not None:
            paginator.page = max(0, min(paginator.total_pages - 1, page - 1))
        await self.send_quotes_list(ctx.message.author, paginator, db_user,
                                    ctx.message.server)
예제 #5
0
    async def quote_find(self,
                         ctx: commands.Context,
                         user: str,
                         *,
                         search: str = None):
        """
        Find the most recent quote matching a user and/or text search.

        Arguments:
        * user: Required. The user to find a quote for, or part of their name or nickname to search,
            or "all". For exact user matches, see `.help quote` for valid formats.
        * search: Optional. Text to search in the quote.

        Examples:
            .quote find Jane - Find a quote for a user whose user/nickname contains "Jane".
            .quote find @JaneDoe flamingo - Find a quote containing "flamingo" by JaneDoe.
            .quote find Jane flamingo - Find a quote matching user "Jane" and containing "flamingo".
        """
        logger.info("quote find: {}".format(message_log_str(ctx.message)))

        try:
            db_user = c.query_user(self.server, user)
        except ValueError:  # not a valid user ID format
            if user != 'all':
                db_user = c.search_users(user)
            else:
                db_user = None

        db_records = c.search_quotes(search, db_user)
        em = self.make_single_embed(db_records[-1])
        await self.bot.say(embed=em)
예제 #6
0
    async def quote(self,
                    ctx: commands.Context,
                    user: str = None,
                    *,
                    search: str = None):
        """!kazhelp
        description: >
            Retrieve a quote matching a user and/or text search. Returns a random quote among all
            matching results.

            TIP: To search for a quote by index number, use {{!quote get}}.
        parameters:
            - name: user
              type: "@user or string or \\"all\\""
              optional: true
              description: >
                The user to find a quote for. This can be an @mention, user ID, part
                of their name or nickname to search, or the special string "all" to find any user
                (i.e. search only by keyword).
            - name: search
              type: string
              optional: true
              description: The text to search.
        examples:
            - command: .quote
              description: Find a random quote.
            - command: .quote Jane
              description: Find a quote from any user whose name/nickname contains "Jane".
            - command: .quote @JaneDoe#0921 flamingo
              description: Find a quote by JaneDoe containing "flamingo".
            - command: .quote Jane flamingo
              description: Find a quote both matching user "Jane" and containing "flamingo".
        """
        if user:
            try:
                db_user = c.query_user(self.server, user)
            except ValueError:  # not a valid user ID format
                if user != 'all':
                    db_user = c.search_users(user)
                else:
                    db_user = None
            db_records = c.search_quotes(search, db_user)
            quote = db_records[random.randint(0, len(db_records) - 1)]
            logger.debug("Selected quote: {!r}".format(quote))
        else:
            quote = c.random_quote()
            logger.info("Selected random quote id={:d} from all users".format(
                quote.quote_id))

        number = quote.get_index() + 1
        len_recs = len(quote.author.quotes)
        em = self.make_single_embed(quote, index=number, total=len_recs)
        await self.bot.say(embed=em)
예제 #7
0
    async def quote_delete(self, ctx: commands.Context, user: str, number):
        """!kazhelp
        description: Delete one or all quotes attributed to a user. This is a moderative command;
            regular users should use {{!quote undo}} or {{!quote rem}}.
        parameters:
            - name: user
              type: "@user"
              description: The user whose quote to delete. Can be an @mention or discord ID.
            - name: number
              type: number or "all"
              description: The ID number of the quote to delete (starting from 1), or "all".
        examples:
            - command: .quote rem @JaneDoe#0921 4
              description: Delete the 4th quote by JaneDoe.
            - command: .quote rem @JaneDoe#0921 all
              description: Remove all quotes by JaneDoe.
        """
        db_user = c.query_user(self.server, user)
        len_recs = len(db_user.quotes)

        if number == 'all':
            logger.info("Removing all {} quotes for {!r}...".format(
                len_recs, db_user))
            c.remove_quotes(db_user.quotes)
            await self.bot.say("Removed all {} quotes for {}.".format(
                len_recs, db_user.mention))
            await self.send_output("Removed all {} quotes for {}.".format(
                len_recs, db_user.mention))
        else:
            try:
                number = int(number)
            except ValueError:
                raise commands.BadArgument(
                    "The number of the quote to delete is required.")

            if number < 1 or number > len_recs:
                logger.warning("Invalid index {:d}".format(number))
                await self.bot.say(
                    "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                    .format(number, db_user.name, len_recs))
                return

            quote = db_user.quotes[number - 1]
            message_text = "Removed quote (mod): {}".format(
                self.format_quote(quote))
            em = self.make_single_embed(quote,
                                        number,
                                        len_recs,
                                        title="Quote deleted.")
            c.remove_quotes([quote])
            await self.bot.say(embed=em)
            await self.send_output(message_text)
예제 #8
0
    async def quote_delete(self, ctx: commands.Context, user: str, number):
        """
        [MOD ONLY] Delete one or all quotes attributed to a user.

        Arguments:
        * user: Required. The user to find a quote for. See `.help quote` for valid formats.
        * number: Required. The ID number of the quote to delete (starting from 1), or "all".

        Examples:
            .quote rem @JaneDoe 4 - Delete the 4th quote by JaneDoe.
            .quote rem @JaneDoe all - Remove all quotes by JaneDoe.
        """
        logger.info("quote del: {}".format(message_log_str(ctx.message)))
        db_user = c.query_user(self.server, user)
        db_records = c.query_author_quotes(db_user)
        len_recs = len(db_records)

        if number == 'all':
            logger.info("Removing all {} quotes for {!r}...".format(
                len_recs, db_user))
            c.remove_quotes(db_records)
            await self.bot.say("Removed all {} quotes for {}.".format(
                len_recs, db_user.mention))
            await self.send_output("Removed all {} quotes for {}.".format(
                len_recs, db_user.mention))
        else:
            try:
                number = int(number)
            except ValueError:
                raise commands.BadArgument("Cannot convert number to int")

            if number < 1 or number > len_recs:
                logger.warning("Invalid index {:d}".format(number))
                await self.bot.say(
                    "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                    .format(number, db_user.name, len_recs))
                return

            quote = db_records[number - 1]
            message_text = "Removed quote (mod): {}".format(
                self.format_quote(quote))
            em = self.make_single_embed(quote,
                                        number,
                                        len_recs,
                                        title="Quote deleted.")
            c.remove_quotes([quote])
            await self.bot.say(embed=em)
            await self.send_output(message_text)
예제 #9
0
    async def quote(self,
                    ctx: commands.Context,
                    user: str,
                    number: int = None):
        """
        Retrieve a quote.

        If a quote number isn't given, find a random quote.

        Arguments:
        * user: Required. The user to find a quote for. Example formats:
            * @mention of the user (make sure it actually links them)
            * User's name + discriminator: JaneDoe#0921
            * Discord ID number: 123456789012345678
        * number: Optional. The ID number of the quote to delete (starting from 1), as shown by
            the `.quote` or `.quote list` commands.

        Examples:
            .quote @JaneDoe - Find a random quote by JaneDoe.
            .quote @JaneDoe 4 - Find the 4th quote by JaneDoe.
        """
        logger.info("quote: {}".format(message_log_str(ctx.message)))
        db_user = c.query_user(self.server, user)
        db_records = c.query_author_quotes(db_user)
        len_recs = len(db_records)

        if number is None:
            number = random.randint(1, len_recs)
            logger.info("Selected random quote {:d} by user {!r}...".format(
                number, db_user))
        else:
            logger.info("Requested quote {:d} by user {!r}".format(
                number, db_user))

        if number < 1 or number > len_recs:
            logger.warning("Invalid index {:d}".format(number))
            await self.bot.say(
                "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                .format(number, db_user.name, len_recs))
            return

        em = self.make_single_embed(db_records[number - 1], number, len_recs)
        await self.bot.say(embed=em)
예제 #10
0
    async def quote_remove(self, ctx: commands.Context, number: int):
        """!kazhelp
        description: |
            Remove one of your own quotes.

            WARNING: This command cannot be undone!

            IMPORTANT: If you are being harassed via quotes, or quote are otherwise being abused,
            please report this to the mods.

            TIP: To delete a quote you quoted (instead of a quote attributed to you), use
            {{!quote undo}} to remove the most recent one. For any other situation, contact the
            mods.
        parameters:
            - name: number
              type: number
              description: The ID number of the quote to delete (starting from 1), as shown by the
                {{!quote}}, {{!quote get}} and {{!quote list}} commands.
        examples:
            - command: .quote del 4
              description: Delete the 4th quote attributed to you.
        """
        db_user = c.query_user(self.server, ctx.message.author.id)
        len_recs = len(db_user.quotes)

        if number < 1 or number > len_recs:
            logger.warning("Invalid index {:d}".format(number))
            await self.bot.say(
                "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                .format(number, db_user.name, len_recs))
            return

        quote = db_user.quotes[number - 1]
        message_text = "Removed quote (remove): {}".format(
            self.format_quote(quote))
        em = self.make_single_embed(quote,
                                    number,
                                    len_recs,
                                    title="Quote deleted.")
        c.remove_quotes([quote])
        await self.bot.say(embed=em)
        await self.send_output(message_text)
예제 #11
0
    async def quote_get(self, ctx: commands.Context, user: str, number: int):
        """!kazhelp
        description: |
            Retrieve a quote by index.
        parameters:
            - name: user
              type: "@user"
              description: >
                The user to find a quote for. Should be an @mention or a discord ID.
            - name: number
              type: number
              optional: true
              description: >
                The ID number of the quote to find (starting from 1), as shown by the {{!quote}} and
                {{!quote list}} commands.
        examples:
            - command: .quote @JaneDoe#0921
              description: Find a random quote by JaneDoe.
            - command: .quote @JaneDoe#0921 4
              description: Find the 4th quote by JaneDoe.
        """
        db_user = c.query_user(self.server, user)
        len_recs = len(db_user.quotes)

        # no quotes for this user
        if len_recs == 0:
            logger.warning("User has no quotes.")
            await self.bot.say("Sorry, {} has no quotes!".format(db_user.name))
            return

        logger.info("Requested quote {:d} by user {!r}".format(
            number, db_user))
        if number < 1 or number > len_recs:
            logger.warning("Invalid index {:d}".format(number))
            await self.bot.say(
                "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                .format(number, db_user.name, len_recs))
            return
        quote = db_user.quotes[number - 1]

        em = self.make_single_embed(quote, number, len_recs)
        await self.bot.say(embed=em)
예제 #12
0
    async def quote_undo(self, ctx: commands.Context):
        """!kazhelp
        description: |
            Remove the last quote you added.

            WARNING: This command cannot be undone!

            TIP: This command only undoes your own calls to {{!quote add}} or {{!quote grab}}. It
            does **not** undo {{!quote rem}}, and does not undo quote commands by other users.

            TIP: To delete quotes attributed to you, use {{!quote rem}}.
        """
        db_user = c.query_user(self.server, ctx.message.author.id)
        quote = db_user.saved_quotes[-1]
        message_text = "Removed quote (undo): {}".format(
            self.format_quote(quote))
        em = self.make_single_embed(quote, title="Quote deleted.")
        c.remove_quotes([quote])
        await self.bot.say(embed=em)
        await self.send_output(message_text)
예제 #13
0
    async def quote_undo(self, ctx: commands.Context):
        """
        Remove the last quote you added.

        THIS COMMAND CANNOT BE UNDONE.

        This command only undoes `.quote add` or `.quote grab` actions. It does NOT undo
        `.quote rem` actions.
        """
        logger.info("quote undo: {}".format(message_log_str(ctx.message)))
        db_user = c.query_user(self.server, ctx.message.author.id)
        db_records = c.query_saved_quotes(db_user)

        quote = db_records[-1]
        message_text = "Removed quote (undo): {}".format(
            self.format_quote(quote))
        em = self.make_single_embed(quote, title="Quote deleted.")
        c.remove_quotes([quote])
        await self.bot.say(embed=em)
        await self.send_output(message_text)
예제 #14
0
    async def quote_remove(self, ctx: commands.Context, number: int):
        """
        Remove one of your own quotes.

        THIS COMMAND CANNOT BE UNDONE.

        This command is limited to quotes attributed to you. For any other situations, please
        contact the moderators to delete quotes.

        Arguments:
        * number: Optional. The ID number of the quote to delete (starting from 1), as shown by
            the `.quote` or `.quote list` commands.

        Examples:
            .quote del 4 - Delete the 4th quote attributed to you.
        """
        logger.info("quote rem: {}".format(message_log_str(ctx.message)))
        db_user = c.query_user(self.server, ctx.message.author.id)
        db_records = c.query_author_quotes(db_user)
        len_recs = len(db_records)

        if number < 1 or number > len_recs:
            logger.warning("Invalid index {:d}".format(number))
            await self.bot.say(
                "Oops, I can't get quote {:d} for {}! Valid quotes are 1 to {:d}"
                .format(number, db_user.name, len_recs))
            return

        quote = db_records[number - 1]
        message_text = "Removed quote (remove): {}".format(
            self.format_quote(quote))
        em = self.make_single_embed(quote,
                                    number,
                                    len_recs,
                                    title="Quote deleted.")
        c.remove_quotes([quote])
        await self.bot.say(embed=em)
        await self.send_output(message_text)
예제 #15
0
    async def quote_grab(self,
                         ctx: commands.Context,
                         user: discord.Member,
                         *,
                         search: str = None):
        """!kazhelp
        description: |
            Find the most recent matching message and add it as a quote.

            This command searches the {{grab_search_max}} most recent messages in the channel. The
            most recent message matching both the user and (if specified) search text is added as a
            quote.

            TIP: To manually add a quote, use {{!quote add}}.
        parameters:
            - name: user
              type: "@user"
              description: >
                The user being quoted. Should be an @mention or a discord ID.
            - name: search
              type: string
              optional: true
              description: The quote text to find.
        examples:
            - command: .quote grab @JaneDoe#0921
              description: Quote the most recent message from JaneDoe.
            - command: .quote grab @JaneDoe#0921 mosh pit
              description: Finds the most recent message from @JaneDoe containing "mosh pit".
        """
        search_messages = self.bot.logs_from(ctx.message.channel,
                                             self.cog_config.grab_search_max)
        async for message in search_messages:             \
                # type: discord.Message

            # if requested author, and this message isn't the invoking one (in case of self-grab)
            if message.author == user and message.id != ctx.message.id:
                if not search or search.lower() in message.content.lower():
                    grabbed_message = message
                    break
        else:  # Nothing found
            if search:
                await self.bot.say(
                    "No message from {} matching '{}' found in the last {:d} messages"
                    .format(user.nick if user.nick else user.name, search,
                            self.cog_config.grab_search_max))
            else:
                await self.bot.say(
                    "No message from {} found in the last {:d} messages".
                    format(user.nick if user.nick else user.name,
                           self.cog_config.grab_search_max))
            return

        message_text = grabbed_message.content
        if grabbed_message.attachments:
            message_text = "{0}\n\n{1}".format(
                message_text,
                '\n'.join(a['url'] for a in ctx.message.attachments))

        if len(message_text) > Quote.MAX_MESSAGE_LEN:
            raise commands.UserInputError(
                "That quote is too long! Maximum length {:d} characters.".
                format(Quote.MAX_MESSAGE_LEN))

        quote = c.store_quote(user=c.query_user(self.server,
                                                grabbed_message.author.id),
                              saved_by=c.query_user(self.server,
                                                    ctx.message.author.id),
                              channel_id=grabbed_message.channel.id,
                              message=message_text,
                              timestamp=grabbed_message.timestamp)

        message_text = "Added quote: {}".format(self.format_quote(quote))
        logger.info(message_text)
        await self.bot.say(
            embed=self.make_single_embed(quote, title="Added quote."))
        await self.send_output(message_text)
예제 #16
0
    async def quote_grab(self,
                         ctx: commands.Context,
                         user: discord.Member,
                         *,
                         search: str = None):
        """
        Find the most recent matching message and add it as a quote.

        This command searches the most recent messages (default 100 messages). The most recent
        message matching both the user and (if specified) search text is added as a quote.

        You can use `.quote add` instead to manually add the quote.

        Arguments:
        * user: Required. The user to find a quote for. See `.help quote` for valid formats.
        * search: Optional. The quote text to find among the user's recent messages.

        Examples:
            .quote grab @JaneDoe
                Quote the most recent message from @JaneDoe.
            .quote grab @JaneDoe mosh pit
                Finds the most recent message from @JaneDoe containing "mosh pit".
        """
        logger.info("quote grab: {}".format(message_log_str(ctx.message)))
        async for message in self.bot.logs_from(ctx.message.channel,
                                                self.grab_max):             \
                # type: discord.Message

            # if requested author, and this message isn't the invoking one (in case of self-grab)
            if message.author == user and message.id != ctx.message.id:
                if not search or search.lower() in message.content.lower():
                    grabbed_message = message
                    break
        else:  # Nothing found
            if search:
                await self.bot.say(("No message from {} matching '{}' "
                                    "found in the last {:d} messages").format(
                                        user.nick if user.nick else user.name,
                                        search, self.grab_max))
            else:
                await self.bot.say(
                    "No message from {} found in the last {:d} messages".
                    format(user.nick if user.nick else user.name,
                           self.grab_max))
            return

        message_text = grabbed_message.content
        if grabbed_message.attachments:
            message_text = "{0}\n\n{1}".format(
                message_text,
                '\n'.join(a['url'] for a in ctx.message.attachments))

        if len(message_text) > Limits.EMBED_FIELD_VALUE:
            raise ValueError(
                "That quote is too long! Maximum length 1024 characters.")

        quote = c.store_quote(user=c.query_user(self.server,
                                                grabbed_message.author.id),
                              saved_by=c.query_user(self.server,
                                                    ctx.message.author.id),
                              channel_id=grabbed_message.channel.id,
                              message=message_text,
                              timestamp=grabbed_message.timestamp)

        message_text = "Added quote: {}".format(self.format_quote(quote))
        logger.info(message_text)
        await self.bot.say(
            embed=self.make_single_embed(quote, title="Added quote."))
        await self.send_output(message_text)