1#!/usr/bin/env python 2# -*- encoding: utf-8 -*- 3from datetime import datetime 4try: 5 from datetime import timezone 6 utc_tz = timezone.utc 7except: 8 ## pytz is deprecated - but as of 2021-11, the icalendar library is only 9 ## compatible with pytz (see https://github.com/collective/icalendar/issues/333 https://github.com/collective/icalendar/issues/335 https://github.com/collective/icalendar/issues/336) 10 import pytz 11 utc_tz = pytz.utc 12 13from caldav.lib.namespace import ns 14from .base import BaseElement, NamedBaseElement, ValuedBaseElement 15 16def _to_utc_date_string(ts): 17 # type (Union[date,datetime]]) -> str 18 """coerce datetimes to UTC (assume localtime if nothing is given)""" 19 if (isinstance(ts, datetime)): 20 try: 21 ## for any python version, this should work for a non-native 22 ## timestamp. 23 ## in python 3.6 and higher, ts.astimezone() will assume a 24 ## naive timestamp is localtime (and so do we) 25 ts = ts.astimezone(utc_tz) 26 except: 27 ## native time stamp and the current python version is 28 ## not able to treat it as localtime. 29 import tzlocal 30 ts = ts.replace(tzinfo=tzlocal.get_localzone()) 31 ts = ts.astimezone(utc_tz) 32 33 return ts.strftime("%Y%m%dT%H%M%SZ") 34 35# Operations 36class CalendarQuery(BaseElement): 37 tag = ns("C", "calendar-query") 38 39class FreeBusyQuery(BaseElement): 40 tag = ns("C", "free-busy-query") 41 42class Mkcalendar(BaseElement): 43 tag = ns("C", "mkcalendar") 44 45class CalendarMultiGet(BaseElement): 46 tag = ns("C", "calendar-multiget") 47 48class ScheduleInboxURL(BaseElement): 49 tag = ns("C", "schedule-inbox-URL") 50 51class ScheduleOutboxURL(BaseElement): 52 tag = ns("C", "schedule-outbox-URL") 53 54# Filters 55class Filter(BaseElement): 56 tag = ns("C", "filter") 57 58 59class CompFilter(NamedBaseElement): 60 tag = ns("C", "comp-filter") 61 62 63class PropFilter(NamedBaseElement): 64 tag = ns("C", "prop-filter") 65 66 67class ParamFilter(NamedBaseElement): 68 tag = ns("C", "param-filter") 69 70 71# Conditions 72class TextMatch(ValuedBaseElement): 73 tag = ns("C", "text-match") 74 75 def __init__(self, value, collation="i;octet", negate=False): 76 super(TextMatch, self).__init__(value=value) 77 self.attributes['collation'] = collation 78 if negate: 79 self.attributes['negate-condition'] = "yes" 80 81 82class TimeRange(BaseElement): 83 tag = ns("C", "time-range") 84 85 def __init__(self, start=None, end=None): 86 ## start and end should be an icalendar "date with UTC time", 87 ## ref https://tools.ietf.org/html/rfc4791#section-9.9 88 super(TimeRange, self).__init__() 89 if start is not None: 90 self.attributes['start'] = _to_utc_date_string(start) 91 if end is not None: 92 self.attributes['end'] = _to_utc_date_string(end) 93 94 95class NotDefined(BaseElement): 96 tag = ns("C", "is-not-defined") 97 98 99# Components / Data 100class CalendarData(BaseElement): 101 tag = ns("C", "calendar-data") 102 103 104class Expand(BaseElement): 105 tag = ns("C", "expand") 106 107 def __init__(self, start, end=None): 108 super(Expand, self).__init__() 109 if start is not None: 110 self.attributes['start'] = _to_utc_date_string(start) 111 if end is not None: 112 self.attributes['end'] = _to_utc_date_string(end) 113 114 115class Comp(NamedBaseElement): 116 tag = ns("C", "comp") 117 118# Uhhm ... can't find any references to calendar-collection in rfc4791.txt 119# and newer versions of baikal gives 403 forbidden when this one is 120# encountered 121# class CalendarCollection(BaseElement): 122# tag = ns("C", "calendar-collection") 123 124 125# Properties 126class CalendarUserAddressSet(BaseElement): 127 tag = ns("C", "calendar-user-address-set") 128 129class CalendarUserType(BaseElement): 130 tag = ns("C", "calendar-user-type") 131 132class CalendarHomeSet(BaseElement): 133 tag = ns("C", "calendar-home-set") 134 135# calendar resource type, see rfc4791, sec. 4.2 136class Calendar(BaseElement): 137 tag = ns("C", "calendar") 138 139class CalendarDescription(ValuedBaseElement): 140 tag = ns("C", "calendar-description") 141 142 143class CalendarTimeZone(ValuedBaseElement): 144 tag = ns("C", "calendar-timezone") 145 146 147class SupportedCalendarComponentSet(ValuedBaseElement): 148 tag = ns("C", "supported-calendar-component-set") 149 150 151class SupportedCalendarData(ValuedBaseElement): 152 tag = ns("C", "supported-calendar-data") 153 154 155class MaxResourceSize(ValuedBaseElement): 156 tag = ns("C", "max-resource-size") 157 158 159class MinDateTime(ValuedBaseElement): 160 tag = ns("C", "min-date-time") 161 162 163class MaxDateTime(ValuedBaseElement): 164 tag = ns("C", "max-date-time") 165 166 167class MaxInstances(ValuedBaseElement): 168 tag = ns("C", "max-instances") 169 170 171class MaxAttendeesPerInstance(ValuedBaseElement): 172 tag = ns("C", "max-attendees-per-instance") 173 174class Allprop(BaseElement): 175 tag = ns("C", "allprop") 176 177class ScheduleTag(BaseElement): 178 tag = ns("C", "schedule-tag") 179