From 52801b4de1d63cd01191acf7fcee137977140ec0 Mon Sep 17 00:00:00 2001 From: lexicade Date: Fri, 27 Jan 2023 21:06:30 +0000 Subject: Project init --- cogs/RoleManager.py | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 cogs/RoleManager.py (limited to 'cogs/RoleManager.py') diff --git a/cogs/RoleManager.py b/cogs/RoleManager.py new file mode 100644 index 0000000..5893e9b --- /dev/null +++ b/cogs/RoleManager.py @@ -0,0 +1,363 @@ +from discord.ext import commands +from discord import abc +import discord +import importlib +import re +import requests +import pandas as pd +import io +import json +import utils +importlib.reload(utils) + + +class RoleManager(commands.Cog): + def __init__(self, bot): + self.bot = bot + global extension_name + extension_name = "[Role Manager] " + + @commands.Cog.listener() + async def on_raw_reaction_add(self, payload): + await self.update_roles(payload.guild_id, payload.message_id, payload.channel_id, payload.user_id, payload.emoji) + + @commands.Cog.listener() + async def on_raw_reaction_remove(self, payload): + await self.update_roles(payload.guild_id, payload.message_id, payload.channel_id, payload.user_id, payload.emoji) + + async def update_roles(self, guild_id, message_id, channel_id: int, user_id, react_emoji: discord.PartialEmoji): + if user_id == self.bot.user.id: + return + + sql_msg_parent = await utils.sql('SELECT id FROM "database1".synthy.menu_parent WHERE guild_id = %s AND message_id = %s', (guild_id, message_id,)) + if sql_msg_parent: + guild = self.bot.get_guild(guild_id) + print(f"guild{guild}") + member = guild.get_member(user_id) + print(f"member{member}") + member_self = guild.get_member(self.bot.user.id) + print(f"member_self{member_self}") + channel = self.bot.get_channel(channel_id) + print(f"channel{channel}") + + if react_emoji.is_unicode_emoji(): + role_emoji = await self.translate_unicode_emoji(str(react_emoji), "emoji") + else: + role_emoji = f"<:{react_emoji.name}:{react_emoji.id}>" + + sql_msg_roles = await utils.sql('SELECT emoji_id, role_id FROM "database1".synthy.menu_child WHERE parent_id = %s AND emoji_id = %s', (sql_msg_parent[0]["id"], role_emoji,)) + sql_msg_roles = [item for item in sql_msg_roles] + if not sql_msg_roles: + + # emb = await utils.notice("Auto-roles - Warning", + # f"The role {role_emoji} does not have an associated role. ", + # colour="orange") + # await utils.log(guild_id, self.bot, emb=emb) + return + + role = guild.get_role(sql_msg_roles[0]["role_id"]) + + if member_self.top_role < role: + message_embed = discord.Embed(title=f"Unable to add/remove {role} as it's ranked higher than mine. Move my role above {role} to fix this.", description="") + await channel.send(embed=message_embed, delete_after=10.0) + + else: + if str(sql_msg_roles[0]["role_id"]) in str(member.roles): + await member.remove_roles(role) + message_embed = discord.Embed(title=f"Removing {role} from {member.name}", description="") + await channel.send(embed=message_embed, delete_after=10.0) + emb = await utils.notice("Role Removed", + f"[ROLES] Removed @{role} from {member.name}", + colour="green") + await utils.log(guild_id, self.bot, emb=emb) + else: + await member.add_roles(role) + message_embed = discord.Embed(title=f"Added {role} to {member.name}", description="") + await channel.send(embed=message_embed, delete_after=10.0) + emb = await utils.notice("Role Removed", + f"[ROLES] Added @{role} to {member.name}", + colour="green") + await utils.log(guild_id, self.bot, emb=emb) + + @commands.group(invoke_without_command=True) + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def menu(self, ctx): + """Customise roles to be given/removed on a reaction""" + prefix = await self.bot.get_prefix(ctx.message) + emb = await utils.embed(ctx, f"Commands for {prefix[2]}menu", "Manage menus to grant roles") + emb = await utils.field(emb, f"{prefix[2]}menu new [menu name]", "Create a new roles menu for your server.") + emb = await utils.field(emb, f"{prefix[2]}menu list", "List all currently used menus.") + emb = await utils.field(emb, f"{prefix[2]}menu list [menu name]", "List all roles for the chosen menu.") + emb = await utils.field(emb, f"{prefix[2]}menu addrole [menu name] [emoji] [role]", "Add a new option to an existing menu.") + emb = await utils.field(emb, f"{prefix[2]}menu removerole [menu name] [role]", "Remove an option from an existing menu.") + await ctx.send(embed=emb) + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def list(self, ctx, *menu): + sql_return = await utils.sql('SELECT id, menu_name FROM "database1".synthy.menu_parent WHERE guild_id = %s', (ctx.guild.id,)) + sql_return = [item for item in sql_return] + # print(sql_return) + + guild_menus = "" + if not sql_return: + guild_menus = "No menus have been created for this server." + else: + for iter in sql_return: + guild_menus = f"{iter['menu_name']}\n{guild_menus}".strip() + + if len(menu) == 0: + emb = await utils.embed(ctx, f"Menus for {ctx.guild.name}", guild_menus) + await ctx.send(embed=emb) + else: + # Validate Menu Parent + menu_name = menu_id = None + for sql_menu in sql_return: + # print(f"Checking {sql_menu['menu_name']} against {menu[0]}") + if sql_menu["menu_name"] == menu[0]: + menu_name = sql_menu["menu_name"] + menu_id = sql_menu["id"] + break + + if menu_id: + guild_menus = await utils.sql('SELECT role_id, emoji_id FROM "database1".synthy.menu_child WHERE parent_id = %s', (menu_id,)) + menu_items = [item for item in guild_menus] + + # all_items = "" + role_list = [] + for item in menu_items: + role_list.append(f"{item['emoji_id']} <@&{item['role_id']}>") + # all_items = f"<@&{item['role_id']}>\n{all_items}" + + emb = await utils.embed(ctx, "", " \n".join(role_list)) + await ctx.send(embed=emb) + + else: + await ctx.send("failed") + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def new(self, ctx, menu_name): + await utils.sql('INSERT INTO "database1".synthy.menu_parent (guild_id, menu_name) VALUES (%s, %s)', (ctx.guild.id, menu_name,)) + + emb = await utils.embed(ctx, f"Created the {menu_name} menu.", "") + await ctx.send(embed=emb) + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def addrole(self, ctx, menu_name, emoji, role): + # Validate Menu Parent + guild_menus = await utils.sql('SELECT id FROM "database1".synthy.menu_parent WHERE guild_id = %s and menu_name = %s', (ctx.guild.id, menu_name,)) + menu_id = [item['id'] for item in guild_menus][0] + + if menu_id is None: + emb = await utils.embed(ctx, f"Menu does not exist.", "") + await ctx.send(embed=emb) + return + + print() + + # Validate Emoji + # Check if custom animated + if re.search(r"", emoji): + emoji_custom = emoji.replace("<:", "").replace(">", "").split(":")[1] + emoji_custom = self.bot.get_emoji(int(emoji_custom)) + + # emoji.guild.id is not ctx.guild.id + if emoji_custom is None: + # Try to find standard emoji + emb = await utils.embed(ctx, f"You must use an emoji from this Discord server", "") + await ctx.send(embed=emb) + + else: + emoji_id = emoji_custom + + # Check if default static + elif await self.translate_unicode_emoji(emoji, "emoji"): + # emoji_id = emoji.encode("raw_unicode_escape") + emoji_id = await self.translate_unicode_emoji(emoji, "emoji") + if not emoji_id: + return + # emoji_id = emoji + + # Fail + else: + await ctx.send("fail") + return + + # Validate Role + role = ctx.guild.get_role(int(role.replace("<@&", "").replace(">", ""))) + if role is None or role == "": + emb = await utils.embed(ctx, f"Role is invalid.", "") + await ctx.send(embed=emb) + return + + await utils.sql('INSERT INTO "database1".synthy.menu_child (emoji_id, role_id, parent_id) VALUES (%s, %s, %s)', (emoji_id, role.id, menu_id,)) + + emb = await utils.embed(ctx, f"Added {role} to {menu_name}.", "") + await ctx.send(embed=emb) + + @commands.command(pass_context=True) + async def tt(self, ctx, emoji): + + emoji = await self.translate_unicode_emoji(emoji, "emoji") + if emoji: + await ctx.send(f"Name: \\{emoji} {emoji}") + # print(f"is_unicode_emoji: {emoji.is_unicode_emoji}") + # print(f"id: {emoji.id}") + + else: + print("Failed") + + @staticmethod + async def translate_unicode_emoji(emoji, field): + return_data = requests.get("https://raw.githubusercontent.com/rainyear/emoji-query/master/emoji.map.json") + # JSON fields: emoji(:emoji:), description:long unicode desc), unicode(Unicode char/str), tags(ignore) + + if return_data.status_code == 200: + data = json.loads(return_data.content.decode()) + output = None + + for i, json_emoji in enumerate(data["names"]): + if emoji == json_emoji["unicode"]: + output = json_emoji[field] + break + elif emoji == json_emoji["emoji"]: + output = json_emoji[field] + break + + # print(emoji, field, output) + return output + + else: + return "Cannot verify emoji. Please try again later." + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def removerole(self, ctx, menu_name, role): + # Validate Menu Parent + guild_menus = await utils.sql('SELECT id FROM "database1".synthy.menu_parent WHERE guild_id = %s and menu_name = %s', (ctx.guild.id, menu_name,)) + menu_id = [item['id'] for item in guild_menus][0] + + # Validate Role + role = ctx.guild.get_role(int(role.replace("<@&", "").replace(">", ""))) + if role is None or role == "": + emb = await utils.embed(ctx, f"Role is invalid.", "") + await ctx.send(embed=emb) + return + + await utils.sql('DELETE FROM "database1".synthy.menu_child WHERE parent_id=%s and role_id=%s', (menu_id, role.id,)) + + emb = await utils.embed(ctx, "", f"Removed {role.id} from {menu_name}.") + await ctx.send(embed=emb) + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def channel(self, ctx, menu_name, channel_id): + menu_message = await utils.sql('SELECT message_id, id FROM "database1".synthy.menu_parent WHERE guild_id = %s AND menu_name = %s', (ctx.guild.id, menu_name,)) + if not menu_message: + emb = await utils.embed(ctx, f"Menu does not exist.", "") + await ctx.send(embed=emb) + return + + # Validate the channel ID + channel_id = channel_id.replace("<#", "").replace(">", "") + channel_object = self.bot.get_channel(int(channel_id)) + if channel_object is None: + emb = await utils.embed(ctx, f"Channel cannot be found", "") + await ctx.send(embed=emb) + return + await utils.sql('UPDATE "database1".synthy.menu_parent SET channel_id = %s WHERE guild_id = %s AND menu_name = %s', (channel_object.id, ctx.guild.id, menu_name,)) + + # Send return message + emb = await utils.embed(ctx, f"Channel has been set to #{channel_object.name}.", "") + await ctx.send(embed=emb) + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True, add_reactions=True) + async def send(self, ctx, menu_name): + # Get Channel + menu_message = await utils.sql('SELECT id, channel_id FROM "database1".synthy.menu_parent WHERE guild_id = %s AND menu_name = %s', (ctx.guild.id, menu_name,)) + channel_object = self.bot.get_channel(int(menu_message[0]["channel_id"])) + + # Create the Menu + if channel_object.permissions_for(ctx.guild.me).embed_links: + emb = await utils.embed(ctx, f"Role Menu", "") + message_sent = await channel_object.send(embed=emb) + await utils.sql('UPDATE "database1".synthy.menu_parent SET message_id = %s WHERE guild_id = %s AND menu_name = %s', (message_sent.id, ctx.guild.id, menu_name,)) + else: + await ctx.send("I can't post to this channel. I need embedded links.") + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def update(self, ctx, menu_name): + # Get Channel + menu_data = await utils.sql('SELECT id, message_id, channel_id FROM "database1".synthy.menu_parent WHERE guild_id = %s AND menu_name = %s', (ctx.guild.id, menu_name,)) + menu_id = menu_data[0]['id'] + menu_message = menu_data[0]['message_id'] + menu_channel = menu_data[0]['channel_id'] + + # Apply Emojis to the new menu + menu_emojis = await utils.sql('SELECT emoji_name, emoji_id FROM "database1".synthy.menu_child WHERE parent_id = %s', (menu_id,)) + # print(menu_emojis) + + if not menu_message: + emb = await utils.embed(ctx, 'This menu has no items.', "") + await ctx.send(embed=emb) + return + + for item in menu_emojis: + set_channel = self.bot.get_channel(int(menu_channel)) + set_message = await set_channel.fetch_message(int(menu_message)) + + # print(f"item['emoji_id'][{item['emoji_id']}]") + if str(item['emoji_id']).startswith(":"): + emoji_unicode = await self.translate_unicode_emoji(item['emoji_id'], "unicode") + # print(f"emoji_unicode[{emoji_unicode}]") + await set_message.add_reaction(emoji_unicode) + + else: + await set_message.add_reaction(item['emoji_id']) + + @menu.command() + @commands.has_permissions(manage_roles=True) + @commands.bot_has_permissions(embed_links=True) + async def body(self, ctx, menu_name, *, body): + # Get Channel + menu_data = await utils.sql('SELECT message_id, channel_id FROM "database1".synthy.menu_parent WHERE guild_id = %s AND menu_name = %s', (ctx.guild.id, menu_name,)) + obj_channel = self.bot.get_channel(menu_data[0]['channel_id']) + obj_message = await obj_channel.fetch_message(menu_data[0]['message_id']) + + await obj_message.edit(content=body) + + +def setup(bot): + print("INFO: Loading [RoleManager]... ", end="") + bot.add_cog(RoleManager(bot)) + print("Done!") + + +def teardown(bot): + print("INFO: Unloading [RoleManager]") + + +# INSERT INTO menu_parent(guild_id, menu_name) +# SELECT 415594259232849920, 'roles2' +# FROM dual +# WHERE NOT EXISTS (SELECT * FROM menu_parent +# WHERE guild_id = 415594259232849920 +# AND menu_name = 'roles2') -- cgit v1.2.3