diff --git a/.env.template b/.env.template index 14d809a1f04bd8efe90617ecaa35ef3e1042ee91..a9a427544e3f95d75fbfd3fa88b7745286896096 100644 --- a/.env.template +++ b/.env.template @@ -17,6 +17,8 @@ DISCORD_ROLE_MSG=<ID of role assignment message> DISCORD_SUPPORT_CHANNEL=<ID of channel where modmail & user news should be forwarded> DISCORD_WELCOME_CHANNEL=<ID of welcome channel> DISCORD_WELCOME_MSG=<ID of welcome message> +DISCORD_SEASONAL_EVENTS_CATEGORY=<ID of Seasonal Events Category> +DISCORD_ADVENT_CALENDAR_CHANNEL_2021=<ID of advent calendar chanel for 2021> # JSON Files DISCORD_CALMDOWN_FILE=<File name for calmdowns JSON file> @@ -25,6 +27,8 @@ DISCORD_ROLES_FILE=<File name for roles JSON file> DISCORD_TEXT_COMMANDS_FILE=<File name for text commands JSON file> DISCORD_TIMER_FILE=<File name for running timers JSON file> DISCORD_APPOINTMENTS_FILE=<File name for running appointments JSON file> +DISCORD_ADVENT_CALENDAR_FILE=<File name for advent calendar JSON file> # Misc DISCORD_DATE_TIME_FORMAT=<Date and time format used for commands like %d.%m.%Y %H:%M> +DISCORD_ADVENT_CALENDAR_START=<Start date and time for advent calendar. Something like "01.12.2021 00:00"> diff --git a/cogs/christmas.py b/cogs/christmas.py new file mode 100644 index 0000000000000000000000000000000000000000..9c530f52b33cb2263233e1b1b6e85f4d1aa64d3d --- /dev/null +++ b/cogs/christmas.py @@ -0,0 +1,169 @@ +import asyncio +import json +import os +from datetime import datetime, timedelta + +from disnake import ApplicationCommandInteraction, Member +from disnake.ext import commands, tasks +from dotenv import load_dotenv + +import utils + +load_dotenv() + + +def create_advent_calendar(): + advent_calendar = [] + startdate = utils.date_from_string(os.getenv("DISCORD_ADVENT_CALENDAR_START")).astimezone() + + for i in range(0, 24): + advent_calendar.append({ + "number": i + 1, + "date": utils.date_to_string(startdate + timedelta(days=i)), + "assigned": False, + "opened": False + }) + + return advent_calendar + + +class Christmas(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.seasonal_events_category = int(os.getenv("DISCORD_SEASONAL_EVENTS_CATEGORY")) + self.advent_calendar_channel = int(os.getenv("DISCORD_ADVENT_CALENDAR_CHANNEL_2021")) + self.file_name = os.getenv("DISCORD_ADVENT_CALENDAR_FILE") + self.advent_calendar = self.load() + self.advent_calendar_loop.start() + + def load(self): + with open(self.file_name, mode='r') as f: + advent_calendar = json.load(f) + + if len(advent_calendar) == 0: + advent_calendar = create_advent_calendar() + + return advent_calendar + + def save(self): + with open(self.file_name, mode='w') as f: + json.dump(self.advent_calendar, f) + + @commands.slash_command(name="advent", guild_ids=[int(os.getenv('DISCORD_GUILD'))]) + async def cmd_advent(self, interaction: ApplicationCommandInteraction): + pass + + @cmd_advent.sub_command(name="list", description="Erhalte die Liste aller Türchen mit Zuordnung und Thema") + @commands.check(utils.is_mod) + async def cmd_advent_list(self, interaction: ApplicationCommandInteraction): + message = f"__**Adventskalender 2021**__\n\n" + + for day in self.advent_calendar: + message += f"{day['number']}. " + if day["assigned"]: + message += f"<@!{day['assignee']}>: \"{day['name']}\"" + else: + message += f"noch nicht zugewiesen" + + message += "\n" + + await interaction.response.send_message(message, ephemeral=True) + + @cmd_advent.sub_command(name="assign", description="Einer Person ein Türchen zuweisen", + guild_ids=[int(os.getenv('DISCORD_GUILD'))]) + @commands.check(utils.is_mod) + async def cmd_advent_assign(self, interaction: ApplicationCommandInteraction, day: int, member: Member, name: str): + if self.advent_calendar[day - 1]["assigned"]: + await interaction.response.send_message("Das gewählte Türchen ist bereits vergeben. \n" + "Wenn du das Türchen an jemand anderen vergeben möchtest, oder das " + "Thema ändern möchtest, verwende `/advent reassign`.", + ephemeral=True) + else: + await interaction.response.defer(ephemeral=True) + await self.assign_day(day, member, name) + await interaction.edit_original_message(content="Das gewählte Türchen wurde vergeben.") + + @cmd_advent.sub_command(name="reassign", description="Ein Türchen neu zuweisen", + guild_ids=[int(os.getenv('DISCORD_GUILD'))]) + @commands.check(utils.is_mod) + async def cmd_advent_reassign(self, interaction: ApplicationCommandInteraction, day: int, member: Member, + name: str): + if not self.advent_calendar[day - 1]["assigned"]: + await interaction.response.send_message("Das gewählte Türchen ist noch nicht vergeben. \n" + "Bitte verwende `/advent assign` um das Türchen an " + "jemanden zu vergeben.", ephemeral=True) + else: + await interaction.response.defer(ephemeral=True) + channel = await self.bot.fetch_channel(self.advent_calendar[day - 1]["channel"]) + old_member = await self.bot.fetch_user(self.advent_calendar[day - 1]["assignee"]) + await channel.set_permissions(old_member, overwrite=None) + await self.assign_day(day, member, name) + await interaction.edit_original_message(content="Das gewählte Türchen wurde neu vergeben.") + + @cmd_advent.sub_command(name="remaining", description="Noch nicht zugewiesene Türchen ausgeben lassen.", + guild_ids=[int(os.getenv('DISCORD_GUILD'))]) + @commands.check(utils.is_mod) + async def cmd_advent_remaining(self, interaction: ApplicationCommandInteraction): + message = f"Noch verfügbare Türchen: " + + for day in self.advent_calendar: + if not day["assigned"]: + message += f"{day['number']}, " + + await interaction.response.send_message(message[:-2], ephemeral=True) + + async def assign_day(self, day: int, member: Member, name: str): + category = await self.bot.fetch_channel(self.seasonal_events_category) + channel = await category.create_text_channel(f"{day}-{name}") + await channel.set_permissions(member.roles[0], view_channel=False) + await channel.set_permissions(member, view_channel=True) + await channel.send(f"Vielen Dank {member.mention}, dass du für das {day}. Türchen etwas zum Thema {name} " + f"vorbereiten möchtest. Dieser Channel ist für dich gedacht. Du kannst hier deinen Beitrag " + f"vorbereiten.\n\n" + f"Am {day}.12.2021 um 00:00 werden alle Nachrichten von dir, die in diesem Channel bis " + f"dahin geschrieben wurden, in einen eigenen Thread für diesen Tag übernommen.\n\n" + f"Beachte bitte, dass Sticker nicht verwendet werden können. Das gleiche gilt für Emojis, " + f"die nicht von diesem Server sind.\n\n" + f"Das Mod-Team wünscht dir viel Spaß bei der Vorbereitung.") + self.advent_calendar[day - 1]["channel"] = channel.id + self.advent_calendar[day - 1]["assigned"] = True + self.advent_calendar[day - 1]["assignee"] = member.id + self.advent_calendar[day - 1]["name"] = name + self.save() + + async def open(self, day): + source_channel = await self.bot.fetch_channel(day["channel"]) + assignee = await self.bot.fetch_user(day["assignee"]) + target_channel = await self.bot.fetch_channel(self.advent_calendar_channel) + thread_name = f"{day['number']}. {day['name']}" + + message = await target_channel.send(f"{day['number']}. \"{day['name']}\", ein Beitrag von {assignee.mention}:") + thread = await message.create_thread(name=thread_name, auto_archive_duration=1440) + day["thread"] = thread.id + day["opened"] = True + + async for msg in source_channel.history(limit=None, oldest_first=True): + if msg.author == assignee: + if len(msg.stickers) > 0: + continue + files = await utils.files_from_attachments(msg.attachments) + await thread.send(content=msg.content, embeds=msg.embeds, files=files) + + await thread.send("--------------------------\nBeginn der Diskussion\n--------------------------") + + self.save() + + @tasks.loop(seconds=10) + async def advent_calendar_loop(self): + now = datetime.now() + for day in self.advent_calendar: + if not day["opened"]: + due_date = utils.date_from_string(day["date"]) + if due_date <= now: + await self.open(day) + else: + return + + @advent_calendar_loop.before_loop + async def before_advent_calendar_loop(self): + await asyncio.sleep(10 - datetime.now().second % 10) diff --git a/root.py b/root.py index 76127b1b95704f6f3fcbb9d14b7b9b0f13297ebb..384ff54544844fe78888f02a8a5c4147b73bb04a 100644 --- a/root.py +++ b/root.py @@ -4,7 +4,7 @@ import disnake from disnake.ext import commands from dotenv import load_dotenv -from cogs import appointments, calmdown, help, links, polls, roles, support, text_commands, timer, welcome +from cogs import appointments, calmdown, help, links, polls, roles, support, text_commands, timer, welcome, christmas # .env file is necessary in the same directory, that contains several strings. load_dotenv() @@ -38,6 +38,7 @@ class Root(commands.Bot): self.add_cog(text_commands.TextCommands(self)) self.add_cog(timer.Timer(self)) self.add_cog(welcome.Welcome(self)) + self.add_cog(christmas.Christmas(self)) bot = Root() diff --git a/utils.py b/utils.py index 28283e453d7bc62a42dab4fe6dfc400fde295a1b..01ee764a104abda7fafc5b35f98057d3aff5b825 100644 --- a/utils.py +++ b/utils.py @@ -1,7 +1,12 @@ import os import re +from datetime import datetime import disnake +from dotenv import load_dotenv + +load_dotenv() +DATE_TIME_FMT = os.getenv("DISCORD_DATE_TIME_FORMAT") async def send_dm(user, message, embed=None): @@ -41,3 +46,19 @@ def to_minutes(time): return h * 60 return int(time) + + +def date_to_string(date: datetime): + return date.strftime(DATE_TIME_FMT) + + +def date_from_string(date: str): + return datetime.strptime(date, DATE_TIME_FMT) + + +async def files_from_attachments(attachments): + files = [] + for attachment in attachments: + files.append(await attachment.to_file(spoiler=attachment.is_spoiler())) + + return files