Exemplo n.º 1
0
    async def cmd_alias(self, args, src, **_):
        """Return a list of all previous names a user has had.

        Syntax: `{p}alias <tag/id>`
        """
        if not args:
            member = src.author
        else:
            member = self.get_member(src, args[0])

        if not self.db.useDB:
            raise CommandOperationError(
                "Database is not configured correctly (or at all)."
                " Contact your bot developer and tell them if you think"
                " this is an error.")

        if member is None:
            raise CommandOperationError(
                "Could not find that member in the guild.\n\nJust a note,"
                " I may have record of them, but it's Iso's policy to not"
                " display userinfo without consent. If you are staff and"
                " have a justified reason for this request, please"
                " ask whoever hosts this bot to manually look up the"
                " records in their database.")

        self.db.add_member(member)

        alias = self.db.get_attribute(member, "aliases")
        if not alias:
            yield "This member has no known aliases."
        else:
            yield underline(f"Aliases of User `{member.id}`:")

            for a in alias:
                yield bold(a)
Exemplo n.º 2
0
    async def cmd_define(
        self,
        args: Args,
        src: Src,
        _language: str = None,
        _l: str = None,
        _etymology: int = None,
        _e: int = None,
        **_,
    ):
        """Find the definition of a word from Wiktionary.

        Syntax: `{p}define <word>`

        Options:
        `--language=<str>`, `-l <str>` :: Specify a language in which to search for the word.
        `--etymology=<int>`, `-e <int>` :: Specify a certain number etymology to be shown.
        """
        if not args:
            return "Wiktionary, the Free Dictionary\nhttps://en.wiktionary.org/"
        word = args[0]
        self.log.f("dict", "Query string: " + word)

        async with src.channel.typing():
            which = _etymology or _e or 0

            ref = Define(word, _language or _l, which)
            url = "https://en.wiktionary.org/wiki/" + word
            if ref.valid:
                em = discord.Embed(color=0xF8F9FA)
                em.set_author(
                    name="'{}' on Wiktionary ({} etymolog{} available)".format(
                        word, ref.alts, "y" if ref.alts == 1 else "ies"),
                    url=url,
                    icon_url=
                    "https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/1122px-Wikipedia-logo-v2.svg.png",
                )
                em.add_field(name="Etymology",
                             value=ref.etymology,
                             inline=False)
                for definition in ref.definitions:
                    em.add_field(
                        name="`{}` ({}):".format(word,
                                                 definition["partOfSpeech"]),
                        value="\n- ".join([
                            text for text in definition["text"]
                            if not re.search(r"^\(.*vulgar.*\)", text.lower())
                        ]),
                        inline=False,
                    )

                return em
            else:
                raise CommandOperationError("No definition found.")
Exemplo n.º 3
0
    def check(self):
        """Check that the MC config is valid."""
        mclists = (
            self.config.get("minecraftDB"),
            self.config.get("minecraftWL"),
            self.config.get("minecraftOP"),
        )

        if None in mclists:
            raise CommandOperationError(
                "Sorry, Petal has not been configured to manage a Minecraft server."
            )
        mcchan = self.config.get("mc_channel")

        if mcchan is None:
            raise CommandOperationError(
                "Sorry, Petal has not been configured"
                " with a Minecraft Management Channel.")
        mcchan = self.client.get_channel(mcchan)

        if mcchan is None:
            raise CommandOperationError(
                "Sorry, the Minecraft Management Channel cannot be found.")
Exemplo n.º 4
0
    async def cmd_purge(self, args, src: Src, **_):
        """Purge up to 200 messages in the current channel.

        Syntax: `{p}purge <number of messages to delete>`
        """
        if len(args) < 1:
            raise CommandArgsError("Please provide a number between 1 and 200")
        try:
            delete_num = int(args[0].strip())
        except ValueError:
            raise CommandInputError("Please make sure your input is a number")
        if not 0 < delete_num <= 200:
            raise CommandInputError(
                "Can only delete between 0 and 200 Messages.")

        confirm_menu: Menu = Menu(
            self.client,
            src.channel,
            "Confirm Purge",
            f"Really delete the last {delete_num} Messages in this Channel?\n"
            f"(This Menu and your Invocation will also be deleted.)",
            src.author,
        )
        confirmed = await confirm_menu.get_bool()

        if confirmed is True:
            try:
                await src.channel.purge(limit=delete_num + 2, check=None)
            except discord.errors.Forbidden:
                raise CommandOperationError(
                    "I don't have permissions to purge messages.")
            else:
                logEmbed = discord.Embed(
                    title="Purge Event",
                    description=f"{delete_num} messages were purged from "
                    f"`#{src.channel.name}` in {src.guild.name} by "
                    f"`{src.author.name}#{src.author.discriminator}`.",
                    color=0x0ACDFF,
                )
                await self.client.log_moderation(embed=logEmbed)

        elif confirmed is False:
            await confirm_menu.add_section("Purge Cancelled.")
            await confirm_menu.post()
        else:
            await confirm_menu.add_section("Confirmation Timed Out.")
            await confirm_menu.post()
Exemplo n.º 5
0
    async def cmd_askpatch(self, args: Args, src: Src, **_):
        """Access the AskPatch database. Functionality determined by subcommand.

        Syntax:
        `{p}askpatch submit "<question>"` - Submit a question to Patch Asks. Should be quoted.
        """
        if not args:
            raise CommandArgsError("Subcommand required.")

        subcom = args.pop(0)

        if subcom == "submit":
            if not args:
                raise CommandInputError("Question cannot be empty.")
            elif len(args) > 1:
                raise CommandInputError("Question should be put in quotes.")
            else:
                msg = args[0]

            response = self.db.submit_motd(src.author.id, msg)
            if response is None:
                raise CommandOperationError(
                    "Unable to add to database, ask your bot owner as to why.")

            em = discord.Embed(
                title="Entry " + str(response["num"]),
                description="New question from " + src.author.name,
                colour=0x8738F,
            )
            em.add_field(name="content", value=response["content"])

            chan = self.client.get_channel(self.config.get("motdModChannel"))
            await self.client.embed(chan, embedded=em)

            return "Question added to database."

        elif subcom in ("approve", "reject", "count"):
            raise CommandAuthError("Restricted subcommand.")
        else:
            raise CommandInputError("Unrecognized subcommand.")
Exemplo n.º 6
0
    async def cmd_kick(
        self,
        args,
        src: discord.Message,
        _reason: str = None,
        _noconfirm: bool = False,
        **_,
    ):
        """Kick a user from a guild.

        Syntax: `{p}kick [OPTIONS] <user tag/id>`

        Options:
        `--reason <str>` :: Provide a reason immediately, rather than typing a reason in a subsequent message.
        `--noconfirm` :: Perform the action immediately, without asking to make sure. ***This can get you in trouble if you mess up with it.***
        """
        if not args:
            raise CommandArgsError("No User specified.")

        if not lambdall(args, lambda x: x.isdigit()):
            raise CommandInputError("All IDs must be positive Integers.")

        guild: discord.Guild = self.client.main_guild
        target: discord.Member = guild.get_member(int(args[0]))
        if target is None:
            raise CommandInputError("Could not get user with that ID.")
        elif target.id == self.client.user.id:
            raise CommandOperationError(
                f"I'm sorry, {src.author.mention}. I'm afraid I can't let you do that."
            )

        if _reason is None:
            await self.client.send_message(
                src.author, src.channel,
                "Please give a reason (just reply below): ")
            try:
                reason = await self.client.wait_for(
                    "message",
                    check=checks.all_checks(
                        checks.Messages.by_user(src.author),
                        checks.Messages.in_channel(src.channel),
                    ),
                    timeout=30,
                )
            except asyncio.TimeoutError:
                raise CommandOperationError(
                    "Timed out while waiting for reason.")
            _reason = reason.content

        targline: str = mono(userline(target))

        if not _noconfirm:
            confirm = await confirm_action(
                self.client,
                src,
                "Member Kick",
                f"Confirm kicking {targline} from {target.guild.name}?",
            )
            if confirm is not True:
                if confirm is False:
                    raise CommandExit("Kick was cancelled.")
                else:
                    raise CommandExit("Confirmation timed out.")

        try:
            await target.kick(reason=_reason)
        except discord.errors.Forbidden:
            raise CommandOperationError(
                "It seems I don't have perms to kick this user.")

        else:
            logEmbed = (discord.Embed(
                title="User Kick", description=_reason,
                colour=0xFF7900).set_author(
                    name=src.author.display_name,
                    icon_url=src.author.avatar_url).add_field(
                        name="Issuer",
                        value=mono(userline(src.author))).add_field(
                            name="Recipient", value=targline).add_field(
                                name="Guild",
                                value=target.guild.name).add_field(
                                    name="Timestamp",
                                    value=str(dt.utcnow())[:-7]).set_thumbnail(
                                        url=target.avatar_url))

            await self.client.log_moderation(embed=logEmbed)
            return f"Successfully Kicked: {targline}"
Exemplo n.º 7
0
    async def cmd_mute(self, args, src: discord.Message, **_):
        """Toggle the mute tag on a user if your guild supports that role.

        Syntax: `{p}mute <user tag/id>`
        """
        if not args:
            raise CommandArgsError("Must provide User ID.")

        if not lambdall(args, lambda x: x.isdigit()):
            raise CommandArgsError("All IDs must be positive Integers.")

        target: discord.Member = self.client.main_guild.get_member(int(
            args[0]))
        if target is None:
            raise CommandInputError(
                f"Could not get user with ID `{int(args[0])}`.")
        elif target.id == self.client.user.id:
            raise CommandInputError(
                f"I'm sorry, {src.author.mention}. I'm afraid I can't let you do that."
            )

        await self.client.send_message(
            src.author,
            src.channel,
            "Please give a reason for the mute (just reply below): ",
        )
        try:
            reason = await self.client.wait_for(
                "message",
                check=checks.all_checks(
                    checks.Messages.by_user(src.author),
                    checks.Messages.in_channel(src.channel),
                ),
                timeout=30,
            )
        except asyncio.TimeoutError:
            raise CommandOperationError("Timed out while waiting for reason.")

        role_mute: discord.Role = discord.utils.get(src.guild.roles,
                                                    name="mute")
        if role_mute is None:
            raise CommandOperationError(
                "This guild does not have a `mute` role. To enable the mute "
                "function, set up the roles and name one `mute`.")
        else:
            try:
                if role_mute in target.roles:
                    await target.remove_roles(role_mute, reason)
                    # await self.client.guild_voice_state(target, mute=False)

                    warnEmbed = discord.Embed(
                        title="User Unmute",
                        description=
                        f"You have been unmuted by {src.author.name}.",
                        colour=0x00FF11,
                    )
                    warnEmbed.set_author(
                        name=self.client.user.name,
                        icon_url="https://puu.sh/tB2KH/cea152d8f5.png",
                    )
                    # warnEmbed.add_field(name="Reason", value=reason.content)
                    warnEmbed.add_field(name="Issuing Server",
                                        value=src.guild.name,
                                        inline=False)
                    muteswitch = "Unmute"

                else:
                    await target.add_roles(role_mute, reason)
                    # await self.client.guild_voice_state(target, mute=True)

                    warnEmbed = discord.Embed(
                        title="User Mute",
                        description=
                        f"You have been muted by {src.author.name}.",
                        colour=0xFF0000,
                    )
                    warnEmbed.set_author(
                        name=self.client.user.name,
                        icon_url="https://puu.sh/tB2KH/cea152d8f5.png",
                    )
                    warnEmbed.add_field(name="Reason", value=reason.content)
                    warnEmbed.add_field(name="Issuing Server",
                                        value=src.guild.name,
                                        inline=False)
                    muteswitch = "Mute"

            except discord.errors.Forbidden:
                raise CommandOperationError(
                    "It seems I don't have permission to mute this user.")
            else:
                yield f"{target.name}  (ID: {target.id}) was successfully {muteswitch}d"

                try:
                    await target.send(embed=warnEmbed)
                except discord.errors.Forbidden:
                    yield (
                        f"  (FAILED to send a DM notification to user `{target.id}`.)",
                        True,
                    )
                else:
                    yield (
                        f"  (A notification was sent in DM to user `{target.id}`.)",
                        True,
                    )

                logEmbed = discord.Embed(
                    title=f"User {muteswitch}",
                    description=reason.content,
                    colour=0x1200FF,
                )

                logEmbed.add_field(name="Issuer",
                                   value=src.author.name + "\n" +
                                   src.author.id)
                logEmbed.add_field(name="Recipient",
                                   value=target.name + "\n" + target.id)
                logEmbed.add_field(name="Server", value=target.guild.name)
                logEmbed.add_field(name="Timestamp",
                                   value=str(dt.utcnow())[:-7])
                logEmbed.set_thumbnail(url=target.avatar_url)

                await self.client.log_moderation(embed=logEmbed)
Exemplo n.º 8
0
    async def cmd_event(self,
                        src,
                        _image: str = None,
                        _message: str = None,
                        _nomenu: bool = False,
                        **_):
        """Post a message announcing the start of an event.

        Define a message which will be sent to one or more predefined channels. The message may include mass pings by way of including tags `{{e}}` and `{{h}}` for substitution.
        Destination channels may be selected conversationally or by way of a reaction-based menu.

        Options:
        `--message=<msg>` :: Define the message to send ahead of time. This will skip the step where Petal asks you what you want the message to say.
        `--nomenu` :: Forsake the Reaction UI and determine destination channels conversationally.
        """
        channels_list = []
        channels_dict = {}
        msg = ""
        for chan in self.config.get("xPostList"):
            channel = self.client.get_channel(chan)
            if channel is not None:
                msg += (str(len(channels_list)) + ". (" + channel.name +
                        " [{}]".format(channel.guild.name) + ")\n")
                channels_list.append(channel)
                channels_dict[channel.guild.name + "/#" +
                              channel.name] = channel
            else:
                self.log.warn(
                    chan +
                    " is not a valid channel. I'd remove it if I were you.")

        # Get channels to send to.
        if _nomenu:
            # Do it only conversationally.
            menu = None
            while True:
                await self.client.send_message(
                    src.author,
                    src.channel,
                    "Hi there, " + src.author.name +
                    "! Please select the number of " +
                    "each guild you want to post " +
                    "to. (dont separate the numbers)",
                )

                await self.client.send_message(src.author, src.channel, msg)

                chans = await Messages.waitfor(
                    self.client,
                    all_checks(Messages.by_user(src.author),
                               Messages.in_channel(src.channel)),
                    timeout=20,
                )

                if chans is None:
                    return (
                        "Sorry, the request timed out. Please make sure you"
                        " type a valid sequence of numbers.")
                if self.validate_channel(channels_list, chans.content):
                    break
                else:
                    await self.client.send_message(
                        src.author,
                        src.channel,
                        "Invalid channel choices. You may try again immediately.",
                    )
            post_to = []
            for i in chans.content:
                print(channels_list[int(i)])
                post_to.append(channels_list[int(i)])
        else:
            # Use the Reaction-based GUI.
            menu = Menu(
                self.client,
                src.channel,
                "Event Announcement Post (by {})".format(
                    src.author.display_name),
                "Use the Reaction Buttons to fill out the Announcement.",
                user=src.author,
            )
            if _image:
                menu.em.set_thumbnail(url=_image)
            selection = await menu.get_multi(list(channels_dict),
                                             title="Target Channels")
            post_to = [
                channels_dict[c] for c in selection if c in channels_dict
            ]
            if not post_to:
                # menu.add_section(
                #     "No valid target channels selected; Post canceled.", "Verdict"
                # )
                # await menu.close("No valid target channels selected; Post canceled.")
                menu.add_section("No Channels selected; Cancelled.",
                                 "Target Channels",
                                 overwrite=-1)
                await menu.post()
                return
            menu.add_section("\n".join([c.mention for c in post_to]),
                             "Target Channels",
                             overwrite=-1)
            await menu.post()

        try:
            msgstr = (_message or (await Messages.waitfor(
                self.client,
                all_checks(
                    Messages.by_user(src.author),
                    Messages.in_channel(src.channel),
                ),
                timeout=120,
                channel=src.channel,
                prompt="What do you want to send?"
                " (remember: {e} = `@ev` and {h} = `@here`)",
            )).content).format(e="@everyone", h="@here")

        except AttributeError:
            # Likely tried to get `None.content`.
            raise CommandOperationError("Text Input timed out.")

        if _nomenu:
            embed = discord.Embed(title="Message to post",
                                  description=msgstr,
                                  colour=0x0ACDFF)
            embed.add_field(name="Channels",
                            value="\n".join([c.mention for c in post_to]))
            await self.client.embed(src.channel, embed)

            msg2 = await Messages.waitfor(
                self.client,
                all_checks(Messages.by_user(src.author),
                           Messages.in_channel(src.channel)),
                timeout=20,
                channel=src.channel,
                prompt="If this is correct, type `confirm`.",
            )

            if msg2 is None:
                return "Event post timed out."
            elif msg2.content.lower() != "confirm":
                return "Event post cancelled."
        else:
            # confirmer = Menu(self.client, src.channel, "Confirm Post", user=src.author)
            menu.add_section(msgstr, "Message Preview")
            proceed = await menu.get_bool(
                prompt="Send this Event Announcement?", title="Confirmation")
            if proceed is None:
                # menu.em.description = "[ Closed ]"
                menu.add_section("Posting timed out.",
                                 "Confirmation",
                                 overwrite=-1)
                return
            elif proceed is not True:
                # menu.em.description = "[ Closed ]"
                menu.add_section("Posting cancelled.",
                                 "Confirmation",
                                 overwrite=-1)
                return

        posted: List[discord.Message] = []
        # TODO
        # em = discord.Embed()
        # if _image:
        #     em.set_image(url=_image)
        for i in post_to:
            posted.append(await i.send(msgstr))
            await asyncio.sleep(1)

        if menu:
            menu.add_section("Messages have been posted.",
                             "Confirmation",
                             overwrite=-1)
            await menu.post()
        else:
            # menu.em.description = "[ Closed ]"
            await self.client.send_message(src.author, src.channel,
                                           "Messages have been posted.")

        try:
            subkey, subname = self.get_event_subscription(msgstr)
        except AttributeError:
            pass
        else:
            if subkey is None:
                return (
                    "I was unable to auto-detect any game titles in your post."
                    " No subscribers will be notified for this event.")
            else:
                n = await Messages.waitfor(
                    self.client,
                    all_checks(Messages.by_user(src.author),
                               Messages.in_channel(src.channel)),
                    timeout=20,
                    channel=src.channel,
                    prompt=
                    f"I auto-detected a possible game in your announcement:"
                    f" **{subname}**. Would you like to notify subscribers? [y/N]",
                )

                if not n:
                    return "Timed out."
                elif n.content.lower() not in ("y", "yes"):
                    return "Subscribers will not be notified."
                else:
                    response = await self.notify_subscribers(
                        src.channel, posted[0], subkey)
                    todelete = "[{}]".format(subkey)
                    for post in posted:
                        content = post.content
                        #    print(content)
                        #    print(todelete)
                        if todelete in content:
                            # print("replacing")
                            content = content.replace(todelete, "")
                            # print("replaced: " + content)
                            await post.edit(content=content)

                    return response
Exemplo n.º 9
0
    async def cmd_send(self,
                       args,
                       src: discord.Message,
                       _everyone: bool = False,
                       _here: bool = False,
                       _identity: str = None,
                       _i: str = None,
                       _image: str = None,
                       _I: str = None,
                       **_):
        """Broadcast an official-looking message into another channel.

        By using the Identity Option, you can specify who the message is from.
        Valid Identities:```\n{}```

        Syntax: `{{p}}send [OPTIONS] <channel-id> ["<message>"]`

        Parameters
        ----------
        _ : dict
            Dict of additional Keyword Args.
        self
            self
        args : List[str]
            List of Positional Arguments supplied after Command.
        src : discord.Message
            The Discord Message that invoked this Command.
        _everyone : bool
            Include an `@everyone` ping in the message. Overrides `--here`.
        _here : bool
            Include a `@here` ping in the message.
        _identity, _i : str
            Select the group/team on whose behalf this message is being sent.
        _image, _I : str
            Provide the URL of an image to be included in the embed.
        """
        if 2 < len(args) < 1:
            raise CommandArgsError(
                "Must provide a Channel ID and, optionally, a quoted message.")
        elif not args[0].isdigit():
            raise CommandArgsError("Channel ID must be integer.")

        destination: discord.TextChannel = self.client.get_channel(
            int(args.pop(0)))
        if not destination:
            raise CommandArgsError("Invalid Channel.")

        if not args:
            await self.client.send_message(
                src.author,
                src.channel,
                "Please give a message to send (just reply below):",
            )
            try:
                msg = await self.client.wait_for(
                    "message",
                    check=checks.all_checks(
                        checks.Messages.by_user(src.author),
                        checks.Messages.in_channel(src.channel),
                    ),
                    timeout=30,
                )
            except asyncio.TimeoutError:
                raise CommandInputError("Timed out while waiting for message.")
            else:
                text = msg.content
        else:
            text = args[0]

        identity = (_identity or _i or default).lower()
        ident = idents.get(identity, idents[list(sorted(idents.keys()))[0]])
        ident["description"] = text
        img = _image or _I

        try:
            preview = discord.Embed(**ident)
            if img:
                preview.set_image(url=img)
            menu = Menu(self.client, src.channel, "", "", user=src.author)
            menu.em = preview

            confirm = await menu.get_bool(
                prompt="Send this message to {} on behalf of {}?\n"
                "(This section will not be sent.)".format(
                    destination.mention, identity) +
                ("\n***NOTE: THIS MESSAGE WILL SEND A MASS PING!***"
                 if _everyone or _here else ""),
                title="Confirm",
            )

            if confirm is True:
                em = discord.Embed(**ident)
                if img:
                    em.set_image(url=img)
                if _everyone:
                    await destination.send("(@everyone)", embed=em)
                elif _here:
                    await destination.send("(@here)", embed=em)
                else:
                    await destination.send(embed=em)
                # await self.client.embed(destination, em)
            elif confirm is False:
                raise CommandExit("Message cancelled.")
            else:
                raise CommandExit("Confirmation timed out.")

        except discord.errors.Forbidden:
            raise CommandOperationError(
                "Failed to send message: Access Denied")
        else:
            return ("{} (ID: `{}`) sent the following message to {}"
                    " on behalf of `{}`:\n{}".format(
                        src.author.name,
                        str(src.author.id),
                        destination.mention,
                        identity,
                        text,
                    ))
Exemplo n.º 10
0
    async def cmd_bugger(self, args: Args, src: Src, **_):
        """Report a bug, adding it to the Trello board.

        Syntax: `{p}bugger "<bug report>"`
        """
        if self.config.get("trello") is None:
            raise CommandOperationError(
                "Sorry, the bot maintainer has not enabled Trello bug reports."
            )
        try:
            url = f"https://api.trello.com/1/lists/{self.config.get('trello/list_id')}/cards"
            params = {
                "key": self.config.get("trello/app_key"),
                "token": self.config.get("trello/token"),
            }
            response = requests.request("GET", url, params=params)

        except KeyError:
            raise CommandOperationError(
                "The Trello keys are misconfigured, check your config file")

        if not response:
            raise CommandOperationError(
                "Could not get cards for the list ID provided. Talk to your bot"
                " owner.")

        ticketnumber = str(
            max((int(card["name"])
                 for card in (response.json()) if card["name"].isnumeric())) +
            1)

        params.update({
            "name":
            ticketnumber.zfill(3),
            "desc": ("{message}\n\n\n\n\n"
                     "Submitted by: {author.name} ({author.id})\n"
                     "Timestamp: {time}\n"
                     "Guild: {guild.name} ({guild.id})\n"
                     "Channel: {channel.name} ({channel.id})".format(
                         message=" ".join(args),
                         author=src.author,
                         channel=src.channel,
                         guild=src.guild,
                         time=dt.utcnow(),
                     )),
            "pos":
            "bottom",
            "idList":
            self.config.get("trello/list_id"),
            "username":
            self.config.get("trello/username"),
        })

        response = requests.request("POST",
                                    "https://api.trello.com/1/cards",
                                    params=params)

        if not response:
            raise CommandOperationError(
                "Could not create bug report. Talk to your bot owner.")

        return f"Created bug report with ID `{ticketnumber}`"
Exemplo n.º 11
0
    async def cmd_osu(self,
                      args: Args,
                      src: Src,
                      _set: str = None,
                      _s: str = None,
                      **_):
        """Display information about an Osu player.

        A username to search may be provided to this command. If no username is provided, the command will try to display your profile instead. If you have not provided your username, your Discord username will be used.
        Your Osu username may be provided with `{p}osu --set <username>`.

        Syntax: `{p}osu [<username>]`

        Options:
        `--set <username>`, `-s <username>` :: Save your Osu username, so you can simply use `{p}osu`.
        """
        if not self.router.osu:
            raise CommandOperationError("Osu Support is not configured.")
        name = _set or _s
        if name:
            osu = args[0] if args else src.author.name

            if not self.db.useDB:
                raise CommandOperationError(
                    "Database is not enabled, so you can't save an osu name.\n"
                    "You can still use `{}osu <username>` though.".format(
                        self.config.prefix))

            self.db.update_member(src.author, {"osu": osu})

            return (
                "You have set `{}` as your preferred OSU account. You can now"
                " run `{}osu` and it will use this name automatically!".format(
                    name, self.config.prefix))

        if not args:
            # No username specified; Print info for invoker
            if self.db.useDB:
                # Check whether the user has provided a specific name
                username = self.db.get_attribute(src.author,
                                                 "osu") or src.author.name
            else:
                # Otherwise, try their Discord username
                username = src.author.name

            user = self.router.osu.get_user(username)

            if user is None:
                raise CommandOperationError(
                    "You have not set an Osu username, and no data was found"
                    " under your Discord username.")
        else:
            user = self.router.osu.get_user(args[0])
            if user is None:
                raise CommandInputError("No user found with Osu! name: " +
                                        args[0])

        em = discord.Embed(
            title=user.name,
            description="https://osu.ppy.sh/u/{}".format(user.id),
            colour=0x0ACDFF,
        )

        em.set_author(name="Osu Data", icon_url=self.client.user.avatar_url)
        em.set_thumbnail(url="http://a.ppy.sh/" + user.id)
        em.add_field(name="Maps Played",
                     value="{:,}".format(int(user.playcount)))
        em.add_field(name="Total Score",
                     value="{:,}".format(int(user.total_score)))
        em.add_field(name="Level",
                     value=str(round(float(user.level), 2)),
                     inline=False)
        em.add_field(name="Accuracy",
                     value=str(round(float(user.accuracy), 2)))
        em.add_field(name="PP Rank",
                     value="{:,}".format(int(user.rank)),
                     inline=False)
        em.add_field(
            name="Local Rank ({})".format(user.country),
            value="{:,}".format(int(user.country_rank)),
        )
        return em
Exemplo n.º 12
0
    async def cmd_askpatch(self, args, src, **_):
        """Access the AskPatch database. Functionality determined by subcommand.

        Syntax:
        `{p}askpatch submit "<question>"` - Submit a question to Patch Asks. Should be quoted.
        `{p}askpatch approve <question-id>` - Approve a submitted question and add it to the Patch Asks DB.
        `{p}askpatch reject <question-id>` - Reject a submitted question from being added.
        `{p}askpatch count` - Return the number of questions currently queued for use.
        """
        if not args:
            raise CommandArgsError("Subcommand required.")

        subcom = args.pop(0)

        if subcom == "submit":
            if not args:
                raise CommandInputError("Question cannot be empty.")
            elif len(args) > 1:
                raise CommandInputError("Question should be put in quotes.")
            else:
                msg = args[0]

            response = self.db.submit_motd(src.author.id, msg)
            if response is None:
                raise CommandOperationError(
                    "Unable to add to database, ask your bot owner as to why."
                )

            em = discord.Embed(
                title=f"Entry {response['num']}",
                description=f"New question from `{userline(src.author)}`",
                colour=0x8738F,
            )
            em.add_field(name="content", value=response["content"])

            chan = self.client.get_channel(self.config.get("motdModChannel"))
            await self.client.embed(chan, embedded=em)

            return "Question added to database."

        elif subcom == "approve":
            if src.channel.id != self.config.get("motdModChannel"):
                raise CommandOperationError("You can't use that here.")
            if not args:
                raise CommandInputError("You need to specify an entry.")
            if not all(x.isdigit() for x in args):
                raise CommandInputError("Every entry must be an integer.")

            for targ in args:
                result = self.db.update_motd(int(targ), approve=True)
                if result is None:
                    raise CommandOperationError(
                        f"No entries exist with id number: {targ}"
                    )

                em = discord.Embed(
                    title=f"Approved {result['num']}",
                    description=result["content"],
                    colour=0x00FF00,
                ).add_field(name="Submitted by", value=f"<@{result['author']}>")

                return em

        elif subcom == "reject":
            if src.channel.id != self.config.get("motdModChannel"):
                raise CommandOperationError("You can't use that here.")
            if not args:
                raise CommandInputError("You need to specify an entry.")
            if not all(x.isdigit() for x in args):
                raise CommandInputError("Every entry must be an integer.")

            for targ in args:
                result = self.db.update_motd(int(targ), approve=False)
                if result is None:
                    raise CommandOperationError(
                        f"No entries exist with id number: {targ}"
                    )

                em = discord.Embed(
                    title=f"Rejected {result['num']}",
                    description=result["content"],
                    colour=0xFFA500,
                ).add_field(name="Submitted by", value=f"<@{result['author']}>")

                return em

        elif subcom == "count":
            count = self.db.motd.count({"approved": True, "used": False})
            return f"Question queue currently contains `{count}` entries."

        else:
            raise CommandInputError("Unrecognized subcommand.")