from operator import itemgetter from typing import TYPE_CHECKING from zoneinfo import ZoneInfo import arrow import bleach import nh3 from django.conf import settings from django.utils.timezone import is_naive if TYPE_CHECKING: from .icalevents.icalparser import Event EVENT_KEYS = ("start", "end", "all_day", "summary", "description", "location", "url") def split_event_dict_list(event_list: "list[dict]") -> tuple[list[dict], list[dict]]: """Splits events and returns list of past events and future events.""" singularity = arrow.utcnow().shift(hours=-2) past = [ev for ev in event_list if ev["end"] < singularity] future = list(reversed([ev for ev in event_list if ev["end"] > singularity])) return past, future def set_event_description(event: "Event") -> "Event": """Clears even description from unwanted tags.""" description: str = event.description or "" event.description = bleach.clean(description, tags=["a", "br"], strip=True) return event def set_event_duration(event: "Event") -> "Event": """Sets duration for event.""" if event.all_day: event.duration = "celĂ˝ den" return event delta = event.end - event.start if delta.days < 1: begin = arrow.get(event.start).to(settings.TIME_ZONE).format("H:mm") end = arrow.get(event.end).to(settings.TIME_ZONE).format("H:mm") event.duration = f"{begin} - {end}" else: begin = arrow.get(event.start).to(settings.TIME_ZONE).format("H:mm") end = arrow.get(event.end).to(settings.TIME_ZONE).format("H:mm (D.M.)") event.duration = f"{begin} - {end}" return event def set_event_timezone(event: "Event") -> "Event": """Sets default project timezone for event if missing.""" if is_naive(event.start) or is_naive(event.end): event.start = event.start.replace(tzinfo=ZoneInfo(settings.TIME_ZONE)) event.end = event.end.replace(tzinfo=ZoneInfo(settings.TIME_ZONE)) return event def process_event(event: "Event") -> dict: """Processes single event for use in Majak""" event = set_event_timezone(event) event = set_event_duration(event) event = set_event_description(event) event.description = nh3.clean( event.description, tags={"h1", "h2", "h3", "h4", "h5", "h6", "a", "em", "p", "b", "strong", "br"}, ) # for event in sorted(cal.events, key=attrgetter("start"), reverse=True): TODO check return {key: getattr(event, key) for key in EVENT_KEYS} def process_event_list(event_list: "list[Event]") -> tuple[list[dict], list[dict]]: """Parses iCalendar source and returns events as list of dicts. Returns tuple of past and future events. """ processed_event_list = list(map(process_event, event_list)) processed_event_list = sorted( processed_event_list, key=itemgetter("start"), reverse=True ) return split_event_dict_list(processed_event_list)