예제 #1
0
    async def on_member_join(self, member: discord.Member):
        """ Called when a member joins a guild (server) the bot is in."""
        log.info("{0.display_name} (ID: {0.id}) joined {0.guild.name}".format(
            member))
        # Updating member list
        if member.id in self.members:
            self.members[member.id].append(member.guild.id)
        else:
            self.members[member.id] = [member.guild.id]

        # No welcome message for lite servers and servers not tracking worlds
        if member.guild.id in config.lite_servers or tracked_worlds.get(
                member.guild.id) is None:
            return

        server_welcome = get_server_property("welcome", member.guild.id, "")
        pm = (config.welcome_pm + "\n" + server_welcome).format(
            user=member,
            server=member.guild,
            bot=self.user,
            owner=member.guild.owner)

        embed = discord.Embed(description="{0.mention} joined.".format(member))
        icon_url = get_user_avatar(member)
        embed.colour = discord.Colour.green()
        embed.set_author(name="{0.name}#{0.discriminator}".format(member),
                         icon_url=icon_url)
        embed.timestamp = dt.datetime.utcnow()

        # Check if user already has characters registered and announce them on log_channel
        # This could be because he rejoined the server or is in another server tracking the same worlds
        world = tracked_worlds.get(member.guild.id)
        if world is not None:
            c = userDatabase.cursor()
            try:
                c.execute(
                    "SELECT name, vocation, ABS(level) as level, guild "
                    "FROM chars WHERE user_id = ? and world = ?", (
                        member.id,
                        world,
                    ))
                results = c.fetchall()
                if len(results) > 0:
                    pm += "\nYou already have these characters in {0} registered to you: {1}"\
                        .format(world, join_list([r["name"] for r in results], ", ", " and "))
                    characters = [
                        "\u2023 {name} - Level {level} {voc} - **{guild}**".
                        format(**c, voc=get_voc_abb_and_emoji(c["vocation"]))
                        for c in results
                    ]
                    embed.add_field(name="Registered characters",
                                    value="\n".join(characters))
            finally:
                c.close()

        await self.send_log_message(member.guild, embed=embed)
        await member.send(pm)
예제 #2
0
    async def on_member_join(self, member: discord.Member):
        """ Called when a member joins a guild (server) the bot is in."""
        log.info("{0.display_name} (ID: {0.id}) joined {0.guild.name}".format(
            member))
        # Updating member list
        if member.id in self.members:
            self.members[member.id].append(member.guild.id)
        else:
            self.members[member.id] = [member.guild.id]

        embed = discord.Embed(description="{0.mention} joined.".format(member),
                              color=discord.Color.green())
        embed.set_author(
            name="{0.name}#{0.discriminator} (ID: {0.id})".format(member),
            icon_url=get_user_avatar(member))

        previously_registered = ""
        # If server is not tracking worlds, we don't check the database
        if member.guild.id in config.lite_servers or self.tracked_worlds.get(
                member.guild.id) is None:
            await self.send_log_message(member.guild, embed=embed)
        else:
            # Check if user already has characters registered and announce them on log_channel
            # This could be because he rejoined the server or is in another server tracking the same worlds
            world = self.tracked_worlds.get(member.guild.id)
            previously_registered = ""
            if world is not None:
                c = userDatabase.cursor()
                try:
                    c.execute(
                        "SELECT name, vocation, ABS(level) as level, guild "
                        "FROM chars WHERE user_id = ? and world = ?", (
                            member.id,
                            world,
                        ))
                    results = c.fetchall()
                    if len(results) > 0:
                        previously_registered = "\n\nYou already have these characters in {0} registered to you: *{1}*"\
                            .format(world, join_list([r["name"] for r in results], ", ", " and "))
                        characters = [
                            "\u2023 {name} - Level {level} {voc} - **{guild}**"
                            .format(**c,
                                    voc=get_voc_abb_and_emoji(c["vocation"]))
                            for c in results
                        ]
                        embed.add_field(name="Registered characters",
                                        value="\n".join(characters))
                finally:
                    c.close()
            self.dispatch("character_change", member.id)
            await self.send_log_message(member.guild, embed=embed)

        welcome_message = get_server_property(member.guild.id, "welcome")
        welcome_channel_id = get_server_property(member.guild.id,
                                                 "welcome_channel",
                                                 is_int=True)
        if welcome_message is None:
            return
        message = welcome_message.format(user=member,
                                         server=member.guild,
                                         bot=self,
                                         owner=member.guild.owner)
        message += previously_registered
        channel = member.guild.get_channel(welcome_channel_id)
        # If channel is not found, send via pm as fallback
        if channel is None:
            channel = member
        try:
            await channel.send(message)
        except discord.Forbidden:
            try:
                # If bot has no permissions to send the message on that channel, send on private message
                # If the channel was already a private message, don't try it again
                if welcome_channel_id is None:
                    return
                await member.send(message)
            except discord.Forbidden:
                pass
예제 #3
0
    async def remove_char(self, ctx: NabCtx, *, name):
        """Removes a registered character.

        Note that you can only remove chars if they are from users exclusively in your server.
        You can't remove any characters that would alter other servers NabBot is in."""
        # This could be used to remove deleted chars so we don't need to check anything
        # Except if the char exists in the database...
        c = userDatabase.cursor()
        try:
            c.execute(
                "SELECT name, user_id, world, guild, abs(level) as level, vocation "
                "FROM chars WHERE name LIKE ?", (name, ))
            result = c.fetchone()
            if result is None or result["user_id"] == 0:
                return await ctx.send(
                    "There's no character with that name registered.")
            if result["world"] != ctx.world:
                return await ctx.send(
                    f"{ctx.tick(False)} The character **{result['name']}** is in a different world."
                )

            user = self.bot.get_member(result["user_id"])
            user_guilds: List[discord.Guild] = []
            if user is not None:
                user_guilds = self.bot.get_user_guilds(user.id)
                for guild in user_guilds:
                    if guild == ctx.guild:
                        continue
                    if self.bot.tracked_worlds.get(guild.id,
                                                   None) != ctx.world:
                        continue
                    member: discord.Member = guild.get_member(ctx.author.id)
                    if member is None or member.guild_permissions.administrator:
                        await ctx.send(
                            f"{ctx.tick(False)} The user of this server is also in another server tracking "
                            f"**{ctx.world}**, where you are not an admin. You can't alter other servers."
                        )
                        return
            username = "******" if user is None else user.display_name
            c.execute("UPDATE chars SET user_id = 0 WHERE name LIKE ?",
                      (name, ))
            await ctx.send(
                "**{0}** was removed successfully from **@{1}**.".format(
                    result["name"], username))
            for server in user_guilds:
                world = self.bot.tracked_worlds.get(server.id, None)
                if world != result["world"]:
                    continue
                if result["guild"] is None:
                    result["guild"] = "No guild"
                log_msg = "{0.mention} unregistered:\n\u2023 {1} - Level {2} {3} - **{4}**". \
                    format(user, result["name"], result["level"], get_voc_abb_and_emoji(result["vocation"]),
                           result["guild"])

                embed = discord.Embed(description=log_msg)
                embed.set_author(name=f"{user.name}#{user.discriminator}",
                                 icon_url=get_user_avatar(user))
                embed.set_footer(text="{0.name}#{0.discriminator}".format(
                    ctx.author),
                                 icon_url=get_user_avatar(ctx.author))
                embed.colour = discord.Colour.dark_teal()

                await self.bot.send_log_message(server, embed=embed)
        finally:
            c.close()
            userDatabase.commit()
예제 #4
0
    async def add_account(self, ctx: NabCtx, *, params):
        """Register a character and all other visible characters to a discord user.

        If a character is hidden, only that character will be added. Characters in other worlds are skipped."""
        params = params.split(",")
        if len(params) != 2:
            raise commands.BadArgument()
        target_name, char_name = params

        user = ctx.author
        world = ctx.world

        target = self.bot.get_member(target_name, ctx.guild)
        if target is None:
            return await ctx.send(
                f"{ctx.tick(False)} I couldn't find any users named @{target_name}"
            )
        if target.bot:
            return await ctx.send(
                f"{ctx.tick(False)} You can't register characters to discord bots!"
            )

        # Get list of the user's shared servers with the bot
        target_guilds = self.bot.get_user_guilds(target.id)
        # Filter only the servers that follow the same as the current context
        target_guilds = list(
            filter(lambda x: self.bot.tracked_worlds.get(x.id) == world,
                   target_guilds))

        msg = await ctx.send(f"{config.loading_emoji} Fetching characters...")
        try:
            char = await get_character(char_name)
            if char is None:
                return await msg.edit(content="That character doesn't exist.")
        except NetworkError:
            return await msg.edit(
                content="I couldn't fetch the character, please try again.")
        chars = char.other_characters
        # If the char is hidden,we still add the searched character, if we have just one, we replace it with the
        # searched char, so we don't have to look him up again
        if len(chars) == 0 or len(chars) == 1:
            chars = [char]
        skipped = []
        updated = []
        added: List[Character] = []
        existent = []
        for char in chars:
            # Skip chars in non-tracked worlds
            if char.world != world:
                skipped.append(char)
                continue
            with closing(userDatabase.cursor()) as c:
                c.execute(
                    "SELECT name, guild, user_id as owner, abs(level) as level "
                    "FROM chars "
                    "WHERE name LIKE ?", (char.name, ))
                db_char = c.fetchone()
            if db_char is not None:
                owner = self.bot.get_member(db_char["owner"])
                # Previous owner doesn't exist anymore
                if owner is None:
                    updated.append({
                        'name': char.name,
                        'world': char.world,
                        'prevowner': db_char["owner"],
                        'vocation': db_char["vocation"],
                        'level': db_char['level'],
                        'guild': db_char['guild']
                    })
                    continue
                # Char already registered to this user
                elif owner.id == target.id:
                    existent.append("{0.name} ({0.world})".format(char))
                    continue
                # Character is registered to another user, we stop the whole process
                else:
                    reply = "A character in that account ({0}) is already registered to **{1.display_name}**"
                    await ctx.send(reply.format(db_char["name"], owner))
                    return
            # If we only have one char, it already contains full data
            if len(chars) > 1:
                try:
                    await ctx.channel.trigger_typing()
                    char = await get_character(char.name)
                except NetworkError:
                    await ctx.send(
                        "I'm having network troubles, please try again.")
                    return
            if char.deleted is not None:
                skipped.append(char)
                continue
            added.append(char)

        if len(skipped) == len(chars):
            await ctx.send(
                f"Sorry, I couldn't find any characters in **{world}**.")
            return

        reply = ""
        log_reply = dict().fromkeys([server.id for server in target_guilds],
                                    "")
        if len(existent) > 0:
            reply += "\nThe following characters were already registered to @{1}: {0}" \
                .format(join_list(existent, ", ", " and "), target.display_name)

        if len(added) > 0:
            reply += "\nThe following characters were added to @{1.display_name}: {0}" \
                .format(join_list(["{0.name} ({0.world})".format(c) for c in added], ", ", " and "), target)
            for char in added:
                log.info(
                    "{2.display_name} registered character {0} was assigned to {1.display_name} (ID: {1.id})"
                    .format(char.name, target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    _guild = "No guild" if char.guild is None else char.guild_name
                    voc = get_voc_abb_and_emoji(char.vocation)
                    log_reply[guild.id] += "\n\u2023 {1.name} - Level {1.level} {2} - **{0}**" \
                        .format(_guild, char, voc)

        if len(updated) > 0:
            reply += "\nThe following characters were reassigned to @{1.display_name}: {0}" \
                .format(join_list(["{name} ({world})".format(**c) for c in updated], ", ", " and "), target)
            for char in updated:
                log.info(
                    "{2.display_name} reassigned character {0} to {1.display_name} (ID: {1.id})"
                    .format(char['name'], target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    char["voc"] = get_voc_abb_and_emoji(char["vocation"])
                    if char["guild"] is None:
                        char["guild"] = "No guild"
                    log_reply[guild.id] += "\n\u2023 {name} - Level {level} {voc} - **{guild}** (Reassigned)". \
                        format(**char)

        for char in updated:
            with userDatabase as conn:
                conn.execute("UPDATE chars SET user_id = ? WHERE name LIKE ?",
                             (target.id, char['name']))
        for char in added:
            with userDatabase as conn:
                conn.execute(
                    "INSERT INTO chars (name,level,vocation,user_id, world, guild) VALUES (?,?,?,?,?,?)",
                    (char.name, char.level * -1, char.vocation, target.id,
                     char.world, char.guild_name))

        with userDatabase as conn:
            conn.execute(
                "INSERT OR IGNORE INTO users (id, name) VALUES (?, ?)", (
                    target.id,
                    target.display_name,
                ))
            conn.execute("UPDATE users SET name = ? WHERE id = ?", (
                target.display_name,
                target.id,
            ))

        await ctx.send(reply)
        for server_id, message in log_reply.items():
            if message:
                message = f"{target.mention} registered:" + message
                embed = discord.Embed(description=message)
                embed.set_author(name=f"{target.name}#{target.discriminator}",
                                 icon_url=get_user_avatar(target))
                embed.colour = discord.Colour.dark_teal()
                icon_url = get_user_avatar(user)
                embed.set_footer(
                    text="{0.name}#{0.discriminator}".format(user),
                    icon_url=icon_url)
                await self.bot.send_log_message(self.bot.get_guild(server_id),
                                                embed=embed)
예제 #5
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()