From da5450cd62477cfc08b340ee2769d408426ff378 Mon Sep 17 00:00:00 2001 From: Siphalor Date: Fri, 12 Mar 2021 14:14:05 +0100 Subject: [PATCH] Add och!groups command --- bot.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++- lib/config.py | 15 +++++++++ lib/utils.py | 11 ++++++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/bot.py b/bot.py index 39659ef..ad93de9 100644 --- a/bot.py +++ b/bot.py @@ -3,6 +3,7 @@ import os import random import re import time +from types import coroutine from typing import Optional, List import discord @@ -12,7 +13,7 @@ from dotenv import load_dotenv from lib.config import config, config_meta, config_load, config_save, config_get, config_set, config_get_descriptions, \ config_set_raw -from lib.utils import async_filter +from lib.utils import async_filter, find_category load_dotenv() TOKEN = os.getenv('DISCORD_TOKEN') @@ -346,6 +347,93 @@ async def quote_remove_command(ctx: commands.Context, author: str, quote: str): await ctx.channel.send("No such quote found!") +@bot.command(name='groups', brief="Manage groups") +async def group_command(ctx: commands.Context, subcommand: Optional[str], arg: Optional[str], + members: commands.Greedy[discord.Member]): + if subcommand is None: + await ctx.send("Available commands: `list`, `create`, `archive`") + return + + guild: discord.Guild = ctx.guild + role_prefix = config_get("groups-role-prefix", guild.id) + + def collect_group_channels(cat: discord.CategoryChannel) -> dict[str, discord.TextChannel]: + return {channel.name: channel for channel in cat.text_channels} + + async def collect_group_roles() -> list[discord.Role]: + return list(filter(lambda role: role.name.startswith(role_prefix), await guild.fetch_roles())) + + async def fail_category(type: str, expected: str): + await ctx.send("Unable to find channel category \"" + expected + "\" for " + type + ". Change in configs.") + + def link_channel(channel: discord.TextChannel, italic: bool = False) -> str: + if italic: + return '[*' + channel.name + '*](https://discord.com/channels/' + str(guild.id) + '/' + str(channel.id) + ')' + return '[' + channel.name + '](https://discord.com/channels/' + str(guild.id) + '/' + str(channel.id) + ')' + + groups_cat = find_category(guild, config_get("groups-category", guild.id)) + if groups_cat is None: + await fail_category("groups", config_get("groups-category", guild.id)) + return + + if subcommand == 'list': + archive_cat = find_category(guild, config_get("groups-archive-category", guild.id)) + if archive_cat is None: + await fail_category("archive", config_get("groups-archive-category", guild.id)) + return + + active_groups = collect_group_channels(groups_cat) + archived_groups = collect_group_channels(archive_cat) + + msg = "" + for role in await collect_group_roles(): + name = role.name[len(role_prefix):] + if name in active_groups: + msg += link_channel(active_groups[name]) + "\n" + elif name in archived_groups: + msg += link_channel(archived_groups[name], True) + "\n" + else: + msg += "*" + name + "*\n" + + embed = discord.Embed(title="Groups", description=msg) + embed.set_footer(text="Italic groups are archived or unavailable.") + await ctx.send(embed=embed) + elif subcommand == 'archive': + if arg is None: + await ctx.send("Group name required!") + return + + groups = collect_group_channels(groups_cat) + if arg in groups: + archive_cat = find_category(guild, config_get("groups-archive-category", guild.id)) + if archive_cat is None: + await fail_category("archive", config_get("groups-archive-category", guild.id)) + return + await groups[arg].edit(reason="Archive group " + arg, category=archive_cat) + + else: + await ctx.send("Can't find that group!") + elif subcommand == 'create': + if arg is None: + await ctx.send("Group name required!") + return + + arg.strip() + + cor = groups_cat.create_text_channel(arg.lower(), reason="Create group " + arg) + cor_role = guild.create_role(name=config_get("groups-role-prefix", guild.id) + arg, + mentionable=True, reason="Create group " + arg) + channel: discord.TextChannel = await cor + cor = channel.edit(sync_permissions=True) + role: discord.Role = await cor_role + await cor + await channel.set_permissions(role, reason="Create group " + arg, read_messages=True) + if members: + for member in members: + await member.add_roles(role, reason="Create group " + arg) + await channel.send("Hi, @" + role.name) + + def _is_message_valid_for_selection(message: discord.Message, reaction_filter: Optional[str] = None) -> bool: if message.clean_content.strip() == '': return False diff --git a/lib/config.py b/lib/config.py index f4dd0a5..1aa3d98 100644 --- a/lib/config.py +++ b/lib/config.py @@ -4,6 +4,9 @@ from typing import Optional, Any CONFIG = 'data/config.json' config: dict = { + 'groups-category': 'groups', + 'groups-archive-category': 'archive', + 'groups-role-prefix': 'group_', 'inf19x-insiders-enable': False, 'loeh-enable': False, 'och-timeout': 10, @@ -13,6 +16,18 @@ config: dict = { 'last-och-time': 0, } config_meta: dict = { + 'groups-category': ( + True, + 'Set the channel category to use for groups' + ), + 'groups-archive-category': ( + True, + 'Sets the archive channel category for groups' + ), + 'groups-role-prefix': ( + True, + 'Prefix to use for group roles' + ), 'inf19x-insiders-enable': ( True, 'Enables university insider jokes of INF19X' diff --git a/lib/utils.py b/lib/utils.py index 908cd65..1c7f654 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1,8 +1,17 @@ from collections import AsyncIterable -from typing import Callable, AsyncGenerator +from typing import Callable, AsyncGenerator, Optional +import discord async def async_filter(fun: Callable, iterable: AsyncIterable) -> AsyncGenerator: async for val in iterable: if fun(val): yield val + + +def find_category(guild: discord.Guild, group: str) -> Optional[discord.CategoryChannel]: + group = group.lower() + for cat in guild.categories: + if cat.name.lower() == group: + return cat + return None