From 2deda42194dbbd5c534f091241ea3a710b8f02ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Sun, 4 Sep 2022 21:41:40 +0000 Subject: [PATCH] CalEvent creation and validation --- api/ovdashboard_api/dav_calendar.py | 77 +++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/api/ovdashboard_api/dav_calendar.py b/api/ovdashboard_api/dav_calendar.py index ec82d5b..8ce54f6 100644 --- a/api/ovdashboard_api/dav_calendar.py +++ b/api/ovdashboard_api/dav_calendar.py @@ -5,7 +5,8 @@ from functools import total_ordering from typing import Iterator from caldav import Calendar -from pydantic import BaseModel +from caldav.lib.error import ReportError +from pydantic import BaseModel, validator from vobject.icalendar import VEvent from . import caldav_principal, get_ttl_hash, run_in_executor, timed_alru_cache @@ -13,12 +14,19 @@ from . import caldav_principal, get_ttl_hash, run_in_executor, timed_alru_cache _logger = logging.getLogger(__name__) +def _string_strip(in_str: str) -> str: + return in_str.strip() + + @total_ordering class CalEvent(BaseModel): - summary: str - description: str - dtstart: datetime - dtend: datetime + summary: str = "" + description: str = "" + dtstart: datetime = datetime.utcnow() + dtend: datetime = datetime.utcnow() + + class Config: + frozen = True def __lt__(self, other: "CalEvent") -> bool: return self.dtstart < other.dtstart @@ -26,6 +34,29 @@ class CalEvent(BaseModel): def __eq__(self, other: "CalEvent") -> bool: return self.dict() == other.dict() + _validate_summary = validator( + "summary", + allow_reuse=True, + )(_string_strip) + + _validate_description = validator( + "description", + allow_reuse=True, + )(_string_strip) + + @classmethod + def from_vevent(cls, event: VEvent) -> "CalEvent": + data = {} + + for key in cls().dict().keys(): + try: + data[key] = event.contents[key][0].value + + except KeyError: + pass + + return cls.parse_obj(data) + @timed_alru_cache(maxsize=20) async def _get_calendar( @@ -50,23 +81,37 @@ async def _get_calendar_events( print(f"updating {calendar_name}") calendar = caldav_principal().calendar(calendar_name) + + date_start = datetime.utcnow().date() + time_min = datetime.min.time() + dt_start = datetime.combine(date_start, time_min) + dt_end = dt_start + timedelta(days=365) + + try: + search_result = calendar.date_search( + start=dt_start, + end=dt_end, + expand=True, + verify_expand=True, + ) + + except ReportError: + _logger.warn("CalDAV server does not support expanded search") + + search_result = calendar.date_search( + start=dt_start, + end=dt_end, + expand=False, + ) + return ( vevent - for event in calendar.date_search( - start=datetime.now(), - end=datetime.now() + timedelta(days=365), - expand=True, - ) + for event in search_result for vevent in event.vobject_instance.contents["vevent"] ) return sorted([ - CalEvent( - summary=vevent.summary.value, - description=vevent.description.value, - dtstart=vevent.dtstart.value, - dtend=vevent.dtend.value, - ) + CalEvent.from_vevent(vevent) for vevent in await _inner() ])