ovdashboard/api/ovdashboard_api/core/caldav.py

102 lines
2.7 KiB
Python
Raw Normal View History

2023-10-26 20:42:26 +00:00
import functools
import logging
2023-10-26 20:42:26 +00:00
import operator
from datetime import datetime, timedelta
2023-10-26 17:04:26 +00:00
from typing import cast
from asyncify import asyncify
2023-10-26 20:42:26 +00:00
from cachetools import TTLCache, cachedmethod
2023-10-26 16:50:04 +00:00
from caldav import Calendar, DAVClient, Event, Principal
2023-10-26 17:04:26 +00:00
from vobject.base import Component, toVName
from .calevent import CalEvent
from .config import Config
from .settings import SETTINGS
2023-10-26 20:42:26 +00:00
from .webdav import davkey
_logger = logging.getLogger(__name__)
class CalDAV:
_caldav_client = DAVClient(
url=SETTINGS.caldav.url,
username=SETTINGS.caldav.username,
password=SETTINGS.caldav.password,
)
2023-10-26 20:42:26 +00:00
_cache = TTLCache(
ttl=SETTINGS.caldav.cache_ttl,
maxsize=SETTINGS.caldav.cache_size,
)
@classmethod
2023-10-26 15:46:12 +00:00
@property
def principal(cls) -> Principal:
"""
Gets the `Principal` object of the main CalDAV client.
"""
return cls._caldav_client.principal()
2023-10-26 15:46:12 +00:00
@classmethod
@property
@asyncify
2023-10-26 20:42:26 +00:00
@cachedmethod(
cache=operator.attrgetter("_cache"),
key=functools.partial(davkey, "calendars"),
)
def calendars(cls) -> list[str]:
"""
Asynchroneously lists all calendars using the main WebDAV client.
"""
_logger.debug("calendars")
return [str(cal.name) for cal in cls.principal.calendars()]
2023-10-26 16:04:03 +00:00
@classmethod
@asyncify
2023-10-26 20:42:26 +00:00
@cachedmethod(
cache=operator.attrgetter("_cache"),
key=functools.partial(davkey, "get_calendar"),
)
def get_calendar(cls, calendar_name: str) -> Calendar:
"""
Get a calendar by name using the CalDAV principal object.
"""
return cls.principal.calendar(calendar_name)
@classmethod
2023-10-26 16:04:03 +00:00
@asyncify
2023-10-26 20:42:26 +00:00
@cachedmethod(
cache=operator.attrgetter("_cache"),
key=functools.partial(davkey, "get_events"),
)
def get_events(cls, calendar_name: str, cfg: Config) -> list[CalEvent]:
"""
Get a sorted list of events by CalDAV calendar name.
"""
_logger.info(f"downloading {calendar_name!r} ...")
2023-10-26 17:04:26 +00:00
dt_start = datetime.combine(
datetime.utcnow().date(),
datetime.min.time(),
)
dt_end = dt_start + timedelta(days=cfg.calendar.future_days)
2023-10-26 17:04:26 +00:00
search_result = cls.principal.calendar(calendar_name).search(
2023-10-26 16:50:04 +00:00
start=dt_start,
end=dt_end,
expand=True,
comp_class=Event,
split_expanded=False,
)
vevents = []
for event in search_result:
2023-10-26 17:04:26 +00:00
vobject = cast(Component, event.vobject_instance)
vevents.extend(vobject.contents[toVName("vevent")])
return sorted(CalEvent.from_vevent(vevent) for vevent in vevents)