import json import re # import sys # needs the following version of discord.py for recurring events to work: https://github.com/DA-344/d.py/tree/recurrent_events # sys.path.insert(1, path_to_discorpy_version) import discord from discord.ext import commands, tasks from dotenv import load_dotenv from os import getenv from github_connector import create_or_update_file, delete_file, similar_exists load_dotenv("./.env") DISCORD_TOKEN = getenv("DISCORD_TOKEN") # Intents are required to listen to events like messages intents = discord.Intents.default() intents.message_content = True intents.members = True intents.reactions = True intents.dm_messages = True # Create an instance of the Bot bot = commands.Bot(command_prefix="!", intents=intents) def getCommitMessage(event): return f"{event.start_time.strftime("%Y-%m-%d")}_{event.name}" def getFilePath(event): return f"_events/{event.start_time.strftime("%Y")}/discord-event-{event.id}.md" def getEventYML(event): if hasattr(event.recurrence_rule, "frequency") and hasattr( event.recurrence_rule, "interval" ): return f'---\nlayout: event\ntitle: "{event.name}"\nauthor: "Netz39 e.V." \nevent:\n start: {event.start_time.strftime("%Y-%m-%d %H:%M:%S")} \n end: {event.end_time.strftime("%Y-%m-%d %H:%M:%S")} \n organizer: "Netz39 Team <kontakt@netz39.de>" \n location: "Leibnizstr. 18, 39104 Magdeburg"\n frequency: "{event.recurrence_rule.frequency}"\n interval: {event.recurrence_rule.interval}\n---\n<!-- event imported from discord manual changes may be overwritten -->' else: return f'---\nlayout: event\ntitle: "{event.name}"\nauthor: "Netz39 e.V." \nevent:\n start: {event.start_time.strftime("%Y-%m-%d %H:%M:%S")} \n end: {event.end_time.strftime("%Y-%m-%d %H:%M:%S")} \n organizer: "Netz39 Team <kontakt@netz39.de>" \n location: "Leibnizstr. 18, 39104 Magdeburg"\n---\n<!-- event imported from discord manual changes may be overwritten -->' def getAdmins(guild): admins = [] for member in guild.members: if member.guild_permissions.administrator: admins.append(member.id) return admins @tasks.loop(hours=24) # Runs every 7 days async def check_events(): await bot.wait_until_ready() for guild in bot.guilds: scheduledEvents = await guild.fetch_scheduled_events() for event in scheduledEvents: await handleEvent(event) async def handleEvent(event): guild = event.guild channel = guild.system_channel admins = getAdmins(guild) eventYML = getEventYML(event) file_path = getFilePath(event) commit_message = getCommitMessage(event) if event.creator_id in admins or similar_exists(event.name): create_or_update_file( file_path, eventYML, f"new event: {commit_message}", ) await channel.send( f"📅 New event '{event.name}' on {event.start_time.strftime("%Y-%m-%d")}." ) else: eventJSON = json.dumps( { "yml": eventYML, "path": file_path, "fileName": commit_message, "name": event.name, "date": event.start_time.strftime("%Y-%m-%d"), }, indent=2, ) for admin in admins: user = await bot.fetch_user(event.creator_id) await sendDm( admin, f"{user.name} added a new Event on {event.start_time.strftime("%Y")}: {event.name}. Like this message to approve.\n\n\n```json\n{eventJSON}```", ) # Event: When the bot is ready @bot.event async def on_ready(): print(f"Logged in as {discord.user}") # Command: !hello @bot.command() async def hello(ctx): await ctx.send( "Hello, I am a bot to add events from discord to the Netz39 calendar on the website!" ) @bot.event async def on_ready(): print(f"Logged in as {bot.user}") for guild in bot.guilds: system_channel = guild.system_channel if system_channel: await system_channel.send("Hello everyone! I'm online and ready to go! 📅") await check_events() @bot.event async def on_scheduled_event_update(event): if event.status != "canceled": await handleEvent(event) @bot.event async def on_scheduled_event_create(event): await handleEvent(event) async def sendDm(userID, message): user = await bot.fetch_user(userID) await user.send(message) @bot.event async def on_reaction_add(reaction, user): message = reaction.message channel = message.channel guild = message.guild admins = getAdmins(guild) if not user.id in admins: return # Ignore non-maintainers if user.bot: return # Ignore bot reactions if ( isinstance(message.channel, discord.DMChannel) and message.author.bot ): # Check if it's a DM and from the bot if reaction.emoji == "👍": messageJSON = json.loads( re.search( "(?s)(?<=```json).*?(?=```)", reaction.message.content ).group() ) create_or_update_file( messageJSON["path"], messageJSON["yml"], f"new event: {messageJSON["fileName"]}", ) await channel.send( f"📅 New event '{messageJSON["name"]}' on {messageJSON["date"]}." ) @bot.event async def on_scheduled_event_delete(event): delete_file(getFilePath(event)) guild = event.guild channel = guild.system_channel await channel.send(f"❌ Event has been canceled: {event.name}") bot.run(DISCORD_TOKEN)