Esempio n. 1
0
    async def get_one(self,
                      opts: Sequence[T_],
                      time: int = 30,
                      title: str = "Select One") -> Optional[T_]:
        """Ask the user to select ONE of a set of predefined options."""
        onum = len(opts)
        if not 1 <= onum <= len(letters):
            return None
        selection = [cancel, *letters[:onum]]
        self.add_section(
            "\n".join(f"{letters[i]}: `{opts[i]}`" for i in range(onum)),
            title)
        buttons: Task = await self.add_buttons(selection)
        await self.post()

        choice = (await Reactions.waitfor(
            self.client,
            all_checks(Reactions.by_user(self.master),
                       Reactions.on_message(self.msg)),
            timeout=time,
        ))[0]

        if not choice or choice.emoji == cancel:
            result = None
        else:
            result = opts[letters.index(choice.emoji)]

        await buttons
        await self.clear()
        return result
Esempio n. 2
0
    async def get_bool(self,
                       time: int = 30,
                       prompt: str = "Select Yes or No",
                       title: str = "Boolean Choice") -> Optional[bool]:
        """Ask the user to click a simple YES or NO."""
        selection = (cancel, confirm)

        # self.em.description = prompt or "Select Yes or No"
        # await self.post()
        # adding = create_task(self.add_buttons(selection))
        self.add_section(prompt, title)
        adding: Task = await self.add_buttons(selection)
        await self.post()

        choice = (await Reactions.waitfor(
            self.client,
            all_checks(Reactions.by_user(self.master),
                       Reactions.on_message(self.msg)),
            timeout=time,
        ))[0]

        await adding
        await self.clear()

        if not choice:
            return None
        elif choice.emoji == confirm:
            return True
        elif choice.emoji == cancel:
            return False
        else:
            return None
Esempio n. 3
0
 async def cmd_repeat(self, src, **_):
     return "You said:```{}```".format((await Messages.waitfor(
         self.client,
         all_checks(Messages.by_user(src.author),
                    Messages.in_channel(src.channel)),
         channel=src.channel,
         prompt="say thing",
     )).content)
Esempio n. 4
0
    async def get_multi(
        self,
        opts: Sequence[T_],
        time: int = 30,
        prompt: str = "Select One or More and Confirm:",
        title: str = "Multiple Choice",
    ) -> Tuple[T_, ...]:
        """Ask the user to select ONE OR MORE of a set of predefined options."""
        onum = len(opts)
        if not 1 <= onum <= len(letters):
            return ()
        selection = [cancel, *letters[:onum], confirm]
        self.add_section(
            "\n".join([prompt] +
                      [f"{letters[i]}: `{opts[i]}`" for i in range(onum)]),
            title,
        )
        buttons: Task = await self.add_buttons(selection)
        await self.post()

        ok = (str(cancel), str(confirm))
        pre = all_checks(Reactions.by_user(self.master),
                         Reactions.on_message(self.msg))

        def check(react_: Reaction, user: User) -> bool:
            return pre(react_, user) and str(react_.emoji) in ok

        choice = (await Reactions.waitfor(self.client, check, timeout=time))[0]

        if not choice or choice.emoji == cancel:
            await self.clear()
            return ()

        try:
            vm: Message = await self.channel.fetch_message(self.msg.id)
        except:
            await self.clear()
            return ()

        results: Tuple[T_, ...] = tuple([
            opts[letters.index(react.emoji)] for react in vm.reactions
            if (react.emoji in selection[1:-1]
                and self.master in await react.users().flatten())
        ])

        await buttons
        await self.clear()
        return results
Esempio n. 5
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}"
Esempio n. 6
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)
Esempio n. 7
0
    async def cmd_warn(self, args, src: discord.Message, **_):
        """Send an official and logged warning to a user.

        Syntax: `{p}warn <user tag/id>`
        """
        if not args:
            return

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

        guild = self.client.main_guild
        userToWarn = guild.get_member(int(args[0]))
        if userToWarn is None:
            return "Could not get user with that ID."
        elif userToWarn.id == self.client.user.id:
            return (
                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 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:
            return "Timed out while waiting for message."

        else:
            try:
                warnEmbed = discord.Embed(
                    title="Official Warning",
                    description="The guild has sent you an official warning",
                    colour=0xFFF600,
                )

                warnEmbed.add_field(name="Reason", value=msg.content)
                warnEmbed.add_field(name="Issuing Server",
                                    value=src.guild.name,
                                    inline=False)
                await self.client.embed(userToWarn, warnEmbed)

            except discord.errors.Forbidden:
                return "It seems I don't have perms to warn this user"
            else:
                logEmbed = discord.Embed(title="User Warn",
                                         description=msg.content,
                                         colour=0xFF600)
                logEmbed.set_author(
                    name=self.client.user.name,
                    icon_url="https://puu.sh/tADFM/dc80dc3a5d.png",
                )
                logEmbed.add_field(name="Issuer",
                                   value=src.author.name + "\n" +
                                   str(src.author.id))
                logEmbed.add_field(name="Recipient",
                                   value=userToWarn.name + "\n" +
                                   str(userToWarn.id))
                logEmbed.add_field(name="Server", value=userToWarn.guild.name)
                logEmbed.add_field(name="Timestamp",
                                   value=str(dt.utcnow())[:-7])
                logEmbed.set_thumbnail(url=userToWarn.avatar_url)

                await self.client.embed(
                    self.client.get_channel(self.config.modChannel), logEmbed)
                return (userToWarn.name + " (ID: " + str(userToWarn.id) +
                        ") was successfully warned")
Esempio n. 8
0
    async def cmd_tempban(
        self,
        args,
        src: discord.Message,
        _reason: str = None,
        _purge: int = 1,
        _days: int = None,
        **_,
    ):
        """Temporarily ban a user.

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

        Options:
        `--reason <str>` :: Provide a reason immediately, rather than typing a reason in a subsequent message.
        `--purge <int>` :: Determine how many days of messages by the banned user to delete. Default is 1. Can be between 0 and 7, inclusive.
        `--days <int>` :: Provide a ban duration immediately, rather than typing a number of days in a subsequent message.
        """
        if not args:
            return

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

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

        if not 0 <= _purge <= 7:
            return "Can only purge between 0 and 7 days of messages, inclusive."

        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:
                return "Timed out while waiting for reason."
            _reason = reason.content

        if not _days:
            await self.client.send_message(src.author, src.channel,
                                           "How long? (days) ")
            try:
                msg2 = await self.client.wait_for(
                    "message",
                    check=(lambda x: checks.all_checks(
                        checks.Messages.by_user(src.author),
                        checks.Messages.in_channel(src.channel),
                    )(x) and x.content.isdigit()),
                    timeout=30,
                )
            except asyncio.TimeoutError:
                return "Timed out while waiting for input"
            _days = int(msg2.content)

        try:
            # petal.logLock = True
            timex = time.time() + timedelta(days=int(_days)).total_seconds()
            self.client.db.update_member(
                userToBan,
                {
                    "banned": True,
                    "bannedFrom": userToBan.guild.id,
                    "banExpires": str(timex).split(".")[0],
                    "tempBanned": True,
                },
            )
            await userToBan.ban(reason=_reason, delete_message_days=_purge)
        except discord.errors.Forbidden:
            return "It seems I don't have perms to ban this user"
        else:
            logEmbed = discord.Embed(title="User Ban",
                                     description=_reason,
                                     colour=0xFF0000)

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

            await self.client.embed(
                self.client.get_channel(self.config.modChannel), logEmbed)
            return (
                userToBan.name + " (ID: " + str(userToBan.id) +
                ") was successfully temp-banned.\n\nThey will be unbanned on "
                + str(dt.utcnow() + timedelta(days=_days))[:-7])
Esempio n. 9
0
    async def cmd_ban(
        self,
        args,
        src: discord.Message,
        _reason: str = None,
        _purge: int = 1,
        _noconfirm: bool = False,
        **_,
    ):
        """Ban a user permanently.

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

        Options:
        `--reason <str>` :: Provide a reason immediately, rather than typing a reason in a subsequent message.
        `--purge <int>` :: Determine how many days of messages by the banned user to delete. Default is 1. Can be between 0 and 7, inclusive.
        `--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:
            return

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

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

        if not 0 <= _purge <= 7:
            return "Can only purge between 0 and 7 days of messages, inclusive."

        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:
                return "Timed out while waiting for reason."

            _reason = reason.content

        if not _noconfirm:
            await self.client.send_message(
                src.author,
                src.channel,
                "You are about to ban: " + userToBan.name +
                ". If this is correct, type `yes`.",
            )
            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:
                return "Timed out... user was not banned."
            if msg.content.lower() != "yes":
                return userToBan.name + " was not banned."

        try:
            # petal.logLock = True
            self.client.db.update_member(userToBan, {
                "banned": True,
                "tempBanned": False,
                "banExpires": None
            })
            await userToBan.ban(reason=_reason, delete_message_days=_purge)
        except discord.errors.Forbidden:
            return "It seems I don't have perms to ban this user."
        else:
            logEmbed = (discord.Embed(
                title="User Ban", description=_reason,
                colour=0xFF0000).set_author(
                    name=self.client.user.name,
                    icon_url="https://" + "puu.sh/tACjX/fc14b56458.png",
                ).add_field(name="Issuer",
                            value=src.author.name + "\n" +
                            str(src.author.id)).add_field(
                                name="Recipient",
                                value=userToBan.name + "\n" +
                                str(userToBan.id)).add_field(
                                    name="Server",
                                    value=userToBan.guild.name).add_field(
                                        name="Timestamp",
                                        value=str(
                                            dt.utcnow())[:-7]).set_thumbnail(
                                                url=userToBan.avatar_url))

            await self.client.embed(
                self.client.get_channel(self.config.modChannel), logEmbed)
            await asyncio.sleep(4)
            # petal.logLock = False
            response = await self.client.send_message(
                src.author,
                src.channel,
                userToBan.name + " (ID: " + str(userToBan.id) +
                ") was successfully banned.",
            )
            try:
                # Post-processing webhook for ban command
                return self.generate_post_process_URI(
                    src.author.name + src.author.discriminator,
                    _reason,
                    response.content,
                    userToBan.name + userToBan.discriminator,
                )
            except Exception as e:
                self.log.err(
                    "Could not generate post_process_message for ban: " +
                    str(e))
                return "Error occurred trying to generate webhook URI"
Esempio n. 10
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
Esempio n. 11
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,
                    ))