import logging from typing import Any, Dict, Union from discord import ApplicationContext, Embed, option, TextChannel, Role from discord import utils as ds_utils from discord.abc import GuildChannel from discord.commands import SlashCommandGroup from discord.ext import commands from libbot import config_get from libbot.pycord.classes import PycordBot from libbot.sync import config_get as sync_config_get from classes.holo_user import HoloUser from enums import Color from modules.database import col_users from modules.utils_sync import guild_name logger = logging.getLogger(__name__) class CustomChannels(commands.Cog): def __init__(self, client: PycordBot): self.client: PycordBot = client @commands.Cog.listener() async def on_guild_channel_delete(self, channel: GuildChannel) -> None: await col_users.find_one_and_update( {"customchannel": channel.id}, {"$set": {"customchannel": None}} ) custom_channel_group: SlashCommandGroup = SlashCommandGroup( "customchannel", "Керування особистим каналом" ) @custom_channel_group.command( name="get", description="Отримати персональний текстовий канал", guild_ids=[sync_config_get("guild")], ) @option("name", description="Назва каналу") @option("reactions", description="Дозволити реакції") @option("threads", description="Дозволити гілки") async def custom_channel_get_cmd( self, ctx: ApplicationContext, name: str, reactions: bool, threads: bool ) -> None: holo_user_ctx: HoloUser = HoloUser(ctx.user) # Return if the user is using the command outside of a guild if not hasattr(ctx.author, "guild"): await ctx.defer(ephemeral=True) await ctx.respond( embed=Embed( title="Помилка виконання", description="Виконання за межами сервера не є можливим.", color=Color.FAIL, ) ) return # Return if the user already has a custom channel if holo_user_ctx.customchannel is not None: await ctx.defer(ephemeral=True) await ctx.respond( embed=Embed( title="Помилка виконання", description="У вас вже є особистий канал.\nДля редагування каналу є `/customchannel edit` або просто відкрийте меню керування вашим каналом.", color=Color.FAIL, ) ) return await ctx.defer() created_channel: TextChannel = await ctx.user.guild.create_text_channel( name=name, reason=f"Користувач {guild_name(ctx.user)} отримав власний приватний канал", category=ds_utils.get( ctx.author.guild.categories, id=await config_get("customchannels", "categories"), ), ) await created_channel.set_permissions( ctx.user.guild.default_role, send_messages=False, add_reactions=reactions, create_public_threads=threads, create_private_threads=threads, ) await created_channel.set_permissions( ctx.user, attach_files=True, manage_messages=True, send_messages=True, embed_links=True, manage_channels=True, ) await holo_user_ctx.set("customchannel", created_channel.id) await ctx.respond( embed=Embed( title="Створено канал", description=f"Вітаємо! Ви створили канал {created_channel.mention}. Для керування ним користуйтесь меню налаштувань каналу а також командою `/customchannel edit`", color=Color.SUCCESS, ) ) bots: Dict[str, Any] = await config_get("bots") for bot in bots: role: Union[Role, None] = ds_utils.get( ctx.user.guild.roles, id=bots[bot]["role"] ) if role is not None: await created_channel.set_permissions( role, view_channel=False, ) @custom_channel_group.command( name="edit", description="Змінити параметри особистого каналу", guild_ids=[sync_config_get("guild")], ) @option("name", description="Назва каналу") @option("reactions", description="Дозволити реакції") @option("threads", description="Дозволити гілки") async def custom_channel_edit_cmd( self, ctx: ApplicationContext, name: str, reactions: bool, threads: bool ) -> None: holo_user_ctx: HoloUser = HoloUser(ctx.user) custom_channel: Union[TextChannel, None] = ds_utils.get( ctx.guild.channels, id=holo_user_ctx.customchannel ) # Return if the channel was not found if custom_channel is None: await ctx.respond( embed=Embed( title="Канал не знайдено", description="Канал, вказаний як ваш, не існує. Можливо, його було вручну видалено раніше.", color=Color.FAIL, ) ) return await custom_channel.edit(name=name) await custom_channel.set_permissions( ctx.user.guild.default_role, send_messages=False, add_reactions=reactions, create_public_threads=threads, create_private_threads=threads, ) await ctx.respond( embed=Embed( title="Канал змінено", description=f"Назва каналу тепер `{name}`, реакції `{reactions}` та дозволено треди `{threads}`", color=Color.FAIL, ) ) @custom_channel_group.command( name="remove", description="Відібрати канал, знищуючи його, та частково повернути кошти", guild_ids=[sync_config_get("guild")], ) @option("confirm", description="Підтвердження операції") async def custom_channel_remove_cmd( self, ctx: ApplicationContext, confirm: bool = False ) -> None: holo_user_ctx: HoloUser = HoloUser(ctx.user) # Return if the user does not have a custom channel if holo_user_ctx.customchannel is None: await ctx.defer(ephemeral=True) await ctx.respond( embed=Embed( title="Помилка виконання", description="У вас немає особистого каналу.", color=Color.FAIL, ) ) return await ctx.defer() custom_channel: Union[TextChannel, None] = ds_utils.get( ctx.guild.channels, id=holo_user_ctx.customchannel ) # Return if the channel was not found if custom_channel is None: await ctx.respond( embed=Embed( title="Канал не знайдено", description="Канал, вказаний як ваш, не існує. Можливо, його було вручну видалено раніше.", color=Color.FAIL, ) ) await holo_user_ctx.set("customchannel", None) return # Return if the confirmation is missing if not confirm: await ctx.respond( embed=Embed( title="Підтвердження не надано", description="Для підтвердження операції додайте до команди параметр `confirm` зі значенням `True`.", color=Color.FAIL, ) ) return await custom_channel.delete(reason="Власник запросив видалення") await holo_user_ctx.set("customchannel", None) try: await ctx.respond( embed=Embed( title="Канал знищено", description="Ви відмовились від каналу та видалили його.", color=Color.DEFAULT, ) ) except Exception as exc: logger.warning( "Could not send a custom channel removal confirmation due to: %s", exc ) def setup(client: PycordBot) -> None: client.add_cog(CustomChannels(client))