From e26957f63e2565a98441258622622031faa487b5 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:50:16 +0100 Subject: [PATCH 01/27] Fix invite url docs --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index 8d130cad9..6ef38accf 100644 --- a/README.md +++ b/README.md @@ -166,15 +166,7 @@ A full guide on how to create your bot's account can be found [here; on Pycord's You'll need to create a [Discord bot](https://discord.com/developers/docs/topics/oauth2#bot-vs-user-accounts) of your own in the [Discord Developer Portal](https://discord.com/developers/applications). It's also handy if you have an empty [guild](https://discord.com/developers/docs/resources/guild) for you to test in. -You can retrieve the correct [invite URL](https://docs.pycord.dev/en/stable/discord.html#inviting-your-bot) to use by navigating to the root folder, then running the following command: - -```shell -poetry run python -m utils generate_invite_url {discord_bot_application_id} {discord_guild_id} -``` - -* `{discord_bot_application_id}` must be replaced by the [application ID](https://discord.com/developers/applications) of your [bot](https://discord.com/developers/docs/topics/oauth2#bot-vs-user-accounts) - -* `{discord_guild_id}` must be replaced by the [snowflake ID](https://discord.com/developers/docs/reference#snowflakes) of your community group's [guild](https://discord.com/developers/docs/resources/guild) +You can retrieve the correct [invite URL](https://docs.pycord.dev/en/stable/discord.html#inviting-your-bot) by simply running TeX-Bot for the first time with DEBUG logging enabled, and the invite url will be printed to the console. ### Setting [Environment Variables](https://wikipedia.org/wiki/Environment_variable) From 9a23142fe8228989d88eaa96db609639260aadf5 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:28:04 +0100 Subject: [PATCH 02/27] move terminology to new file --- README.md | 34 ---------------------------------- TERMINOLOGY.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 TERMINOLOGY.md diff --git a/README.md b/README.md index 6ef38accf..38a03176d 100644 --- a/README.md +++ b/README.md @@ -13,40 +13,6 @@ This is a [Discord bot](https://discord.com/developers/docs/topics/oauth2#bot-vs Featured in the [CSS Discord guild](https://cssbham.com/discord). -## Terminology - -### ["Guild"](https://discord.com/developers/docs/resources/guild) Vs ["Server"](https://wikipedia.org/wiki/Discord#Servers) - -Confusingly, [Discord](https://discord.com) uses the term ["guild"](https://discord.com/developers/docs/resources/guild) to refer to a [Discord "server"](https://wikipedia.org/wiki/Discord#Servers), when communicating with developers. -Therefore, the same terminology (["guild"](https://discord.com/developers/docs/resources/guild)) will be used across all documentation in this project. -(See [the Discord developer docs](https://discord.com/developers/docs/resources/guild) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#discord.Guild) for more information.) - -The term "main guild" is used throughout the code in this repository to refer specifically to your community group's main [Discord guild](https://discord.com/developers/docs/resources/guild). - -### "User" Vs "Member" Vs "Guest" - -#### [Discord Objects](https://discord.com/developers/docs) - -In the context of [Discord](https://discord.com) itself, a ["user"](https://discord.com/developers/docs/resources/user) object represents a [Discord](https://discord.com) account not connected to any specific [guild](https://discord.com/developers/docs/resources/guild). -Therefore, it can be [messaged via DM](https://dictionary.com/browse/dm) or be retrieved via its [snowflake ID](https://discord.com/developers/docs/reference#snowflakes), but little else can be done with it. -(See [the Discord developer docs](https://discord.com/developers/docs/resources/user) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#users) for more information.) - -In contrast, a [Discord "member" object](https://discord.com/developers/docs/resources/guild#guild-member-object) is a [user](https://discord.com/developers/docs/resources/user) attached to a specific [guild](https://discord.com/developers/docs/resources/guild). -Therefore, it can have [roles](https://discord.com/developers/docs/topics/permissions#role-object), be [banned](https://discord.com/developers/docs/resources/guild#ban-object) & have many other actions applied to it. -(See [the Discord developer docs](https://discord.com/developers/docs/resources/guild#guild-member-object) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#discord.Member) for more information.) - -#### Community Group Membership - -In the context of your community group's membership structure, a "member" is a person that has purchased a membership to join your community group. -This is in contrast to a "guest", which is a person that has not purchased a membership. -Guests often can only attend events that are open to anyone (i.e. **not** members only), and have limited communication/perks within your [Discord guild](https://discord.com/developers/docs/resources/guild). -Some commands may require you to create [roles](https://discord.com/developers/docs/topics/permissions#role-object) within your [Discord guild](https://discord.com/developers/docs/resources/guild), to differentiate between these different types of users. - -#### Other Uses - -In some other contexts, the term "user" may be used to refer to any person/organisation making use of this project. -(E.g. the description within [the "Error Codes" section](#error-codes).) - ## Error Codes Users of TeX-Bot may encounter an error code when executing a slash-command fails. diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md new file mode 100644 index 000000000..b751d35ea --- /dev/null +++ b/TERMINOLOGY.md @@ -0,0 +1,39 @@ +# TeX-Bot-Py-V2 Terminology + +## ["Guild"](https://discord.com/developers/docs/resources/guild) Vs ["Server"](https://wikipedia.org/wiki/Discord#Servers) + +Confusingly, [Discord](https://discord.com) uses the term ["guild"](https://discord.com/developers/docs/resources/guild) to refer to a [Discord "server"](https://wikipedia.org/wiki/Discord#Servers), when communicating with developers. +Therefore, the same terminology (["guild"](https://discord.com/developers/docs/resources/guild)) will be used across all documentation in this project. +(See [the Discord developer docs](https://discord.com/developers/docs/resources/guild) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#discord.Guild) for more information.) + +The term "main guild" is used throughout the code in this repository to refer specifically to your community group's main [Discord guild](https://discord.com/developers/docs/resources/guild). + +## "User" Vs "Member" Vs "Guest" + +### [Discord Objects](https://discord.com/developers/docs) + +In the context of [Discord](https://discord.com) itself, a ["user"](https://discord.com/developers/docs/resources/user) object represents a [Discord](https://discord.com) account not connected to any specific [guild](https://discord.com/developers/docs/resources/guild). +Therefore, it can be [messaged via DM](https://dictionary.com/browse/dm) or be retrieved via its [snowflake ID](https://discord.com/developers/docs/reference#snowflakes), but little else can be done with it. +(See [the Discord developer docs](https://discord.com/developers/docs/resources/user) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#users) for more information.) + +In contrast, a [Discord "member" object](https://discord.com/developers/docs/resources/guild#guild-member-object) is a [user](https://discord.com/developers/docs/resources/user) attached to a specific [guild](https://discord.com/developers/docs/resources/guild). +Therefore, it can have [roles](https://discord.com/developers/docs/topics/permissions#role-object), be [banned](https://discord.com/developers/docs/resources/guild#ban-object) & have many other actions applied to it. +(See [the Discord developer docs](https://discord.com/developers/docs/resources/guild#guild-member-object) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#discord.Member) for more information.) + +### Community Group Membership + +In the context of your community group's membership structure, a "member" is a person that has purchased a membership to join your community group. +This is in contrast to a "guest", which is a person that has not purchased a membership. +Guests often can only attend events that are open to anyone (i.e. **not** members only), and have limited communication/perks within your [Discord guild](https://discord.com/developers/docs/resources/guild). +Some commands may require you to create [roles](https://discord.com/developers/docs/topics/permissions#role-object) within your [Discord guild](https://discord.com/developers/docs/resources/guild), to differentiate between these different types of users. + +### Other Uses + +In some other contexts, the term "user" may be used to refer to any person/organisation making use of this project. +(E.g. the description within [the "Error Codes" section](#error-codes).) + + + + + + From e99b152a1dce7eb8b1cc3c989b298711c5d478c0 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:35:47 +0100 Subject: [PATCH 03/27] start contributing guides --- CONTRIBUTING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 80f63e1a0..d4a55646b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -221,3 +221,16 @@ If you see an error, we encourage you to **be bold** and fix it yourself, rather If you are stuck, need help, or have a question, the best place to ask is on our Discord. Happy contributing! + +## Guides + +### Creating a New Cog + + +### Creating a New Environment Variable + + +### Creating a Response Button + + + From 36bcb411bff26c13996a50dbb8d17ee1685f9f15 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:36:12 +0100 Subject: [PATCH 04/27] formatting --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4a55646b..6aa5227df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -222,6 +222,13 @@ If you are stuck, need help, or have a question, the best place to ask is on our Happy contributing! + + + + + + + ## Guides ### Creating a New Cog From 3cf257e72c992a74b5bd07651751cd7d13840ac4 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:11:39 +0100 Subject: [PATCH 05/27] add some stuff --- TERMINOLOGY.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index b751d35ea..23b47d1bf 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -8,6 +8,35 @@ Therefore, the same terminology (["guild"](https://discord.com/developers/docs/r The term "main guild" is used throughout the code in this repository to refer specifically to your community group's main [Discord guild](https://discord.com/developers/docs/resources/guild). +## [Application Commands](https://discord.com/developers/docs/interactions/application-commands) + +An [Application Command](https://discord.com/developers/docs/interactions/application-commands) can be a [Slash Command](#slash-commands), [Message Command](#message-commands) or [User Command](#user-commands). + +Bots are limited to only 100 [Slash Commands](#slash-commands), 5 [Message Commands](#message-commands) and 5 [User Commands](#user-commands). + +The primary difference is the way these commands are triggered. [Slash Commands](#slash-commands) are triggered by sending a message + + +### [Slash Commands](https://discord.com/developers/docs/interactions/application-commands#slash-commands) + +Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. + + + + +### [Message Commands]() + + + + + +### [User Commands]() + + + + + + ## "User" Vs "Member" Vs "Guest" ### [Discord Objects](https://discord.com/developers/docs) From a60e4606e9749d1fbc4a9e5fda9f7a1cbd42a6a5 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:15:50 +0100 Subject: [PATCH 06/27] add --- TERMINOLOGY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index 23b47d1bf..c4ea8f0e8 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -14,7 +14,7 @@ An [Application Command](https://discord.com/developers/docs/interactions/applic Bots are limited to only 100 [Slash Commands](#slash-commands), 5 [Message Commands](#message-commands) and 5 [User Commands](#user-commands). -The primary difference is the way these commands are triggered. [Slash Commands](#slash-commands) are triggered by sending a message +The primary difference is the way these commands are triggered. [Slash Commands](#slash-commands) are triggered by sending a message into the chat, while both [User Commands](#user-commands) and [Message Commands](#message-commands) are triggered via a UI context menu provided by right-clicking on a [User](https://discord.com/developers/docs/resources/user) or [Message](https://discord.com/developers/docs/resources/message) respectively. ### [Slash Commands](https://discord.com/developers/docs/interactions/application-commands#slash-commands) From 36097b355bc4ec93a2395acfd5d05240d1841db8 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:19:14 +0100 Subject: [PATCH 07/27] add links --- TERMINOLOGY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index c4ea8f0e8..a1b073d3a 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -24,13 +24,13 @@ Slash commands, also known as `CHAT_INPUT` commands are executed via sending a c -### [Message Commands]() +### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) -### [User Commands]() +### [User Commands](https://discord.com/developers/docs/interactions/application-commands#user-commands) From 1f0b22222df551a9032212ac5ac37bbff1d1ca01 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:51:08 +0100 Subject: [PATCH 08/27] add example --- TERMINOLOGY.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index a1b073d3a..2a2541231 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -19,10 +19,16 @@ The primary difference is the way these commands are triggered. [Slash Commands] ### [Slash Commands](https://discord.com/developers/docs/interactions/application-commands#slash-commands) -Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. - - - +Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. These can be defined using the `discord.slash_command` decorator as follows: +```python +@discord.slash_command( + name="command-name", + description="a description of what the command does", +) +async def command_name(self, ctx: TeXBotApplicationContext): + """Doc string goes here.""" + pass # command functions go here +``` ### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) @@ -34,6 +40,8 @@ Slash commands, also known as `CHAT_INPUT` commands are executed via sending a c +## Interaction + From a08567974bcea3384e1bf5353278c830022dfe3c Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:54:06 +0100 Subject: [PATCH 09/27] add missing cogs from list --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6aa5227df..58884de1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,8 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i * [`cogs/__init__.py`](cogs/__init__.py): instantiates all the cog classes within this directory +* [`cogs/annual_handover_and_reset.py](cogs/annual_handover_and_reset.py): cogs for annual handover procedures and role resets + * [`cogs/archive.py`](cogs/archive.py): cogs for archiving categories of channels within your group's Discord guild * [`cogs/command_error.py`](cogs/command_error.py): cogs for sending error messages when commands fail to complete/execute @@ -81,10 +83,14 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i * [`cogs/edit_message.py`](cogs/edit_message.py): cogs for editing messages that were previously sent by TeX-Bot +* [`cogs/get_token_authorisation.py`](cogs/get_token_authorisation.py): cogs for retrieving the current status of the supplied authentication token + * [`cogs/induct.py`](cogs/induct.py): cogs for inducting people into your group's Discord guild * [`cogs/kill.py`](cogs/kill.py): cogs related to the shutdown of TeX-Bot +* [`cogs/make_applicant`](cogs/make_applicant.py): cogs related to making users into applicants + * [`cogs/make_member.py`](cogs/make_member.py): cogs related to making guests into members * [`cogs/ping.py`](cogs/ping.py): cog to request a [ping](https://wikipedia.org/wiki/Ping-pong_scheme#Internet) response From 4e3d8a7731cff0d56502b6e4deb67e5e0b0ef14b Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:02:40 +0100 Subject: [PATCH 10/27] add link --- TERMINOLOGY.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index 2a2541231..f5f739f45 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -30,6 +30,10 @@ async def command_name(self, ctx: TeXBotApplicationContext): pass # command functions go here ``` +For more example usages, check the [Guides](CONTRIBUTING#guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. + + + ### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) From da2f219890c3934687650d839c5044e07ccea282 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:04:36 +0100 Subject: [PATCH 11/27] fix link --- TERMINOLOGY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index f5f739f45..b20aa8e98 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -30,7 +30,7 @@ async def command_name(self, ctx: TeXBotApplicationContext): pass # command functions go here ``` -For more example usages, check the [Guides](CONTRIBUTING#guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. +For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. From c007fbea91e878cea0646255e1938a160c51cb08 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:04:53 +0100 Subject: [PATCH 12/27] add backtick --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58884de1c..471ab1db0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,7 +73,7 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i * [`cogs/__init__.py`](cogs/__init__.py): instantiates all the cog classes within this directory -* [`cogs/annual_handover_and_reset.py](cogs/annual_handover_and_reset.py): cogs for annual handover procedures and role resets +* [`cogs/annual_handover_and_reset.py`](cogs/annual_handover_and_reset.py): cogs for annual handover procedures and role resets * [`cogs/archive.py`](cogs/archive.py): cogs for archiving categories of channels within your group's Discord guild From b6f73625c2e42cec91c91177a3a71c64a5e1076e Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:25:58 +0100 Subject: [PATCH 13/27] add some stuff --- TERMINOLOGY.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index b20aa8e98..94044f3dc 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -8,8 +8,17 @@ Therefore, the same terminology (["guild"](https://discord.com/developers/docs/r The term "main guild" is used throughout the code in this repository to refer specifically to your community group's main [Discord guild](https://discord.com/developers/docs/resources/guild). + +## [Interactions](https://discord.com/developers/docs/interactions/overview) + + + + + + ## [Application Commands](https://discord.com/developers/docs/interactions/application-commands) + An [Application Command](https://discord.com/developers/docs/interactions/application-commands) can be a [Slash Command](#slash-commands), [Message Command](#message-commands) or [User Command](#user-commands). Bots are limited to only 100 [Slash Commands](#slash-commands), 5 [Message Commands](#message-commands) and 5 [User Commands](#user-commands). @@ -19,6 +28,7 @@ The primary difference is the way these commands are triggered. [Slash Commands] ### [Slash Commands](https://discord.com/developers/docs/interactions/application-commands#slash-commands) + Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. These can be defined using the `discord.slash_command` decorator as follows: ```python @discord.slash_command( @@ -30,22 +40,21 @@ async def command_name(self, ctx: TeXBotApplicationContext): pass # command functions go here ``` -For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. - - - -### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) +For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. +### Context Commands +#### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) -### [User Commands](https://discord.com/developers/docs/interactions/application-commands#user-commands) +Message commands, also known as `Message-Context Commands`, are executed via right-clicking on a [Message](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. +The main difference between [Context Commands](#context-commands) and [Slash Commands](#slash-commands) is that [Context Commands](#context-commands) do not take user defined arguments and are limited to the [Message](https://discord.com/developers/docs/resources/message) that the command is issued on and the context which is passed along side it. -## Interaction +#### [User Commands](https://discord.com/developers/docs/interactions/application-commands#user-commands) From 22ebb492595f0fc7eaf935d65be8ca85bfdf541d Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Wed, 2 Apr 2025 09:20:14 +0100 Subject: [PATCH 14/27] Add some stuff --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e89f876fb..d37337145 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -218,6 +218,8 @@ Happy contributing! ### Creating a New Cog +Firstly, create a new file in the `cogs` folder. You should name the file something representative of what the cog will do. + ### Creating a New Environment Variable From 51d79e78a9a72b8818e2cba96583b6027fccb7a0 Mon Sep 17 00:00:00 2001 From: Matty Widdop <18513864+MattyTheHacker@users.noreply.github.com> Date: Wed, 9 Apr 2025 19:26:04 +0000 Subject: [PATCH 15/27] fix warnings --- TERMINOLOGY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index 94044f3dc..bed9e1378 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -49,7 +49,7 @@ For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the #### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) -Message commands, also known as `Message-Context Commands`, are executed via right-clicking on a [Message](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. +Message commands, also known as `Message-Context Commands`, are executed via right-clicking on a [Message](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. The main difference between [Context Commands](#context-commands) and [Slash Commands](#slash-commands) is that [Context Commands](#context-commands) do not take user defined arguments and are limited to the [Message](https://discord.com/developers/docs/resources/message) that the command is issued on and the context which is passed along side it. From 9bf2ebe4cdf5a82876740b9ea7ca88552e4120b9 Mon Sep 17 00:00:00 2001 From: Matty Widdop <18513864+MattyTheHacker@users.noreply.github.com> Date: Wed, 9 Apr 2025 19:28:21 +0000 Subject: [PATCH 16/27] remove empty whitespace --- CONTRIBUTING.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d37337145..fcfac1b83 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -208,12 +208,6 @@ If you are stuck, need help, or have a question, the best place to ask is on our Happy contributing! - - - - - - ## Guides ### Creating a New Cog From a5423b3531e379f7ffdb50eeec3b11b851567bd3 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Sat, 10 May 2025 18:34:20 +0100 Subject: [PATCH 17/27] more terms --- TERMINOLOGY.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index bed9e1378..0ef287f7d 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -11,9 +11,13 @@ The term "main guild" is used throughout the code in this repository to refer sp ## [Interactions](https://discord.com/developers/docs/interactions/overview) +Interactions in Discord are a way for bots to communicate with users in a structured and interactive manner. They include various types of commands and events that allow users to interact with the bot. The primary types of interactions are: +1. **Application Commands**: These include Slash Commands, Message Commands, and User Commands. They are predefined commands that users can invoke to perform specific actions. +2. **Message Components**: These are interactive elements like buttons, select menus, and modals that can be attached to messages to provide a richer user experience. +3. **Modal Submissions**: These are forms that users can fill out and submit, allowing bots to collect structured input from users, though TeX-Bot does not currently make use of these. - +For more details, refer to the [Discord Developer Documentation on Interactions](https://discord.com/developers/docs/interactions/overview). ## [Application Commands](https://discord.com/developers/docs/interactions/application-commands) From 149c8114273768100c0e2de46ee390684a251fc8 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Sat, 10 May 2025 19:07:41 +0100 Subject: [PATCH 18/27] Add example cog --- CONTRIBUTING.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fcfac1b83..4c413c8fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -212,8 +212,79 @@ Happy contributing! ### Creating a New Cog -Firstly, create a new file in the `cogs` folder. You should name the file something representative of what the cog will do. - +Cogs are modular components of the bot that group related commands and listeners into a single class. To create a new cog, follow these steps: + +1. **Create the Cog File** + - Navigate to the `cogs` folder. + - Create a new Python file with a name that reflects the purpose of the cog (e.g., `example_cog.py`). + +2. **Define the Cog Class** + - Import the necessary modules, including `TeXBotBaseCog` from `utils`. + - Define a class that inherits from `TeXBotBaseCog`. + - Add a docstring to describe the purpose of the cog. + + Example: + ```python + from utils import TeXBotBaseCog + + class ExampleCog(TeXBotBaseCog): + """A cog for demonstrating functionality.""" + + def __init__(self, bot): + self.bot = bot + ``` + +3. **Add Commands and Listeners** + - Define methods within the class for commands and event listeners. + - Use decorators like `@discord.slash_command` or `@TeXBotBaseCog.listener` to specify their purpose. + - Include any necessary checks using `CommandChecks` decorators. + + Example: + ```python + import discord + from utils import CommandChecks + + __all__: "Sequence[str]" = ( + "ExampleCog", + ) + + class ExampleCog(TeXBotBaseCog): + """A cog for demonstrating functionality.""" + + ``` + +4. **Register the Cog** + - Open `cogs/__init__.py`. + - Add your new cog class to the list of cogs in the `setup` function. + - Also, include the cog in the `__all__` sequence to ensure it is properly exported. + + Example: + ```python + from .example_cog import ExampleCog + + __all__: "Sequence[str]" = ( + ...existing cogs... + "ExampleCog", + ) + + def setup(bot: "TeXBot") -> None: + """Add all the cogs to the bot, at bot startup.""" + cogs: Iterable[type[TeXBotBaseCog]] = ( + ...existing cogs... + ExampleCog, + ) + Cog: type[TeXBotBaseCog] + for Cog in cogs: + bot.add_cog(Cog(bot)) + ``` + +5. **Test the Cog** + - Run the bot and ensure the new cog is loaded without errors. + - Test the commands and listeners to verify they work as expected. + +6. **Document the Cog** + - Add comments and docstrings to explain the functionality of the cog. + - Update the `CONTRIBUTING.md` file or other relevant documentation if necessary. ### Creating a New Environment Variable From 0c24b54faeb3d8d0f83db9aa1eb7de04edc03111 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Sat, 10 May 2025 19:18:42 +0100 Subject: [PATCH 19/27] env example --- CONTRIBUTING.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c413c8fd..39e35f447 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -207,7 +207,6 @@ If you are stuck, need help, or have a question, the best place to ask is on our Happy contributing! - ## Guides ### Creating a New Cog @@ -288,6 +287,51 @@ Cogs are modular components of the bot that group related commands and listeners ### Creating a New Environment Variable +To add a new environment variable to the project, follow these steps: + +1. **Define the Variable in `.env`** + - Open the `.env` file in the root directory (or create one if it doesn't exist). + - Add the new variable in the format `VARIABLE_NAME=value`. + - Ensure the variable name is descriptive and uses uppercase letters with underscores. + +2. **Update `config.py`** + - Open the `config.py` file. + - Add a new setup method in the `Settings` class to validate and load the variable. For example: + ```python + @classmethod + def _setup_new_variable(cls) -> None: + raw_value: str | None = os.getenv("NEW_VARIABLE") + + if not raw_value or not re.fullmatch(r"", raw_value): + raise ImproperlyConfiguredError("NEW_VARIABLE is invalid or missing.") + + cls._settings["NEW_VARIABLE"] = raw_value + ``` + - Replace `` with a regular expression to validate the variable's format, if applicable. + +3. **Call the Setup Method** + - Add the new setup method to the `_setup_env_variables` method in `config.py`: + ```python + @classmethod + def _setup_env_variables(cls) -> None: + if cls._is_env_variables_setup: + logger.warning("Environment variables have already been set up.") + return + + cls._settings = {} + + cls._setup_new_variable() + # Add other setup methods here + + cls._is_env_variables_setup = True + ``` + +4. **Document the Variable** + - Update the `README.md` file under the "Setting Environment Variables" section to include the new variable, its purpose, and any valid values. + +5. **Test the Variable** + - Run the bot and ensure the new variable is loaded correctly. + - Test edge cases, such as missing or invalid values, to confirm proper error handling. ### Creating a Response Button From ef4615d7aacfd43c9583650b855a5c1e96579c46 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Sat, 10 May 2025 19:21:28 +0100 Subject: [PATCH 20/27] response button --- CONTRIBUTING.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39e35f447..e33c2a2ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -335,5 +335,61 @@ To add a new environment variable to the project, follow these steps: ### Creating a Response Button +Response buttons are interactive UI components that allow users to respond to bot messages with predefined actions. To create a response button, follow these steps: + +1. **Define the Button Class** + - Create a class that inherits from `discord.ui.View`. + - Add button methods using the `@discord.ui.button` decorator. + - Each button method should define the button's label, style, and custom ID. + + Example: + ```python + from discord.ui import View + + class ConfirmActionView(View): + """A discord.View containing buttons to confirm or cancel an action.""" + + @discord.ui.button( + label="Yes", + style=discord.ButtonStyle.green, + custom_id="confirm_yes", + ) + async def confirm_yes(self, button: discord.Button, interaction: discord.Interaction) -> None: + # Handle the 'Yes' button click + await interaction.response.send_message("Action confirmed.", ephemeral=True) + + @discord.ui.button( + label="No", + style=discord.ButtonStyle.red, + custom_id="confirm_no", + ) + async def confirm_no(self, button: discord.Button, interaction: discord.Interaction) -> None: + # Handle the 'No' button click + await interaction.response.send_message("Action canceled.", ephemeral=True) + ``` + +2. **Send the View with a Message** + - Use the `view` parameter of the `send` or `respond` method to attach the button view to a message. + + Example: + ```python + await ctx.send( + content="Do you want to proceed?", + view=ConfirmActionView(), + ) + ``` + +3. **Handle Button Interactions** + - Define logic within each button method to handle user interactions. + - Use `interaction.response` to send feedback or perform actions based on the button clicked. + +4. **Test the Button** + - Run the bot and ensure the buttons appear and function as expected. + - Test edge cases, such as multiple users interacting with the buttons simultaneously. + +5. **Document the Button** + - Add comments and docstrings to explain the purpose and functionality of the button. + - Update relevant documentation if necessary. + From dd61e5116a660ed7c0aac9515bfaf4d61692b95d Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Tue, 13 May 2025 14:17:23 +0100 Subject: [PATCH 21/27] blah blah --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e33c2a2ea..76e1a93af 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -229,8 +229,8 @@ Cogs are modular components of the bot that group related commands and listeners class ExampleCog(TeXBotBaseCog): """A cog for demonstrating functionality.""" - def __init__(self, bot): - self.bot = bot + def do_something(arguments): + print("do something") ``` 3. **Add Commands and Listeners** From a8ab5c83036ea877ec1ba1ea456ea6ea3f31d014 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Tue, 13 May 2025 14:33:52 +0100 Subject: [PATCH 22/27] db stuff first run --- CONTRIBUTING.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76e1a93af..2e79bbf0b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -391,5 +391,102 @@ Response buttons are interactive UI components that allow users to respond to bo - Add comments and docstrings to explain the purpose and functionality of the button. - Update relevant documentation if necessary. +### Creating and Interacting with Django Models + +Django models are used to interact with the database in this project. They allow you to define the structure of your data and provide an API to query and manipulate it. To create and interact with Django models, follow these steps: + +1. **Define a Model** + - Navigate to the `db/core/models/` directory. + - Create a new Python file with a name that reflects the purpose of the model (e.g., `example_model.py`). + - Define a class that inherits from `django.db.models.Model`. + - Add fields to the class to represent the data structure. + + Example: + ```python + from django.db import models + + class ExampleModel(models.Model): + """A model for demonstrating functionality.""" + name = models.CharField(max_length=255) + created_at = models.DateTimeField(auto_now_add=True) + ``` + +2. **Apply Migrations** + - Run the following commands to create and apply migrations for your new model: + ```shell + uv run python manage.py makemigrations + uv run python manage.py migrate + ``` + +3. **Query the Model** + - Use Django's ORM to interact with the model. For example: + ```python + from db.core.models.example_model import ExampleModel + + class ExampleCog(TeXBotBaseCog): + """A cog for demonstrating model access.""" + + async def create_example(self, name: str) -> None: + """Create a new instance of ExampleModel.""" + await ExampleModel.objects.acreate(name=name) + + async def retrieve_examples(self) -> list[ExampleModel]: + """Retrieve all instances of ExampleModel.""" + return await ExampleModel.objects.all() + + async def filter_examples(self, name: str) -> list[ExampleModel]: + """Filter instances of ExampleModel by name.""" + return await ExampleModel.objects.filter(name=name) + + async def update_example(self, example: ExampleModel, new_name: str) -> None: + """Update the name of an ExampleModel instance.""" + example.name = new_name + await example.asave() + + async def delete_example(self, example: ExampleModel) -> None: + """Delete an ExampleModel instance.""" + await example.adelete() + ``` + +4. **Document the Model** + - Add comments and docstrings to explain the purpose and functionality of the model. + +### Member Retrieval DB Queries via Hashed Discord ID + +To retrieve members from the database using their hashed Discord ID, follow these steps: + +1. **Hash the Discord ID** + - Use a consistent hashing algorithm to hash the Discord ID before storing or querying it in the database. + + Example: + ```python + import hashlib + + def hash_discord_id(discord_id: str) -> str: + return hashlib.sha256(discord_id.encode()).hexdigest() + ``` + +2. **Query the Database** + - Use the hashed Discord ID to retrieve the corresponding member from the database. + + Example: + ```python + from db.core.models.member import Member + + hashed_id = hash_discord_id("123456789012345678") + member = Member.objects.filter(hashed_discord_id=hashed_id).first() + + if member: + print(f"Member found: {member.name}") + else: + print("Member not found.") + ``` + +3. **Test the Query** + - Ensure the query works as expected by testing it with valid and invalid hashed Discord IDs. + +4. **Document the Query** + - Add comments and docstrings to explain the purpose and functionality of the query. + From 1e5355b653e03f2a6cfbf9d9d7cd90562b7cdb52 Mon Sep 17 00:00:00 2001 From: MattyTheHacker <18513864+MattyTheHacker@users.noreply.github.com> Date: Thu, 15 May 2025 10:31:16 +0100 Subject: [PATCH 23/27] add gdpr warning --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e79bbf0b..3033db561 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -393,6 +393,11 @@ Response buttons are interactive UI components that allow users to respond to bo ### Creating and Interacting with Django Models +#### Data Protection Consideration + +When making changes to the database model, it is essential to consider the data protection implications of these changes. If personal data is being collected, stored or processed, it is essential that this is in compliance with the law. In the UK, the relevant law is the [Data Protection Act 2018](https://www.legislation.gov.uk/ukpga/2018/12/contents). As a general rule, any changes that have data protection implications should be checked and approved by the organisation responsible for running the application. + + Django models are used to interact with the database in this project. They allow you to define the structure of your data and provide an API to query and manipulate it. To create and interact with Django models, follow these steps: 1. **Define a Model** From 84430ffdd4bcb2625284828ba0a4bdc2123d091d Mon Sep 17 00:00:00 2001 From: Matty Widdop <18513864+MattyTheHacker@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:51:15 +0100 Subject: [PATCH 24/27] Apply suggestions from code review Co-authored-by: Matt Norton Signed-off-by: Matty Widdop <18513864+MattyTheHacker@users.noreply.github.com> --- CONTRIBUTING.md | 103 ++++++++++++++++++++++++++++++------------------ TERMINOLOGY.md | 23 ++--------- 2 files changed, 68 insertions(+), 58 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3033db561..14edbefac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -211,10 +211,10 @@ Happy contributing! ### Creating a New Cog -Cogs are modular components of the bot that group related commands and listeners into a single class. To create a new cog, follow these steps: +Cogs are modular components of TeX-Bot that group related commands and listeners into a single class. To create a new cog, follow these steps: 1. **Create the Cog File** - - Navigate to the `cogs` folder. + - Navigate to the `cogs/` directory. - Create a new Python file with a name that reflects the purpose of the cog (e.g., `example_cog.py`). 2. **Define the Cog Class** @@ -235,7 +235,7 @@ Cogs are modular components of the bot that group related commands and listeners 3. **Add Commands and Listeners** - Define methods within the class for commands and event listeners. - - Use decorators like `@discord.slash_command` or `@TeXBotBaseCog.listener` to specify their purpose. + - Use decorators like `@discord.slash_command()` or `@TeXBotBaseCog.listener()` to register the callback method to their [interaction](TERMINOLOGY.md#Interactions) type. - Include any necessary checks using `CommandChecks` decorators. Example: @@ -253,9 +253,8 @@ Cogs are modular components of the bot that group related commands and listeners ``` 4. **Register the Cog** - - Open `cogs/__init__.py`. - - Add your new cog class to the list of cogs in the `setup` function. - - Also, include the cog in the `__all__` sequence to ensure it is properly exported. + - Edit `cogs/__init__.py` to add your new cog class to the list of cogs in the `setup` function. + - Also, include the cog class in the `__all__` sequence to ensure it is properly exported. Example: ```python @@ -278,7 +277,7 @@ Cogs are modular components of the bot that group related commands and listeners ``` 5. **Test the Cog** - - Run the bot and ensure the new cog is loaded without errors. + - Run the bot with your changes and ensure the new cog is loaded without errors. - Test the commands and listeners to verify they work as expected. 6. **Document the Cog** @@ -289,14 +288,14 @@ Cogs are modular components of the bot that group related commands and listeners To add a new environment variable to the project, follow these steps: -1. **Define the Variable in `.env`** - - Open the `.env` file in the root directory (or create one if it doesn't exist). +1. **Define the Variable in development `.env`** + - Open the `.env` file in the project root directory (or create one if it doesn't exist). - Add the new variable in the format `VARIABLE_NAME=value`. - Ensure the variable name is descriptive and uses uppercase letters with underscores. 2. **Update `config.py`** - Open the `config.py` file. - - Add a new setup method in the `Settings` class to validate and load the variable. For example: + - Add a new private setup method in the `Settings` class to validate and load the variable. For example: ```python @classmethod def _setup_new_variable(cls) -> None: @@ -330,17 +329,17 @@ To add a new environment variable to the project, follow these steps: - Update the `README.md` file under the "Setting Environment Variables" section to include the new variable, its purpose, and any valid values. 5. **Test the Variable** - - Run the bot and ensure the new variable is loaded correctly. - - Test edge cases, such as missing or invalid values, to confirm proper error handling. + - Run the bot with your changes and ensure the new variable is loaded correctly. + - Test edge cases, such as missing, blank or invalid values in the `.env` file, to confirm that error handling functions correctly. ### Creating a Response Button Response buttons are interactive UI components that allow users to respond to bot messages with predefined actions. To create a response button, follow these steps: 1. **Define the Button Class** - - Create a class that inherits from `discord.ui.View`. - - Add button methods using the `@discord.ui.button` decorator. - - Each button method should define the button's label, style, and custom ID. + - Create a new class in your cog file that inherits from `discord.ui.View`. + - Add button callback response methods using the `@discord.ui.button` decorator. + - Each button method should define the button's label, style, and a custom response ID. Example: ```python @@ -365,11 +364,11 @@ Response buttons are interactive UI components that allow users to respond to bo ) async def confirm_no(self, button: discord.Button, interaction: discord.Interaction) -> None: # Handle the 'No' button click - await interaction.response.send_message("Action canceled.", ephemeral=True) + await interaction.response.send_message("Action cancelled.", ephemeral=True) ``` 2. **Send the View with a Message** - - Use the `view` parameter of the `send` or `respond` method to attach the button view to a message. + - Use the `view` parameter of the `send` or `respond` method to attach the button view to a message. This could be sent in response to a command, event handler or scheduled task. Example: ```python @@ -384,7 +383,7 @@ Response buttons are interactive UI components that allow users to respond to bo - Use `interaction.response` to send feedback or perform actions based on the button clicked. 4. **Test the Button** - - Run the bot and ensure the buttons appear and function as expected. + - Run the bot with your changes and ensure the buttons appear and function as expected. - Test edge cases, such as multiple users interacting with the buttons simultaneously. 5. **Document the Button** @@ -396,31 +395,56 @@ Response buttons are interactive UI components that allow users to respond to bo #### Data Protection Consideration When making changes to the database model, it is essential to consider the data protection implications of these changes. If personal data is being collected, stored or processed, it is essential that this is in compliance with the law. In the UK, the relevant law is the [Data Protection Act 2018](https://www.legislation.gov.uk/ukpga/2018/12/contents). As a general rule, any changes that have data protection implications should be checked and approved by the organisation responsible for running the application. - - Django models are used to interact with the database in this project. They allow you to define the structure of your data and provide an API to query and manipulate it. To create and interact with Django models, follow these steps: 1. **Define a Model** - Navigate to the `db/core/models/` directory. - Create a new Python file with a name that reflects the purpose of the model (e.g., `example_model.py`). - - Define a class that inherits from `django.db.models.Model`. - - Add fields to the class to represent the data structure. + - If your model is a new property related to each Discord member (E.g. the number of smiley faces of each Discord member, then define a class that inherits from `BaseDiscordMemberWrapper` (found within the `.utils` module within the `db/core/models/` directory). + - If your model is unrelated to Discord members, then define a class that inherits from `AsyncBaseModel` (also found within the `.utils` module within the `db/core/models/` directory). + - Add your Django fields to the class to represent the model's data structure. + - If your model inherits from `BaseDiscordMemberWrapper` then you *must* declare a field called `discord_member` which must be either a Django `ForeignKey` field or a `OneToOneField`, depending upon the relationship between your model and each Discord member. + - Define the static class string holding the display name for multiple instances of your class (E.g., `INSTANCES_NAME_PLURAL: str = "Members' Smiley Faces"`) Example: ```python from django.db import models - class ExampleModel(models.Model): + from .utils import AsyncBaseModel, BaseDiscordMemberWrapper + + class ExampleModel(AsyncBaseModel): """A model for demonstrating functionality.""" + + INSTANCES_NAME_PLURAL: str = "Example Model objects" + name = models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) - ``` + class MemberSmileyFaces(BaseDiscordMemberWrapper): + """Model to represent the number of smiley faces of each Discord member.""" + + INSTANCES_NAME_PLURAL: str = "Discord Members' Smiley Faces" + + discord_member = models.OneToOneField( + DiscordMember, + on_delete=models.CASCADE, + related_name="smiley_faces", + verbose_name="Discord Member", + blank=False, + null=False, + primary_key=True, + ) + count = models.IntegerField( + "Number of smiley faces", + null=False, + blank=True, + default=0, + ) 2. **Apply Migrations** - Run the following commands to create and apply migrations for your new model: ```shell - uv run python manage.py makemigrations - uv run python manage.py migrate + uv run manage.py makemigrations + uv run manage.py migrate ``` 3. **Query the Model** @@ -454,7 +478,7 @@ Django models are used to interact with the database in this project. They allow ``` 4. **Document the Model** - - Add comments and docstrings to explain the purpose and functionality of the model. + - Add comments and docstrings to explain the purpose and functionality of your new model. ### Member Retrieval DB Queries via Hashed Discord ID @@ -472,26 +496,27 @@ To retrieve members from the database using their hashed Discord ID, follow thes ``` 2. **Query the Database** - - Use the hashed Discord ID to retrieve the corresponding member from the database. + - A custom filter field is implemented for models that inherit from `BaseDiscordMemberWrapper`, this allows you to filter using the unhashed Discord ID, despite only the hashed Discord ID being stored in the database. Example: ```python - from db.core.models.member import Member + from db.core.models.member_smiley_faces import MemberSmileyFaces - hashed_id = hash_discord_id("123456789012345678") - member = Member.objects.filter(hashed_discord_id=hashed_id).first() + class MyExampleCommandCog(TeXBotBaseCog): + @tasks.loop(minutes=5) + async def check_member_smiley_faces(self) -> None: + member_smiley_faces = await MemberSmileyFaces.objects.filter(discord_id=1234567).afirst() - if member: - print(f"Member found: {member.name}") - else: - print("Member not found.") + if member_smiley_faces: + print(f"Member's smiley faces found: {member_smiley_faces.discord_member.name}") + else: + print("Member's smiley facesnot found.") ``` +It is unlikely that you will need to query the `DiscordMember` model directly. Instead the attributes of the member can be accessed by the relationship between each new Django model to the `DiscordMember` model. + 3. **Test the Query** - - Ensure the query works as expected by testing it with valid and invalid hashed Discord IDs. + - Ensure the query works as expected by testing it with valid and invalid Discord IDs. 4. **Document the Query** - Add comments and docstrings to explain the purpose and functionality of the query. - - - diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index 0ef287f7d..85e58e43d 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -11,7 +11,7 @@ The term "main guild" is used throughout the code in this repository to refer sp ## [Interactions](https://discord.com/developers/docs/interactions/overview) -Interactions in Discord are a way for bots to communicate with users in a structured and interactive manner. They include various types of commands and events that allow users to interact with the bot. The primary types of interactions are: +Interactions in Discord are a way for bots to communicate with users in a structured and interactive manner. They are the initial entry point to allow users to begin interacting with the bot. (Note that a Discord bot's functionality could also be triggered via non-interaction methods like scheduled tasks or event handlers.) The primary types of interactions are: 1. **Application Commands**: These include Slash Commands, Message Commands, and User Commands. They are predefined commands that users can invoke to perform specific actions. 2. **Message Components**: These are interactive elements like buttons, select menus, and modals that can be attached to messages to provide a richer user experience. @@ -33,19 +33,10 @@ The primary difference is the way these commands are triggered. [Slash Commands] ### [Slash Commands](https://discord.com/developers/docs/interactions/application-commands#slash-commands) -Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. These can be defined using the `discord.slash_command` decorator as follows: -```python -@discord.slash_command( - name="command-name", - description="a description of what the command does", -) -async def command_name(self, ctx: TeXBotApplicationContext): - """Doc string goes here.""" - pass # command functions go here -``` +Slash commands, also known as `CHAT_INPUT` commands are executed via sending a chat message and are made up of a name, description and a set of options. These can be defined using the `@discord.slash_command()` decorator. -For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the [CONTRIBUTING](CONTRIBUTING.md) doc. +For example usages, check the [Guides section](CONTRIBUTING.md#Guides) of the [CONTRIBUTING.md document](CONTRIBUTING.md). ### Context Commands @@ -53,7 +44,7 @@ For more example usages, check the [Guides](CONTRIBUTING#Guides) section of the #### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) -Message commands, also known as `Message-Context Commands`, are executed via right-clicking on a [Message](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. +Message-context commands, are executed via right-clicking on a [Discord *Message*](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. The interaction callback method is provided information about which message was clicked, along with which user clicked it. The main difference between [Context Commands](#context-commands) and [Slash Commands](#slash-commands) is that [Context Commands](#context-commands) do not take user defined arguments and are limited to the [Message](https://discord.com/developers/docs/resources/message) that the command is issued on and the context which is passed along side it. @@ -85,9 +76,3 @@ Some commands may require you to create [roles](https://discord.com/developers/d In some other contexts, the term "user" may be used to refer to any person/organisation making use of this project. (E.g. the description within [the "Error Codes" section](#error-codes).) - - - - - - From c2087b57addc55a00091f73cf07d2a68f86c554d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 16:51:59 +0000 Subject: [PATCH 25/27] [pre-commit.ci lite] apply automatic fixes --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14edbefac..1c60f1d78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -421,7 +421,7 @@ Django models are used to interact with the database in this project. They allow created_at = models.DateTimeField(auto_now_add=True) class MemberSmileyFaces(BaseDiscordMemberWrapper): """Model to represent the number of smiley faces of each Discord member.""" - + INSTANCES_NAME_PLURAL: str = "Discord Members' Smiley Faces" discord_member = models.OneToOneField( From 5edaf39813e772c4696892dd89c813345d739f24 Mon Sep 17 00:00:00 2001 From: Matt Norton Date: Fri, 13 Jun 2025 03:29:50 +0100 Subject: [PATCH 26/27] Fix minor docs errors --- CONTRIBUTING.md | 20 ++++++++++---------- README.md | 6 +++--- TERMINOLOGY.md | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c60f1d78..6a7ed240f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ We recommend also reading the following if you're unsure or not confident: * [Contributing To An Open Source Project For The First Time](https://firsttimersonly.com) TeX-Bot is written in [Python](https://python.org) using [Pycord](https://pycord.dev) and uses Discord's [slash-commands](https://support.discord.com/hc/articles/1500000368501-Slash-Commands-FAQ) & [user-commands](https://guide.pycord.dev/interactions/application-commands/context-menus). -We would recommend being somewhat familiar with the [Pycord library](https://docs.pycord.dev), [Python language](https://docs.python.org/3/reference/index) & [project terminology](README.md#terminology) before contributing. +We would recommend being somewhat familiar with the [Pycord library](https://docs.pycord.dev), [Python language](https://docs.python.org/3/reference/index) & [project terminology](TERMINOLOGY.md) before contributing. ## Using the Issue Tracker @@ -52,13 +52,13 @@ If you are submitting a feature request, please include the steps to implement t ### Top level files * [`main.py`](main.py): is the main entrypoint to instantiate the [`Bot` object](https://docs.pycord.dev/stable/api/clients.html#discord.Bot) & run it -* [`exceptions.py`](exceptions.py): contains common [exception](https://docs.python.org/3/tutorial/errors) subclasses that may be raised when certain errors occur -* [`config.py`](config.py): retrieves the [environment variables](README.md#setting-environment-variables) & populates the correct values into the `settings` object +* [`exceptions/`](exceptions): contains common [exception](https://docs.python.org/3/tutorial/errors) subclasses that may be raised when certain errors occur +* [`config.py`](config.py): retrieves the [environment variables](README.md#setting-environment-variables) and populates the correct values into the `settings` object ### Other significant directories * [`cogs/`](cogs): contains all the [cogs](https://guide.pycord.dev/popular-topics/cogs) within this project, see [below](#cogs) for more information -* [`utils/`](utils): contains common utility classes & functions used by the top-level modules & cogs +* [`utils/`](utils): contains common utility classes and functions used by the top-level modules and cogs * [`db/core/models/`](db/core/models): contains all the [database ORM models](https://docs.djangoproject.com/en/stable/topics/db/models) to interact with storing information longer-term (between individual command events) * [`tests/`](tests): contains the complete test suite for this project, based on the [Pytest framework](https://pytest.org) @@ -107,11 +107,11 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i * [`cogs/startup.py`](cogs/startup.py): cogs for startup & bot initialisation -* [`cogs/stats.py`](cogs/stats.py): cogs for displaying stats about your group's Discord guild, as well as its channels & Discord members +* [`cogs/stats/`](cogs/stats): cogs for displaying stats about your group's Discord guild, as well as its channels & Discord members * [`cogs/strike.py`](cogs/strike.py): cogs for applying moderation actions to Discord members -* [`cogs/write_roles.py`](cogs/write_roles.py): cogs relating to sending the message that contains all the opt-in roles, into the "#**roles**" channel +* [`cogs/write_roles.py`](cogs/write_roles.py): cogs relating to sending the message, that contains all the opt-in roles, into the "#**roles**" channel ## Making Your First Contribution @@ -155,7 +155,7 @@ It can be run with the following command: uv run mypy . ``` -Although there is [a PyCharm plugin](https://github.com/leinardi/mypy-pycharm#mypy-pycharm) to provide GUI control & inline warnings for [mypy](https://mypy-lang.org), it has been rather temperamental recently. +Although there is [a PyCharm plugin](https://github.com/leinardi/mypy-pycharm#mypy-pycharm) to provide GUI control and inline warnings for [mypy](https://mypy-lang.org), it has been rather temperamental recently. So it is suggested to avoid using it, and run [mypy](https://mypy-lang.org) from the command-line instead. #### PyMarkdown @@ -326,7 +326,7 @@ To add a new environment variable to the project, follow these steps: ``` 4. **Document the Variable** - - Update the `README.md` file under the "Setting Environment Variables" section to include the new variable, its purpose, and any valid values. + - Update the `README.md` file under the "Setting Environment Variables" section to include the new variable, its purpose and any valid values. 5. **Test the Variable** - Run the bot with your changes and ensure the new variable is loaded correctly. @@ -339,7 +339,7 @@ Response buttons are interactive UI components that allow users to respond to bo 1. **Define the Button Class** - Create a new class in your cog file that inherits from `discord.ui.View`. - Add button callback response methods using the `@discord.ui.button` decorator. - - Each button method should define the button's label, style, and a custom response ID. + - Each button method should define the button's label, a custom response ID and style. Example: ```python @@ -513,7 +513,7 @@ To retrieve members from the database using their hashed Discord ID, follow thes print("Member's smiley facesnot found.") ``` -It is unlikely that you will need to query the `DiscordMember` model directly. Instead the attributes of the member can be accessed by the relationship between each new Django model to the `DiscordMember` model. + It is unlikely that you will need to query the `DiscordMember` model directly. Instead, the attributes of the member can be accessed by the relationship between each new Django model to the `DiscordMember` model. 3. **Test the Query** - Ensure the query works as expected by testing it with valid and invalid Discord IDs. diff --git a/README.md b/README.md index 32fe3877f..ddff89496 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Featured in the [CSS Discord guild](https://cssbham.com/discord). ## Error Codes Users of TeX-Bot may encounter an error code when executing a slash-command fails. -If a user encounters any of these errors, please communicate the error to the committee member that has been assigned to upkeep & deployment of your instance of TeX-Bot. +If a user encounters any of these errors, please communicate the error to the committee member that has been assigned to upkeep and deployment of your instance of TeX-Bot. The meaning of each error code is given here: * `E1011` - The value for the [environment variable](https://wikipedia.org/wiki/Environment_variable) `DISCORD_GUILD_ID` is an [ID](https://discord.com/developers/docs/reference#snowflakes) that references a [Discord guild](https://discord.com/developers/docs/resources/guild) that does not exist @@ -136,7 +136,7 @@ You'll also need to set a number of [environment variables](https://wikipedia.or (This setting is optional. Error logs will **always** be sent to the [console](https://wikipedia.org/wiki/Terminal_emulator), this setting allows them to also be sent to a [Discord log channel](https://docs.pycord.dev/en/stable/api/models.html#discord.TextChannel).) -* `ORGANISATION_ID`: Your Guild society ID. This is used to dynamically create the members list among other needed URLs. +* `ORGANISATION_ID`: Your Guild society ID. This is used to dynamically fetch your community group's list of members, among other necessary URLs. * `MEMBERS_LIST_URL_SESSION_COOKIE`: The members-list [URL](https://wikipedia.org/wiki/URL) [session cookie](https://wikipedia.org/wiki/HTTP_cookie#Session_cookie). (If your group's members-list is stored at a [URL](https://wikipedia.org/wiki/URL) that requires [authentication](https://wikipedia.org/wiki/Authentication), this [session cookie](https://wikipedia.org/wiki/HTTP_cookie#Session_cookie) should [authenticate](https://wikipedia.org/wiki/Authentication) TeX-Bot to view your group's members-list, as if it were [logged in to the website](https://wikipedia.org/wiki/Login_session) as a Committee member. @@ -176,7 +176,7 @@ This will ensure your code meets the standard required for this project and give This project follows the [semantic versioning scheme](https://semver.org). We currently treat TeX-Bot as alpha software, and as such no numbered release has been made yet. -When selecting a version tag to use for [deploying TeX-Bot as a container image](#deploying-in-production) there are multiple tag schemes available: +When selecting a version tag to use for [deploying TeX-Bot as a container image](#deploying-in-production), there are multiple tag schemes available: * `latest` - The most recent numerically tagged version released * `br-` - The most recent commit from a given branch in this repository (E.g. `br-main`) (N.B. this does not include branches of forks of this repository) diff --git a/TERMINOLOGY.md b/TERMINOLOGY.md index 85e58e43d..bb20f4f5f 100644 --- a/TERMINOLOGY.md +++ b/TERMINOLOGY.md @@ -44,9 +44,9 @@ For example usages, check the [Guides section](CONTRIBUTING.md#Guides) of the [C #### [Message Commands](https://discord.com/developers/docs/interactions/application-commands#message-commands) -Message-context commands, are executed via right-clicking on a [Discord *Message*](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. The interaction callback method is provided information about which message was clicked, along with which user clicked it. +Message-context commands are executed via right-clicking on a [Discord *Message*](https://discord.com/developers/docs/resources/message), clicking "Apps", then selecting the command from the menu. The interaction callback method is provided information about which message was clicked, along with which user clicked it. -The main difference between [Context Commands](#context-commands) and [Slash Commands](#slash-commands) is that [Context Commands](#context-commands) do not take user defined arguments and are limited to the [Message](https://discord.com/developers/docs/resources/message) that the command is issued on and the context which is passed along side it. +The main difference between [Context Commands](#context-commands) and [Slash Commands](#slash-commands) is that [Context Commands](#context-commands) do not take user defined arguments and are limited to the [Message](https://discord.com/developers/docs/resources/message) that the command is issued on and the context which is passed alongside it. #### [User Commands](https://discord.com/developers/docs/interactions/application-commands#user-commands) @@ -62,7 +62,7 @@ Therefore, it can be [messaged via DM](https://dictionary.com/browse/dm) or be r (See [the Discord developer docs](https://discord.com/developers/docs/resources/user) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#users) for more information.) In contrast, a [Discord "member" object](https://discord.com/developers/docs/resources/guild#guild-member-object) is a [user](https://discord.com/developers/docs/resources/user) attached to a specific [guild](https://discord.com/developers/docs/resources/guild). -Therefore, it can have [roles](https://discord.com/developers/docs/topics/permissions#role-object), be [banned](https://discord.com/developers/docs/resources/guild#ban-object) & have many other actions applied to it. +Therefore, it can have [roles](https://discord.com/developers/docs/topics/permissions#role-object), be [banned](https://discord.com/developers/docs/resources/guild#ban-object) and have many other actions applied to it. (See [the Discord developer docs](https://discord.com/developers/docs/resources/guild#guild-member-object) & [Pycord's docs](https://docs.pycord.dev/en/stable/api/models.html#discord.Member) for more information.) ### Community Group Membership @@ -75,4 +75,4 @@ Some commands may require you to create [roles](https://discord.com/developers/d ### Other Uses In some other contexts, the term "user" may be used to refer to any person/organisation making use of this project. -(E.g. the description within [the "Error Codes" section](#error-codes).) +(E.g. the description within [the "Error Codes" section](README.md#error-codes).) From 1a6ff7595f5786cee7ca7acea5d30d500764b0bb Mon Sep 17 00:00:00 2001 From: Holly <25277367+Thatsmusic99@users.noreply.github.com> Date: Sun, 15 Jun 2025 13:49:43 +0100 Subject: [PATCH 27/27] Allow committee-elect to update actions (and appear in auto-complete) (#508) Signed-off-by: Holly <25277367+Thatsmusic99@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Matty Widdop <18513864+MattyTheHacker@users.noreply.github.com> --- cogs/committee_actions_tracking.py | 52 ++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/cogs/committee_actions_tracking.py b/cogs/committee_actions_tracking.py index 35c1fee9e..ccea5bc98 100644 --- a/cogs/committee_actions_tracking.py +++ b/cogs/committee_actions_tracking.py @@ -1,5 +1,6 @@ """Contains cog classes for tracking committee-actions.""" +import contextlib import logging import random from enum import Enum @@ -11,6 +12,7 @@ from db.core.models import AssignedCommitteeAction, DiscordMember from exceptions import ( + CommitteeElectRoleDoesNotExistError, CommitteeRoleDoesNotExistError, InvalidActionDescriptionError, InvalidActionTargetError, @@ -129,11 +131,22 @@ async def autocomplete_get_committee_members( except CommitteeRoleDoesNotExistError: return set() + committee_elect_role: discord.Role | None = None + with contextlib.suppress(CommitteeElectRoleDoesNotExistError): + committee_elect_role = await ctx.bot.committee_elect_role + return { discord.OptionChoice( name=f"{member.display_name} ({member.global_name})", value=str(member.id) ) - for member in committee_role.members + for member in ( + set(committee_role.members) + | ( + set(committee_elect_role.members) + if committee_elect_role is not None + else set() + ) + ) if not member.bot } @@ -281,9 +294,7 @@ async def create( required=True, parameter_name="status", ) - @CommandChecks.check_interaction_user_has_committee_role - @CommandChecks.check_interaction_user_in_main_guild - async def update_status( + async def update_status( # NOTE: Committee role check is not present because non-committee can have actions, and need to be able to list their own actions. self, ctx: "TeXBotApplicationContext", action_id: str, status: str ) -> None: """ @@ -561,9 +572,7 @@ async def action_all_committee( default=None, parameter_name="status", ) - @CommandChecks.check_interaction_user_has_committee_role - @CommandChecks.check_interaction_user_in_main_guild - async def list_user_actions( + async def list_user_actions( # NOTE: Committee role check is not present because non-committee can have actions, and need to be able to list their own actions. self, ctx: "TeXBotApplicationContext", *, @@ -575,15 +584,32 @@ async def list_user_actions( Definition and callback of the "/list" command. Takes in a user and lists out their current actions. + If no user is specified, the user issuing the command will be used. + If a user has the committee role, they can list actions for other users. + If a user does not have the committee role, they can only list their own actions. """ - action_member: discord.Member | discord.User + action_member_id = action_member_id.strip() + + action_member: discord.Member | discord.User = ( + await self.bot.get_member_from_str_id(action_member_id) + if action_member_id + else ctx.user + ) - if action_member_id: - action_member = await self.bot.get_member_from_str_id( - action_member_id, + if action_member != ctx.user and not await self.bot.check_user_has_committee_role( + ctx.user + ): + await ctx.respond( + content="Committee role is required to list actions for other users.", + ephemeral=True, ) - else: - action_member = ctx.user + logger.debug( + "User: %s, tried to list actions for user: %s, " + "but did not have the committee role.", + ctx.user, + action_member, + ) + return user_actions: list[AssignedCommitteeAction]