コード例 #1
0
    async def on_command_error(self, ctx: utils.Context,
                               error: commands.CommandError):
        """Listens for command not found errors and tries to run them as interactions"""

        if not isinstance(error, commands.CommandNotFound):
            return

        # Deal with common aliases
        command_name = ctx.invoked_with.lower()
        for aliases in COMMON_COMMAND_ALIASES:
            if command_name in aliases:
                command_name = aliases[0]

        # See if we wanna deal with it
        guild_ids = [0] if ctx.guild is None else [0, ctx.guild.id]
        async with self.bot.database() as db:
            rows = await db(
                "SELECT response FROM interaction_text WHERE interaction_name=$1 AND guild_id=ANY($2::BIGINT[]) ORDER BY RANDOM() LIMIT 1",
                command_name.lower(), guild_ids)
        if not rows:
            self.logger.info("Nothing found")
            return  # No responses found

        # Create a command we can invoke
        ctx.interaction_response = rows[0]['response']
        ctx.interaction_name = command_name
        ctx.invoke_meta = True
        ctx.command = self.bot.get_command("interaction_command_meta")
        await self.bot.invoke(ctx)
コード例 #2
0
    async def copymee6roles(self, ctx: utils.Context):
        """Copies the Mee6 roles into your static role handling"""

        async with ctx.typing():

            # Get data from the Mee6 API
            base = "https://mee6.xyz/api/plugins/levels/leaderboard/"
            async with self.bot.session.get(base + str(ctx.guild.id)) as r:
                data = await r.json()
            if str(r.status) == '404':
                return await ctx.send(
                    "The leaderboard page for this guild is either not public or not present - Mee6 must be on your server for this to work."
                )
            await ctx.send(
                f"Grabbed {len(data['role_rewards'])} roles from Mee6 - now saving to database..."
            )

            # Save to db
            role_rewards = data['role_rewards']
            async with self.bot.database() as db:
                for role in role_rewards:
                    await db(
                        """INSERT INTO static_role_gain (guild_id, role_id, threshold)
                        VALUES ($1, $2, $3) ON CONFLICT (role_id) DO NOTHING""",
                        ctx.guild.id, int(role['role']['id']),
                        self.get_messages_by_level(role['rank']))

        # Remove cached roles for the guild
        cog = self.bot.get_cog("RoleHandler")
        if cog:
            cog.static_role_handles[ctx.guild.id] = None

        # Output to user
        return await ctx.send(
            f"Saved {len(role_rewards)} role rewards from Mee6.")
コード例 #3
0
    async def copymee6exp(self, ctx: utils.Context):
        """Copies the Mee6 exp into Cerberus"""

        # Check that they're not already copied
        async with self.bot.database() as db:
            data = await db("SELECT * FROM copied_mee6_exp WHERE guild_id=$1",
                            ctx.guild.id)
        if data:
            return await ctx.send(
                "You've already copied over your exp from Mee6.")

        async with ctx.typing():

            # Get data from the Mee6 API
            base = "https://mee6.xyz/api/plugins/levels/leaderboard/"
            user_data = []
            i = 0
            while True:
                async with self.bot.session.get(base + str(ctx.guild.id),
                                                params={
                                                    'page': i,
                                                    'limit': 1000
                                                }) as r:
                    data = await r.json()
                if str(r.status) == '404':
                    return await ctx.send(
                        "The leaderboard page for this guild is either not public or not present - Mee6 must be on your server for this to work."
                    )
                elif str(r.status)[0] != '2':
                    return await ctx.send(data)
                self.logger.info(
                    f"Grabbed Mee6 leaderboard data for guild {ctx.guild.id} page {i}"
                )
                if data['players']:
                    user_data.extend(data['players'])
                else:
                    break
                i += 1
            await ctx.send(
                f"Grabbed data from Mee6, now putting {len(user_data)} fields into the database - this may take a few minutes."
            )

            # Store in database
            async with self.bot.database() as db:
                await db(
                    "INSERT INTO copied_mee6_exp VALUES ($1) ON CONFLICT (guild_id) DO NOTHING",
                    ctx.guild.id)
                for user in user_data:
                    self.bot.message_count[(int(
                        user['id']), ctx.guild.id)] += user['message_count']
                    await db(
                        """INSERT INTO static_user_messages (user_id, guild_id, message_count)
                        VALUES ($1, $2, $3) ON CONFLICT (user_id, guild_id) DO UPDATE SET message_count=$3""",
                        int(user['id']), ctx.guild.id,
                        self.bot.message_count[(int(user['id']),
                                                ctx.guild.id)])

        return await ctx.send(
            f"Copied over {len(user_data)} users' exp from Mee6.")
コード例 #4
0
    async def on_command_error(self, ctx: utils.Context,
                               error: commands.CommandError):
        """CommandNotFound handler so the bot can search for that custom command"""

        # Handle commandnotfound which is really just handling the set/get/delete/etc commands
        if not isinstance(error, commands.CommandNotFound):
            return

        # Get the command and used template
        matches = self.COMMAND_REGEX.search(
            ctx.message.content[len(ctx.prefix):])
        if not matches:
            return
        command_operator = matches.group("command")  # get/get/delete/edit
        template_name = matches.group("template")  # template name

        # Filter out DMs
        if isinstance(ctx.channel, discord.DMChannel):
            return  # Fail silently on DM invocation

        # Find the template they asked for on their server
        async with self.bot.database() as db:
            template = await utils.Template.fetch_template_by_name(
                db, ctx.guild.id, template_name, fetch_fields=False)
        if not template:
            self.logger.info(
                f"Failed at getting template '{template_name}' in guild {ctx.guild.id}"
            )
            return  # Fail silently on template doesn't exist

        # Invoke command
        metacommand: utils.Command = self.bot.get_command(
            f'{command_operator.lower()}_profile_meta')
        ctx.command = metacommand
        ctx.template = template
        ctx.invoke_meta = True
        try:
            self.bot.dispatch("command", ctx)
            await metacommand.invoke(
                ctx)  # This converts the args for me, which is nice
        except (commands.CommandInvokeError, commands.CommandError) as e:
            self.bot.dispatch(
                "command_error", ctx, e
            )  # Throw any errors we get in this command into its own error handler
コード例 #5
0
    async def on_command_error(self, ctx: utils.Context,
                               error: commands.CommandError):
        """CommandNotFound handler so the bot can search for that custom command"""

        # Handle commandnotfound which is really just handling the set/get/delete/etc commands
        if not isinstance(error, commands.CommandNotFound):
            return

        # Get the command and used profile
        matches = self.COMMAND_REGEX.search(
            ctx.message.content[len(ctx.prefix):])
        if not matches:
            return
        command_operator = matches.group(1)  # get/get/delete/edit
        profile_name = matches.group(2)  # profile name

        # Filter out DMs
        if isinstance(ctx.channel, discord.DMChannel):
            return  # Fail silently on DM invocation

        # Find the profile they asked for on their server
        guild_commands = utils.Profile.all_guilds[ctx.guild.id]
        profile = guild_commands.get(profile_name)
        if not profile:
            self.logger.info(
                f"Failed at getting profile '{profile_name}' in guild {ctx.guild.id}"
            )
            return  # Fail silently on profile doesn't exist

        # Invoke command
        metacommand: utils.Command = self.bot.get_command(
            f'{command_operator.lower()}_profile_meta')
        ctx.command = metacommand
        ctx.profile = profile
        ctx.invoke_meta = True
        try:
            self.bot.dispatch("command", ctx)
            await metacommand.invoke(
                ctx)  # This converts the args for me, which is nice
        except commands.CommandError as e:
            self.bot.dispatch(
                "command_error", ctx, e
            )  # Throw any errors we get in this command into its own error handler
コード例 #6
0
    async def custom_command_listener(self, ctx:utils.Context, error:commands.CommandError):
        """Catch command error, look to see if it's a custom, respond accordingly"""

        # Make sure we need to care
        if not isinstance(error, commands.CommandNotFound):
            return

        # Check responses
        command_name = ctx.invoked_with.lower()
        async with self.bot.database() as db:
            metadata = await db("SELECT * FROM command_names WHERE (command_name=$1 OR $1=ANY(aliases)) AND guild_id=$2 ORDER BY RANDOM() LIMIT 1", command_name, ctx.guild.id)
        if not metadata:
            return

        # Invoke command
        metacommand: utils.Command = self.bot.get_command('interaction_response_metacommand')
        ctx.command = metacommand
        ctx.response_metadata = metadata
        ctx.invoke_meta = True
        try:
            await ctx.command.invoke(ctx)  # This converts the args for me, which is nice
        except commands.CommandError as e:
            self.bot.dispatch("command_error", ctx, e)
コード例 #7
0
ファイル: fursona_commands.py プロジェクト: schlopp/Honey
    async def importsona(self, ctx: utils.Context):
        """Get your sona from another server"""

        # See if they're setting one up already
        if ctx.author.id in self.currently_setting_sonas:
            return await ctx.send(
                "You're already setting up a sona! Please finish that one off first!"
            )

        # Try and send them an initial DM
        try:
            await ctx.author.send(
                f"Now taking you through importing your sona to **{ctx.guild.name}**!"
            )
        except discord.Forbidden:
            return await ctx.send(
                "I couldn't send you a DM! Please open your DMs for this server and try again."
            )
        self.currently_setting_sonas.add(ctx.author.id)
        await ctx.send("Sent you a DM!")

        # Get sona data
        async with self.bot.database() as db:
            database_rows = await db("SELECT * FROM fursonas WHERE user_id=$1",
                                     ctx.author.id)

        # Format that into a list
        all_user_sonas = []
        for row in database_rows:
            guild = self.bot.get_guild(
                row['guild_id']) or await self.bot.fetch_guild(row['guild_id'])
            # user_sona_information[guild].append(row)

            # Add to the all sona list
            menu_data = dict(row)
            menu_data.update({"guild_name": guild.name})
            all_user_sonas.append(menu_data)

        # Let's add our other servers via their APIs
        for api_data in self.OTHER_FURRY_GUILD_DATA[::-1]:

            # Format data
            url = api_data['url']
            params = {
                i: o.format(user=ctx.author, guild=ctx.guild, bot=self.bot)
                for i, o in api_data.get('params', dict()).copy().items()
            }
            headers = {
                i: o.format(user=ctx.author, guild=ctx.guild, bot=self.bot)
                for i, o in api_data.get('headers', dict()).copy().items()
            }

            # Run request
            async with self.bot.session.get(url,
                                            params=params,
                                            headers=headers) as r:
                try:
                    grabbed_sona_data = await r.json()
                except Exception:
                    grabbed_sona_data = {'data': []}

            # Add to lists
            if grabbed_sona_data['data']:
                guild_id = api_data['guild_id']
                guild_name = api_data['name']

                # Add to the all sona list
                for sona in grabbed_sona_data['data']:
                    menu_data = sona.copy()
                    menu_data.update({
                        "guild_name": guild_name,
                        "guild_id": guild_id
                    })
                    all_user_sonas.append(menu_data)

        # Filter the list
        all_user_sonas = [
            i for i in all_user_sonas if i['guild_id'] != ctx.guild.id
        ]
        if not self.bot.guild_settings[ctx.guild.id]["nsfw_is_allowed"]:
            all_user_sonas = [i for i in all_user_sonas if i['nsfw'] is False]
        if not all_user_sonas:
            self.currently_setting_sonas.remove(ctx.author.id)
            return await ctx.send(
                "You have no sonas available to import from other servers.")

        # Send it off to the user
        pages = menus.MenuPages(
            source=FursonaPageSource(all_user_sonas, per_page=1))
        await pages.start(ctx, channel=ctx.author, wait=True)

        # Ask if the user wants to import the sona they stopped on
        sona_data = pages.raw_sona_data
        ask_import_message = await ctx.author.send(
            f"Do you want to import your sona from **{sona_data['guild_name']}**?"
        )
        await ask_import_message.add_reaction(self.CHECK_MARK_EMOJI)
        await ask_import_message.add_reaction(self.CROSS_MARK_EMOJI)
        try:
            check = lambda r, u: r.message.id == ask_import_message.id and u.id == ctx.author.id
            reaction, _ = await self.bot.wait_for("reaction_add",
                                                  check=check,
                                                  timeout=120)
        except asyncio.TimeoutError:
            self.currently_setting_sonas.remove(ctx.author.id)
            return await ctx.author.send("Timed out asking about sona import.")

        # Import data
        self.currently_setting_sonas.remove(ctx.author.id)
        emoji = str(reaction.emoji)
        if emoji == self.CROSS_MARK_EMOJI:
            return await ctx.author.send(
                "Alright, cancelled importing your sona.")
        command = self.bot.get_command("setsonabyjson")
        ctx.information = sona_data
        return await command.invoke(ctx)
コード例 #8
0
ファイル: fursona_commands.py プロジェクト: schlopp/Honey
    async def setsona(self, ctx: utils.Context):
        """Stores your fursona information in the bot"""

        # See if the user already has a fursona stored
        async with self.bot.database() as db:
            rows = await db(
                "SELECT * FROM fursonas WHERE guild_id=$1 AND user_id=$2",
                ctx.guild.id, ctx.author.id)
        current_sona_names = [row['name'].lower() for row in rows]
        ctx.current_sona_names = current_sona_names

        # See if they're at the limit
        try:
            sona_limit = max(o for i, o in self.bot.guild_settings[
                ctx.guild.id]['role_sona_count'].items()
                             if int(i) in ctx.author._roles)
        except ValueError:
            sona_limit = 1
        if len(current_sona_names) >= sona_limit:
            return await ctx.send(
                "You're already at the sona limit - you have to delete one to be able to set another."
            )

        # See if they're setting one up already
        if ctx.author.id in self.currently_setting_sonas:
            return await ctx.send(
                "You're already setting up a sona! Please finish that one off first!"
            )

        # Try and send them an initial DM
        user = ctx.author
        start_message = f"Now taking you through setting up your sona on **{ctx.guild.name}**!\n"
        if not self.bot.guild_settings[ctx.guild.id]["nsfw_is_allowed"]:
            start_message += f"NSFW fursonas are not allowed for **{ctx.guild.name}** and will be automatically declined.\n"
        try:
            await user.send(start_message.strip())
        except discord.Forbidden:
            return await ctx.send(
                "I couldn't send you a DM! Please open your DMs for this server and try again."
            )
        self.currently_setting_sonas.add(user.id)
        await ctx.send("Sent you a DM!")

        # Ask about name
        name_message = await self.send_verification_message(
            user, "What is the name of your sona?")
        if name_message is None:
            return self.currently_setting_sonas.remove(user.id)
        if name_message.content.lower() in current_sona_names:
            self.currently_setting_sonas.remove(user.id)
            return await user.send(
                f"You already have a sona with the name `{name_message.content}`. Please start your setup again and provide a different name."
            )

        # Ask about gender
        gender_message = await self.send_verification_message(
            user, "What's your sona's gender?")
        if gender_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about age
        age_message = await self.send_verification_message(
            user, "How old is your sona?")
        if age_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about species
        species_message = await self.send_verification_message(
            user, "What species is your sona?")
        if species_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about orientation
        orientation_message = await self.send_verification_message(
            user, "What's your sona's orientation?")
        if orientation_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about height
        height_message = await self.send_verification_message(
            user, "How tall is your sona?")
        if height_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about weight
        weight_message = await self.send_verification_message(
            user, "What's the weight of your sona?")
        if weight_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about bio
        bio_message = await self.send_verification_message(
            user, "What's the bio of your sona?", max_length=1000)
        if bio_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about image
        def check(m) -> bool:
            return all([
                isinstance(m.channel, discord.DMChannel),
                m.author.id == user.id,
                any([
                    m.content.lower() == "no",
                    self.get_image_from_message(m)
                ]),
            ])

        image_message = await self.send_verification_message(
            user,
            "Do you have an image for your sona? Please post it if you have one (as a link or an attachment), or say `no` to continue without.",
            check=check)
        if image_message is None:
            return self.currently_setting_sonas.remove(user.id)

        # Ask about NSFW
        if self.bot.guild_settings[ctx.guild.id]["nsfw_is_allowed"]:
            check = lambda m: isinstance(
                m.channel, discord.DMChannel
            ) and m.author.id == user.id and m.content.lower(
            ) in ["yes", "no"]
            nsfw_message = await self.send_verification_message(
                user,
                "Is your sona NSFW? Please either say `yes` or `no`.",
                check=check)
            if nsfw_message is None:
                return self.currently_setting_sonas.remove(user.id)
            else:
                nsfw_content = nsfw_message.content.lower()
        else:
            nsfw_content = "no"

        # Format that into data
        image_content = None if image_message.content.lower(
        ) == "no" else self.get_image_from_message(image_message)
        information = {
            'name': name_message.content,
            'gender': gender_message.content,
            'age': age_message.content,
            'species': species_message.content,
            'orientation': orientation_message.content,
            'height': height_message.content,
            'weight': weight_message.content,
            'bio': bio_message.content,
            'image': image_content,
            'nsfw': nsfw_content == "yes",
        }
        self.currently_setting_sonas.remove(user.id)
        ctx.information = information
        if information['nsfw'] and not self.bot.guild_settings[
                ctx.guild.id]["nsfw_is_allowed"]:
            return await user.send(
                "Your fursona has been automatically declined as it is NSFW")
        await self.bot.get_command("setsonabyjson").invoke(ctx)