-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #315 from medieteknik-kth/feature/repeatable_events
[project] Repeatable Events Implementation
- Loading branch information
Showing
17 changed files
with
675 additions
and
270 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from calendar import Calendar | ||
from datetime import timedelta | ||
from textwrap import dedent | ||
from typing import Any, Dict, List | ||
from models.content.event import Event, EventTranslation, Frequency | ||
from utility.translation import get_translation | ||
|
||
|
||
def generate_ics(calendar: Calendar, events: List[Event], language: str) -> str: | ||
ics = dedent(f"""\ | ||
BEGIN:VCALENDAR | ||
VERSION:2.0 | ||
X-WR-CALNAME:{calendar.name} | ||
X-WR-TIMEZONE:Europe/Stockholm | ||
PRODID:-//medieteknik//Calendar 1.0//{language[0:2].upper()} | ||
CALSCALE:GREGORIAN""") | ||
|
||
for event in events: | ||
if not event: | ||
continue | ||
translation = get_translation( | ||
EventTranslation, ["event_id"], {"event_id": event.event_id}, language | ||
) | ||
|
||
if not isinstance(translation, EventTranslation): | ||
return None | ||
|
||
rrule = "" | ||
if event.repeatable_event: | ||
rrule = f"FREQ={event.repeatable_event.frequency.value};".upper() | ||
|
||
if event.repeatable_event.interval: | ||
rrule += f"INTERVAL={event.repeatable_event.interval};" | ||
|
||
if event.repeatable_event.end_date: | ||
rrule += f"UNTIL={event.repeatable_event.end_date.strftime('%Y%m%dT%H%M%S')};" | ||
|
||
if event.repeatable_event.max_occurrences: | ||
rrule += f"COUNT={event.repeatable_event.max_occurrences};" | ||
|
||
ics += dedent(f""" | ||
BEGIN:VEVENT | ||
UID:{str(event.event_id) + '@medieteknik.com'} | ||
DTSTAMP:{event.created_at.strftime("%Y%m%dT%H%M%S" + "Z")} | ||
SUMMARY:{translation.title} | ||
LOCATION:{event.location} | ||
LAST-MODIFIED:{event.last_updated.strftime("%Y%m%dT%H%M%S" + "Z")} | ||
DTSTART:{event.start_date.strftime("%Y%m%dT%H%M%S") + "Z"} | ||
DTEND:{(event.start_date + timedelta(minutes=event.duration)).strftime("%Y%m%dT%H%M%S") + "Z"}""") | ||
if translation.description or rrule: | ||
ics += "\n" | ||
if translation.description: | ||
ics += f"DESCRIPTION:{translation.description}" | ||
|
||
if translation.description and rrule: | ||
ics += "\n" | ||
|
||
if rrule: | ||
ics += f"RRULE:{rrule}" | ||
|
||
ics += "\nEND:VEVENT" | ||
|
||
ics += "\nEND:VCALENDAR" | ||
ics = dedent(ics) | ||
|
||
return ics | ||
|
||
|
||
def generate_events(event: Event, start_date, end_date) -> List: | ||
""" | ||
Generate a list of occurrences for a repeatable event. | ||
Args: | ||
event: The event to generate occurrences for | ||
start_date: The start date of the range | ||
end_date: The end date of the range | ||
Returns: | ||
List: A list of occurrences for the event | ||
""" | ||
occurrences = [] | ||
current_occurrence = event.start_date | ||
occurrence_count = 0 | ||
|
||
if not event.repeatable_event: | ||
return occurrences | ||
|
||
repeat = event.repeatable_event | ||
|
||
while current_occurrence < end_date: | ||
event_end_time = current_occurrence + timedelta(minutes=event.duration) | ||
|
||
if (repeat.end_date and current_occurrence > repeat.end_date) or ( | ||
repeat.max_occurrences and occurrence_count >= repeat.max_occurrences | ||
): | ||
break | ||
|
||
if current_occurrence >= start_date: | ||
occurrences.append( | ||
{ | ||
"event": event, | ||
"start_date": current_occurrence, | ||
"end_date": event_end_time, | ||
} | ||
) | ||
occurrence_count += 1 | ||
|
||
match event.repeatable_event.frequency: | ||
case Frequency.DAILY: | ||
current_occurrence += timedelta(days=event.repeatable_event.interval) | ||
case Frequency.WEEKLY: | ||
current_occurrence += timedelta(weeks=event.repeatable_event.interval) | ||
case Frequency.MONTHLY: | ||
current_occurrence = current_occurrence.replace( | ||
month=current_occurrence.month + event.repeatable_event.interval | ||
) | ||
case Frequency.YEARLY: | ||
current_occurrence = current_occurrence.replace( | ||
year=current_occurrence.year + event.repeatable_event.interval | ||
) | ||
|
||
return occurrences |
Oops, something went wrong.