diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..57a530e --- /dev/null +++ b/app/models.py @@ -0,0 +1,99 @@ +from datetime import datetime, date, timedelta, timezone +from caldav.objects import Event as CaldavEvent +import dataclasses + +from icalendar import Event as IcEvent +from icalendar import Calendar as Icalendar + +@dataclasses.dataclass +class Event(): + summary: str + dtstart: datetime + dtend: datetime + is_all_day: bool + + @classmethod + def fromCalDavEvents(cls, caldav_events: [CaldavEvent]) -> list['Event']: + + events = [] + + for event in caldav_events: + date_value = event.vobject_instance.vevent.dtstart.value + if isinstance(date_value, datetime): + dt_start = date_value + is_all_day = False + elif isinstance(date_value, date): + d_start = date_value + dt_start = datetime(d_start.year, d_start.month, d_start.day, tzinfo=datetime.now(timezone.utc).astimezone().tzinfo) + is_all_day = True + else: + raise Exception + + date_value = event.vobject_instance.vevent.dtend.value + if isinstance(date_value, datetime): + dt_end = date_value + elif isinstance(date_value, date): + d_end = date_value + dt_end = datetime(d_end.year, d_end.month, d_end.day,tzinfo=datetime.now(timezone.utc).astimezone().tzinfo) + date_value = dt_end + else: + raise Exception + + events.append(Event( + summary=event.vobject_instance.vevent.summary.value, + dtstart=dt_start, + dtend=dt_end, + is_all_day = is_all_day + )) + return events + + @classmethod + def fromIcalendar(cls, icalendar: Icalendar) -> list['Event']: + events = [] + for event in [e for e in icalendar.subcomponents if isinstance(e, IcEvent)]: + date_value = event['DTSTART'].dt + if isinstance(date_value, datetime): + dt_start = date_value + is_all_day = False + elif isinstance(date_value, date): + d_start = date_value + dt_start = datetime(d_start.year, d_start.month, d_start.day, tzinfo=datetime.now(timezone.utc).astimezone().tzinfo) + is_all_day = True + else: + raise Exception + + date_value = event['DTEND'].dt if event.get('DTEND') else event['DTSTART'].dt + if isinstance(date_value, datetime): + dt_end = date_value + elif isinstance(date_value, date): + d_end = date_value + dt_end = datetime(d_end.year, d_end.month, d_end.day,tzinfo=datetime.now(timezone.utc).astimezone().tzinfo) + else: + raise Exception + + events.append(Event( + summary=event['summary'], + dtstart=dt_start, + dtend=dt_end, + is_all_day = is_all_day + )) + + return events + + @property + def range_str(self) -> str: + start_time_str = self.dtstart.strftime('%-I') + end_time_str = self.dtend.strftime('%-I') + + if not(self.dtstart.hour and self.dtend.hour): + return "" + + if self.dtstart.minute: start_time_str += self.dtstart.strftime(':%M') + if self.dtend.minute: end_time_str += self.dtend.strftime(':%M') + + if not ((self.dtstart.hour < 12 and self.dtend.hour < 12) or (self.dtstart.hour > 12 and self.dtend.hour > 12)): + start_time_str += self.dtstart.strftime("%p") + + end_time_str += self.dtend.strftime("%p") + + return f"{start_time_str}-{end_time_str}" diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html index 0d1d556..bced635 100644 --- a/app/templates/dashboard.html +++ b/app/templates/dashboard.html @@ -18,19 +18,19 @@
- {% for day, event in days %} + {% for day, events in days %}
{{ day.strftime('%A') }}
- {% if event %} + {% for event in events %}
- {{ event.summary.value }}
- {% if event.dtstart.value.strftime('%H') != "00" %} - {{ event.dtstart.value.strftime('%-I:%M %p') }}
{{ event.dtend.value.strftime('%-I:%M %p') }} + {{ event.summary }}
+ {% if not event.is_all_day %} + {{ event.range_str }} {% endif %}
- {% endif %} + {% endfor %}
{% endfor %}
diff --git a/app/views.py b/app/views.py index be5edcd..5249bd1 100644 --- a/app/views.py +++ b/app/views.py @@ -1,12 +1,13 @@ from app import app -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import os import caldav import datetime from icalendar import cal, Event from flask import render_template +from .models import Event import requests -url = os.getenv('caldav_url') +caldav_url = os.getenv('caldav_url') username = os.getenv('username') password = os.getenv('password') cal_id = os.getenv('cal_id') @@ -17,42 +18,49 @@ def daterange(start_date, end_date): yield datetime.datetime.date(start_date + timedelta(n)) @app.route('/') -def hello_world(): - date_obj = datetime.datetime.now() - - start_of_week = date_obj - timedelta(days=date_obj.weekday()) # Monday +def dashboard(): + today = datetime.datetime.now(tz=datetime.datetime.now(timezone.utc).astimezone().tzinfo) + # today = datetime.datetime(2022,5,30, tzinfo=datetime.datetime.now(timezone.utc).astimezone().tzinfo) + start_of_week = today - timedelta(days=today.weekday()) # Monday end_of_week = start_of_week + timedelta(days=7) # Sunday - with caldav.DAVClient(url=url, username=username, password=password) as client: + events = [] + + for url in [ + 'https://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics', + ]: + r = requests.get(url) + c = cal.Calendar.from_ical(r.content) + + events += Event.fromIcalendar(c) + + with caldav.DAVClient(url=caldav_url, username=username, password=password) as client: my_principal = client.principal() calendars = my_principal.calendars() - calendar = my_principal.calendar(cal_id=cal_id) - events_fetched = calendar.date_search( - start=start_of_week, end=end_of_week, expand=False) + for id in [cal_id]: + calendar = my_principal.calendar(cal_id=id) + events += Event.fromCalDavEvents(calendar.date_search( + start=start_of_week, end=end_of_week, expand=False)) - events_fetched_by_date = {} - for event in events_fetched: - value = event.vobject_instance.vevent.dtstart.value - if isinstance(value, datetime.datetime): - events_fetched_by_date[datetime.datetime.date(value)] = event - elif isinstance(value, datetime.date): - events_fetched_by_date[value] = event - else: - raise Exception + for url in [ + 'http://ical-cdn.teamsnap.com/team_schedule/5f1ddc9e-15b0-4912-84a2-11cc70e9e375.ics' + ]: + r = requests.get(url) + c = cal.Calendar.from_ical(r.content) + + events += Event.fromIcalendar(c) + + days = [] + for single_date in daterange(start_of_week, end_of_week): + days_events = [e for e in events if (e.dtstart.date() <= single_date <= e.dtend.date())] + days.append((single_date, days_events)) - days = [] - for single_date in daterange(start_of_week, end_of_week): - event = events_fetched_by_date.get(single_date) - if event: - days.append((single_date, event.vobject_instance.vevent)) - else: - days.append((single_date,[])) # breakpoint() pass # r = "
".join([event.vobject_instance.vevent.summary.value for event in events_fetched if event.vobject_instance.vevent.dtstart.value < datetime.now()]) - return render_template("dashboard.html", days=days, today=datetime.datetime.now()) + return render_template("dashboard.html", + days=days, + today=today) -if __name__ == '__main__': - app.run(host='0.0.0.0', port=81) \ No newline at end of file