示例#1
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
示例#2
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)
示例#3
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."))
示例#4
0
    async def mute(
        self,
        ctx,
        users: commands.Greedy[discord.Member],
        duration: Optional[TimedeltaConverter] = None,
        *,
        reason: str = None,
    ):
        """Mute users."""
        if not users:
            return await ctx.send_help()
        if duration is None:
            duration = timedelta(minutes=10)
        duration_seconds = duration.total_seconds()
        guild = ctx.guild
        roleid = await self.__config.guild(guild).muterole()
        if roleid is None:
            await ctx.send(
                "There is currently no mute role set for this server. If you would like one to be automatically setup then type yes, otherwise type no then one can be set via {}mute roleset <role>"
                .format(ctx.prefix))
            try:
                pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
                msg = await ctx.bot.wait_for("message", check=pred, timeout=60)
            except asyncio.TimeoutError:
                return await ctx.send("Alright, cancelling the operation.")

            if pred.result:
                await msg.add_reaction("\N{WHITE HEAVY CHECK MARK}")
                await self.create_muted_role(guild)
                roleid = await self.__config.guild(guild).muterole()
            else:
                await msg.add_reaction("\N{WHITE HEAVY CHECK MARK}")
                return
        mutedrole = guild.get_role(roleid)
        if mutedrole is None:
            return await ctx.send(
                f"The mute role for this server is invalid. Please set one up using {ctx.prefix}mute roleset <role>."
            )
        completed = []
        failed = []
        async with self.__config.muted() as muted:
            if str(ctx.guild.id) not in muted:
                muted[str(ctx.guild.id)] = {}
            for user in users:
                if user == ctx.author:
                    failed.append(f"{user} - Self harm is bad.")
                    continue
                if not await is_allowed_by_hierarchy(self.bot, self.__config,
                                                     guild, ctx.author, user):
                    failed.append(
                        f"{user} - You are not higher than this user in the role hierarchy"
                    )
                    continue
                if guild.me.top_role <= user.top_role or user == guild.owner:
                    failed.append(
                        f"{user} - Discord hierarcy rules prevent you from muting this user."
                    )
                    continue
                await user.add_roles(
                    mutedrole,
                    reason="Muted by {} for {}{}".format(
                        ctx.author,
                        humanize_timedelta(timedelta=duration),
                        f" | Reason: {reason}" if reason is not None else "",
                    ),
                )
                expiry = datetime.now() + timedelta(seconds=duration_seconds)
                muted[str(ctx.guild.id)][str(user.id)] = {
                    "time": datetime.now().timestamp(),
                    "expiry": expiry.timestamp(),
                }
                await modlog.create_case(
                    ctx.bot,
                    ctx.guild,
                    ctx.message.created_at,
                    "smute",
                    user,
                    ctx.author,
                    reason,
                    expiry,
                )
                log.info(
                    f"{user} muted by {ctx.author} in {ctx.guild} for {humanize_timedelta(timedelta=duration)}"
                )
                completed.append(user)
        msg = "{}".format(
            "\n**Reason**: {}".format(reason) if reason is not None else "")
        if completed:
            await ctx.send(
                f"`{humanize_list(list(map(inline, [str(x) for x in completed])))}` has been muted for {humanize_timedelta(timedelta=duration)}.{msg}"
            )
        if failed:
            failemsg = "\n{}".format("\n".join(failed))
            await ctx.send(
                f"{len(failed)} user{'s' if len(failed) > 1 else ''} failed to be muted for the following reasons.{failemsg}"
            )
示例#5
0
    async def bots(self,
                   ctx,
                   state: bool,
                   channel: Optional[discord.TextChannel] = None,
                   *,
                   word: str = None):
        """Enable highlighting of bot messages.

        Expects a valid bool. Not passing a word will enable/disable bot highlighting for all
        highlights.
        """
        channel = channel or ctx.channel
        check = self.channel_check(ctx, channel)
        if not check:
            await ctx.send(
                "Either you or the bot does not have permission for that channel."
            )
            return
        if word is None:
            msg = "enable" if state else "disable"
            await ctx.send(
                f"Are you sure you wish to {msg} the highlighting of bot messages for all your highlights? Type yes to confirm otherwise type no."
            )
            try:
                pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
                await ctx.bot.wait_for("message", check=pred, timeout=20)
            except asyncio.TimeoutError:
                await ctx.send("Exiting operation.")
                return

            if pred.result:
                async with self.config.channel(
                        channel).highlight() as highlight:
                    highlights = highlight.get(str(ctx.author.id))
                    if not highlights:
                        return await ctx.send(
                            "You do not have any highlights setup.")
                    for word in highlights:
                        highlight[str(ctx.author.id)][word]["bots"] = state
                if state:
                    await ctx.send(
                        "Bots will now trigger all of your highlights.")
                else:
                    await ctx.send(
                        "Bots will no longer trigger on any of your highlights."
                    )

                await self.generate_cache()
                return

            else:
                await ctx.send("Cancelling.")
                return
        word = word.lower()
        async with self.config.channel(channel).highlight() as highlight:
            highlights = highlight.get(str(ctx.author.id))
            if not highlights:
                return await ctx.send("You do not have any highlights setup.")
            if word not in highlight[str(ctx.author.id)]:
                return await ctx.send(
                    f"You do not have a highlight for `{word}` setup in {channel}"
                )
            highlight[str(ctx.author.id)][word]["bots"] = state
            if state:
                await ctx.send(
                    f"The highlight `{word}` will now be triggered by bots in {channel}."
                )
            else:
                await ctx.send(
                    f"The highlight `{word}` will no longer be trigged by bots in {channel}."
                )

        await self.generate_cache()
示例#6
0
    async def joinmessage(
        self, ctx, raffle: RaffleFactoryConverter, *, join_message: Union[bool, str]
    ):
        """Edit the join message of a raffle.

        Once you provide a join message, you will have the chance
        to add additional messages, which will be selected at random
        when a user joins the raffle.

        Use `0` or `false` to disable this condition.

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

            raffle_data = r.get(raffle, None)

            if not join_message:
                with contextlib.suppress(KeyError):
                    del raffle_data["join_message"]
                return await ctx.send(
                    _(
                        "Join message feature removed from this raffle. It will now use the default."
                    )
                )

            elif join_message is True:
                return await ctx.send(
                    _('Please provide a number, or "false" to disable this condition.')
                )

            else:
                try:
                    raffle_safe_member_scanner(join_message, "join_message")
                except InvalidArgument as e:
                    return await ctx.send(format_traceback(e))

                message = _(
                    "Would you like to add additional end messages to be selected from at random?"
                )

                can_react = ctx.channel.permissions_for(ctx.me).add_reactions
                if not can_react:
                    message += " (y/n)"
                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. Saving join message as "{}".'.format(
                                join_message
                            )
                        )
                    )

                if predicate.result:
                    interaction = await start_interactive_message_session(
                        ctx, self.bot, "join_message", message
                    )
                    if interaction is False:
                        data = join_message
                        await ctx.send(
                            _(
                                "Join message set to what you provided previously: {}".format(
                                    join_message
                                )
                            )
                        )
                    else:
                        data = [join_message] + interaction
                        await ctx.send(_("Join messages updated for this raffle."))
                else:
                    data = join_message
                    await ctx.send(_("Join message updated for this raffle."))
                raffle_data["join_message"] = data

        await self.clean_guild_raffles(ctx)
示例#7
0
            await question.delete()
            await ctx.send("Okay then :D")
        if not pred.result:
            await question.delete()
            return await ctx.send("Canceled!")
        else:
            if can_react:
                with suppress(discord.Forbidden):
                    await question.clear_reactions()
        await self.config.guild(ctx.guild).set_raw(action, value=None)
        await ctx.send("Removed the {}!".format(action))

            pred = ReactionPredicate.yes_or_no(question, ctx.author)
            event = "reaction_add"
        else:
            pred = MessagePredicate.yes_or_no(ctx)
            event = "message"
        try:
            await ctx.bot.wait_for(event, check=pred, timeout=20)
        except asyncio.TimeoutError:
            await question.delete()
            await ctx.send("Okay then :D")
        if not pred.result:
            await question.delete()
            return await ctx.send("Canceled!")
        else:
            if can_react:
                with suppress(discord.Forbidden):
                    await question.clear_reactions()
        await self.config.guild(ctx.guild).set_raw(action, value=None)
        await ctx.send("Removed the {}!".format(action))
示例#8
0
    async def get_option(
        self, ctx: commands.Context, *, added_required: bool = False
    ) -> SlashOption:
        name_desc = [
            "What should the argument name be and description be?",
            "The argument name and description should be split by a `:`.",
            "Example: `member:A member of this server.`\n",
            "*Slash argument names may not exceed 32 characters and can only contain characters "
            "that are alphanumeric or '_' or '-'.",
            "The argument description must be less than or equal to 100 characters.*",
        ]
        name_pred = MessagePredicate.regex(ARGUMENT_NAME_DESCRIPTION, ctx)
        await self.send_and_query_response(ctx, "\n".join(name_desc), name_pred)
        match = name_pred.result
        name, description = match.group(1), match.group(2)

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

        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),
        )
        if option_type == "choices":
            choices = await self.get_choices(ctx)
            option_type = "STRING"
        else:
            choices = []
        option_type = SlashOptionType[option_type.upper()]

        if not added_required:
            pred = MessagePredicate.yes_or_no(ctx)
            await self.send_and_query_response(
                ctx,
                "Is this argument required? (Y/n)\n*Keep in mind that if you choose to make this argument optional, all following arguments must also be optional.*",
                pred,
            )
            required = pred.result
        else:
            await ctx.send(
                "This argument was automatically made optional as the previous one was optional.",
                delete_after=15,
            )
            required = False

        return SlashOption(
            name=name,
            description=description,
            option_type=option_type,
            required=required,
            choices=choices,
        )
示例#9
0
    async def _user_report(
        self,
        ctx: commands.Context,
        image_proof_url: str,
        do_imgur_upload: bool,
        member: Union[discord.Member, int],
        ban_message: str,
    ):
        """Perform user report."""
        description = ""
        sent = []
        is_error = False
        config_services = await self.config.guild(ctx.guild).services()
        if isinstance(member, discord.Member):
            member_id = member.id
            member_avatar_url = member.avatar_url
        else:
            member_id = member
            member_avatar_url = None

        # Gather services that can have reports sent to them
        report_services = []
        for service_name, service_config in config_services.items():
            if not service_config.get("enabled", False):
                continue  # This service is not enabled
            service_class = self.all_supported_services.get(service_name, None)
            if not service_class:
                continue  # This service is not supported
            try:
                service_class().report
            except AttributeError:
                continue  # This service does not support reporting
            api_key = await self.get_api_key(service_name, config_services)
            if not api_key:
                continue  # This service needs an API key set to work
            report_services.append((service_class(), api_key))

        # Send error if there are no services to send to
        if not report_services:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    "Error",
                    discord.Colour.red(),
                    "No services have been set up. Please check `[p]bancheckset service settings` for more details.",
                    member_avatar_url,
                ),
            )
            return

        # Upload to Imgur if needed
        if do_imgur_upload:
            service_keys = await self.bot.get_shared_api_tokens("imgur")
            imgur_client_id = service_keys.get("client_id", False)
            if not imgur_client_id:
                await ctx.send(
                    error(
                        "This command requires that you have an Imgur Client ID. Please set one with `.imgurcreds`."
                    )
                )
                return
            image_proof_url = await Imgur.upload(image_proof_url, imgur_client_id)
            if not image_proof_url:
                await ctx.send(
                    error(
                        "Uploading image to Imgur failed. Ban report has not been sent."
                    )
                )
                return

        # Ask if the user really wants to do this
        pred = MessagePredicate.yes_or_no(ctx)
        await ctx.send(
            question(
                f"Are you **sure** you want to send this ban report for **{member}**? (yes/no)"
            )
        )
        try:
            await ctx.bot.wait_for("message", check=pred, timeout=30)
        except asyncio.TimeoutError:
            pass
        if pred.result:
            pass
        else:
            await ctx.send(error("Sending ban report has been canceled."))
            return

        # Send report to services
        for report_service_tuple in report_services:
            response = await report_service_tuple[0].report(
                member_id,
                report_service_tuple[1],
                ctx.author.id,
                ban_message,
                image_proof_url,
            )
            sent.append(response.service)
            if response.result and response.reason:
                description += checkmark(
                    f"**{response.service}:** Sent ({response.reason})\n"
                )
            elif response.result:
                description += checkmark(f"**{response.service}:** Sent\n")
            else:
                is_error = True
                description += error(
                    f"**{response.service}:** Failure ({response.reason if response.reason else 'No reason given'})\n"
                )

        # Generate results
        if is_error:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    f"Errors occurred while sending reports for **{member}**",
                    discord.Colour.red(),
                    description,
                    member_avatar_url,
                ),
            )
        else:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    f"Reports sent for **{member}**",
                    discord.Colour.green(),
                    f"Services: {', '.join(sent)}",
                    member_avatar_url,
                ),
            )
示例#10
0
    async def challengeuser(self,
                            ctx: commands.Context,
                            user: discord.Member,
                            *,
                            reason: str = None):
        """Make an user pass the captcha again."""
        if user.bot:  # Do not challenge bot.
            await ctx.send(
                "Bots are my friend, I cannot let you do that to them.")
            return
        if user is ctx.author:
            await ctx.send(
                "Really... REALLY? ARE YOU TRYING TO CHALLENGE YOURSELF?")
            return
        if user.top_role >= ctx.author.top_role:
            await ctx.send(
                "This user has a role who is higher or equal to your higher role, I "
                "cannot let you do that.")
            return

        data = await self.data.guild(ctx.guild).all()
        # Get channel
        verifchannel = data["verifchannel"]
        if not verifchannel:
            await ctx.send("There is no verification channel registered.")
            return
        channel = self.bot.get_channel(verifchannel)
        if not channel:
            await ctx.send(
                "I cannot find the verification channel, please add one again."
            )
            return

        # Permissions checker (In case someone changed something meanwhile)
        needed_permissions = [
            "manage_messages",
            "read_messages",
            "send_messages",
            "manage_roles",
        ]
        checker = self._permissions_checker(needed_permissions, channel)
        if isinstance(checker, str):
            await ctx.send(checker)
            return  # Missing perm(s)

        await ctx.send(
            "This will remove all roles to the users that will get challenged, he will"
            "receive his roles back after passing the captcha or get kicked if fail, "
            "would you like to continue? (Y/N)")
        pred = MessagePredicate.yes_or_no(ctx)
        await self.bot.wait_for("message", check=pred)
        if not pred.result:
            await ctx.send("We're sleeping, for now...")
            return

        # Start challenge
        if not reason:
            reason = (
                "Hello [user], a server administrator challenged you for a second time in "
                "this server, please complete the following captcha. If you fail or take "
                "too much time to answer (5 minutes), you will be automatically kicked "
                "from this server.\nNote: The captcha doesn't include space.".
                replace("[user]", user.mention))
        roles = self._roles_keeper(user)
        await self._roles_remover(user, roles)
        if data["temprole"]:
            role = ctx.guild.get_role(data["temprole"])
            await user.add_roles(role,
                                 reason="Temporary role given by captcha.")
        async with ctx.typing():
            captched, bot_message, user_message = await self.challenger(
                user, channel, f"Challenged manually by {ctx.author}", reason)

            final = await channel.send("You {term} the captcha.".format(
                term="completed" if captched else "failed"))
            has_been_kicked = False
            if captched:
                await self._add_roles(user, roles)
                await self._report_log(user, "completed",
                                       f"Completed captcha.")
            else:
                await self._report_log(user, "kick", "Failed captcha.")
                result = await self._mute_or_unmute_user(channel, user, False)
                if not result:  # Immediate kick
                    await self._kicker(user,
                                       "Failed the captcha. (Immediate kick)")
                    has_been_kicked = True
            await asyncio.sleep(5)
            if not captched and not has_been_kicked:
                await self._kicker(user, "Failed the captcha.")
            await bot_message.delete()
            await user_message.delete()
            await final.delete()
            del self.in_challenge[user.id]
示例#11
0
    async def applysetup(self, ctx: commands.Context):
        """Go through the initial setup process."""
        bot = self.bot
        guild = ctx.guild
        pred = MessagePredicate.yes_or_no(ctx)
        applicant = get(guild.roles, name="Staff Applicant")
        channel = get(guild.text_channels, name="applications")

        await ctx.send(
            "This will create required channel and role. Do you wish to continue? (yes/no)"
        )
        try:
            await 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 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 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 = {
                    guild.default_role: discord.PermissionOverwrite(
                        send_messages=False
                    ),
                    guild.me: discord.PermissionOverwrite(send_messages=True),
                }
            else:
                overwrites = {
                    guild.default_role: discord.PermissionOverwrite(
                        read_messages=False
                    ),
                    guild.me: discord.PermissionOverwrite(read_messages=True),
                }
            try:
                await 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."
        )
示例#12
0
    async def release(self, ctx, id: int):
        """Release a pokémon."""
        conf = await self.user_is_global(ctx.author)
        if not await conf.has_starter():
            return await ctx.send(
                _(
                    "You haven't picked a starter pokemon yet! Check out {prefix} before trying to release a pokemon."
                ).format(prefix=ctx.clean_prefix)
            )
        if id <= 0:
            return await ctx.send(_("The ID must be greater than 0!"))
        async with ctx.typing():
            result = self.cursor.execute(
                SELECT_POKEMON,
                (ctx.author.id,),
            ).fetchall()
        pokemons = [None]
        for data in result:
            pokemons.append([json.loads(data[0]), data[1]])
        if not pokemons:
            return await ctx.send(_("You don't have any pokémon, trainer!"))
        if id >= len(pokemons):
            return await ctx.send(
                _(
                    "You don't have a pokemon at that slot.\nID refers to the position within your pokémon listing.\nThis is found at the bottom of the pokemon on `[p]list`"
                )
            )
        pokemon = pokemons[id]
        name = self.get_name(pokemon[0]["name"], ctx.author)
        await ctx.send(
            _(
                "You are about to free {name}, if you wish to continue type `yes`, otherwise type `no`."
            ).format(name=name)
        )
        try:
            pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
            await ctx.bot.wait_for("message", check=pred, timeout=20)
        except asyncio.TimeoutError:
            await ctx.send("Exiting operation.")
            return

        if pred.result:
            msg = ""
            userconf = await self.user_is_global(ctx.author)
            pokeid = await userconf.pokeid()
            if id < pokeid:
                msg += _(
                    "\nYour default pokemon may have changed. I have tried to account for this change."
                )
                await userconf.pokeid.set(pokeid - 1)
            elif id == pokeid:
                msg += _(
                    "\nYou have released your selected pokemon. I have reset your selected pokemon to your first pokemon."
                )
                await userconf.pokeid.set(1)
            self.cursor.execute(
                "DELETE FROM users where message_id = ?",
                (pokemon[1],),
            )
            await ctx.send(_("Your {name} has been freed.{msg}").format(name=name, msg=msg))
        else:
            await ctx.send(_("Operation cancelled."))
示例#13
0
    async def open(self, ctx: commands.Context, *, title: str):
        """Open a new issue. Does NOT reopen."""
        try:
            token = await self._get_token(ctx)
            repo = await self._get_repo(ctx)
        except EXCEPTIONS as e:
            return await self._handle_error(ctx, e)

        await ctx.send(
            "Your next message will be the description of the issue. If you answer exactly "
            "`cancel` I won't make an issue.\n"
            "You've got 5 minutes, remember the 2000 Discord character limit!")
        try:
            answer: discord.Message = await self.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(ctx),
                timeout=300.0)
        except TimeoutError:
            return await ctx.send("Aborting.")
        if answer.content.casefold() == "cancel":
            return await ctx.send("Aborting.")
        else:
            description = answer.content

        await ctx.send(
            "Do you want to add one or more labels to this issue? (yes or no, 15 seconds)"
        )
        pred = MessagePredicate.yes_or_no(ctx)
        try:
            answer = await self.bot.wait_for("message",
                                             check=pred,
                                             timeout=15.0)
        except TimeoutError:
            return await ctx.send("Aborting.")

        to_add: List[str] = []
        if pred.result is True:
            repo_labels = await GitHubAPI.get_repo_labels(token, repo)
            rl_names = []
            for label in repo_labels:
                rl_names.append(label["name"])

            avaliable_labels = inline_hum_list(rl_names)
            await ctx.send(
                "You have 30 seconds, please say what label you want to add. Any invalid input "
                "will be ignored. This is case sensitive. Say `exit` to abort creating the issue, "
                f"or **`create` to make the issue**.\n\nAvaliable labels: {avaliable_labels}"
            )

            def check(msg: discord.Message):
                return (msg.author == ctx.author and msg.channel == ctx.channel
                        and (msg.content in rl_names
                             or msg.content.casefold() in ["create", "exit"]))

            to_add = []
            while True:
                try:
                    answer = await self.bot.wait_for("message",
                                                     check=check,
                                                     timeout=30.0)
                except TimeoutError:
                    await ctx.send("Timeout on this label.")
                    break
                if answer.content.casefold() == "exit":
                    await ctx.send("Exiting. No changes were saved.")
                    return
                if answer.content.casefold() == "create":
                    break
                elif answer.content in to_add:
                    await ctx.send(
                        "It looks like that label's already on the issue. Choose another, 30 "
                        "seconds.")
                    continue
                to_add.append(answer.content)
                rl_names.remove(answer.content)

                avaliable_labels = inline_hum_list(rl_names)
                used_labels = inline_hum_list(to_add)
                await ctx.send(
                    "Label added. Again, 30 seconds. Say another label name if you want to add "
                    "more, `create` to create the issue or `exit` to exit without saving.\n\n"
                    f"Avaliable labels: {avaliable_labels}\nLabels currently on issue: "
                    f"{used_labels}")
        try:
            resp = await GitHubAPI.create_issue(token, repo, title,
                                                description, to_add)
        except EXCEPTIONS as e:
            return await self._handle_error(ctx, e)

        await ctx.send("Created issue {}: {}".format(
            resp.get("number"), "<{}>".format(resp.get("html_url"))))
示例#14
0
    async def _user_report(
        self,
        ctx: commands.Context,
        image_proof_url: str,
        do_imgur_upload: bool,
        member: Union[discord.Member, int],
        ban_message: str,
    ):
        """Perform user report."""
        description = ""
        sent = []
        is_error = False
        config_services = await self.config.guild(ctx.guild).services()
        for service_name, service_config in config_services.items():
            if not service_config.get("enabled", False):
                continue
            service_class = self.all_supported_services.get(
                service_name, False)
            if not service_class:
                continue
            api_key = await self.get_api_key(service_name, config_services)
            if not api_key:
                continue
            try:
                service_class().report
            except AttributeError:
                continue  # This service does not support reporting
            if do_imgur_upload:
                service_keys = await self.bot.get_shared_api_tokens("imgur")
                imgur_client_id = service_keys.get("client_id", False)
                if not imgur_client_id:
                    await ctx.send(
                        error(
                            "This command requires that you have an Imgur Client ID. Please set one with `.imgurcreds`."
                        ))
                    return
                image_proof_url = await Imgur.upload(image_proof_url,
                                                     imgur_client_id)
                if not image_proof_url:
                    await ctx.send(
                        error(
                            "Uploading image to Imgur failed. Ban report has not been sent."
                        ))
                    return
            pred = MessagePredicate.yes_or_no(ctx)
            await ctx.send(
                question(
                    "Are you **sure** you want to send this ban report for **{}**? (yes/no)"
                    .format(member)))
            try:
                await ctx.bot.wait_for("message", check=pred, timeout=30)
            except asyncio.TimeoutError:
                pass
            if pred.result:
                pass
            else:
                await ctx.send(error("Sending ban report has been canceled."))
                return

            if isinstance(member, discord.Member):
                member_id = member.id
                member_avatar_url = member.avatar_url
            else:
                member_id = member
                member_avatar_url = None

            response = await service_class().report(member_id, api_key,
                                                    ctx.author.id, ban_message,
                                                    image_proof_url)
            sent.append(response.service)
            if response.result and response.reason:
                description += "**{}:** Sent ({})\n".format(
                    response.service, response.reason)
            elif response.result:
                description += "**{}:** Sent\n".format(response.service)
            elif not response.result and response.reason:
                is_error = True
                description += "**{}:** Failure ({})\n".format(
                    response.service, response.reason)
            else:
                is_error = True
                description += "**{}:** Failure (HTTP error {})\n".format(
                    response.service, response.http_status)
        if is_error:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    "Errors occured while sending reports for **{}**".format(
                        member),
                    discord.Colour.red(),
                    description,
                    member_avatar_url,
                ),
            )
        elif not sent:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    "Error",
                    discord.Colour.red(),
                    "No services have been set up. Please check `[p]bancheckset` for more details.",
                    member_avatar_url,
                ),
            )
        else:
            await self.send_embed(
                ctx.channel,
                self.embed_maker(
                    "Reports sent for **{}**".format(member),
                    discord.Colour.green(),
                    "Services: {}".format(", ".join(sent)),
                    member_avatar_url,
                ),
            )