import json import re # needs the following version of discord.py for recurring events to work: https://github.com/DA-344/d.py/tree/recurrent_events 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") CHANNEL_ID = int(getenv("CHANNEL_ID")) GUILD_ID = int(getenv("GUILD_ID")) MAINTAINERS = json.loads(getenv("MAINTAINERS")) 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): return f'<!-- event imported from discord manual changes may be overwritten\n -->---\n \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} ---' def addMaintainer(maintainer): MAINTAINERS.append(maintainer) with open(".env", "r") as fileR: # read a list of lines into data data = fileR.readlines() data[6] = f"MAINTAINERS='{json.dumps(MAINTAINERS)}'" with open(".env", "w") as fileW: fileW.writelines(data) @tasks.loop(hours=24) # Runs every 7 days async def check_events(): await bot.wait_until_ready() guild = bot.get_guild(GUILD_ID) channel = guild.get_channel(CHANNEL_ID) if not channel: return scheduledEvents = await guild.fetch_scheduled_events() for event in scheduledEvents: await handleEvent(event) async def handleEvent(event): eventYML = getEventYML(event) file_path = getFilePath(event) commit_message = getCommitMessage(event) if event.creator_id in MAINTAINERS or similar_exists(event.name): create_or_update_file( file_path, eventYML, f"new event: {commit_message}", ) channel = bot.get_channel(CHANNEL_ID) 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 maintainer in MAINTAINERS: user = await bot.fetch_user(event.creator_id) await sendDm( maintainer, 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}") channel = bot.get_channel(CHANNEL_ID) await channel.send("Hello everyone! I'm online and ready to go! 📅") await check_events() @bot.event async def on_scheduled_event_update(event): 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): if not user.id in MAINTAINERS: return # Ignore non-maintainers if user.bot: return # Ignore bot reactions if ( isinstance(reaction.message.channel, discord.DMChannel) and reaction.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"]}", ) channel = bot.get_channel(CHANNEL_ID) await channel.send( f"📅 New event '{messageJSON["name"]}' on {messageJSON["date"]}." ) @bot.event async def on_scheduled_event_delete(event): delete_file(getFilePath(event)) channel = bot.get_channel(CHANNEL_ID) await channel.send(f"❌ Event has been canceled: {event.name}") bot.run(DISCORD_TOKEN)