From 2d2631bfacc2aefc39c62451d6cc7ae9406df03c Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 15:39:53 -0400 Subject: [PATCH 01/11] Create request class. --- cogs/commands/request.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 cogs/commands/request.py diff --git a/cogs/commands/request.py b/cogs/commands/request.py new file mode 100644 index 0000000..1e10088 --- /dev/null +++ b/cogs/commands/request.py @@ -0,0 +1,28 @@ +""" +Contains commands to request things from admins. +""" + +import nextcord +from nextcord.ext import commands + + +class RequestCog(commands.Cog, name="Request Commands"): + """ + Class holds request commands. + """ + + @nextcord.slash_command() + async def request(self, interaction: nextcord.Interaction): + """ + Parent slash command for help. Never called. + """ + + @request.subcommand(description="Request to change your Dakiny nickname") + async def change_username(self, interaction: nextcord.Interaction, new_username: str): + """ + Sends a message to admins to request a username change. + + Args: + interaction (nextcord.Interaction): Interaction that invoked the command. + new_username(str): The username to change to. + """ From f71df0b7f4905203720d29b76bcb3f696e1359bd Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 15:41:12 -0400 Subject: [PATCH 02/11] Add the admin channel id to config. --- config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config.py b/config.py index 979ac75..d2715ec 100644 --- a/config.py +++ b/config.py @@ -11,6 +11,7 @@ class Params: """ active_category_id: int + admin_channel_id: int annoucement_category_id: int archive_channel_group_id: int clan_council_elect_role_id: int From 9cae7d002a280db528f28b713af10275b9e43f05 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 16:35:03 -0400 Subject: [PATCH 03/11] Create initial command action. --- cogs/commands/__init__.py | 2 ++ cogs/commands/request.py | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/cogs/commands/__init__.py b/cogs/commands/__init__.py index 6f55dc7..9ebd402 100644 --- a/cogs/commands/__init__.py +++ b/cogs/commands/__init__.py @@ -4,6 +4,7 @@ Cog loader. Adds all command cogs to the bot. from nextcord.ext import commands +from cogs.commands.request import RequestCog from cogs.commands.test import TestCog @@ -13,4 +14,5 @@ def setup(bot: commands.Bot): """ Adds all command classes to bot. """ + bot.add_cog(RequestCog(bot)) bot.add_cog(TestCog(bot)) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index 1e10088..a3d292f 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -5,12 +5,20 @@ Contains commands to request things from admins. import nextcord from nextcord.ext import commands +from config import DakinyConfig + class RequestCog(commands.Cog, name="Request Commands"): """ Class holds request commands. """ + def __init__(self, bot) -> None: + """ + Default constructor for RequestCog class. Does nothing. + """ + self.bot: commands.Bot = bot + @nextcord.slash_command() async def request(self, interaction: nextcord.Interaction): """ @@ -26,3 +34,8 @@ class RequestCog(commands.Cog, name="Request Commands"): interaction (nextcord.Interaction): Interaction that invoked the command. new_username(str): The username to change to. """ + + config: DakinyConfig = self.bot.config + content = f'<@{interaction.user.id}> would like to change their username to "{new_username}"' + await self.bot.get_channel(config.params.admin_channel_id).send(content=content) + await interaction.response.send_message("Request sent to admins.", ephemeral=True) From 7789e679cefc7edae3fde3c2926902ab459874c9 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 18:18:31 -0400 Subject: [PATCH 04/11] Flush out view with approve and deny actions. --- cogs/commands/request.py | 45 +++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index a3d292f..94c2035 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -1,7 +1,9 @@ """ -Contains commands to request things from admins. +Contains commands and views for request commands. """ +from typing import Optional + import nextcord from nextcord.ext import commands @@ -26,9 +28,15 @@ class RequestCog(commands.Cog, name="Request Commands"): """ @request.subcommand(description="Request to change your Dakiny nickname") - async def change_username(self, interaction: nextcord.Interaction, new_username: str): + async def change_nickname( + self, + interaction: nextcord.Interaction, + new_nickname: str = nextcord.SlashOption( + required=True, min_length=2, max_length=32, description="Your requested new nickname." + ), + ): """ - Sends a message to admins to request a username change. + Sends a message to admins to request a nickname change. Args: interaction (nextcord.Interaction): Interaction that invoked the command. @@ -36,6 +44,33 @@ class RequestCog(commands.Cog, name="Request Commands"): """ config: DakinyConfig = self.bot.config - content = f'<@{interaction.user.id}> would like to change their username to "{new_username}"' - await self.bot.get_channel(config.params.admin_channel_id).send(content=content) + content = f'<@{interaction.user.id}> would like to change their username to "{new_nickname}"' + view = UsernameRequest(interaction.user.id, new_nickname) + await self.bot.get_channel(config.params.admin_channel_id).send(content=content, view=view) await interaction.response.send_message("Request sent to admins.", ephemeral=True) + + +class UsernameRequest(nextcord.ui.View): + """ + View provides approve and deny buttons and action for a username change request. + """ + + def __init__(self, id: int, new_nickname: str, *, timeout: float | None = 180, auto_defer: bool = True): + super().__init__(timeout=timeout, auto_defer=auto_defer) + self.id = id + self.new_nickname = new_nickname + + @nextcord.ui.button(label="Approve", style=nextcord.ButtonStyle.green) + async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + user = interaction.guild.get_member(self.id) + if user is not None: + user.edit(nick=self.new_nickname) + content = interaction.message.content + f" Approved by <@{interaction.user.id}>" + await interaction.response.send_message(content=content, view=None) + else: + await interaction.response.send_message("An error occured while changing the user's nickname.", view=None) + + @nextcord.ui.button(label="Deny", style=nextcord.ButtonStyle.red) + async def deny(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + content = interaction.message.content + f" Denied by <@{interaction.user.id}>" + await interaction.response.send_message(content=content, view=None) From b292fc09fe4f20ae6ea00583d096740d1a29e94b Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 18:30:05 -0400 Subject: [PATCH 05/11] Log into gitea registry. --- .gitea/workflows/build_develop.yml | 6 ++++++ .gitea/workflows/build_latest.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.gitea/workflows/build_develop.yml b/.gitea/workflows/build_develop.yml index a9f721a..b83d756 100644 --- a/.gitea/workflows/build_develop.yml +++ b/.gitea/workflows/build_develop.yml @@ -12,6 +12,12 @@ jobs: fetch-depth: 0 - name: Install Docker uses: https://github.com/papodaca/install-docker-action@v1 + - name: Log into container registry + uses: docker/login-action@v2 + with: + registry: gitea.cheezers.org + username: imcompiling + password: ${{ secrets.PASSWORD }} - name: Build Docker Image run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:develop . - name: Push Docker Image diff --git a/.gitea/workflows/build_latest.yml b/.gitea/workflows/build_latest.yml index a04a2fc..0a7dc01 100644 --- a/.gitea/workflows/build_latest.yml +++ b/.gitea/workflows/build_latest.yml @@ -14,6 +14,12 @@ jobs: fetch-depth: 0 - name: Install Docker uses: https://github.com/papodaca/install-docker-action@v1 + - name: Log into container registry + uses: docker/login-action@v2 + with: + registry: gitea.cheezers.org + username: imcompiling + password: ${{ secrets.PASSWORD }} - name: Build Docker Image run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:latest . - name: Push Docker Image From 757a753cf52b522c13d16e84cbf16510748db38e Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 19:03:29 -0400 Subject: [PATCH 06/11] I want to edit the message, not send a new one. --- cogs/commands/request.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index 94c2035..5083504 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -2,8 +2,6 @@ Contains commands and views for request commands. """ -from typing import Optional - import nextcord from nextcord.ext import commands @@ -44,7 +42,7 @@ class RequestCog(commands.Cog, name="Request Commands"): """ config: DakinyConfig = self.bot.config - content = f'<@{interaction.user.id}> would like to change their username to "{new_nickname}"' + content = f'<@{interaction.user.id}> would like to change their username to "{new_nickname}."' view = UsernameRequest(interaction.user.id, new_nickname) await self.bot.get_channel(config.params.admin_channel_id).send(content=content, view=view) await interaction.response.send_message("Request sent to admins.", ephemeral=True) @@ -55,22 +53,24 @@ class UsernameRequest(nextcord.ui.View): View provides approve and deny buttons and action for a username change request. """ - def __init__(self, id: int, new_nickname: str, *, timeout: float | None = 180, auto_defer: bool = True): + def __init__(self, user_id: int, new_nickname: str, *, timeout: float | None = 180, auto_defer: bool = True): super().__init__(timeout=timeout, auto_defer=auto_defer) - self.id = id + self.user_id = user_id self.new_nickname = new_nickname @nextcord.ui.button(label="Approve", style=nextcord.ButtonStyle.green) async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): - user = interaction.guild.get_member(self.id) + user = interaction.guild.get_member(self.user_id) if user is not None: user.edit(nick=self.new_nickname) - content = interaction.message.content + f" Approved by <@{interaction.user.id}>" - await interaction.response.send_message(content=content, view=None) + content = interaction.message.content + f" Approved by <@{interaction.user.id}.>" + await interaction.response.edit_message(content=content, view=None) else: - await interaction.response.send_message("An error occured while changing the user's nickname.", view=None) + await interaction.response.edit_message( + content="An error occured while changing the user's nickname.", view=None + ) @nextcord.ui.button(label="Deny", style=nextcord.ButtonStyle.red) async def deny(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): - content = interaction.message.content + f" Denied by <@{interaction.user.id}>" - await interaction.response.send_message(content=content, view=None) + content = interaction.message.content + f" Denied by <@{interaction.user.id}.>" + await interaction.response.edit_message(content=content, view=None) From 6ae722beb951ce5390106d18a60a6ec2531c5644 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 19:16:47 -0400 Subject: [PATCH 07/11] Need member intent. --- dakiny_bot.py | 2 +- permissions_required.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dakiny_bot.py b/dakiny_bot.py index 1cf8a18..fb7bba8 100644 --- a/dakiny_bot.py +++ b/dakiny_bot.py @@ -26,7 +26,7 @@ def main(cfg: DakinyConfig): # intents.guilds = True # To enable the members priveleged intent: - # intents.members = True + intents.members = True bot = commands.Bot(intents=intents) bot.config = cfg diff --git a/permissions_required.txt b/permissions_required.txt index bc1e455..2431bd9 100644 --- a/permissions_required.txt +++ b/permissions_required.txt @@ -1,4 +1,6 @@ Discord permissions required for bot to operate: manage channels -manage roles \ No newline at end of file +manage roles +manage user? +need member intent \ No newline at end of file From ee2aaba42158e9e0bfbeb4d32c5063a46259e450 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 19:16:59 -0400 Subject: [PATCH 08/11] Must await the edit. --- cogs/commands/request.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index 5083504..d7c694d 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -62,8 +62,8 @@ class UsernameRequest(nextcord.ui.View): async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): user = interaction.guild.get_member(self.user_id) if user is not None: - user.edit(nick=self.new_nickname) - content = interaction.message.content + f" Approved by <@{interaction.user.id}.>" + await user.edit(nick=self.new_nickname) + content = interaction.message.content + f" Approved by <@{interaction.user.id}>." await interaction.response.edit_message(content=content, view=None) else: await interaction.response.edit_message( From 271cf146978d1c1e2bd704bdef0ceeecfdb282ca Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 19:21:11 -0400 Subject: [PATCH 09/11] Need to be able to manage nicknames. --- permissions_required.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/permissions_required.txt b/permissions_required.txt index 2431bd9..0f473fe 100644 --- a/permissions_required.txt +++ b/permissions_required.txt @@ -2,5 +2,5 @@ Discord permissions required for bot to operate: manage channels manage roles -manage user? +manage nicknames need member intent \ No newline at end of file From fa3fc6bd75183fd212fe3522f80d04bc1433ecaf Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 21:08:16 -0400 Subject: [PATCH 10/11] Added logic to handle bot being unable to change a nickname due to role hierarchy. --- cogs/commands/request.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index d7c694d..b505d86 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -62,9 +62,20 @@ class UsernameRequest(nextcord.ui.View): async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): user = interaction.guild.get_member(self.user_id) if user is not None: - await user.edit(nick=self.new_nickname) - content = interaction.message.content + f" Approved by <@{interaction.user.id}>." - await interaction.response.edit_message(content=content, view=None) + try: + await user.edit(nick=self.new_nickname) + content = interaction.message.content + f"\nApproved by <@{interaction.user.id}>." + await interaction.response.edit_message(content=content, view=None) + except nextcord.errors.Forbidden: + await interaction.response.send_message( + content="Please change manually.", + ephemeral=True, + ) + content = ( + interaction.message.content + + "\n\nFailed. User has too high permissions for bot to change nickname." + ) + await interaction.followup.edit_message(interaction.message.id, content=content, view=None) else: await interaction.response.edit_message( content="An error occured while changing the user's nickname.", view=None @@ -72,5 +83,5 @@ class UsernameRequest(nextcord.ui.View): @nextcord.ui.button(label="Deny", style=nextcord.ButtonStyle.red) async def deny(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): - content = interaction.message.content + f" Denied by <@{interaction.user.id}.>" + content = interaction.message.content + f"\nDenied by <@{interaction.user.id}.>" await interaction.response.edit_message(content=content, view=None) From 8c20641041d69ffcda9ece90d736f366ca19e21f Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 29 Jul 2023 21:13:14 -0400 Subject: [PATCH 11/11] Added doc strings for the approve and deny buttons. --- cogs/commands/request.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index b505d86..7a4f69f 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -60,6 +60,15 @@ class UsernameRequest(nextcord.ui.View): @nextcord.ui.button(label="Approve", style=nextcord.ButtonStyle.green) async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + """ + Approve button for a nickname change request. Changes the target's nickname to self.new_nickname. + Catches an error if the target as a higher role than the bot. + Removes the view from the interaction message. + + Args: + button (nextcord.ui.Button): Unused. + interaction (nextcord.Interaction): The interaction of the user clicking the button. + """ user = interaction.guild.get_member(self.user_id) if user is not None: try: @@ -83,5 +92,12 @@ class UsernameRequest(nextcord.ui.View): @nextcord.ui.button(label="Deny", style=nextcord.ButtonStyle.red) async def deny(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + """ + Deny button for a nickname request. Just removes the view and logs who denied the request. + + Args: + button (nextcord.ui.Button): Unused. + interaction (nextcord.Interaction): The interaction of the user clicking the button. + """ content = interaction.message.content + f"\nDenied by <@{interaction.user.id}.>" await interaction.response.edit_message(content=content, view=None)