diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b94708ff..8c9eb83a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -125,6 +125,7 @@ model AFKModel { reason String since DateTime @default(now()) guild_id BigInt + perm_afk Boolean @default(false) guild Guild @relation(fields: [guild_id], references: [guild_id]) @@unique([member_id, guild_id]) @@ -187,4 +188,4 @@ enum CaseType { UNTEMPBAN POLLBAN POLLUNBAN -} +} \ No newline at end of file diff --git a/tux/cogs/utility/afk.py b/tux/cogs/utility/afk.py index 7306b258..92fefac2 100644 --- a/tux/cogs/utility/afk.py +++ b/tux/cogs/utility/afk.py @@ -14,7 +14,7 @@ from tux.utils.flags import generate_usage -class AFK(commands.Cog): +class Afk(commands.Cog): def __init__(self, bot: Tux) -> None: self.bot = bot self.db = AfkController() @@ -90,7 +90,8 @@ async def remove_afk(self, message: discord.Message) -> None: if entry.since + timedelta(seconds=10) > datetime.now(ZoneInfo("UTC")): return - + if await self.db.is_perm_afk(message.author.id, guild_id=message.guild.id): + return assert isinstance(message.author, discord.Member) await self.db.remove_afk(message.author.id) @@ -143,4 +144,4 @@ async def check_afk(self, message: discord.Message) -> None: async def setup(bot: Tux): - await bot.add_cog(AFK(bot)) + await bot.add_cog(Afk(bot)) diff --git a/tux/cogs/utility/permafk.py b/tux/cogs/utility/permafk.py new file mode 100644 index 00000000..7ac0d9dd --- /dev/null +++ b/tux/cogs/utility/permafk.py @@ -0,0 +1,71 @@ +import contextlib +import textwrap + +import discord +from discord.ext import commands + +from tux.bot import Tux +from tux.database.controllers import AfkController +from tux.utils.constants import CONST +from tux.utils.flags import generate_usage + + +class PermAfk(commands.Cog): + def __init__(self, bot: Tux) -> None: + self.bot = bot + self.db = AfkController() + self.permafk.usage = generate_usage(self.permafk) + + async def remove_afk(self, target: int) -> None: + await self.db.remove_afk(target) + + @commands.hybrid_command(name="permafk") + @commands.guild_only() + async def permafk(self, ctx: commands.Context[Tux], *, reason: str = "No reason.") -> discord.Message: + """ + Set yourself permanently AFK until you rerun the command. + + Parameters + ---------- + ctx : commands.Context[Tux] + The context of the command. + reason : str, optional + The reason you are AFK. + """ + + target = ctx.author + + assert ctx.guild + assert isinstance(target, discord.Member) + + if await self.db.is_afk(target.id, guild_id=ctx.guild.id): + await self.remove_afk(target.id) + + return await ctx.send("Welcome back!") + + if len(target.display_name) >= CONST.NICKNAME_MAX_LENGTH - 6: + truncated_name = f"{target.display_name[: CONST.NICKNAME_MAX_LENGTH - 9]}..." + new_name = f"[AFK] {truncated_name}" + + else: + new_name = f"[AFK] {target.display_name}" + + shortened_reason = textwrap.shorten(reason, width=100, placeholder="...") + await self.db.insert_afk(target.id, target.display_name, shortened_reason, ctx.guild.id, True) + + with contextlib.suppress(discord.Forbidden): + await target.edit(nick=new_name) + + return await ctx.send( + content="\N{SLEEPING SYMBOL} || You are now permanently afk! To remove afk run this command again. " + + f"Reason: `{shortened_reason}`", + allowed_mentions=discord.AllowedMentions( + users=False, + everyone=False, + roles=False, + ), + ) + + +async def setup(bot: Tux): + await bot.add_cog(PermAfk(bot)) diff --git a/tux/database/controllers/afk.py b/tux/database/controllers/afk.py index 5e54c047..c1867dbd 100644 --- a/tux/database/controllers/afk.py +++ b/tux/database/controllers/afk.py @@ -22,7 +22,20 @@ async def is_afk(self, member_id: int, *, guild_id: int) -> bool: entry = await self.get_afk_member(member_id, guild_id=guild_id) return entry is not None - async def insert_afk(self, member_id: int, nickname: str, reason: str, guild_id: int) -> AFKModel: + async def is_perm_afk(self, member_id: int, *, guild_id: int) -> bool: + is_user_perm_afk = await self.table.find_first( + where={"member_id": member_id, "guild_id": guild_id, "perm_afk": True}, + ) + return is_user_perm_afk is not None + + async def insert_afk( + self, + member_id: int, + nickname: str, + reason: str, + guild_id: int, + perm_afk: bool = False, + ) -> AFKModel: await self.ensure_guild_exists(guild_id) return await self.table.create( @@ -31,6 +44,7 @@ async def insert_afk(self, member_id: int, nickname: str, reason: str, guild_id: "nickname": nickname, "reason": reason, "guild_id": guild_id, + "perm_afk": perm_afk, }, )