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)
def check(self, ctx): """Check which users are currently not registered.""" if not ctx.message.channel.is_private: return True author = ctx.message.author if author.id in mod_ids + owner_ids: author_servers = get_user_servers(self.bot, author.id) else: author_servers = get_user_admin_servers(self.bot, author.id) embed = discord.Embed(description="Members with unregistered users.") yield from self.bot.send_typing(ctx.message.channel) c = userDatabase.cursor() try: for server in author_servers: world = tracked_worlds.get(server.id, None) if world is None: continue c.execute( "SELECT user_id FROM chars WHERE world LIKE ? GROUP BY user_id", (world, )) result = c.fetchall() if len(result) <= 0: embed.add_field( name=server.name, value="There are no registered characters.", inline=False) continue users = [str(i["user_id"]) for i in result] empty_members = list() for member in server.members: if member.id == self.bot.user.id: continue if member.id not in users: empty_members.append("**@" + member.display_name + "**") if len(empty_members) == 0: embed.add_field(name=server.name, value="There are no unregistered users.", inline=False) continue field_value = "\n{0}".format("\n".join(empty_members)) split_value = split_message(field_value, FIELD_VALUE_LIMIT) for empty_member in split_value: if empty_member == split_value[0]: name = server.name else: name = "\u200F" embed.add_field(name=name, value=empty_member, inline=False) yield from self.bot.say(embed=embed) finally: c.close()
def remove_char(self, ctx, *, name): """Removes a registered character. The syntax is: /stalk removechar name""" if not ctx.message.channel.is_private: return True # This could be used to remove deleted chars so we don't need to check anything # Except if the char exists in the database... yield from self.bot.send_typing(ctx.message.channel) c = userDatabase.cursor() try: c.execute( "SELECT name, user_id, world, ABS(last_level) as level, vocation " "FROM chars WHERE name LIKE ?", (name, )) result = c.fetchone() if result is None: yield from self.bot.say( "There's no character with that name registered.") return user = get_member(self.bot, result["user_id"]) username = "******" if user is None else user.display_name c.execute("DELETE FROM chars WHERE name LIKE ?", (name, )) yield from self.bot.say( "**{0}** was removed successfully from **@{1}**.".format( result["name"], username)) if user is not None: for server in get_user_servers(self.bot, user.id): world = tracked_worlds.get(server.id, None) if world != result["world"]: continue log_msg = "{0.mention} removed **{1}** ({2} {3}) from {4.mention}.".\ format(ctx.message.author, result["name"], result["level"], result["vocation"], user) yield from send_log_message(self.bot, server, log_msg) return finally: c.close() userDatabase.commit()
async def unregistered(self, ctx): """Check which users are currently not registered.""" world = tracked_worlds.get(ctx.guild.id, None) entries = [] if world is None: await ctx.send("This server is not tracking any worlds.") return with closing(userDatabase.cursor()) as c: c.execute( "SELECT user_id FROM chars WHERE world LIKE ? GROUP BY user_id", (world, )) result = c.fetchall() if len(result) <= 0: await ctx.send("There are no registered characters.") return users = [i["user_id"] for i in result] for member in ctx.guild.members: # type: discord.Member if member.id == ctx.me.id: continue if member.id not in users: entries.append( f"@**{member.display_name}** \u2014 Joined on: **{member.joined_at.date()}**" ) if len(entries) == 0: await ctx.send("There are no unregistered users.") return pages = Paginator(self.bot, message=ctx.message, entries=entries, title="Unregistered members", per_page=10) try: await pages.paginate() except CannotPaginate as e: await ctx.send(e)
def add_account(self, ctx, *, 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. The syntax is the following: /stalk addacc user,char""" if not ctx.message.channel.is_private: return True params = params.split(",") if len(params) != 2: yield from self.bot.say( "The correct syntax is: ``/stalk addacc username,character``") return author = ctx.message.author if author.id in mod_ids + owner_ids: author_servers = get_user_servers(self.bot, author.id) else: author_servers = get_user_admin_servers(self.bot, author.id) author_worlds = get_user_worlds(self.bot, author.id) user = get_member_by_name(self.bot, params[0], server_list=author_servers) user_servers = get_user_servers(self.bot, user.id) user_worlds = get_user_worlds(self.bot, user.id) common_worlds = list(set(author_worlds) & set(user_worlds)) yield from self.bot.send_typing(ctx.message.channel) character = yield from get_character(params[1]) if user is None: yield from self.bot.say( "I don't see any user named **{0}** in the servers you manage." .format(params[0])) return if type(character) is not dict: if character == ERROR_NETWORK: yield from self.bot.say( "I couldn't fetch the character, please try again.") elif character == ERROR_DOESNTEXIST: yield from self.bot.say("That character doesn't exists.") return c = userDatabase.cursor() try: chars = character['chars'] # If the char is hidden,we still add the searched character if len(chars) == 0: yield from self.bot.say("Character is hidden.") chars = [character] skipped = list() added = list() added_tuples = list() reassigned_tuples = list() existent = list() error = list() for char in chars: # Character not in followed server(s), skip. if char['world'] not in common_worlds: skipped.append([char["name"], char["world"]]) continue name = char["name"] # If char is the same we already looked up, no need to look him up again if character["name"] == char["name"]: char = character else: char = yield from get_character(char["name"]) if type(char) is not dict: error.append(name) continue # Skip characters scheduled for deletion if char.get("deleted", False): skipped.append([char["name"], char["world"]]) continue c.execute( "SELECT id, name,user_id FROM chars WHERE name LIKE ?", (char['name'], )) result = c.fetchone() # Char is already in database if result is not None: # Registered to different user if str(result["user_id"]) != user.id: current_user = get_member(self.bot, result["user_id"]) # Char is registered to user no longer in server if current_user is None: added.append(char) reassigned_tuples.append(( user.id, result["id"], )) continue else: yield from self.bot.say( "{0} is already assigned to {1}. We can't add any other of these " "characters.".format( char["name"], current_user.display_name)) return # Registered to current user existent.append(char) continue added.append(char) added_tuples.append(( char["name"], char["level"] * -1, char["vocation"], user.id, char["world"], )) 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, )) c.executemany( "INSERT INTO chars(name,last_level,vocation,user_id, world) VALUES (?,?,?,?,?)", added_tuples) c.executemany("UPDATE chars SET user_id = ? WHERE id = ?", reassigned_tuples) reply = "" log_reply = dict().fromkeys([server.id for server in user_servers], "") if added: reply += "\nThe following characters were registered or reassigned successfully:" for char in added: char["guild"] = char.get("guild", "No guild") reply += "\n\t**{name}** ({level} {vocation}) - **{guild}**".format( **char) # Announce on server log of each server for server in user_servers: # Only announce on worlds where the character's world is tracked if tracked_worlds.get(server.id, None) == char["world"]: log_reply[ server. id] += "\n\t{name} - {level} {vocation} - **{guild}**".format( **char) if existent: reply += "\nThe following characters were already registered to this user:"******"guild"] = char.get("guild", "No guild") reply += "\n\t**{name}** ({level} {vocation}) - **{guild}**".format( **char) if skipped: reply += "\nThe following characters were skipped (not in tracked worlds or scheduled deletion):" for char, world in skipped: reply += "\n\t{0} ({1})".format(char, world) if error: reply += "\nThe following characters couldn't be fetched: " reply += ", ".join(error) yield from self.bot.say(reply) for server_id, message in log_reply.items(): if message: message = "{0.mention} registered the following characters to {1.mention}: {2}".format( author, user, message) yield from send_log_message(self.bot, self.bot.get_server(server_id), message) return finally: c.close() userDatabase.commit()
def add_char(self, ctx, *, params): """Registers a tibia character to a discord user. The syntax is: /stalk addchar user,character""" if not ctx.message.channel.is_private: return True params = params.split(",") if len(params) != 2: yield from self.bot.say( "The correct syntax is: ``/stalk addchar username,character``") return author = ctx.message.author if author.id in mod_ids + owner_ids: author_servers = get_user_servers(self.bot, author.id) else: author_servers = get_user_admin_servers(self.bot, author.id) author_worlds = get_user_worlds(self.bot, author.id) # Only search in the servers the command author is user = get_member_by_name(self.bot, params[0], server_list=author_servers) user_servers = get_user_servers(self.bot, user.id) user_worlds = get_user_worlds(self.bot, author.id) common_worlds = list(set(author_worlds) & set(user_worlds)) yield from self.bot.send_typing(ctx.message.channel) char = yield from get_character(params[1]) if user is None: yield from self.bot.say( "I don't see any user named **{0}** in the servers you manage." .format(params[0])) return if type(char) is not dict: if char == ERROR_NETWORK: yield from self.bot.say( "I couldn't fetch the character, please try again.") elif char == ERROR_DOESNTEXIST: yield from self.bot.say("That character doesn't exists.") return if char["world"] not in common_worlds: yield from self.bot.say( "**{name}** ({world}) is not in a world you can manage.". format(**char)) return if char.get("deleted", False): yield from self.bot.say( "**{name}** ({world}) is scheduled for deletion and can't be added." .format(**char)) return c = userDatabase.cursor() try: c.execute("SELECT id, name, user_id FROM chars WHERE name LIKE ?", (char['name'], )) result = c.fetchone() # Char is already in database if result is not None: # Update name if it was changed if char['name'] != params[1]: c.execute("UPDATE chars SET name = ? WHERE id = ?", ( char['name'], result["id"], )) yield from self.bot.say( "This character's name was changed from **{0}** to **{1}**" .format(params[1], char['name'])) # Registered to a different user if result["user_id"] != user.id: current_user = get_member(self.bot, result["user_id"]) # User no longer in server if current_user is None: c.execute("UPDATE chars SET user_id = ? WHERE id = ?", ( user.id, result["id"], )) yield from self.bot.say( "This character was registered to a user no longer in server. " "It was assigned to this user successfully.") # Log on relevant servers for server in user_servers: world = tracked_worlds.get(server.id, None) if world == char["world"]: log_msg = "{0.mention} registered **{1}** ({2} {3}) to {4.mention}." yield from send_log_message( self.bot, server, log_msg.format(author, char["name"], char["level"], char["vocation"], user)) else: yield from self.bot.say( "This character is already registered to **@{0}**". format(current_user.display_name)) return # Registered to current user yield from self.bot.say( "This character is already registered to this user.") return c.execute( "INSERT INTO chars (name,last_level,vocation,user_id, world) VALUES (?,?,?,?,?)", (char["name"], char["level"] * -1, char["vocation"], user.id, char["world"])) # 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, )) yield from self.bot.say( "**{0}** was registered successfully to this user.".format( char['name'])) # Log on relevant servers for server in user_servers: world = tracked_worlds.get(server.id, None) if world == char["world"]: char["guild"] = char.get("guild", "No guild") log_msg = "{0.mention} registered **{1}** ({2} {3}, {4}) to {5.mention}." yield from send_log_message( self.bot, server, log_msg.format(author, char["name"], char["level"], char["vocation"], char["guild"], user)) return finally: c.close() userDatabase.commit()