Ejemplo n.º 1
0
    async def edit(
        self,
        ctx: commands.Context,
        command: str,
        *,
        response=None,
        cooldowns: Mapping[str, int] = None,
        ask_for: bool = True,
    ):
        """Edit an already existing custom command"""
        ccinfo = await self.db(ctx.guild).commands.get_raw(command, default=None)

        # Check if this command is registered
        if not ccinfo:
            raise NotFound()

        author = ctx.message.author

        if ask_for and not response:
            await ctx.send(_("Do you want to create a 'randomized' custom command? (y/n)"))

            pred = MessagePredicate.yes_or_no(ctx)
            try:
                await self.bot.wait_for("message", check=pred, timeout=30)
            except TimeoutError:
                await ctx.send(_("Response timed out, please try again later."))
                return
            if pred.result is True:
                response = await self.get_responses(ctx=ctx)
            else:
                await ctx.send(_("What response do you want?"))
                try:
                    resp = await self.bot.wait_for(
                        "message", check=MessagePredicate.same_context(ctx), timeout=180
                    )
                except TimeoutError:
                    await ctx.send(_("Response timed out, please try again later."))
                    return
                response = resp.content

        if response:
            # test to raise
            ctx.cog.prepare_args(response if isinstance(response, str) else response[0])
            ccinfo["response"] = response

        if cooldowns:
            ccinfo.setdefault("cooldowns", {}).update(cooldowns)
            for key, value in ccinfo["cooldowns"].copy().items():
                if value <= 0:
                    del ccinfo["cooldowns"][key]

        if author.id not in ccinfo["editors"]:
            # Add the person who invoked the `edit` coroutine to the list of
            # editors, if the person is not yet in there
            ccinfo["editors"].append(author.id)

        ccinfo["edited_at"] = self.get_now()

        await self.db(ctx.guild).commands.set_raw(command, value=ccinfo)
Ejemplo n.º 2
0
 async def loa_time_input(ctx: commands.Context):
     """Handles getting Start and End Dates/Times for LOAs"""
     await ctx.maybe_send_embed(
         "When will your LOA begin? Enter as *`month/day`* or *`3d`*." + "\n"
         "Enter *`now`* if it will begin right now." + "\n"
         "Enter *`cancel`* to cancel submission."
     )
     try:
         msg = await ctx.bot.wait_for(
             "message", check=MessagePredicate.same_context(ctx), timeout=30
         )
     except asyncio.TimeoutError:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     if msg.content.lower().strip() in ["exit", "cancel", "stop", "no"]:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     startdate = await Time.fromString(msg.content)
     if startdate is None:
         startdate = await Date.fromString(msg.content)
     await ctx.maybe_send_embed(
         "When will your LOA end? Enter as *`month/day`* or *`3d`*." + "\n"
         "Enter *`cancel`* to cancel submission."
     )
     try:
         msg = await ctx.bot.wait_for(
             "message", check=MessagePredicate.same_context(ctx), timeout=30
         )
     except asyncio.TimeoutError:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     if msg.content.lower().strip() in ["exit", "cancel", "stop", "no"]:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     enddate = await Time.fromString(msg.content)
     if enddate is None:
         enddate = await Date.fromString(msg.content)
     if enddate is None:
         return await ctx.maybe_send_embed("Unable to parse End Date.")
     await ctx.maybe_send_embed(
         "Enter your reason for your LOA." + "\n" "Enter *`cancel`* to cancel submission."
     )
     try:
         msg = await ctx.bot.wait_for(
             "message", check=MessagePredicate.same_context(ctx), timeout=45
         )
     except asyncio.TimeoutError:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     if msg.content.lower().strip() in ["exit", "cancel", "stop", "no"]:
         return await ctx.maybe_send_embed("LOA Submission Cancelled.")
     reason = msg.content
     return startdate, enddate, reason
Ejemplo n.º 3
0
    async def get_responses(self, ctx):
        intro = _(
            "Welcome to the interactive random {cc} maker!\n"
            "Every message you send will be added as one of the random "
            "responses to choose from once this {cc} is "
            "triggered. To exit this interactive menu, type `{quit}`"
        ).format(cc="customcommand", quit="exit()")
        await ctx.send(intro)

        responses = []
        args = None
        while True:
            await ctx.send(_("Add a random response:"))
            msg = await self.bot.wait_for("message", check=MessagePredicate.same_context(ctx))

            if msg.content.lower() == "exit()":
                break
            else:
                try:
                    this_args = ctx.cog.prepare_args(msg.content)
                except ArgParseError as e:
                    await ctx.send(e.args[0])
                    continue
                if args and args != this_args:
                    await ctx.send(_("Random responses must take the same arguments!"))
                    continue
                args = args or this_args
                responses.append(msg.content)
        return responses
Ejemplo n.º 4
0
async def get_command_for_exceeded_points(ctx: commands.Context):
    """Gets the command to be executed when the user is at or exceeding
    the points threshold for the action"""
    await ctx.send(
        _(
            "Enter the command to be run when the user **exceeds the points for "
            "this action to occur.**\n**If you do not wish to have a command run, enter** "
            "`none`.\n\nEnter it exactly as you would if you were "
            "actually trying to run the command, except don't put a prefix and "
            "use `{user}` in place of any user/member arguments\n\n"
            "WARNING: The command entered will be run without regard to checks or cooldowns. "
            "Commands requiring bot owner are not allowed for security reasons.\n\n"
            "Please wait 15 seconds before entering your response."
        )
    )
    await asyncio.sleep(15)

    await ctx.send(_("You may enter your response now."))

    try:
        msg = await ctx.bot.wait_for(
            "message", check=MessagePredicate.same_context(ctx), timeout=30
        )
    except asyncio.TimeoutError:
        return None
    else:
        if msg.content == "none":
            return None

    command, m = get_command_from_input(ctx.bot, msg.content)
    if command is None:
        await ctx.send(m)
        return None

    return command
Ejemplo n.º 5
0
 async def changeIcon(self, ctx):
     """Modify your SCP:SL Server's Icon as shown on discord."""
     if not await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "SCPSL Module disabled on this server. Use `{prefix}scpsl enable` to enable the module for this server.".format(
                 prefix=ctx.prefix
             )
         )
     server = await self.config.guild(ctx.guild).server()
     global_servers = await self.config.global_servers()
     guildID = str(ctx.guild.id)
     if not guildID in global_servers and not server:
         try:
             await ctx.send(f"{ctx.guild.name} does not have a registered SCP:SL server")
         except discord.Forbidden:
             pass
         return
     await ctx.send("Enter a url to set as your Icon Thumbnail.")
     try:
         msg = await ctx.bot.wait_for(
             "message", check=MessagePredicate.same_context(ctx), timeout=25
         )
     except asyncio.TimeoutError:
         return await ctx.send("Server Registration Cancelled.")
     if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
         return await ctx.send("Server Editing Cancelled.")
     image = msg.content.strip()
     d = {"icon_url": image}
     await self.updateServer(ctx, d)
Ejemplo n.º 6
0
    async def _confirm(ctx: commands.Context) -> bool:
        """Ask "Are you sure?" and get the response as a bool."""
        if ctx.guild is None or ctx.guild.me.permissions_in(ctx.channel).add_reactions:
            msg = await ctx.send(_("Are you sure?"))
            # noinspection PyAsyncCall
            task = start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS, ctx.bot.loop)
            pred = ReactionPredicate.yes_or_no(msg, ctx.author)
            try:
                await ctx.bot.wait_for("reaction_add", check=pred, timeout=30)
            except asyncio.TimeoutError:
                await ctx.send(_("Response timed out."))
                return False
            else:
                task.cancel()
                agreed = pred.result
            finally:
                await msg.delete()
        else:
            await ctx.send(_("Are you sure? (y/n)"))
            pred = MessagePredicate.yes_or_no(ctx)
            try:
                await ctx.bot.wait_for("message", check=pred, timeout=30)
            except asyncio.TimeoutError:
                await ctx.send(_("Response timed out."))
                return False
            else:
                agreed = pred.result

        if agreed is False:
            await ctx.send(_("Action cancelled."))
        return agreed
Ejemplo n.º 7
0
    async def applysetup(self, ctx: commands.Context):
        """Go through the initial setup process."""
        pred = MessagePredicate.yes_or_no(ctx)
        applicant = get(ctx.guild.roles, name="Staff Applicant")
        channel = get(ctx.guild.text_channels, name="applications")

        await ctx.send(
            "This will create required channel and role. Do you wish to continue? (yes/no)"
        )
        try:
            await self.bot.wait_for("message", timeout=30, check=pred)
        except asyncio.TimeoutError:
            return await ctx.send("You took too long. Try again, please.")
        if pred.result is False:
            return await ctx.send("Setup cancelled.")
        if applicant is None:
            try:
                await ctx.guild.create_role(
                    name="Staff Applicant", reason="Application cog setup"
                )
            except discord.Forbidden:
                return await ctx.send(
                    "Uh oh. Looks like I don't have permissions to manage roles."
                )
        if channel is None:
            await ctx.send(
                "Do you want everyone to see the applications channel? (yes/no)"
            )
            try:
                await self.bot.wait_for("message", timeout=30, check=pred)
            except asyncio.TimeoutError:
                return await ctx.send("You took too long. Try again, please.")
            if pred.result is True:
                overwrites = {
                    ctx.guild.default_role: discord.PermissionOverwrite(
                        send_messages=False
                    ),
                    ctx.guild.me: discord.PermissionOverwrite(send_messages=True),
                }
            else:
                overwrites = {
                    ctx.guild.default_role: discord.PermissionOverwrite(
                        read_messages=False
                    ),
                    ctx.guild.me: discord.PermissionOverwrite(read_messages=True),
                }
            try:
                await ctx.guild.create_text_channel(
                    "applications",
                    overwrites=overwrites,
                    reason="Application cog setup",
                )
            except discord.Forbidden:
                return await ctx.send(
                    "Uh oh. Looks like I don't have permissions to manage channels."
                )
        await ctx.send(
            "You have finished the setup! Please, move your new channel to the category you want it in."
        )
Ejemplo n.º 8
0
    async def discover_guild(
        self,
        author: discord.User,
        *,
        mod: bool = False,
        permissions: Union[discord.Permissions, dict] = None,
        prompt: str = "",
    ):
        """
        discovers which of shared guilds between the bot
        and provided user based on conditions (mod or permissions is an or)
        prompt is for providing a user prompt for selection
        """
        shared_guilds = []
        if permissions is None:
            perms = discord.Permissions()
        elif isinstance(permissions, discord.Permissions):
            perms = permissions
        else:
            perms = discord.Permissions(**permissions)

        for guild in self.bot.guilds:
            x = guild.get_member(author.id)
            if x is not None:
                if await self.internal_filter(x, mod, perms):
                    shared_guilds.append(guild)
        if len(shared_guilds) == 0:
            raise ValueError("No Qualifying Shared Guilds")
        if len(shared_guilds) == 1:
            return shared_guilds[0]
        output = ""
        guilds = sorted(shared_guilds, key=lambda g: g.name)
        for i, guild in enumerate(guilds, 1):
            output += "{}: {}\n".format(i, guild.name)
        output += "\n{}".format(prompt)

        for page in pagify(output, delims=["\n"]):
            await author.send(box(page))

        try:
            message = await self.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(channel=author.dm_channel,
                                                    user=author),
                timeout=45,
            )
        except asyncio.TimeoutError:
            await author.send(
                _("You took too long to select. Try again later."))
            return None

        try:
            message = int(message.content.strip())
            guild = guilds[message - 1]
        except (ValueError, IndexError):
            await author.send(_("That wasn't a valid choice."))
            return None
        else:
            return guild
Ejemplo n.º 9
0
    async def enter_article(self, ctx, selected_domain):

        message = await ctx.send(content="Enter the wikia article for " + selected_domain["name"] + ":", delete_after=10)
        response = await ctx.bot.wait_for("message", check=MessagePredicate.same_context(ctx))

        response = str(response.content).replace(" ", "+")

        return response
Ejemplo n.º 10
0
 async def confirmation(self, ctx: commands.Context, _type: str):
     await ctx.send(
         f"Are you sure you want to {_type} {ctx.me.name}? (yes/no)")
     with contextlib.suppress(asyncio.TimeoutError):
         pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
         await ctx.bot.wait_for("message", check=pred, timeout=60)
         return pred.result
     return False
Ejemplo n.º 11
0
    async def start(self, ctx: commands.Context):
        """
        Begin a game session with Aikanator.

        To answer a question, you can use the following terms:
        - "yes" OR "y" OR "0" for answering "Yes".
        - "no" OR "n" OR "1" for answer "No".
        - "i" OR "idk" OR "i dont know" OR "i don't know" OR "2" for answer "I don't know".
        - "probably" OR "p" OR "3" for answering "Probably".
        - "probably not" OR "pn" OR "4" for answering "Probably not".

        You can also say "b" or "back" to change your last question.
        """

        await ctx.send_help()
        await ctx.send("Are you ready to answer Akinator's questions? (y/n)")
        check = MessagePredicate.yes_or_no(ctx=ctx)
        try:
            await self.bot.wait_for("message", timeout=60, check=check)
        except TimeoutError:
            check.result = False
        if not check.result:
            await ctx.send("See you later then! \N{WAVING HAND SIGN}")
            return
        await ctx.send("Let's go!")
        game_class = UserGame(ctx.author, ctx.channel, self.bot)
        self.ongoing_games[ctx.author.id] = game_class
        await ctx.send(
            "Do you wish to set a specific language? If so, please specify it now (Find all "
            "available language at <https://github.com/NinjaSnail1080/akinator.py#functions>) else "
            "just say 'no'."
        )
        try:
            res = await self.bot.wait_for(
                "message", timeout=60, check=MessagePredicate.same_context(ctx=ctx)
            )
        except asyncio.TimeoutError:
            await ctx.send("You didn't answered in time... \N{PENSIVE FACE}")
            return
        res = res.content.lower()
        lang = res if res not in ("no", "n") else "en"
        await game_class.start_akinator_game(language=lang)
        try:
            del self.ongoing_games[ctx.author.id]
        except KeyError:
            pass
Ejemplo n.º 12
0
    async def deny(self, ctx: commands.Context, target: discord.Member):
        """Deny a staff applicant.
        <target> can be a mention or an ID"""
        try:
            accepter = get(ctx.guild.roles,
                           id=await self.config.guild(ctx.guild).accepter_id())
        except TypeError:
            accepter = None
        if not accepter:
            if not ctx.author.guild_permissions.administrator:
                return await ctx.send("Uh oh, you cannot use this command.")
        else:
            if accepter not in ctx.author.roles:
                return await ctx.send("Uh oh, you cannot use this command.")
        try:
            applicant = get(ctx.guild.roles,
                            id=await
                            self.config.guild(ctx.guild).applicant_id())
        except TypeError:
            applicant = None
        if not applicant:
            applicant = get(ctx.guild.roles, name="Staff Applicant")
            if not applicant:
                return await ctx.send(
                    "Uh oh, the configuration is not correct. Ask the Admins to set it."
                )
        if applicant in target.roles:
            await ctx.send("Would you like to specify a reason? (yes/no)")
            pred = MessagePredicate.yes_or_no(ctx)
            try:
                await self.bot.wait_for("message", timeout=30, check=pred)
            except asyncio.TimeoutError:
                return await ctx.send("You took too long. Try again, please.")
            if pred.result:
                await ctx.send("Please, specify your reason now.")

                def check(m):
                    return m.author == ctx.author

                try:
                    reason = await self.bot.wait_for("message",
                                                     timeout=120,
                                                     check=check)
                except asyncio.TimeoutError:
                    return await ctx.send(
                        "You took too long. Try again, please.")
                await target.send(
                    f"Your application in {ctx.guild.name} has been denied.\n*Reason:* {reason.content}"
                )
            else:
                await target.send(
                    f"Your application in {ctx.guild.name} has been denied.")
            await target.remove_roles(applicant)
            await ctx.send(f"Denied {target.mention}'s application.")
        else:
            await ctx.send(
                f"Uh oh. Looks like {target.mention} hasn't applied for anything."
            )
Ejemplo n.º 13
0
    async def accept(self, ctx: commands.Context, target: discord.Member):
        """Accept a staff applicant.

        <target> can be a mention or an ID."""
        if not await self.config.guild(ctx.guild).channel_id():
            return await ctx.send(
                "Uh oh, the configuration is not correct. Ask the Admins to set it."
            )

        try:
            accepter = ctx.guild.get_role(
                await self.config.guild(ctx.guild).accepter_id()
            )
        except TypeError:
            accepter = None
        if (
            not accepter
            and not ctx.author.guild_permissions.administrator
            or (accepter and accepter not in ctx.author.roles)
        ):
            return await ctx.send("Uh oh, you cannot use this command.")

        applicant = None
        if await self.config.guild(ctx.guild).applicant_id():
            try:
                applicant = ctx.guild.get_role(
                    await self.config.guild(ctx.guild).applicant_id()
                )
            except TypeError:
                applicant = None
            if not applicant:
                applicant = get(ctx.guild.roles, name="Staff Applicant")
            if not applicant:
                return await ctx.send(
                    "Uh oh, the configuration is not correct. Ask the Admins to set it."
                )
            if applicant not in target.roles:
                return await ctx.send(
                    f"Uh oh. Looks like {target.mention} hasn't applied for anything."
                )

        await ctx.send(f"What role do you want to accept {target.name} as?")
        role = MessagePredicate.valid_role(ctx)
        try:
            await self.bot.wait_for("message", timeout=30, check=role)
        except asyncio.TimeoutError:
            return await ctx.send("You took too long. Try again, please.")
        role_add = role.result
        try:
            await target.add_roles(role_add)
        except discord.Forbidden:
            return await ctx.send(
                "Uh oh, I cannot give them the role. It might be above all of my roles."
            )
        if applicant:
            await target.remove_roles(applicant)
        await ctx.send(f"Accepted {target.mention} as {role_add}.")
        await target.send(f"You have been accepted as {role_add} in {ctx.guild.name}.")
Ejemplo n.º 14
0
    async def repl(self, ctx):
        """
        Open an interactive REPL.

        The REPL will only recognise code as messages which start with a
        backtick. This includes codeblocks, and as such multiple lines can be
        evaluated.
        """
        if ctx.channel.id in self.sessions:
            await ctx.send(
                _("Already running a REPL session in this channel. Exit it with `quit`.")
            )
            return

        variables = Env.from_context(ctx)
        compiler = Compiler()

        self.sessions[ctx.channel.id] = True
        await ctx.send(_("Enter code to execute or evaluate. `exit()` or `quit` to exit."))

        while True:
            response = await ctx.bot.wait_for("message", check=MessagePredicate.regex(r"^`", ctx))

            if ctx.channel.id not in self.sessions:
                return
            if not self.sessions[ctx.channel.id]:
                continue

            cleaned = self.cleanup_code(response.content).strip()

            if cleaned.rstrip("( )") in ("quit", "exit", "stop"):
                del self.sessions[ctx.channel.id]
                await ctx.send(_("Exiting."))
                return

            if cleaned.startswith("from __future__ import"):
                try:
                    cleaned = self.handle_future(cleaned, compiler)
                except SyntaxError as e:
                    asyncio.ensure_future(
                        self.send_interactive(
                            ctx,
                            "# Exception:\nTraceback (most recent call last):\n"
                            + "".join(traceback.format_exception_only(type(e), e)),
                        )
                    )
                    continue

            await self.my_exec(
                ctx,
                cleaned,
                variables,
                "eval",
                "single",
                "exec",
                compiler=compiler,
                message=response,
            )
Ejemplo n.º 15
0
    async def delete_reminder(self, ctx: commands.Context, index: str):
        """Logic to delete reminders."""
        if not index:
            return
        author = ctx.message.author
        users_reminders = await self.get_user_reminders(author.id)

        if not users_reminders:
            await self.send_message(ctx,
                                    "You don't have any upcoming reminders.")
            return

        if index == "all":
            # Ask if the user really wants to do this
            pred = MessagePredicate.yes_or_no(ctx)
            await self.send_message(
                ctx,
                "Are you **sure** you want to remove all of your reminders? (yes/no)",
            )
            try:
                await ctx.bot.wait_for("message", check=pred, timeout=30)
            except asyncio.TimeoutError:
                pass
            if pred.result:
                pass
            else:
                await self.send_message(ctx,
                                        "I have left your reminders alone.")
                return
            await self._do_reminder_delete(users_reminders)
            await self.send_message(
                ctx, "All of your reminders have been removed.")
            return

        if index == "last":
            reminder_to_delete = users_reminders[len(users_reminders) - 1]
            await self._do_reminder_delete(reminder_to_delete)
            await self.send_message(
                ctx,
                "Your most recently created reminder (ID# **{}**) has been removed."
                .format(reminder_to_delete["USER_REMINDER_ID"]),
            )
            return

        try:
            int_index = int(index)
        except ValueError:
            await ctx.send_help()
            return

        reminder_to_delete = self.get_reminder(users_reminders, int_index)
        if reminder_to_delete:
            await self._do_reminder_delete(reminder_to_delete)
            await self.send_message(
                ctx,
                "Reminder with ID# **{}** has been removed.".format(int_index))
        else:
            await self.send_non_existant_msg(ctx, int_index)
Ejemplo n.º 16
0
    async def discover_guild(
        self,
        author: discord.User,
        *,
        mod: bool = False,
        permissions: Union[discord.Permissions, dict] = None,
        prompt: str = "",
    ):
        """
        discovers which of shared guilds between the bot
        and provided user based on conditions (mod or permissions is an or)

        prompt is for providing a user prompt for selection
        """
        shared_guilds = []
        if permissions is None:
            perms = discord.Permissions()
        elif isinstance(permissions, discord.Permissions):
            perms = permissions
        else:
            perms = discord.Permissions(**permissions)

        for guild in self.bot.guilds:
            x = guild.get_member(author.id)
            if x is not None:
                if await self.internal_filter(x, mod, perms):
                    shared_guilds.append(guild)
        if len(shared_guilds) == 0:
            raise ValueError("No Qualifying Shared Guilds")
        if len(shared_guilds) == 1:
            return shared_guilds[0]
        output = ""
        guilds = sorted(shared_guilds, key=lambda g: g.name)
        for i, guild in enumerate(guilds, 1):
            output += "{}: {}\n".format(i, guild.name)
        output += "\n{}".format(prompt)

        for page in pagify(output, delims=["\n"]):
            await author.send(box(page))

        try:
            message = await self.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(channel=author.dm_channel, user=author),
                timeout=45,
            )
        except asyncio.TimeoutError:
            await author.send(_("You took too long to select. Try again later."))
            return None

        try:
            message = int(message.content.strip())
            guild = guilds[message - 1]
        except (ValueError, IndexError):
            await author.send(_("That wasn't a valid choice."))
            return None
        else:
            return guild
Ejemplo n.º 17
0
 async def ticketset_case_add(self, ctx: commands.Context,
                              emoji: typing.Union[discord.Emoji, str]):
     """Add a support case type."""
     if await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "Uh oh, you cannot add nor remove cases while support is enabled."
         )
     cases = await self.config.guild(ctx.guild).cases.get_raw()
     try:
         if cases[emoji]:
             return await ctx.send(
                 "Uh oh, that emoji is already registered.")
     except KeyError:
         pass
     try:
         await ctx.message.add_reaction(emoji)
     except discord.HTTPException:
         return await ctx.send("Uh oh, I cannot use that emoji.")
     await ctx.send(
         "What is the title of this case? (e.g. Role change requested)")
     try:
         title = await self.bot.wait_for(
             "message",
             timeout=60,
             check=MessagePredicate.same_context(ctx))
     except asyncio.TimeoutError:
         return await ctx.send("You took too long.")
     await ctx.send(
         "What's the message in the reaction message? (e.g. to request a role change)"
     )
     try:
         desc = await self.bot.wait_for(
             "message",
             timeout=60,
             check=MessagePredicate.same_context(ctx))
     except asyncio.TimeoutError:
         return await ctx.send("You took too long.")
     await self.config.guild(ctx.guild).cases.set_raw(emoji,
                                                      value={
                                                          "title":
                                                          title.content,
                                                          "desc":
                                                          desc.content
                                                      })
     await ctx.send(f"{title.content} was assigned to {emoji}.")
Ejemplo n.º 18
0
    async def add_role(self,
                       ctx: GuildContext,
                       role: discord.Role,
                       member: discord.Member,
                       *,
                       reason: str = f"Added by {__cogname__}"):
        """
        Adds specified role to given user
        """
        if not await self.config.role(role).addable():
            return await ctx.maybe_send_embed("Role isn't set as addable.")
        try:
            if role in member.roles:
                return await ctx.maybe_send_embed(
                    "Member already has that role.")

            data = await self.config.role(role).USERS()
            if len(ctx.message.attachments):
                attachment = ctx.message.attachments[0]
                reason_message = REASON_MSG.format(reason, role,
                                                   attachment.url)
            else:
                await ctx.send(
                    f"Couldn't find attachment, do you want to continue without adding attachment?"
                )
                pred = MessagePredicate.yes_or_no(ctx)

                try:
                    await self.bot.wait_for("message", check=pred, timeout=30)
                except asyncio.TimeoutError:
                    return await ctx.send("Timed out.")

                if pred.result:
                    reason_message = REASON_MSG.format(reason, role,
                                                       "No attachment.")
                else:
                    return await ctx.maybe_send_embed("Cancelling command.")

            case = await modlog.create_case(
                self.bot,
                member.guild,
                ctx.message.created_at,
                "roleupdate",
                member,
                moderator=ctx.author,
                reason=reason_message,
            )

            caseno = case.case_number
            data[member.id] = caseno
            await self.config.role(role).USERS.set(data)

            await member.add_roles(role)
            await ctx.tick()
        except discord.Forbidden:
            return await ctx.maybe_send_embed(
                "Can't do that. Discord role heirarchy applies here.")
Ejemplo n.º 19
0
    async def getInput(self, ctx: commands.Context, turn):
        position = MessagePredicate.contained_in(
            self.options, channel=ctx.channel, user=turn)
        try:
            choice = await ctx.bot.wait_for("message", check=position, timeout=5.0)
        except asyncio.TimeoutError:
            return None

        return int(choice.content)
Ejemplo n.º 20
0
    async def mod(self, ctx, module: str = None):
        """Get module versions."""
        
        if not module:
            embed = self.modvinfo_format(base)
            embed.color = await ctx.embed_colour()
            embed.set_footer(
                text="Find a specific module version by adding the module argument."
            )
            await ctx.send(embed=embed)
            return await ctx.send_help()

        await ctx.trigger_typing()

        try:
            MOD = __import__(module)
        except ModuleNotFoundError:
            none_found = "- You do not have an installed module named `{}`.".format(module)
            pipinstall = await ctx.send(box(none_found + "\n--- Would you like to pip install it? (yes/no)", lang="diff"))
            try:
                pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
                msg = await ctx.bot.wait_for("message", check=pred, timeout=20)
            except asyncio.TimeoutError:
                return await pipinstall.edit(content=box(none_found, lang="diff"))
            if pred.result:
                return await ctx.invoke(self.bot.get_command("pipinstall"), module)
            else:
                return await pipinstall.edit(content=box(none_found, lang="diff"))

        check_attrs = self.check_attrs(MOD)

        if not check_attrs:
            return await ctx.send(
                box("# Could not find a version for `{}`.", lang="cs").format(MOD.__name__)
            )

        vinfo = check_attrs

        if isinstance(vinfo[0], tuple) and vinfo[1] == "(Core/Builtin Python)":
            value = ("{}." * len(vinfo[0])).strip('.').format(*vinfo[0])
            attr = f"None {vinfo[1]}"
        
        elif isinstance(vinfo[0], (list, tuple)):
            value = ("{}." * len(vinfo[0])).strip('.').format(*vinfo[0])
            attr = f"`{MOD.__name__}{vinfo[1]}`"

        else:
            value = vinfo[0]
            attr = f"`{MOD.__name__}{vinfo[1]}`"


        await ctx.send(
            box(
                f"Attribute: {attr}\nFound version info for [{module}]: {value}",
                lang="yaml",
            )
        )
Ejemplo n.º 21
0
    async def delete_reminder(self, ctx: commands.Context, index: str):
        """Logic to delete reminders."""
        if not index:
            return
        author = ctx.message.author
        to_remove = await self.get_user_reminders(author.id)

        if not to_remove:
            await self.send_message(ctx, "You don't have any upcoming reminders.")
            return

        async with self.config.reminders() as current_reminders:
            if index == "all":
                # Ask if the user really wants to do this
                pred = MessagePredicate.yes_or_no(ctx)
                await self.send_message(
                    ctx,
                    "Are you **sure** you want to remove all of your reminders? (yes/no)",
                )
                try:
                    await ctx.bot.wait_for("message", check=pred, timeout=30)
                except asyncio.TimeoutError:
                    pass
                if pred.result:
                    pass
                else:
                    await self.send_message(ctx, "I have left your reminders alone.")
                    return
                for reminder in to_remove:
                    current_reminders.remove(reminder)
                await self.send_message(ctx, "All of your reminders have been removed.")
                return

            if index == "last":
                current_reminders.remove(to_remove[len(to_remove) - 1])
                await self.send_message(
                    ctx, "Your most recently created reminder has been removed."
                )
                return

            try:
                int_index = int(index)
            except ValueError:
                return
            if int_index > 0:
                if len(to_remove) < int_index:
                    await self.send_message(
                        ctx,
                        "You don't have that many reminders! (you only have {})".format(
                            len(to_remove)
                        ),
                    )
                else:
                    current_reminders.remove(to_remove[int_index - 1])
                    await self.send_message(
                        ctx, "Reminder #{} has been removed.".format(int_index)
                    )
Ejemplo n.º 22
0
        async def get_input(timeout=30):
            pred = await ctx.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(ctx),
                timeout=timeout)
            if pred.content.strip().lower() == "cancel":
                raise CancellationError

            return pred.content.strip()
Ejemplo n.º 23
0
 async def confirm(self, ctx, *, msg="Are you sure?"):
     """
     Handles confirmations for commands.
     Optionally can supply a message that is displayed to the user. Defaults to 'Are you sure?'.
     """
     await ctx.channel.send(f"{msg} (y/n)")
     pred = MessagePredicate.yes_or_no(ctx)
     await self.bot.wait_for("message", check=pred)
     return pred.result
Ejemplo n.º 24
0
    async def conversation(self, ctx: commands.Context):
        """Start a conversation with Cleverbot
        You don't need to use a prefix or the command using this mode."""

        if ctx.author.id in self.conversation:
            await ctx.send("There's already a conversation running. Say `close` to stop it.")
            return

        session = await self._make_cleverbot_session()
        self.conversation[ctx.author.id] = {
            "session": session,
            "task": None,
        }

        # Handled when the cog is restarted/unloaded, which we will let the user know.

        await ctx.send(
            "Starting a new Cleverbot session!\n\nSay `close` to stop the conversation"
            " with me !\n\nYour conversation will be automatically closed if CleverBot"
            " receive no answer.\nThis conversation is only available in this channel."
        )

        prefixes = tuple(await self.bot.get_valid_prefixes())

        try:
            while True:
                self.conversation[ctx.author.id]["task"] = task = asyncio.Task(
                    self.bot.wait_for(
                        "message", check=MessagePredicate.same_context(ctx), timeout=300
                    )
                )
                try:
                    message = await task.get_coro()  # Wait for user message...
                except asyncio.TimeoutError:
                    await ctx.send(
                        "You haven't answered me! \N{PENSIVE FACE}\nI'm closing our session..."
                    )
                    break
                except asyncio.CancelledError:
                    await ctx.send("Our session has been cancelled due to cog unload! Closing...")
                    break
                if message.content.startswith(prefixes):
                    continue
                if message.content.lower() in ("close", "c"):
                    await ctx.send("Alright, bye then. \N{WAVING HAND SIGN}")
                    break
                async with ctx.typing():
                    answer, answered = await self.ask_question(
                        session, message.content, message.author.id
                    )
                await message.reply(answer)
                if not answered:
                    break
                continue
        finally:
            await self.conversation[ctx.author.id]["session"].close()
            del self.conversation[ctx.author.id]
Ejemplo n.º 25
0
    async def blackjack_game(self, ctx, amount):
        ph = deck.deal(num=2)
        ph_count = deck.bj_count(ph)
        dh = deck.deal(num=2)

        # End game if player has 21
        if ph_count == 21:
            return ph, dh, amount, None
        options = (_("hit"), _("stay"), _("double"))
        condition1 = MessagePredicate.lower_contained_in(options, ctx=ctx)
        condition2 = MessagePredicate.lower_contained_in((_("hit"), _("stay")),
                                                         ctx=ctx)

        embed = self.bj_embed(ctx, ph, dh, ph_count, initial=True)
        msg = await ctx.send(ctx.author.mention, embed=embed)

        try:
            choice = await ctx.bot.wait_for("message",
                                            check=condition1,
                                            timeout=35.0)
        except asyncio.TimeoutError:
            dh = self.dealer(dh)
            return ph, dh, amount, msg

        if choice.content.lower() == _("stay"):
            dh = self.dealer(dh)
            return ph, dh, amount, msg

        if choice.content.lower() == _("double"):
            return await self.double_down(ctx,
                                          ph,
                                          dh,
                                          amount,
                                          condition2,
                                          message=msg)
        else:
            ph, dh, message = await self.bj_loop(ctx,
                                                 ph,
                                                 dh,
                                                 ph_count,
                                                 condition2,
                                                 message=msg)
            dh = self.dealer(dh)
            return ph, dh, amount, msg
    async def newcontributors_interactive(self, ctx: GuildContext) -> None:
        """Interactively add contributors.

        Integrates with Red.
        """
        member_converter = commands.MemberConverter()
        pending_contributors = await self.__config.pending_contributors()
        new_added_contributors = {}

        early_exit = False
        for user_id, author_data in pending_contributors.items():
            discord_user_id_line = (
                f"**Discord user ID:** {discord_user_id}\n" if
                (discord_user_id :=
                 author_data.get('discord_user_id')) is not None else "")
            bot_msg = await ctx.send(
                f"**GitHub Username:** {author_data['username']}\n"
                f"**Commit author name:** {author_data['name']}\n"
                f"**Commit author email:** {author_data['email']}\n"
                f"{discord_user_id_line}"
                "Use Red's `?assign` command or send user ID to add contributor."
                " Type `exit` to finish, use `skip` to skip the contributor.")

            while not early_exit:
                user_msg = await self.bot.wait_for(
                    "message_without_command",
                    check=MessagePredicate.same_context(ctx))
                content = user_msg.content

                if content == "exit":
                    early_exit = True
                    continue
                if content == "skip":
                    break

                if user_msg.content.startswith("?assign "):
                    view = StringView(user_msg.content)
                    view.skip_string("?assign ")
                    content = view.get_quoted_word()

                try:
                    member = await member_converter.convert(ctx, content)
                except commands.BadArgument as e:
                    await ctx.send(f"{e}. Please try passing user ID"
                                   " or using `?assign` command again.")
                    continue

                author_data["discord_user_id"] = member.id
                new_added_contributors[user_id] = author_data
                break
            else:
                # early-exit by breaking out of for loop
                await safe_delete_message(bot_msg)
                break

            await safe_delete_message(bot_msg)
Ejemplo n.º 27
0
    async def race_select(
        self,
        ctx: commands.Context,
        embed: Embed,
        message: discord.Message,
        do_once: bool = True,
    ) -> bool:
        """Requests information from the member about the race of the
        character being registered.

        Args:
            ctx (commands.Context): Same as `RegisterSession.ctx`
            embed (Embed): Same as `RegisterSession.embed`
            message (discord.Message): Same as `RegisterSession.message`
            do_once (bool): The parameter allows not to perform actions that
                are not needed during a recursive method call.

        Returns:
            bool: Whether the correct information is received or not.

        """
        _config = config.humanize
        races = _config.races.values()
        if do_once:
            embed.description = (
                "**Выберите расу персонажа**\n\n"
                f"**Возможные варианты:** {', '.join(races)}.")
            await message.edit(embed=embed)
            do_once = False
        try:
            race = await self.ctx.bot.wait_for(
                "message",
                timeout=60.0,
                check=MessagePredicate.same_context(ctx))
            race_content = race.content.lower()
            await race.delete()
            if race_content not in races:
                incorrect = await ctx.send("Недопустимый ввод!")
                race_select = await self.race_select(ctx, embed, message,
                                                     do_once)
                await incorrect.delete()
                if race_select:
                    return True
                else:
                    await self.cancel(embed, message)
                    return False
            self.char["race"] = list(_config.races.keys())[list(
                _config.races.values()).index(race_content)]
            embed.add_field(name="Раса",
                            value=race_content.title(),
                            inline=True)
            await message.edit(embed=embed)
            return True
        except asyncio.TimeoutError:
            await self.cancel(embed, message)
            return False
Ejemplo n.º 28
0
    async def migratecustomcom(self, ctx: commands.Context):
        """
        Migrate the CustomCommand cog's server commands into tags.

        This converts all custom commands created into tags with the command text as TagScript.
        Randomized commands are converted into random blocks.
        Commands with converters are converted into indexed args blocks.
        This action cannot be undone.

        **Example:**
        `[p]migratealias`
        """
        await ctx.send(
            f"Are you sure you want to migrate CustomCommands data to tags? (Y/n)"
        )
        pred = MessagePredicate.yes_or_no(ctx)
        try:
            await self.bot.wait_for("message", check=pred, timeout=30)
        except asyncio.TimeoutError:
            return await ctx.send(
                "Query timed out, not migrating CustomCommands to tags.")
        if pred.result is False:
            return await ctx.send("Migration cancelled.")

        cc_config = Config.get_conf(None,
                                    414589031223512,
                                    cog_name="CustomCommands")
        migrated_guilds = 0
        migrated_ccs = 0
        all_guild_data: dict = await cc_config.all_guilds()

        async for guild_id, guild_data in AsyncIter(all_guild_data.items(),
                                                    steps=100):
            if not guild_data["commands"]:
                continue
            migrated_guilds += 1
            for name, command in guild_data["commands"].items():
                if not command:
                    continue  # some keys in custom commands config are None instead of being deleted
                try:
                    tag = self.convert_customcommand(guild_id, name, command)
                except Exception as exc:
                    log.exception(
                        "An exception occured while converting custom command %s (%r) from guild %s"
                        % (name, command, guild_id),
                        exc_info=exc,
                    )
                    return await ctx.send(
                        f"An exception occured while converting custom command `{name}` from "
                        f"server {guild_id}. Check your logs for more details and report this to the cog author."
                    )
                await tag.initialize()
                migrated_ccs += 1
        await ctx.send(
            f"Migrated {migrated_ccs} custom commands from {migrated_guilds} servers to tags."
        )
Ejemplo n.º 29
0
 async def wait_for_message(self, ctx: commands.Context, content: str):
     msg = await ctx.send(content)
     pred = MessagePredicate.same_context(ctx)
     try:
         message = await self.bot.wait_for("message", check=pred, timeout=60)
     except AsyncTimeoutError:
         return None
     finally:
         await msg.delete()
     return message.content
Ejemplo n.º 30
0
    async def desc_select(
        self,
        ctx: commands.Context,
        embed: Embed,
        message: discord.Message,
        do_once: bool = True,
    ) -> bool:
        """Requests information from the member about the description of the
        character being registered.

        Args:
            ctx (commands.Context): Same as `RegisterSession.ctx`
            embed (Embed): Same as `RegisterSession.embed`
            message (discord.Message): Same as `RegisterSession.message`
            do_once (bool): The parameter allows not to perform actions that
                are not needed during a recursive method call.

        Returns:
            bool: Whether the correct information is received or not.

        """
        if do_once:
            embed.description = (
                "**Опишите своего персонажа**\n\n"
                "В описании персонажа должно быть **не менее 50** и **не более 2000 символов**.\n"
                "Описание персонажа должно состоять из символов **латинского алфавита** или **кириллицы.**"
            )
            await message.edit(embed=embed)
            do_once = False
        try:
            desc = await self.ctx.bot.wait_for(
                "message",
                timeout=600.0,
                check=MessagePredicate.same_context(ctx))
            desc_content = desc.content
            await desc.delete()
            if not re.match(
                    """[a-zа-яA-ZА-ЯёЁ\d\s!.,%*'";:()\[\]<>\-«»—]{50,2000}""",
                    desc_content):
                incorrect = await ctx.send("Недопустимый ввод!")
                desc_select = await self.desc_select(ctx, embed, message,
                                                     do_once)
                await incorrect.delete()
                if desc_select:
                    return True
                else:
                    await self.cancel(embed, message)
                    return False
            self.char["desc"] = desc_content
            embed.description = italics(desc_content)
            await message.edit(embed=embed)
            return True
        except asyncio.TimeoutError:
            await self.cancel(embed, message)
            return False
Ejemplo n.º 31
0
 async def _ask_for_role_add(self, ctx: commands.Context):
     await ctx.send("Do you use a role to access to the server? (y/n)")
     try:
         predicator = MessagePredicate.yes_or_no(ctx)
         await self.bot.wait_for("message", timeout=30, check=predicator)
     except asyncio.TimeoutError:
         await ctx.send("Question cancelled, caused by timeout.")
         return
     if predicator.result:
         await ctx.send(
             "Which role should I give when user pass captcha? (Role ID/Name/Mention)"
         )
         role = MessagePredicate.valid_role(ctx)
         try:
             await self.bot.wait_for("message", timeout=60, check=role)
         except asyncio.TimeoutError:
             await ctx.send("Question cancelled, caused by timeout.")
             return
         await self.data.guild(ctx.guild).autorole.set(role.result.id)
     return True
Ejemplo n.º 32
0
    async def rolereq_clear(self, ctx, raffle: RaffleFactoryConverter):
        """Clear the role requirement list for a raffle.


        **Arguments:**
            - `<raffle>` - The name of the raffle.
        """
        async with self.config.guild(ctx.guild).raffles() as r:

            raffle_data = r.get(raffle, None)

            rolesreq = raffle_data.get("roles_needed_to_enter", [])

            if rolesreq is None:
                return await ctx.send(_("There are no required roles."))

            message = _(
                "Are you sure you want to clear the role requirement list for this raffle?"
            )
            can_react = ctx.channel.permissions_for(ctx.me).add_reactions
            if not can_react:
                message += " (yes/no)"
            message = await ctx.send(message)
            if can_react:
                start_adding_reactions(message,
                                       ReactionPredicate.YES_OR_NO_EMOJIS)
                predicate = ReactionPredicate.yes_or_no(message, ctx.author)
                event_type = "reaction_add"
            else:
                predicate = MessagePredicate.yes_or_no(ctx)
                event_type = "message"

            try:
                await self.bot.wait_for(event_type,
                                        check=predicate,
                                        timeout=30)
            except asyncio.TimeoutError:
                await ctx.send(_("You took too long to respond."))
                return

            if predicate.result:
                with contextlib.suppress(KeyError):
                    # Still wanna remove empty list here
                    del raffle_data["roles_needed_to_enter"]
                msg = "Role requirement list cleared for this raffle."
                try:
                    await message.edit(content=msg)
                except discord.NotFound:
                    await ctx.send(msg)

            else:
                await ctx.send(_("No changes have been made."))

            await self.clean_guild_raffles(ctx)
Ejemplo n.º 33
0
async def add_random_messages(ctx, original_ping_message):
    await ctx.send(
        "Would you like to add more messages to select from at random? (y/n)")
    try:
        pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
        await ctx.bot.wait_for("message", check=pred, timeout=60)
    except asyncio.TimeoutError:
        await ctx.send("You took too long to respond, I assumed yes.")
        return original_ping_message
    if pred.result:
        await ctx.send(
            "Keep adding messages until you are satisfied. Type **stop()** to stop gathering messages."
        )
        check = lambda x: x.author == ctx.author and x.channel == ctx.channel
        messages = [original_ping_message]
        while True:
            await ctx.send("Add a random response:")
            try:
                message = await ctx.bot.wait_for("message",
                                                 check=check,
                                                 timeout=60)
            except asyncio.TimeoutError:
                await ctx.send(
                    f"You took too long to respond - gathered {len(messages)} messages."
                )
                return messages
            if message.content.lower() in ("stop()", "exit()", "quit()"):
                await ctx.send(f"Stopping - gathered {len(messages)} messages."
                               )
                return messages
            try:
                message.content.format(author=Member(ctx.author),
                                       latency=round(ctx.bot.latency * 1000,
                                                     2))
            except KeyError as e:
                curled = curl(str(e).strip("'"))
                await ctx.send(
                    f"{curled} is not a recognized variable, skipping...")
                continue
            except commands.BadArgument as e:
                curled = curl(f"author.{e}")
                await ctx.send(
                    f"{curled} is not valid, author has no attribute {e}, skipping..."
                )
                continue
            except Exception:
                # catch chained attributeerrors and such
                await ctx.send(
                    "This message doesn't look right. Please consult the docs for more information. Skipping for now..."
                )
                continue
            messages.append(message.content)
    else:
        return original_ping_message
Ejemplo n.º 34
0
 async def autoconfig(self, ctx: commands.Context):
     """Automatically set Captcher."""
     await ctx.send(
         "This command will:\n"
         "- Create a new role called: Unverified\n"
         "- Create a new channel called: #verification\n"
         "- Create a new channel called: #verification-logs\n"
         "\nBot will overwrite all channels to:\n"
         "- Do not allow Unverified to read in others channels.\n"
         "- Unverified will be able to read & send message in #verification.\n"
         "\nDo you wish to continue?")
     try:
         predicator = MessagePredicate.yes_or_no(ctx)
         await self.bot.wait_for("message", timeout=30, check=predicator)
     except asyncio.TimeoutError:
         await ctx.send("Command cancelled, caused by timeout.")
     if predicator.result:
         if not ctx.channel.permissions_for(ctx.guild.me).administrator:
             await ctx.send("I require the Administrator permission first.")
             return  # In case it's funny to remove perm after using command.
         await self.data.guild(ctx.guild).clear()
         possible_result = await self._overwrite_server(ctx)
         if possible_result:
             await ctx.send(possible_result)
             return
     else:
         await ctx.send("Uhm, why does the captain' had this idea...")
         return
     r = await self._ask_for_role_add(ctx)
     if r:
         await ctx.send("Configuration is done. Activate Captcher? (y/n)")
         try:
             predicator = MessagePredicate.yes_or_no(ctx)
             await self.bot.wait_for("message",
                                     timeout=30,
                                     check=predicator)
         except asyncio.TimeoutError:
             await ctx.send("Question cancelled, caused by timeout.")
         if predicator.result:
             await self.data.guild(ctx.guild).active.set(True)
         await ctx.send("Done.")
Ejemplo n.º 35
0
    async def get_option(self, ctx: commands.Context) -> SlashOption:
        name_desc = (
            "What should the argument name be?\n"
            "Slash argument names may not exceed 32 characters and can only contain characters "
            "that are alphanumeric or '_' or '-'.")
        name_pred = MessagePredicate.regex(SLASH_NAME, ctx)
        await self.send_and_query_response(ctx, name_desc, name_pred)
        title = name_pred.result.group(1)
        description = await self.send_and_query_response(
            ctx,
            "What should the argument description be? (maximum 100 characters)",
            MessagePredicate.length_less(101, ctx),
        )

        valid_option_types = [
            name.lower() for name in SlashOptionType.__members__.keys()
            if not name.startswith("SUB")
        ]

        option_query = [
            "What should the argument type be?",
            f"Valid option types: {humanize_list([inline(n) for n in valid_option_types])}",
            "(select `string` if you don't understand)",
        ]
        option_type = await self.send_and_query_response(
            ctx,
            "\n".join(option_query),
            MessagePredicate.lower_contained_in(valid_option_types, ctx),
        )
        option_type = SlashOptionType[option_type.upper()]

        pred = MessagePredicate.yes_or_no(ctx)
        await self.send_and_query_response(ctx,
                                           "Is this argument required? (Y/n)",
                                           pred)
        required = pred.result

        return SlashOption(name=title,
                           description=description,
                           option_type=option_type,
                           required=required)
Ejemplo n.º 36
0
    async def name_select(
        self,
        ctx: commands.Context,
        embed: Embed,
        message: discord.Message,
        do_once: bool = True,
    ) -> bool:
        """Requests information from the member about the name of the
        character being registered.

        Args:
            ctx (commands.Context): Same as `RegisterSession.ctx`
            embed (Embed): Same as `RegisterSession.embed`
            message (discord.Message): Same as `RegisterSession.message`
            do_once (bool): The parameter allows not to perform actions that
                are not needed during a recursive method call.

        Returns:
            bool: Whether the correct information is received or not.

        """
        if do_once:
            embed.description = (
                "**Выберите имя персонажа**\n\n"
                "В имени персонажа должно быть **не менее 3** и **не более 25 символов**.\n"
                "Имя персонажа должно состоять из символов **латинского алфавита** или **кириллицы.**"
            )
            await message.edit(embed=embed)
            do_once = False
        try:
            name = await self.ctx.bot.wait_for(
                "message",
                timeout=60.0,
                check=MessagePredicate.same_context(ctx))
            name_content = name.content
            await name.delete()
            if not re.match("""^[a-zа-яA-ZА-ЯёЁ\s'-]{3,25}$""", name_content):
                incorrect = await ctx.send("Недопустимый ввод!")
                name_select = await self.name_select(ctx, embed, message,
                                                     do_once)
                await incorrect.delete()
                if name_select:
                    return True
                else:
                    await self.cancel(embed, message)
                    return False
            self.char["name"] = name_content
            embed.add_field(name="Имя", value=name_content, inline=True)
            await message.edit(embed=embed)
            return True
        except asyncio.TimeoutError:
            await self.cancel(embed, message)
            return False
Ejemplo n.º 37
0
    async def create(self, ctx, trigger_name: str, *, triggered_by: str):
        """
        Create a trigger.

        Variables can be used within the responses.
        user: The user that triggered the trigger.
        channel: The channel the trigger was triggered in.
        message: The message that triggered the trigger.
        guild: The guild the trigger was triggered in.
        uses: The number of times the trigger has been used.
        trigger: The name of the trigger that was triggered.

        Example: `{user} has triggered the trigger {trigger} in {channel} {uses} times.`
        """
        trigger_name = trigger_name.lower()
        triggers = await self.config.guild(ctx.guild).triggers()
        if trigger_name in triggers:
            await ctx.send("Trigger already exists.")
            return
        responses = []
        await ctx.send(
            "Every message you send will be counted as a response. To exit or finish adding responses, type `exit`."
        )
        while True:
            msg = await self.bot.wait_for(
                "message", check=MessagePredicate.same_context(ctx))

            if msg.content.lower() == "exit":
                break
            elif len(msg.content) > 2000:
                await ctx.send(
                    "The text response you're trying to create has more than 2000 characters.\nI cannot send messages that are longer than 2000 characters, please try again."
                )
                continue
            await msg.add_reaction("✅")
            responses.append(msg.content)
        async with self.config.guild(ctx.guild).triggers() as triggers:
            triggers[trigger_name] = {
                "trigger": triggered_by,
                "responses": responses,
                "owner": ctx.author.id,
                "guild": ctx.guild.id,
                "cooldown": 0,
                "timestamp": None,
                "uses": 0,
                "toggle": True,
                "case_sensitive": False,
                "word_boundary": False,
            }
            await self.update_trigger(ctx.guild, trigger_name,
                                      triggers[trigger_name])

        await ctx.send("Trigger created.")
Ejemplo n.º 38
0
    async def dataconversioncommand(self, ctx: commands.Context, v2path: str):
        """Interactive prompt for importing data from Red V2.

        Takes the path where the V2 install is, and overwrites
        values which have entries in both V2 and v3; use with caution.
        """
        resolver = SpecResolver(Path(v2path.strip()))

        if not resolver.available:
            return await ctx.send(
                _(
                    "There don't seem to be any data files I know how to "
                    "handle here. Are you sure you gave me the base "
                    "installation path?"
                )
            )
        while resolver.available:
            menu = _("Please select a set of data to import by number, or 'exit' to exit")
            for index, entry in enumerate(resolver.available, 1):
                menu += "\n{}. {}".format(index, entry)

            menu_message = await ctx.send(box(menu))

            try:
                message = await self.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=60
                )
            except asyncio.TimeoutError:
                return await ctx.send(_("Try this again when you are ready."))
            else:
                if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]:
                    return await ctx.tick()
                try:
                    message = int(message.content.strip())
                    to_conv = resolver.available[message - 1]
                except (ValueError, IndexError):
                    await ctx.send(_("That wasn't a valid choice."))
                    continue
                else:
                    async with ctx.typing():
                        await resolver.convert(self.bot, to_conv)
                    await ctx.send(_("{} converted.").format(to_conv))
            await menu_message.delete()
        else:
            return await ctx.send(
                _(
                    "There isn't anything else I know how to convert here.\n"
                    "There might be more things I can convert in the future."
                )
            )
Ejemplo n.º 39
0
async def do_install_agreement(ctx: commands.Context):
    downloader = ctx.cog
    if downloader is None or downloader.already_agreed:
        return True

    await ctx.send(T_(REPO_INSTALL_MSG))

    try:
        await ctx.bot.wait_for(
            "message", check=MessagePredicate.lower_equal_to("i agree", ctx), timeout=30
        )
    except asyncio.TimeoutError:
        await ctx.send(_("Your response has timed out, please try again."))
        return False

    downloader.already_agreed = True
    return True
Ejemplo n.º 40
0
 async def changeName(self, ctx):
     """Modify your SCP:SL Server's Name as appeared on discord."""
     if not await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "SCPSL Module disabled on this server. Use `{prefix}scpsl enable` to enable the module for this server.".format(
                 prefix=ctx.prefix
             )
         )
     server = await self.config.guild(ctx.guild).server()
     global_servers = await self.config.global_servers()
     guildID = str(ctx.guild.id)
     endport = startport = None
     if not guildID in global_servers and not server:
         try:
             await ctx.send(f"{ctx.guild.name} does not have a registered SCP:SL server")
         except discord.Forbidden:
             pass
         return
     name = None
     while name is None:
         await ctx.send(
             "Enter a name to be displayed for your SCP:SL Server." + "\n"
             "__*Type `default` to use the discord server's name by default.*__"
         )
         try:
             msg = await ctx.bot.wait_for(
                 "message", check=MessagePredicate.same_context(ctx), timeout=25
             )
         except asyncio.TimeoutError:
             return await ctx.send("Server Editing Cancelled.")
         if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
             return await ctx.send("Server Editing Cancelled.")
         name = msg.content[:40]  # 40 Character Limit
         try:
             await self.verifyName(name)
         except AliasTaken as e:
             await ctx.send(str(e))
             name = None
             continue
         else:
             ip = msg.content.strip()
     d = {"name": name}
     await self.updateServer(ctx, d)
Ejemplo n.º 41
0
    async def check_100_plus(ctx: commands.Context, number: int) -> bool:
        """
        Called when trying to delete more than 100 messages at once.

        Prompts the user to choose whether they want to continue or not.

        Tries its best to cleanup after itself if the response is positive.
        """

        prompt = await ctx.send(
            _("Are you sure you want to delete {number} messages? (y/n)").format(number=number)
        )
        response = await ctx.bot.wait_for("message", check=MessagePredicate.same_context(ctx))

        if response.content.lower().startswith("y"):
            await prompt.delete()
            try:
                await response.delete()
            except discord.HTTPException:
                pass
            return True
        else:
            await ctx.send(_("Cancelled."))
            return False
Ejemplo n.º 42
0
 async def changeIP(self, ctx):
     """Modify your SCP:SL Server's IP Address."""
     if not await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "SCPSL Module disabled on this server. Use `{prefix}scpsl enable` to enable the module for this server.".format(
                 prefix=ctx.prefix
             )
         )
     server = await self.config.guild(ctx.guild).server()
     global_servers = await self.config.global_servers()
     guildID = str(ctx.guild.id)
     if not guildID in global_servers and not server:
         try:
             await ctx.send(f"{ctx.guild.name} does not have a registered SCP:SL server")
         except discord.Forbidden:
             pass
         return
     ip = None
     while ip is None:
         await ctx.send("Enter the IP Address of your SCP:SL Server.")
         try:
             msg = await ctx.bot.wait_for(
                 "message", check=MessagePredicate.same_context(ctx), timeout=25
             )
         except asyncio.TimeoutError:
             return await ctx.send("Server Registration Cancelled.")
         if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
             return await ctx.send("Server Editing Cancelled.")
         test = await IPconvert(msg.content)
         if test is None:
             await ctx.send("Invalid IP Address.")
             continue
         else:
             ip = msg.content.strip()
     d = {"ip": ip}
     await self.updateServer(ctx, d)
Ejemplo n.º 43
0
    async def registration_input(self, ctx):
        """Handles getting required input for registering SCPSL servers to the bot."""
        attempt = 0
        ip = endport = startport = aliases = None
        while ip is None:
            await ctx.send(
                "Enter the IP Address of your SCP:SL Server." + "\n"
                "__*Type `cancel` to Cancel at any moment.*__"
            )
            try:
                msg = await ctx.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=25
                )
            except asyncio.TimeoutError:
                return await ctx.send("Server Registration Cancelled.")
            if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
                return await ctx.send("Server Registration Cancelled.")
            ipAddress = await IPconvert(msg.content)
            if ipAddress is None:
                await ctx.send("Invalid IP Address.")
                continue
            else:
                ip = msg.content.strip()
        while endport is None or startport is None:
            await ctx.send(
                f"Enter a port range to track at {ip}. Serpate with `-`" + "\n"
                '*Ex.  "7777 - 7780"*'
            )
            try:
                msg = await ctx.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=25
                )
            except asyncio.TimeoutError:
                return await ctx.send("Server Registration Cancelled.")
            if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
                return await ctx.send("Server Registration Cancelled.")
            if "-" in msg.content:
                startport, endport = msg.content.split("-")
                try:
                    startport = int(startport)
                    endport = int(endport)
                except ValueError:
                    await ctx.send("Invalid Port Range.")
                    continue
            else:
                startport = 7777
                if len(msg.content.strip()) <= 4:
                    try:
                        endport = int(msg.content.strip())
                    except ValueError:
                        await ctx.send("Invalid Port Range.")
                        continue
                else:
                    await ctx.send("Invalid Port Range. Expected a 4 digit port.")
                    continue
            if startport > endport:
                await ctx.send(
                    f'Invalid port range. Startport "{startport}" cannot be higher than Endport "{endport}"'
                )
                startport = endport = None
                continue

        while aliases is None:
            await ctx.send(
                "Enter a list of Aliases to use `!status <alias>` to view your Server status. *Max. 3 Aliases*"
            )
            try:
                msg = await ctx.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=35
                )
            except asyncio.TimeoutError:
                return await ctx.send("Server Registration Cancelled.")
            if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
                return await ctx.send("Server Registration Cancelled.")
            aliases = msg.content.strip().split(" ")
            if not aliases:
                aliases = []
            else:
                try:
                    await self.verifyAlias(aliases)
                    # aliases = [alias.lower() for alias in aliases[:3] if await self.verifyAlias(alias)]
                except AliasTaken as e:
                    await ctx.send(str(e))
                    aliases = None
                    continue
                else:
                    aliases = [alias.lower() for alias in aliases[:3]]
            return ip, endport, startport, aliases
Ejemplo n.º 44
0
 async def range(self, ctx):
     """Modify your SCP:SL Server's portrange to track."""
     if not await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "SCPSL Module disabled on this server. Use `{prefix}scpsl enable` to enable the module for this server.".format(
                 prefix=ctx.prefix
             )
         )
     server = await self.config.guild(ctx.guild).server()
     global_servers = await self.config.global_servers()
     guildID = str(ctx.guild.id)
     endport = startport = None
     if not guildID in global_servers and not server:
         try:
             await ctx.send(f"{ctx.guild.name} does not have a registered SCP:SL server")
         except discord.Forbidden:
             pass
         return
     while endport is None or startport is None:
         await ctx.send(
             "Enter a port range to track. Serpate with `-`. Enter single port to set endport"
             + "\n"
             '*Ex.  Range : "7777 - 7780"*   *Endport : 7778*'
         )
         try:
             msg = await ctx.bot.wait_for(
                 "message", check=MessagePredicate.same_context(ctx), timeout=25
             )
         except asyncio.TimeoutError:
             return await ctx.send("Server Editing Cancelled.")
         if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
             return await ctx.send("Server Editing Cancelled.")
         if "-" in msg.content:
             startport, endport = msg.content.split("-")
             try:
                 startport = int(startport)
                 endport = int(endport)
             except ValueError:
                 await ctx.send("Invalid Port Range.")
                 continue
         else:
             if server:
                 startport = server["startport"]
             elif guildID in global_servers:
                 async with self.config.global_servers() as global_servers:
                     server = global_servers[guildID]
                     startport = server["startport"]
             if len(msg.content.strip()) <= 4:
                 try:
                     endport = int(msg.content.strip())
                 except ValueError:
                     await ctx.send("Invalid Port Range.")
                     continue
             else:
                 await ctx.send("Invalid Port Range. Expected a 4 digit port.")
                 continue
         if startport > endport:
             await ctx.send(
                 f'Invalid port range. Startport "{startport}" cannot be higher than Endport "{endport}"'
             )
             startport = endport = None
             continue
     d = {
         "endport": endport,
         "startport": startport,
         "portrange": list(
             range(startport, endport + 1) if endport >= startport else range(7777, 7778)
         ),
     }
     await self.updateServer(ctx, d)
Ejemplo n.º 45
0
 async def _aliases(self, ctx):
     """Modify your SCP:SL Server's aliases. Will overwrite previous aliases."""
     if not await self.config.guild(ctx.guild).enabled():
         return await ctx.send(
             "SCPSL Module disabled on this server. Use `{prefix}scpsl enable` to enable the module for this server.".format(
                 prefix=ctx.prefix
             )
         )
     server = await self.config.guild(ctx.guild).server()
     global_servers = await self.config.global_servers()
     guildID = str(ctx.guild.id)
     if not guildID in global_servers and not server:
         try:
             await ctx.send(f"{ctx.guild.name} does not have a registered SCP:SL server")
         except discord.Forbidden:
             pass
         return
     if (
         server
     ):  # Remove and Store Aliases to bypass Alias Verification from checking own server's aliases
         temp_aliases = server.pop("aliases")
         await self.config.guild(ctx.guild).server.set(server)
     elif guildID in global_servers:
         async with self.config.global_servers() as global_servers:
             svr = global_servers[ctx.guild.id]
             temp_aliases = svr.pop("aliases")
     d = {"aliases": temp_aliases}
     aliases = None
     while aliases is None:
         await ctx.send(
             "Enter a list of Aliases to use `!status <alias>` to view your Server status. *Max. 3 Aliases*"
             + "\n"
             "*Type `cancel` to Cancel.*"
         )
         try:
             msg = await ctx.bot.wait_for(
                 "message", check=MessagePredicate.same_context(ctx), timeout=35
             )
         except asyncio.TimeoutError:
             if server:  # Readd temp stored aliases
                 server.update(d)
                 await self.config.guild(ctx.guild).server.set(server)
             elif guildID in global_servers:
                 async with self.config.global_servers() as global_servers:
                     server = global_servers[ctx.guild.id]
                     server.update(d)
                     global_servers[ctx.guild.id] = server
             return await ctx.send("Server Editing Cancelled.")
         if msg.content.strip().lower() in ["cancel", "exit", "stop"]:
             if server:  # Readd temp stored aliases
                 server.update(d)
                 await self.config.guild(ctx.guild).server.set(server)
             elif guildID in global_servers:
                 async with self.config.global_servers() as global_servers:
                     server = global_servers[ctx.guild.id]
                     server.update(d)
                     global_servers[ctx.guild.id] = server
             return await ctx.send("Server Editing Cancelled.")
         aliases = msg.content.strip().split(" ")
         if not aliases:
             aliases = []
         else:
             try:
                 await self.verifyAlias(aliases)
             except AliasTaken as e:
                 await ctx.send(str(e))
                 aliases = None
                 continue
             else:
                 aliases = [alias.lower() for alias in aliases[:3]]
     d = {"aliases": list(aliases)}
     await self.updateServer(ctx, d)
Ejemplo n.º 46
0
    async def report(self, ctx: commands.Context, *, _report: str = ""):
        """Send a report.

        Use without arguments for interactive reporting, or do
        `[p]report <text>` to use it non-interactively.
        """
        author = ctx.author
        guild = ctx.guild
        if guild is None:
            guild = await self.discover_guild(
                author, prompt=_("Select a server to make a report in by number.")
            )
        if guild is None:
            return
        g_active = await self.config.guild(guild).active()
        if not g_active:
            return await author.send(_("Reporting has not been enabled for this server"))
        if guild.id not in self.antispam:
            self.antispam[guild.id] = {}
        if author.id not in self.antispam[guild.id]:
            self.antispam[guild.id][author.id] = AntiSpam(self.intervals)
        if self.antispam[guild.id][author.id].spammy:
            return await author.send(
                _(
                    "You've sent too many reports recently. "
                    "Please contact a server admin if this is important matter, "
                    "or please wait and try again later."
                )
            )
        if author.id in self.user_cache:
            return await author.send(
                _(
                    "Please finish making your prior report before trying to make an "
                    "additional one!"
                )
            )
        self.user_cache.append(author.id)

        if _report:
            _m = copy(ctx.message)
            _m.content = _report
            _m.content = _m.clean_content
            val = await self.send_report(_m, guild)
        else:
            try:
                await author.send(
                    _(
                        "Please respond to this message with your Report."
                        "\nYour report should be a single message"
                    )
                )
            except discord.Forbidden:
                return await ctx.send(_("This requires DMs enabled."))

            try:
                message = await self.bot.wait_for(
                    "message",
                    check=MessagePredicate.same_context(ctx, channel=author.dm_channel),
                    timeout=180,
                )
            except asyncio.TimeoutError:
                return await author.send(_("You took too long. Try again later."))
            else:
                val = await self.send_report(message, guild)

        with contextlib.suppress(discord.Forbidden, discord.HTTPException):
            if val is None:
                await author.send(
                    _("There was an error sending your report, please contact a server admin.")
                )
            else:
                await author.send(_("Your report was submitted. (Ticket #{})").format(val))
                self.antispam[guild.id][author.id].stamp()
Ejemplo n.º 47
0
    async def _cog_update(self, ctx, cog_name: InstalledCog = None):
        """Update all cogs, or one of your choosing."""
        installed_cogs = set(await self.installed_cogs())

        async with ctx.typing():
            if cog_name is None:
                updated = await self._repo_manager.update_all_repos()

            else:
                try:
                    updated = await self._repo_manager.update_repo(cog_name.repo_name)
                except KeyError:
                    # Thrown if the repo no longer exists
                    updated = {}

            updated_cogs = set(cog for repo in updated for cog in repo.available_cogs)
            installed_and_updated = updated_cogs & installed_cogs

            if installed_and_updated:
                await self._reinstall_requirements(installed_and_updated)
                await self._reinstall_cogs(installed_and_updated)
                await self._reinstall_libraries(installed_and_updated)
                message = _("Cog update completed successfully.")

                cognames = {c.name for c in installed_and_updated}
                message += _("\nUpdated: ") + humanize_list(tuple(map(inline, cognames)))
            else:
                await ctx.send(_("All installed cogs are already up to date."))
                return
        await ctx.send(message)

        cognames &= set(ctx.bot.extensions.keys())  # only reload loaded cogs
        if not cognames:
            return await ctx.send(
                _("None of the updated cogs were previously loaded. Update complete.")
            )
        message = _("Would you like to reload the updated cogs?")
        can_react = ctx.channel.permissions_for(ctx.me).add_reactions
        if not can_react:
            message += " (y/n)"
        query: discord.Message = await ctx.send(message)
        if can_react:
            # noinspection PyAsyncCall
            start_adding_reactions(query, ReactionPredicate.YES_OR_NO_EMOJIS, ctx.bot.loop)
            pred = ReactionPredicate.yes_or_no(query, ctx.author)
            event = "reaction_add"
        else:
            pred = MessagePredicate.yes_or_no(ctx)
            event = "message"
        try:
            await ctx.bot.wait_for(event, check=pred, timeout=30)
        except asyncio.TimeoutError:
            await query.delete()
            return

        if pred.result is True:
            if can_react:
                with contextlib.suppress(discord.Forbidden):
                    await query.clear_reactions()
            await ctx.invoke(ctx.bot.get_cog("Core").reload, *cognames)
        else:
            if can_react:
                await query.delete()
            else:
                await ctx.send(_("OK then."))