Exemple #1
0
    async def cleanup(self, ctx: NabCtx, limit: int = 50):
        """Cleans the channel from bot commands.

        If the bot has `Manage Messages` permission, it will also delete command invocation messages."""
        count = 0
        prefixes = get_server_property(ctx.guild.id,
                                       "prefixes",
                                       deserialize=True,
                                       default=config.command_prefix)
        # Also skip death and levelup messages from cleanup
        announce_prefix = (config.levelup_emoji, config.death_emoji,
                           config.pvpdeath_emoji)
        if ctx.bot_permissions.manage_messages:

            def check(m: discord.Message):
                return (m.author == ctx.me and not m.content.startswith(announce_prefix)) or \
                       m.content.startswith(tuple(prefixes))

            deleted = await ctx.channel.purge(limit=limit, check=check)
            count = len(deleted)
        else:
            with ctx.typing():
                async for msg in ctx.channel.history(limit=limit):
                    if msg.author == ctx.me:
                        await msg.delete()
                        count += 1
        if not count:
            return await ctx.send("There are no messages to clean.",
                                  delete_after=10)

        await ctx.send(f"{ctx.tick()} Deleted {count:,} messages.",
                       delete_after=20)
Exemple #2
0
    async def checkchannel(self,
                           ctx: NabCtx,
                           *,
                           channel: discord.TextChannel = None):
        """Checks the channel's permissions.

        Makes sure that the bot has all the required permissions to work properly.
        If no channel is specified, the current one is checked."""
        if channel is None:
            channel = ctx.channel
        permissions = channel.permissions_for(ctx.me)
        content = f"**Checking {channel.mention}:**"
        if permissions.administrator:
            content += f"\n{ctx.tick(True)} I have `Administrator` permission."
            await ctx.send(content)
            return
        perm_dict = dict(permissions)
        check_permissions = {
            "read_messages":
            ["error", "I won't be able to see commands in here."],
            "send_messages": ["error", "I won't be able to respond in here."],
            "add_reactions": [
                "error",
                "Pagination or commands that require emoji confirmation won't work."
            ],
            "external_emojis":
            ["warn", "I won't be able to show my emojis in some commands."],
            "read_message_history":
            ["error", "I won't be able to see your reactions in commands."],
            "manage_messages": [
                "warn",
                "Command pagination won't work well and I won't be able to delete messages "
                "in the ask channel."
            ],
            "embed_links":
            ["error", "I won't be able to show many of my commands."],
            "attach_files":
            ["warn", "I won't be able to show images in some of my commands."]
        }
        ok = True
        for k, v in check_permissions.items():
            level, explain = v
            if not perm_dict[k]:
                ok = False
                perm_name = k.replace("_", " ").title()
                icon = ctx.tick(
                    False) if level == "error" else config.warn_emoji
                content += f"\nMissing `{perm_name}` permission"
                content += f"\n\t{icon} {explain}"
        if ok:
            content += f"\n{ctx.tick(True)} All permissions are correct!"
        await ctx.send(content)
Exemple #3
0
    async def postguild(self,
                        ctx: NabCtx,
                        guild,
                        invite=None,
                        reddit=None,
                        *,
                        member: discord.Member = None):
        """Creates an advertisement post on the reddit guilds channel

        Parameters:
        **guild**: The guild's name, if it has multiple words, surround with quotes.
        **invite**: Invite link to their discord, if available. Type - to ignore.
        **reddit**: The reddit's username of the person to contact. Type - to ignore.
        **member**: The discord's username of the person to contact. Type - or leave blank to omit.
        """
        await ctx.message.delete()
        with ctx.typing():
            try:
                guild = await get_guild(guild)
                if guild is None:
                    ctx.send(
                        f"I couldn't find any guild named '**{guild}**'. "
                        f"Please use quotes for names with multiple words.",
                        delete_after=10)
                    return
            except NetworkError:
                ctx.send("I'm having network issues, please try later.",
                         delete_after=10)
                return

        channel: discord.TextChannel = ctx.guild.get_channel(GUILDS_CHANNEL)
        if channel is None:
            await ctx.send(
                "The channel for reddit guilds seems to have been deleted.")
            return

        embed = discord.Embed(title=f"{guild.name} ({guild.world})",
                              description=guild.description,
                              colour=discord.Colour.blurple(),
                              url=guild.url)
        embed.set_thumbnail(url=guild.logo)
        embed.add_field(name="In-game contact",
                        value=f"[{guild.members[0]['name']}]"
                        f"({get_character_url(guild.members[0]['name'])})")
        if member is not None:
            embed.add_field(name="Discord contact", value=member.mention)
        if not invite or invite != "-":
            invite = f"―――――――――――――――――――――\nDiscord Invite: {invite}"
        else:
            invite = "―――――――――――――――――――――"

        if not reddit or reddit != "-":
            embed.add_field(
                name="Reddit contact",
                value=f"[u/{reddit}](https://reddit.com/u/{reddit})")
        try:
            await channel.send(invite, embed=embed)
            await ctx.send(ctx.tick(), delete_after=10)
        except discord.Forbidden:
            await ctx.send(
                f"I don't have permissions to write on {channel.mention}.",
                delete_after=10)
        except discord.HTTPException:
            await ctx.send(
                "Something went wrong when trying to post the message.",
                delete_after=10)
Exemple #4
0
    async def add_char(self, ctx: NabCtx, *, params):
        """Registers a character to a user.

        The character must be in the world you're tracking.
        If the desired character is already assigned to someone else, the user must use `claim`."""
        params = params.split(",")
        if len(params) != 2:
            raise commands.BadArgument()

        user = self.bot.get_member(params[0], ctx.guild)
        if user is None:
            return await ctx.send(
                f"{ctx.tick(False)} I don't see any user named **{params[0]}** in this server."
            )
        user_servers = self.bot.get_user_guilds(user.id)

        with ctx.typing():
            try:
                char = await get_character(params[1])
                if char is None:
                    await ctx.send("That character doesn't exist")
                    return
            except NetworkError:
                await ctx.send(
                    "I couldn't fetch the character, please try again.")
                return
            if char.world != ctx.world:
                await ctx.send(
                    "**{0.name}** ({0.world}) is not in a world you can manage."
                    .format(char))
                return
            if char.deleted is not None:
                await ctx.send(
                    "**{0.name}** ({0.world}) is scheduled for deletion and can't be added."
                    .format(char))
                return
            embed = discord.Embed()
            embed.set_author(name=f"{user.name}#{user.discriminator}",
                             icon_url=get_user_avatar(user))
            embed.colour = discord.Colour.dark_teal()
            icon_url = get_user_avatar(ctx.author)
            embed.set_footer(text="{0.name}#{0.discriminator}".format(
                ctx.author),
                             icon_url=icon_url)

            with closing(userDatabase.cursor()) as c:
                c.execute(
                    "SELECT id, name, user_id FROM chars WHERE name LIKE ?",
                    (char.name, ))
                result = c.fetchone()
                if result is not None:
                    # Registered to a different user
                    if result["user_id"] != user.id:
                        current_user = self.bot.get_member(result["user_id"])
                        # User registered to someone else
                        if current_user is not None:
                            await ctx.send(
                                "This character is already registered to  **{0.name}#{0.discriminator}**"
                                .format(current_user))
                            return
                        # User no longer in any servers
                        c.execute("UPDATE chars SET user_id = ? WHERE id = ?",
                                  (
                                      user.id,
                                      result["id"],
                                  ))
                        await ctx.send(
                            "This character was reassigned to this user successfully."
                        )
                        userDatabase.commit()
                        for server in user_servers:
                            world = self.bot.tracked_worlds.get(
                                server.id, None)
                            if world == char.world:
                                guild = "No guild" if char.guild is None else char.guild_name
                                embed.description = "{0.mention} registered:\n\u2023 {1} - Level {2} {3} - **{4}**"\
                                    .format(user, char.name, char.level, get_voc_abb_and_emoji(char.vocation), guild)
                                await self.bot.send_log_message(server,
                                                                embed=embed)
                    else:
                        await ctx.send(
                            "This character is already registered to this user."
                        )
                    return
                c.execute(
                    "INSERT INTO chars (name,level,vocation,user_id, world, guild) VALUES (?,?,?,?,?,?)",
                    (char.name, char.level * -1, char.vocation, user.id,
                     char.world, char.guild_name))
                # Check if user is already registered
                c.execute("SELECT id from users WHERE id = ?", (user.id, ))
                result = c.fetchone()
                if result is None:
                    c.execute("INSERT INTO users(id,name) VALUES (?,?)", (
                        user.id,
                        user.display_name,
                    ))
                await ctx.send(
                    "**{0}** was registered successfully to this user.".format(
                        char.name))
                # Log on relevant servers
                for server in user_servers:
                    world = self.bot.tracked_worlds.get(server.id, None)
                    if world == char.world:
                        guild = "No guild" if char.guild is None else char.guild_name
                        embed.description = "{0.mention} registered:\n\u2023 {1}  - Level {2} {3} - **{4}**"\
                            .format(user, char.name, char.level, get_voc_abb_and_emoji(char.vocation), guild)
                        await self.bot.send_log_message(server, embed=embed)
                userDatabase.commit()
Exemple #5
0
    async def namelock(self, ctx: NabCtx, *, params):
        """Register the name of a new character that was namelocked.

        Characters that get namelocked can't be searched by their old name, so they must be reassigned manually.

        If the character got a name change (from the store), searching the old name redirects to the new name, so
        these are usually reassigned automatically.

        In order for the command to work, the following conditions must be met:

        - The old name must exist in NabBot's characters database.
        - The old name must not be a valid character in Tibia.com
        - The new name must be a valid character in Tibia.com
        - They must have the same vocation, not considering promotions.
        """
        params = params.split(",")
        if len(params) != 2:
            await ctx.send("The correct syntax is: `/namelock oldname,newname")
            return

        old_name = params[0]
        new_name = params[1]
        with ctx.typing():
            c = userDatabase.cursor()
            try:
                c.execute("SELECT * FROM chars WHERE name LIKE ? LIMIT 1",
                          (old_name, ))
                old_char_db = c.fetchone()
                # If character wasn't registered, there's nothing to do.
                if old_char_db is None:
                    await ctx.send(
                        "I don't have a character registered with the name: **{0}**"
                        .format(old_name))
                    return
                # Search old name to see if there's a result
                try:
                    old_char = await get_character(old_name)
                except NetworkError:
                    await ctx.send(
                        "I'm having problem with 'the internet' as you humans say, try again."
                    )
                    return
                # Check if returns a result
                if old_char is not None:
                    if old_name.lower() == old_char.name.lower():
                        await ctx.send(
                            "The character **{0}** wasn't namelocked.".format(
                                old_char.name))
                    else:
                        await ctx.send(
                            "The character **{0}** was renamed to **{1}**.".
                            format(old_name, old_char.name))
                        # Renaming is actually done in get_character(), no need to do anything.
                    return

                # Check if new name exists
                try:
                    new_char = await get_character(new_name)
                except NetworkError:
                    await ctx.send(
                        "I'm having problem with 'the internet' as you humans say, try again."
                    )
                    return
                if new_char is None:
                    await ctx.send(
                        "The character **{0}** doesn't exist.".format(new_name)
                    )
                    return
                # Check if vocations are similar
                if not (old_char_db["vocation"].lower()
                        in new_char.vocation.lower()
                        or new_char.vocation.lower()
                        in old_char_db["vocation"].lower()):
                    await ctx.send(
                        "**{0}** was a *{1}* and **{2}** is a *{3}*. I think you're making a mistake."
                        .format(old_char_db["name"], old_char_db["vocation"],
                                new_char.name, new_char.vocation))
                    return
                confirm_message = "Are you sure **{0}** ({1} {2}) is **{3}** ({4} {5}) now? `yes/no`"
                await ctx.send(
                    confirm_message.format(old_char_db["name"],
                                           abs(old_char_db["level"]),
                                           old_char_db["vocation"],
                                           new_char.name, new_char.level,
                                           new_char.vocation))

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

                try:
                    reply = await self.bot.wait_for("message",
                                                    timeout=50.0,
                                                    check=check)
                    if reply.content.lower() not in ["yes", "y"]:
                        await ctx.send("No then? Alright.")
                        return
                except asyncio.TimeoutError:
                    await ctx.send("No answer? I guess you changed your mind.")
                    return

                # Check if new name was already registered
                c.execute("SELECT * FROM chars WHERE name LIKE ?",
                          (new_char.name, ))
                new_char_db = c.fetchone()

                if new_char_db is None:
                    c.execute(
                        "UPDATE chars SET name = ?, vocation = ?, level = ? WHERE id = ?",
                        (
                            new_char.name,
                            new_char.vocation,
                            new_char.level,
                            old_char_db["id"],
                        ))
                else:
                    # Replace new char with old char id and delete old char, reassign deaths and levelups
                    c.execute(
                        "DELETE FROM chars WHERE id = ?",
                        (old_char_db["id"]),
                    )
                    c.execute("UPDATE chars SET id = ? WHERE id = ?", (
                        old_char_db["id"],
                        new_char_db["id"],
                    ))
                    c.execute("UPDATE char_deaths SET id = ? WHERE id = ?", (
                        old_char_db["id"],
                        new_char_db["id"],
                    ))
                    c.execute("UPDATE char_levelups SET id = ? WHERE id = ?", (
                        old_char_db["id"],
                        new_char_db["id"],
                    ))

                await ctx.send("Character renamed successfully.")
            finally:
                c.close()
                userDatabase.commit()