From 20dfa9ef9f47e6ba52ebb4b2f4f959ffa9103166 Mon Sep 17 00:00:00 2001
From: 0ry5 <oscar.bloch@posteo.de>
Date: Tue, 29 Apr 2025 12:16:43 +0200
Subject: [PATCH] include d.py submodule by DA-344

---
 .gitmodules       |   3 ++
 Dockerfile        |   6 ++-
 bot.py            | 134 +++++++++++++++++++++++-----------------------
 d.py              |   1 +
 initSubmodules.sh |   3 ++
 5 files changed, 79 insertions(+), 68 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 d.py
 create mode 100644 initSubmodules.sh

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..fd97893
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "d.py"]
+	path = d.py
+	url = https://github.com/DA-344/d.py.git
diff --git a/Dockerfile b/Dockerfile
index 7c451c1..a41add0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,9 +2,11 @@ FROM python:3
 
 RUN mkdir /source
 
-COPY ./bot.py ./github_connector.py ./requirements.txt /source/
+COPY ./bot.py ./github_connector.py ./README.md ./requirements.txt ./.example.env ./initSubmodules.sh /source/
 
-WORKDIR /source
+WORKDIR /source/
+
+RUN bash initSubmodules.sh
 
 RUN pip install -r requirements.txt
 
diff --git a/bot.py b/bot.py
index 6c9e5f3..8ecc3b6 100644
--- a/bot.py
+++ b/bot.py
@@ -1,9 +1,8 @@
 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
-# uncomment following lines
-# import sys 
-# sys.path.insert(1, '/path/to/Posthorn/vendor/d.py')
+import sys
+
+sys.path.insert(1, "./d.py")
 import discord
 from discord.ext import commands, tasks
 from dotenv import load_dotenv
@@ -26,56 +25,70 @@ bot = commands.Bot(command_prefix="!", intents=intents)
 
 
 def getCommitMessage(event):
-    return f"{event.start_time.strftime('%Y-%m-%d')}_{event.name}"
+    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"
+    return f"_events/{event.start_time.strftime("%Y")}/discord-event-{event.id}.md"
+
+
+days = {
+    0: "MO",
+    1: "TU",
+    2: "WE",
+    3: "TH",
+    4: "FR",
+    5: "SA",
+    6: "SU",
+}
+
+
+def asDayStr(day):
+    return days[day]
+
+
+def asDayToupleStr(day):
+    return f"{day[0]}{days[day[1]]}"
+
+
+def weekdaysToString(weekdays):
+    asStr = map(asDayStr, weekdays)
+    return ",".join(asStr)
+
+
+def n_weekdaysToString(weekdays):
+    asStr = map(asDayToupleStr, weekdays)
+    return ",".join(asStr)
 
-def getDay(day):
-    match day:
-        case 0:
-            return 'MO'
-        case 1:
-            return 'TU'
-        case 2:
-            return 'WE'
-        case 3:
-            return 'TH'
-        case 4:
-            return 'FR'
-        case 5:
-            return 'SA'
-        case 6:
-            return 'SU'
-        case _:
-            raise Exception(f'no matching day for int {day}')
 
 def getRrule(event):
-    byDay = False
-    if hasattr(event.recurrence_rule, "n_weekdays"):
-        weekdays = event.recurrence_rule.n_weekdays
-        i = 0
-        for week, day in weekdays:
-            comma = ''
-            if i < len(weekdays) - 1:
-                comma = ','
-            byDay = f'{str(week)}{getDay(day)}{comma}'
-            i += 1
-    if byDay:
-        return f"FREQ={event.recurrence_rule.frequency.name.upper()};INTERVAL={event.recurrence_rule.interval};BYDAY={byDay}"
-    else:
-        return f"FREQ={event.recurrence_rule.frequency.name.upper()};INTERVAL={event.recurrence_rule.interval}"
+    recurrence_rule = event.recurrence_rule
+    rrule = ""
+    if hasattr(recurrence_rule, "frequency") and hasattr(recurrence_rule, "interval"):
+        freq = f"FREQ={str.upper(recurrence_rule.frequency.name)};"
+        inter = f"INTERVAL={recurrence_rule.interval};"
+        dtstart = f'DTSTART={event.start_time.strftime("%Y%m%dT%H%M%S")}'
+
+        if hasattr(recurrence_rule, "weekdays") and len(recurrence_rule.weekdays) != 0:
+            rrule = f'rrule: "{freq}{inter}BYDAY={weekdaysToString(recurrence_rule.weekdays)};{dtstart}"\n'
+        elif (
+            hasattr(recurrence_rule, "n_weekdays")
+            and len(recurrence_rule.n_weekdays) != 0
+        ):
+            rrule = f'rrule: "{freq}{inter}BYDAY={n_weekdaysToString(recurrence_rule.n_weekdays)};{dtstart}"\n'
+        else:
+            rrule = f'rrule: "{freq}{inter}{dtstart}"\n'
+    return rrule
+
 
 def getEventYML(event):
-    location = "LeibnizstraรŸe 32, 39104 Magdeburg"
-    if hasattr(event, 'location'):
-        location = event.location
-
-    if hasattr(event, "recurrence_rule") and 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: "{location}"\n  rrule: "{getRrule(event)}"\n---\n<!-- event imported from discord manual changes may be overwritten -->\n{event.description}'
+    base = 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'
+    comment = "<!-- event imported from discord manual changes may be overwritten -->"
+    if hasattr(event, "recurrence_rule"):
+        rrule = getRrule(event)
+        return f"{base}{rrule}---\n{comment}"
     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: "{location}"\n---\n<!-- event imported from discord manual changes may be overwritten -->\n{event.description}'
+        return f"{base}---\n{comment}"
 
 
 def getAdmins(guild):
@@ -92,10 +105,10 @@ async def check_events():
     for guild in bot.guilds:
         scheduledEvents = await guild.fetch_scheduled_events()
         for event in scheduledEvents:
-            await handleEvent(event, True)
+            await handleEvent(event)
 
 
-async def handleEvent(event, isUpdate = False):
+async def handleEvent(event, isNew=True):
     guild = event.guild
     channel = guild.system_channel
     admins = getAdmins(guild)
@@ -107,23 +120,12 @@ async def handleEvent(event, isUpdate = False):
         create_or_update_file(
             file_path,
             eventYML,
-            f"new event: {commit_message}",
+            f"{commit_message}",
         )
-        if not isUpdate:
-            embed = discord.Embed(
-                title=f"๐Ÿ“… New event on {event.start_time.strftime('%Y-%m-%d')}",
-                description=f"### {event.name}\n\n{event.description}\n\n",
-                color=discord.Color.light_embed()
+        if isNew:
+            await channel.send(
+                f"๐Ÿ“… New event '{event.name}' on {event.start_time.strftime("%Y-%m-%d")}."
             )
-            if hasattr(event, "cover_image") and event.cover_image:
-                embed.set_image(url=event.cover_image.url)
-            embed.add_field(name="๐Ÿ“… Time", value=event.start_time.strftime("%Y-%m-%d %HUhr"), inline=True)
-            if hasattr(event, 'location'):
-                embed.add_field(name="๐Ÿ“ Location", value=event.location, inline=True)
-            eventLink = f"[๐Ÿ”— Netz39](https://www.netz39.de/events/2025/discord-event-{event.id})";
-            embed.add_field(value=eventLink, name="", inline=False)
-            embed.set_footer(text="Donโ€™t miss it! ")
-            await channel.send(embed=embed)
     else:
         eventJSON = json.dumps(
             {
@@ -139,7 +141,7 @@ async def handleEvent(event, isUpdate = False):
             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}```",
+                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}```",
             )
 
 
@@ -170,7 +172,7 @@ async def on_ready():
 @bot.event
 async def on_scheduled_event_update(before, after):
     if after.status != "canceled":
-        await handleEvent(after, True)
+        await handleEvent(after, False)
 
 
 @bot.event
@@ -207,10 +209,10 @@ async def on_reaction_add(reaction, user):
             create_or_update_file(
                 messageJSON["path"],
                 messageJSON["yml"],
-                f"new event: {messageJSON['fileName']}",
+                f"new event: {messageJSON["fileName"]}",
             )
             await channel.send(
-                f"๐Ÿ“… New event '{messageJSON['name']}' on {messageJSON['date']}."
+                f"๐Ÿ“… New event '{messageJSON["name"]}' on {messageJSON["date"]}."
             )
 
 
diff --git a/d.py b/d.py
new file mode 160000
index 0000000..7756a3a
--- /dev/null
+++ b/d.py
@@ -0,0 +1 @@
+Subproject commit 7756a3a206f0792e34410e999b5280e32318880c
diff --git a/initSubmodules.sh b/initSubmodules.sh
new file mode 100644
index 0000000..70b4ec0
--- /dev/null
+++ b/initSubmodules.sh
@@ -0,0 +1,3 @@
+git clone 'https://github.com/DA-344/d.py.git'
+cd d.py
+git checkout 'recurrent_events'
\ No newline at end of file