Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
python-version: 3.12

- name: Run Ruff
run: poetry run ruff check . --no-fix
run: poetry run ruff check . --no-fix --extend-select TD002,TD003

poetry-check:
runs-on: ubuntu-latest
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ We recommend also reading the following if you're unsure or not confident:
* [How To Make A Pull Request](https://makeapullrequest.com)
* [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).
This 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.

## Using the Issue Tracker

We use [GitHub issues](https://docs.github.com/issues) to track bugs and feature requests.
If you find an issue with TeX-Bot, the best place to report it is through the issue tracker.
If you find an issue with the bot, the best place to report it is through the issue tracker.
If you are looking for issues to contribute code to, it's a good idea to look at the [issues labelled "good-first-issue"](https://github.com/CSSUoB/TeX-Bot-Py-V2/issues?q=label%3A%22good+first+issue%22)!

When submitting an issue, please be as descriptive as possible.
Expand Down Expand Up @@ -79,7 +79,7 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i

* [`cogs/delete_all.py`](cogs/delete_all.py): cogs for deleting all permanent data stored in a specific object's table in the database

* [`cogs/edit_message.py`](cogs/edit_message.py): cogs for editing messages that were previously sent by TeX-Bot
* [`cogs/edit_message.py`](cogs/edit_message.py): cogs for editing messages that were previously sent by the bot

* [`cogs/induct.py`](cogs/induct.py): cogs for inducting people into your group's Discord guild

Expand All @@ -89,7 +89,7 @@ There are separate cog files for each activity, and one [`__init__.py`](cogs/__i

* [`cogs/ping.py`](cogs/ping.py): cog to request a [ping](https://wikipedia.org/wiki/Ping-pong_scheme#Internet) response

* [`cogs/remind_me.py`](cogs/remind_me.py): cogs to ask TeX-Bot to send a reminder message at a later date
* [`cogs/remind_me.py`](cogs/remind_me.py): cogs to ask the bot to send a reminder message at a later date

* [`cogs/send_get_roles_reminders.py`](cogs/send_get_roles_reminders.py): cogs relating to sending reminders, to Discord members, about opt-in roles.
(See [Repeated Tasks Conditions](README.md#repeated-tasks-conditions) for which conditions are required to be met, to execute this task)
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ WORKDIR /app
COPY LICENSE .en[v] config.py main.py messages.json ./
RUN chmod +x main.py

COPY exceptions/ ./exceptions/
COPY utils/ ./utils/
COPY db/ ./db/
COPY cogs/ ./cogs/
COPY db/ ./db/
COPY utils/ ./utils/
COPY exceptions/ ./exceptions/

ENTRYPOINT ["python", "-m", "main"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ The meaning of each error code is given here:
* `E1023` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-object) with the name "@**Member**".
(This [role](https://discord.com/developers/docs/topics/permissions#role-object) is required for the `/makemember` & `/ensure-members-inducted` [commands](https://discord.com/developers/docs/interactions/application-commands))

* `E1024` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-object) with the name "@**Archivist**".
* `E1024` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-object) with the name "**@Archivist**".
(This [role](https://discord.com/developers/docs/topics/permissions#role-object) is required for the `/archive` [command](https://discord.com/developers/docs/interactions/application-commands))

* `E1025` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-object) with the name "@**Applicant**". (This [role](https://discord.com/developers/docs/topics/permissions#role-object) is required for the `/make-applicant` [command](https://discord.com/developers/docs/interactions/application-commands) and respective user and message commands)
* `E1025` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-object) with the name "**@Applicant**". (This [role](https://discord.com/developers/docs/topics/permissions#role-object) is required for the `/make-applicant` [command](https://discord.com/developers/docs/interactions/application-commands) and respective user and message commands)

* `E1026` - Your [Discord guild](https://discord.com/developers/docs/resources/guild) does not contain a [role](https://discord.com/developers/docs/topics/permissions#role-objec) with the name "@**Committee-Elect**".
(This [role](https://discord.com/developers/docs/topics/permissions#role-object) is required for the `/handover` [command](https://discord.com/developers/docs/interactions/application-commands))
Expand Down
6 changes: 3 additions & 3 deletions cogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

__all__: Sequence[str] = (
"ArchiveCommandCog",
"GetTokenAuthorisationCommandCog",
"GetTokenAuthorisationCommand",
"CommandErrorCog",
"DeleteAllCommandsCog",
"EditMessageCommandCog",
Expand Down Expand Up @@ -51,7 +51,7 @@
from cogs.command_error import CommandErrorCog
from cogs.delete_all import DeleteAllCommandsCog
from cogs.edit_message import EditMessageCommandCog
from cogs.get_token_authorisation import GetTokenAuthorisationCommandCog
from cogs.get_token_authorisation import GetTokenAuthorisationCommand
from cogs.induct import (
EnsureMembersInductedCommandCog,
InductContextCommandsCog,
Expand Down Expand Up @@ -82,7 +82,7 @@ def setup(bot: TeXBot) -> None:
"""Add all the cogs to the bot, at bot startup."""
cogs: Iterable[type[TeXBotBaseCog]] = (
ArchiveCommandCog,
GetTokenAuthorisationCommandCog,
GetTokenAuthorisationCommand,
CommandErrorCog,
DeleteAllCommandsCog,
EditMessageCommandCog,
Expand Down
20 changes: 10 additions & 10 deletions cogs/annual_handover_and_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class CommitteeHandoverCommandCog(TeXBotBaseCog):

@discord.slash_command( # type: ignore[no-untyped-call, misc]
name="committee-handover",
description="Initiates the annual Discord handover procedure for new committee.",
description="Initiates the annual Discord handover procedure for new committee",
)
@CommandChecks.check_interaction_user_has_committee_role
@CommandChecks.check_interaction_user_in_main_guild
Expand All @@ -45,9 +45,9 @@ async def committee_handover(self, ctx: TeXBotApplicationContext) -> None:
To do this, TeX-Bot will need to hold a role above that of the "Committee" role.
"""
# NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent
main_guild: discord.Guild = self.tex_bot.main_guild
committee_role: discord.Role = await self.tex_bot.committee_role
committee_elect_role: discord.Role = await self.tex_bot.committee_elect_role
main_guild: discord.Guild = self.bot.main_guild
committee_role: discord.Role = await self.bot.committee_role
committee_elect_role: discord.Role = await self.bot.committee_elect_role

initial_response: discord.Interaction | discord.WebhookMessage = await ctx.respond(
content=":hourglass: Running handover procedures... :hourglass:",
Expand Down Expand Up @@ -168,7 +168,7 @@ class AnnualRolesResetCommandCog(TeXBotBaseCog):

@discord.slash_command( # type: ignore[no-untyped-call, misc]
name="annual-roles-reset",
description="Removes the @Member role and academic year roles from all users.",
description="Removes the @Member role and academic year roles from all users",
)
@CommandChecks.check_interaction_user_has_committee_role
@CommandChecks.check_interaction_user_in_main_guild
Expand All @@ -181,8 +181,8 @@ async def annual_roles_reset(self, ctx: TeXBotApplicationContext) -> None:
the GroupMadeMember database model.
"""
# NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent
main_guild: discord.Guild = self.tex_bot.main_guild
member_role: discord.Role = await self.tex_bot.member_role
main_guild: discord.Guild = self.bot.main_guild
member_role: discord.Role = await self.bot.member_role

logger.debug("Reset roles command called.")
initial_response: discord.Interaction | discord.WebhookMessage = await ctx.respond(
Expand Down Expand Up @@ -246,8 +246,8 @@ async def increment_year_channels(self, ctx: TeXBotApplicationContext) -> None:
- Creates a new "first-years" channel
"""
# NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent
main_guild: discord.Guild = self.tex_bot.main_guild
guest_role: discord.Role = await self.tex_bot.guest_role
main_guild: discord.Guild = self.bot.main_guild
guest_role: discord.Role = await self.bot.guest_role

initial_message: discord.Interaction | discord.WebhookMessage = await ctx.respond(
content=":hourglass: Incrementing year channels... :hourglass:",
Expand All @@ -262,7 +262,7 @@ async def increment_year_channels(self, ctx: TeXBotApplicationContext) -> None:
await initial_message.edit(
content=":hourglass: Archiving \"final-years\" channel... :hourglass:",
)
archivist_role: discord.Role = await self.tex_bot.archivist_role
archivist_role: discord.Role = await self.bot.archivist_role

await final_year_channel.set_permissions(guest_role, overwrite=None)
await final_year_channel.set_permissions(archivist_role, read_messages=True)
Expand Down
56 changes: 26 additions & 30 deletions cogs/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

import logging
import re
from collections.abc import Set
from logging import Logger
from typing import Final

import discord

Expand All @@ -23,34 +21,34 @@
TeXBotBaseCog,
)

logger: Final[Logger] = logging.getLogger("TeX-Bot")
logger: Logger = logging.getLogger("TeX-Bot")


class ArchiveCommandCog(TeXBotBaseCog):
"""Cog class that defines the "/archive" command and its call-back method."""

@staticmethod
async def autocomplete_get_categories(ctx: TeXBotAutocompleteContext) -> Set[discord.OptionChoice] | Set[str]: # noqa: E501
async def autocomplete_get_categories(ctx: TeXBotAutocompleteContext) -> set[discord.OptionChoice]: # noqa: E501
"""
Autocomplete callable that generates the set of available selectable categories.

The list of available selectable categories is unique to each member and is used in
The list of available selectable categories is unique to each member, and is used in
any of the "archive" slash-command options that have a category input-type.
"""
if not ctx.interaction.user:
return set()

try:
if not await ctx.tex_bot.check_user_has_committee_role(ctx.interaction.user):
return set()

main_guild: discord.Guild = ctx.tex_bot.main_guild
interaction_user: discord.Member = await ctx.tex_bot.get_main_guild_member(
main_guild: discord.Guild = ctx.bot.main_guild
interaction_user: discord.Member = await ctx.bot.get_main_guild_member(
ctx.interaction.user,
)
except (BaseDoesNotExistError, DiscordMemberNotInMainGuildError):
return set()

if not await ctx.bot.check_user_has_committee_role(interaction_user):
return set()

return {
discord.OptionChoice(name=category.name, value=str(category.id))
for category
Expand Down Expand Up @@ -82,15 +80,15 @@ async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) ->
have the "Archivist" role.
"""
# NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent
main_guild: discord.Guild = self.tex_bot.main_guild
interaction_member: discord.Member = await self.tex_bot.get_main_guild_member(ctx.user)
committee_role: discord.Role = await self.tex_bot.committee_role
guest_role: discord.Role = await self.tex_bot.guest_role
member_role: discord.Role = await self.tex_bot.member_role
archivist_role: discord.Role = await self.tex_bot.archivist_role
everyone_role: discord.Role = await self.tex_bot.get_everyone_role()

if not re.fullmatch(r"\A\d{17,20}\Z", str_category_id):
main_guild: discord.Guild = self.bot.main_guild
interaction_member: discord.Member = await self.bot.get_main_guild_member(ctx.user)
committee_role: discord.Role = await self.bot.committee_role
guest_role: discord.Role = await self.bot.guest_role
member_role: discord.Role = await self.bot.member_role
archivist_role: discord.Role = await self.bot.archivist_role
everyone_role: discord.Role = await self.bot.get_everyone_role()

if not re.match(r"\A\d{17,20}\Z", str_category_id):
await self.command_send_error(
ctx,
message=f"{str_category_id!r} is not a valid category ID.",
Expand Down Expand Up @@ -123,19 +121,19 @@ async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) ->
channel: AllChannelTypes
for channel in category.channels:
try:
CHANNEL_NEEDS_COMMITTEE_ARCHIVING: bool = (
channel_needs_committee_archiving: bool = (
channel.permissions_for(committee_role).is_superset(
discord.Permissions(view_channel=True),
) and not channel.permissions_for(guest_role).is_superset(
discord.Permissions(view_channel=True),
)
)
CHANNEL_NEEDS_NORMAL_ARCHIVING: bool = (
channel.permissions_for(guest_role).is_superset(
discord.Permissions(view_channel=True),
)
channel_needs_normal_archiving: bool = channel.permissions_for(
guest_role,
).is_superset(
discord.Permissions(view_channel=True),
)
if CHANNEL_NEEDS_COMMITTEE_ARCHIVING:
if channel_needs_committee_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
Expand All @@ -157,7 +155,7 @@ async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) ->
reason=f"{interaction_member.display_name} used \"/archive\".",
)

elif CHANNEL_NEEDS_NORMAL_ARCHIVING:
elif channel_needs_normal_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
Expand Down Expand Up @@ -199,14 +197,12 @@ async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) ->
await self.command_send_error(
ctx,
message=(
"TeX-Bot does not have access to "
"the channels in the selected category."
"Bot does not have access to the channels in the selected category."
),
)
logger.error( # noqa: TRY400
(
"TeX-Bot did not have access to "
"the channels in the selected category: "
"Bot did not have access to the channels in the selected category: "
"%s."
),
category.name,
Expand Down
10 changes: 4 additions & 6 deletions cogs/command_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import contextlib
import logging
from logging import Logger
from typing import Final

import discord
from discord import Forbidden
Expand All @@ -21,7 +20,7 @@
from exceptions.base import BaseErrorWithErrorCode
from utils import CommandChecks, TeXBotApplicationContext, TeXBotBaseCog

logger: Final[Logger] = logging.getLogger("TeX-Bot")
logger: Logger = logging.getLogger("TeX-Bot")


class CommandErrorCog(TeXBotBaseCog):
Expand Down Expand Up @@ -49,16 +48,15 @@ async def on_application_command_error(self, ctx: TeXBotApplicationContext, erro
elif isinstance(error, CheckAnyFailure):
if CommandChecks.is_interaction_user_in_main_guild_failure(error.checks[0]):
message = (
"You must be a member of "
f"the {self.tex_bot.group_short_name} Discord server "
f"You must be a member of the {self.bot.group_short_name} Discord server "
"to use this command."
)

elif CommandChecks.is_interaction_user_has_committee_role_failure(error.checks[0]):
# noinspection PyUnusedLocal
committee_role_mention: str = "@Committee"
with contextlib.suppress(CommitteeRoleDoesNotExistError):
committee_role_mention = (await self.tex_bot.committee_role).mention
committee_role_mention = (await self.bot.committee_role).mention
message = f"Only {committee_role_mention} members can run this command."

await self.command_send_error(
Expand Down Expand Up @@ -87,4 +85,4 @@ async def on_application_command_error(self, ctx: TeXBotApplicationContext, erro
if message_part
),
)
await self.tex_bot.close()
await self.bot.close()
6 changes: 2 additions & 4 deletions cogs/delete_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ class DeleteAllCommandsCog(TeXBotBaseCog):
"""Cog class that defines the "/delete-all" command group and command call-back methods."""

delete_all: discord.SlashCommandGroup = discord.SlashCommandGroup(
name="delete-all",
description=(
"Delete all instances of the selected object type from the backend database"
),
"delete-all",
"Delete all instances of the selected object type from the backend database",
)

@staticmethod
Expand Down
Loading