Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue CSSUoB#154 (Archive Single Channel) #178

Closed
wants to merge 6 commits into from
Closed
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
222 changes: 108 additions & 114 deletions cogs/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ 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]: # noqa: E501
async def autocomplete_get_channels(ctx: TeXBotAutocompleteContext) -> set[discord.OptionChoice]: # noqa: E501
"""
Autocomplete callable that generates the set of available selectable categories.
Autocomplete callable that generates the set of available selectable channels.

The list of available selectable categories is unique to each member, and is used in
The list of available selectable channels 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:
Expand All @@ -45,33 +45,34 @@ async def autocomplete_get_categories(ctx: TeXBotAutocompleteContext) -> set[dis
return set()

return {
discord.OptionChoice(name=category.name, value=str(category.id))
for category
in main_guild.categories
if category.permissions_for(interaction_user).is_superset(
discord.OptionChoice(name=channel.name, value=str(channel.id))
for channel
in main_guild.channels
if channel.permissions_for(interaction_user).is_superset(
discord.Permissions(send_messages=True, view_channel=True)
)
) and isinstance(channel, (discord.VoiceChannel | discord.StageChannel
| discord.TextChannel | discord.ForumChannel))
}

@discord.slash_command( # type: ignore[no-untyped-call, misc]
name="archive",
description="Archives the selected category."
description="Archives the selected channel."
)
@discord.option( # type: ignore[no-untyped-call, misc]
name="category",
description="The category to archive.",
name="channel",
description="The channel to archive.",
input_type=str,
autocomplete=discord.utils.basic_autocomplete(autocomplete_get_categories), # type: ignore[arg-type]
autocomplete=discord.utils.basic_autocomplete(autocomplete_get_channels), # type: ignore[arg-type]
required=True,
parameter_name="str_category_id"
parameter_name="str_channel_id"
)
@CommandChecks.check_interaction_user_has_committee_role
@CommandChecks.check_interaction_user_in_main_guild
async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) -> None:
async def archive(self, ctx: TeXBotApplicationContext, str_channel_id: str) -> None:
"""
Definition & callback response of the "archive" command.

The "archive" command hides a given category from view of casual members unless they
The "archive" command hides a given channel from view of casual members unless they
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
Expand All @@ -83,132 +84,125 @@ async def archive(self, ctx: TeXBotApplicationContext, str_category_id: str) ->
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):
if not re.match(r"\A\d{17,20}\Z", str_channel_id):
await self.command_send_error(
ctx,
message=f"{str_category_id!r} is not a valid category ID."
message=f"{str_channel_id!r} is not a valid channel ID."
)
return

category_id: int = int(str_category_id)
channel_id: int = int(str_channel_id)

category: discord.CategoryChannel | None = discord.utils.get(
main_guild.categories,
id=category_id
channel: discord.VoiceChannel | discord.StageChannel | discord.TextChannel \
| discord.ForumChannel | discord.CategoryChannel | None = discord.utils.get(
main_guild.channels,
id=channel_id
)
if not category:
if not channel:
await self.command_send_error(
ctx,
message=f"Category with ID {str(category_id)!r} does not exist."
message=f"Channel with ID {str(channel_id)!r} does not exist."
)
return

if "archive" in category.name:
if "archive" in channel.name:
await ctx.respond(
(
":information_source: No changes made. "
"Category has already been archived. :information_source:"
"Channel has already been archived. :information_source:"
),
ephemeral=True
)
return

# noinspection PyUnreachableCode
channel: (
discord.VoiceChannel
| discord.StageChannel
| discord.TextChannel
| discord.ForumChannel
| discord.CategoryChannel
)
for channel in category.channels:
try:
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(
try:
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)
)
await channel.edit(name=f"archive - {channel.name}")
if channel_needs_committee_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
await channel.set_permissions(
guest_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
member_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
committee_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)

elif channel_needs_normal_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
if channel_needs_committee_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
await channel.set_permissions(
guest_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
member_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
committee_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)

elif channel_needs_normal_archiving:
await channel.set_permissions(
everyone_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
await channel.set_permissions(
guest_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
member_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
committee_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
await channel.set_permissions(
archivist_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=True
)

else:
await self.command_send_error(
ctx,
message=f"Channel {channel.mention} had invalid permissions"
)
logger.error(
"Channel %s had invalid permissions, so could not be archived.",
channel.name
)
return

except discord.Forbidden:
await channel.set_permissions(
guest_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
member_role,
overwrite=None,
reason=f"{interaction_member.display_name} used \"/archive\"."
)
await channel.set_permissions(
committee_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=False
)
await channel.set_permissions(
archivist_role,
reason=f"{interaction_member.display_name} used \"/archive\".",
view_channel=True
)

else:
await self.command_send_error(
ctx,
message=(
"Bot does not have access to the channels in the selected category."
)
message=f"Channel {channel.mention} had invalid permissions"
)
logger.error(
(
"Bot did not have access to the channels in the selected category: "
"%s."
),
category.name
"Channel %s had invalid permissions, so could not be archived.",
channel.name
)
return
except discord.Forbidden:
await self.command_send_error(
ctx,
message=(
"Bot does not have access to the the selected channel."
)
)
logger.error(
(
"Bot did not have access to the selected channel: "
"%s."
),
channel.name
)
return

await ctx.respond("Category successfully archived", ephemeral=True)
await ctx.respond("Channel successfully archived", ephemeral=True)
Loading