import discord from discord import ui from redbot.core import Config, checks, commands class Forums(commands.Cog): """Custom cog intended for use on the Galaxy discord server. Developed by SeaswimmerTheFsh.""" def __init__(self, bot): self.bot = bot self.config = Config.get_conf(self, identifier=2352711325) self.config.register_guild( request_roles=[], forum_channel="", forum_tag="" ) @commands.command() async def resolved(self, ctx: commands.Context, *, reason: str = None): """Marks a thread as resolved.""" if isinstance(ctx.channel, discord.Thread) and ctx.channel.parent_id == await self.config.guild(ctx.guild).forum_channel(): request_role_ids = await self.config.guild(ctx.guild).request_roles() request_roles = [ctx.guild.get_role(role_id) for role_id in request_role_ids] match = any(role in ctx.author.roles for role in request_roles) passed_info = { "ctx": ctx } if match and reason: passed_info.update({"reason": reason}) if match or ctx.author.id == ctx.channel.owner.id: msg = await ctx.send("Are you sure you'd like to mark this thread as resolved?") passed_info.update({"msg": msg}) await msg.edit(view=self.ResolvedButtons(timeout=180, passed_info=passed_info)) else: await ctx.message.add_reaction("❌") await ctx.message.delete(5) class ResolvedButtons(ui.View): def __init__(self, timeout, passed_info: dict): super().__init__() self.timeout = timeout self.ctx: commands.Context = passed_info['ctx'] self.msg: discord.Message = passed_info['msg'] if 'reason' in passed_info: self.reason: str = passed_info['reason'] else: self.reason = False self.config = Config.get_conf(None, cog_name='Forums', identifier=2352711325) @ui.button(label="Yes", style=discord.ButtonStyle.success, emoji="✅") async def resolved_button_yes(self, interaction: discord.Interaction, button: ui.Button): request_role_ids = await self.config.guild(interaction.guild).request_roles() request_roles = [interaction.guild.get_role(role_id) for role_id in request_role_ids] match = any(role in interaction.user.roles for role in request_roles) if match or interaction.user.id == interaction.channel.owner.id: await interaction.response.defer() if self.reason: response_reason = f"Thread closed by {interaction.user.mention} with reason: {self.reason}" reason = f"Thread closed by {interaction.user.name} ({interaction.user.id}) with reason: {self.reason}" else: response_reason = f"Thread closed by {interaction.user.mention}" reason = f"Thread closed by {interaction.user.name} ({interaction.user.id})" await self.msg.edit(content=response_reason, view=None) await self.ctx.message.delete() tag = interaction.channel.parent.get_tag(await self.config.guild(interaction.guild).forum_tag()) if tag in interaction.channel.applied_tags: await interaction.channel.edit(locked=True, archived=True, reason=reason) else: await interaction.channel.edit(locked=True, archived=True, applied_tags=interaction.channel.applied_tags + [tag], reason=reason) else: await interaction.response.send_message(content="You cannot close this thread!", ephemeral=True) @ui.button(label="No", style=discord.ButtonStyle.danger, emoji="✖️") async def resolved_button_no(self, interaction: discord.Interaction, button: ui.Button): request_role_ids = await self.config.guild(interaction.guild).request_roles() request_roles = [interaction.guild.get_role(role_id) for role_id in request_role_ids] match = any(role in interaction.user.roles for role in request_roles) if match or interaction.user.id == interaction.channel.owner.id: await interaction.response.defer() await self.msg.delete() await self.ctx.message.delete() else: await interaction.response.send_message(content="You cannot close this thread!", ephemeral=True) @commands.group(name='resolvedset', autohelp=True, aliases=['resolvedconfig']) @commands.guild_only() @commands.admin() async def resolvedset(self, ctx: commands.Context): """Manages the configuration for the [p]resolved command.""" @resolvedset.group(name='role', invoke_without_command=True, aliases=['roles']) @commands.guild_only() @commands.admin() async def resolvedset_role(self, ctx: commands.Context): """Manages the allowed roles list.""" current_list = await self.config.guild(ctx.guild).request_roles() already_in_list = [] for role_id in current_list: role_obj = ctx.guild.get_role(role_id) if role_obj: already_in_list.append(role_obj.mention) split_content = ctx.message.content.split() command = split_content[:2] if already_in_list: await ctx.send("Roles already in the allowed roles list:\n" + "\n".join(already_in_list) + f"\nUse `{command} add` to add roles to this list.\nUse `{command} role remove` to remove roles from this list.", allowed_mentions=discord.AllowedMentions(roles=False)) else: await ctx.send(f"No roles are currently in the allowed roles list.\nUse `{command} add` to add some!") @resolvedset_role.command(name='add') @commands.guild_only() @commands.admin() async def resolvedset_role_add(self, ctx: commands.Context, role: discord.Role = None): """Adds roles to the allowed roles list.""" current_list = await self.config.guild(ctx.guild).request_roles() if role: if role.id in current_list: await ctx.send("This role is already in the allowed roles list!") return else: current_list.append(role.id) await self.config.guild(ctx.guild).request_roles.set(current_list) await ctx.send(f"{role.mention} has been added to the allowed roles list.", allowed_mentions = discord.AllowedMentions(roles=False)) else: await ctx.send("Please provide a valid role.") @resolvedset_role.command(name='remove') @commands.guild_only() @commands.admin() async def resolvedset_role_remove(self, ctx: commands.Context, role: discord.Role = None): """Removes roles from the allowed roles list.""" current_list = await self.config.guild(ctx.guild).request_roles() if role.id in current_list: current_list.remove(role.id) await self.config.guild(ctx.guild).request_roles.set(current_list) await ctx.send(f"{role.mention} has been removed from the allowed roles list.", allowed_mentions = discord.AllowedMentions(roles=False)) else: await ctx.send("Please provide a valid role that exists in the allowed roles list.") def create_select_options(self, ctx: commands.Context, data): options = [] for tag in data: emoji = ctx.guild.get_emoji(tag.emoji.id) if tag.emoji.id else str(tag.emoji.name) options.append(discord.SelectOption(label=tag.name, emoji=emoji, description="", value=tag.id)) return options @resolvedset.command(name="tag") async def resolvedset_tag(self, ctx: commands.Context, channel: discord.ForumChannel): """Sets the tag used by the [p]resolved command.""" options = self.create_select_options(ctx, channel.available_tags) tag = channel.get_tag(await self.config.guild(ctx.guild).forum_tag()) msg = await ctx.send(f"Forum tag is currently set to `{str(tag)}`.") await msg.edit(view=SelectView(msg, options)) @resolvedset.command(name="channel") async def resolvedset_channel(self, ctx: commands.Context, channel: discord.ForumChannel): """Sets the tag used by the [p]resolved command.""" await self.config.guild(ctx.guild).forum_channel.set(channel.id) await ctx.send(f"Forum channel has been set to `{channel.name}`.") class Select(ui.Select): def __init__(self, message, options): self.message = message super().__init__(placeholder="Select an option", max_values=1, min_values=1, options=options) async def callback(self, interaction: discord.Interaction): msg: discord.Message = self.message config = Config.get_conf(None, cog_name='Forums', identifier=2352711325) await config.guild(msg.guild).forum_tag.set(int(self.values[0])) await msg.edit(content=f"Set resolved tag to {self.values[0]}", view=None) await interaction.response.defer() class SelectView(ui.View): def __init__(self, message, options, *, timeout=180): super().__init__(timeout=timeout) self.add_item(Select(message, options))