Skip to content

Commit

Permalink
feat: Add listener for teacher perms change
Browse files Browse the repository at this point in the history
refactor: Split most of the logic into separate functions

docs: Add command description

refactor: Use embed description instead of field

refactor: use list, tuple, callablestring, cachedproperty

refactor: Use @cached_property for teacher_info_channel

feat: Don't ping, add full names

refactor: Remove TODOs
  • Loading branch information
1ukastesar committed Apr 12, 2024
1 parent 5de8f47 commit 1d3b3a1
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 31 deletions.
4 changes: 4 additions & 0 deletions cogs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def bot_room(self) -> disnake.TextChannel:
def bot_dev_channel(self) -> disnake.TextChannel:
return self.bot.get_channel(self.config.bot_dev_channel)

@cached_property
def teacher_info_channel(self) -> disnake.TextChannel:
return self.bot.get_channel(self.config.teacher_info_channel)

def cog_unload(self) -> None:
for task in self.tasks:
task.cancel()
59 changes: 28 additions & 31 deletions cogs/fitwide/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import subprocess
from datetime import datetime, timezone
from io import BytesIO

import disnake
Expand Down Expand Up @@ -502,6 +503,7 @@ async def fitwide_checks_error(self, inter: disnake.ApplicationCommandInteractio
@commands.check(room_check.is_in_modroom)
@commands.slash_command(name="gen_teacher_info", description=MessagesCZ.gen_teacher_info_brief)
async def gen_teacher_info(self, inter: disnake.ApplicationCommandInteraction):
"""Generate teacher info channel"""
await inter.response.defer()
await inter.send(MessagesCZ.gen_teacher_info_start)

Expand All @@ -511,24 +513,18 @@ async def gen_teacher_info(self, inter: disnake.ApplicationCommandInteraction):
for semester_name in features.CATEGORIES_NAMES
]

# TODO remove in production - masks errors we want to know about
# Remove None values
categories = [category for category in categories if category is not None]

# Check if all categories were found
if None in categories:
await inter.edit_original_response(MessagesCZ.gen_teacher_info_inv_catg)
return

teacher_roles = [
disnake.utils.get(inter.guild.roles, id=role_id) for role_id in self.config.teacher_roles
]
teacher_roles = await features.get_teacher_roles(inter.guild)

if None in teacher_roles:
await inter.edit_original_response(MessagesCZ.gen_teacher_info_inv_roles)
return

teacher_info_channel = self.bot.get_channel(self.config.teacher_info_channel)
teacher_info_channel = self.teacher_info_channel
if teacher_info_channel is None:
await inter.edit_original_response(MessagesCZ.gen_teacher_info_channel_none)
return
Expand All @@ -537,33 +533,34 @@ async def gen_teacher_info(self, inter: disnake.ApplicationCommandInteraction):
await teacher_info_channel.purge()
await teacher_info_channel.send(MessagesCZ.gen_teacher_info_header)

# Get all semester channels
# Run through all semester channels
for index, category in enumerate(categories):
progress_bar = utils.create_bar(index, len(categories))
await inter.edit_original_message(
content=MessagesCZ.gen_teacher_info_processing.format(progress_bar=progress_bar)
content=MessagesCZ.gen_teacher_info_processing(progress_bar=progress_bar)
)
for channel in category.channels:
channel_teachers = []
for user, permission in channel.overwrites.items():
if not isinstance(user, disnake.Member): # Only user overwrites
continue

# Check if user is a teacher
if not set(user.roles).intersection(teacher_roles):
continue

# Check if user has permission to read messages
if not permission.read_messages:
continue

channel_teachers.append(user)

if channel_teachers:
message = f"**{channel.name.upper()}:**\n"
for teacher in channel_teachers:
# TODO add teacher's full name
message += f"- {teacher.mention}\n"
await teacher_info_channel.send(message)
perms_list = await features.get_teacher_perms_list(channel, teacher_roles)
if perms_list is not None:
await teacher_info_channel.send(
perms_list, allowed_mentions=disnake.AllowedMentions.none()
)

await inter.edit_original_response(MessagesCZ.gen_teacher_info_success)

@commands.Cog.listener()
async def on_guild_channel_update(
self, before: disnake.abc.GuildChannel, after: disnake.abc.GuildChannel
) -> None:
"""Update teacher info channel on permissions change"""
if before.overwrites != after.overwrites and after.category.name in features.CATEGORIES_NAMES:
perms_list_before, perms_list_after = await features.update_teacher_info(
after, self.teacher_info_channel
)
if perms_list_before is None and perms_list_after is None:
return
embed = disnake.Embed(title="Teacher permissions update", color=disnake.Colour.yellow())
missing = "None"
embed.description = f"## Old permissions\n{perms_list_before or missing}\n## New permissions\n{perms_list_after or missing}"
embed.timestamp = datetime.now(tz=timezone.utc)
await self.log_channel.send(embed=embed, allowed_mentions=disnake.AllowedMentions.none())
68 changes: 68 additions & 0 deletions cogs/fitwide/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from disnake.ext import commands

import utils
from config.app_config import Config
from database.verification import ValidPersonDB

CATEGORIES_NAMES = [
"1. semestr", "2. semestr", "3. semestr", "4. semestr", "5. semestr",
Expand Down Expand Up @@ -71,3 +73,69 @@ async def set_channel_permissions_for_new_students(
for channel in channels:
await channel.set_permissions(bit0, read_messages=True)
await channel.set_permissions(mit0, read_messages=True)


async def get_teacher_roles(guild: disnake.Guild) -> list[disnake.Role]:
return [disnake.utils.get(guild.roles, id=role_id) for role_id in Config.teacher_roles]


async def get_teacher_perms_list(
channel: disnake.abc.GuildChannel, teacher_roles: list[disnake.Role]
) -> str | None:
"""Get message with teacher permissions"""
channel_teachers = []
for user, permission in channel.overwrites.items():
if not isinstance(user, disnake.Member): # Only user overwrites
continue

# Check if user is a teacher
if not set(user.roles).intersection(teacher_roles):
continue

# Check if user has permission to read messages
if not permission.read_messages:
continue

channel_teachers.append(user)

perms_list = None

if channel_teachers:
perms_list = f"**{channel.name.upper()}: {channel.mention}**\n"
for teacher in channel_teachers:
perms_list += f"- {teacher.mention}"
user = ValidPersonDB.get_user_by_id(teacher.id)
if user:
perms_list += f" ({user.name})"
perms_list += "\n"

return perms_list


async def update_teacher_info(
channel: disnake.abc.GuildChannel, teacher_info_channel: disnake.TextChannel
) -> tuple[str | None, str | None]:
"""Update teacher info channel"""
teacher_roles = await get_teacher_roles(channel.guild)
perms_list = await get_teacher_perms_list(channel, teacher_roles)

# Don't ping anyone
no_one = disnake.AllowedMentions.none()

if perms_list:
async for message in teacher_info_channel.history():
if message.author == channel.guild.me and channel.name.upper() in message.content:
old_content = message.content
await message.edit(content=perms_list, allowed_mentions=no_one)
return old_content, perms_list
elif channel.name.upper() in message.content:
old_content = message.content
await message.delete()
await teacher_info_channel.send(perms_list, allowed_mentions=no_one)
return old_content, perms_list

# Channel had no listing yet
await teacher_info_channel.send(perms_list, allowed_mentions=no_one)
return None, perms_list

return None, None

0 comments on commit 1d3b3a1

Please sign in to comment.