def _deserialize(self, data): """ Convert a JSON compatible serialization of this object into the actual object. """ self.start = DateTime.parseText(data["start"]) if data["start"] else None self.end = DateTime.parseText(data["end"]) if data["end"] else None self.tzinfo = Timezone(tzid=data["tzinfo"]) if data["tzinfo"] else None
def testRoundtrip(self): data1 = ( "20110102", "20110103T121212", "20110103T121212Z", "00010102", "00010103T121212", "00010103T121212Z", ) data2 = ( ("20110102", "20110102"), ("2011-01-02", "20110102"), ("20110103T121212", "20110103T121212"), ("2011-01-03T12:12:12", "20110103T121212"), ("20110103T121212Z", "20110103T121212Z"), ("2011-01-03T12:12:12Z", "20110103T121212Z"), ("20110103T121212+0100", "20110103T121212+0100"), ("2011-01-03T12:12:12-0500", "20110103T121212-0500"), ("20110103T121212,123", "20110103T121212"), ("2011-01-03T12:12:12,123", "20110103T121212"), ("20110103T121212,123Z", "20110103T121212Z"), ("2011-01-03T12:12:12,123Z", "20110103T121212Z"), ("20110103T121212,123+0100", "20110103T121212+0100"), ("2011-01-03T12:12:12,123-0500", "20110103T121212-0500"), ) for item in data1: dt = DateTime.parseText(item, False) self.assertEqual(dt.getText(), item, "Failed on: %s" % (item,)) for item, result in data2: dt = DateTime.parseText(item, True) self.assertEqual(dt.getText(), result, "Failed on: %s" % (item,))
def testRoundtrip(self): data1 = ( "20110102", "20110103T121212", "20110103T121212Z", "00010102", "00010103T121212", "00010103T121212Z", ) data2 = ( ("20110102", "20110102"), ("2011-01-02", "20110102"), ("20110103T121212", "20110103T121212"), ("2011-01-03T12:12:12", "20110103T121212"), ("20110103T121212Z", "20110103T121212Z"), ("2011-01-03T12:12:12Z", "20110103T121212Z"), ("20110103T121212+0100", "20110103T121212+0100"), ("2011-01-03T12:12:12-0500", "20110103T121212-0500"), ("20110103T121212,123", "20110103T121212"), ("2011-01-03T12:12:12,123", "20110103T121212"), ("20110103T121212,123Z", "20110103T121212Z"), ("2011-01-03T12:12:12,123Z", "20110103T121212Z"), ("20110103T121212,123+0100", "20110103T121212+0100"), ("2011-01-03T12:12:12,123-0500", "20110103T121212-0500"), ) for item in data1: dt = DateTime.parseText(item, False) self.assertEqual(dt.getText(), item, "Failed on: %s" % (item, )) for item, result in data2: dt = DateTime.parseText(item, True) self.assertEqual(dt.getText(), result, "Failed on: %s" % (item, ))
def test_calendar_query_bogus_timezone_id(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ TimezoneCache.create() self.addCleanup(TimezoneCache.clear) calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData(), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(),), end="%04d1101T000000Z" % (DateTime.getToday().getYear(),), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), caldavxml.TimeZoneID.fromString("bogus"), ) result = yield self.calendar_query(query, got_xml=None, expected_code=responsecode.FORBIDDEN) self.assertTrue("valid-timezone" in result)
def _addTask(self): # Don't perform any operations until the client is up and running if not self._client.started: return succeed(None) calendars = self._calendarsOfType(caldavxml.calendar, "VTODO") while calendars: calendar = self.random.choice(calendars) calendars.remove(calendar) # Copy the template task and fill in some of its fields # to make a new task to create on the calendar. vcalendar = self._taskTemplate.duplicate() vtodo = vcalendar.mainComponent() uid = str(uuid4()) due = self._taskStartDistribution.sample() vtodo.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vtodo.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vtodo.replaceProperty(Property("DUE", due)) vtodo.replaceProperty(Property("UID", uid)) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def getVToDos(self, only_due, all_dates, upto_due_date, list): # Get current date-time less one day to test for completed events during the last day minusoneday = DateTime() minusoneday.setNowUTC() minusoneday.offsetDay(-1) today = DateTime() today.setToday() # Look at each VToDo for vtodo in self.getComponents(definitions.cICalComponent_VTODO): # Filter out done (that were complted more than a day ago) or cancelled to dos if required if only_due: if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled: continue elif ( (vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and (not vtodo.hasCompleted() or (vtodo.getCompleted() < minusoneday)) ): continue # Filter out those with end after chosen date if required if not all_dates: if vtodo.hasEnd() and (vtodo.getEnd() > upto_due_date): continue elif not vtodo.hasEnd() and (today > upto_due_date): continue
def _initEvent(self): # Don't perform any operations until the client is up and running if not self._client.started: return succeed(None) try: calendar = self._calendarsOfType(caldavxml.calendar, "VEVENT")[0] except IndexError: # There is no calendar return succeed(None) self.myEventHref = '{}{}.ics'.format(calendar.url, str(uuid4())) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) vevent.replaceProperty(Property("DESCRIPTION", "AlarmAcknowledger")) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) d = self._client.addEvent(self.myEventHref, vcalendar) return self._newOperation("create", d)
def test_calendar_query_bogus_timezone_id(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ TimezoneCache.create() self.addCleanup(TimezoneCache.clear) calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData(), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(), ), end="%04d1101T000000Z" % (DateTime.getToday().getYear(), ), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), caldavxml.TimeZoneID.fromString("bogus"), ) result = yield self.calendar_query( query, got_xml=None, expected_code=responsecode.FORBIDDEN) self.assertTrue("valid-timezone" in result)
def __init__(self, parent=None): super(VToDo, self).__init__(parent=parent) self.mPriority = 0 self.mStatus = definitions.eStatus_VToDo_None self.mPercentComplete = 0 self.mCompleted = DateTime() self.mHasCompleted = False
def actionExpand(self, request, tzid): """ Expand a timezone within specified start/end dates. """ if set(request.args.keys()) - set(("start", "end",)): self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST) start = request.args.get("start", ()) if len(start) == 0: self.problemReport("invalid-start", "Missing start request-URI query parameter", responsecode.BAD_REQUEST) if len(start) > 1: self.problemReport("invalid-start", "Too many start request-URI query parameters", responsecode.BAD_REQUEST) elif len(start) == 1: try: if len(start[0]) != 20: raise ValueError() start = DateTime.parseText(start[0], fullISO=True) except ValueError: self.problemReport("invalid-start", "Invalid start request-URI query parameter value", responsecode.BAD_REQUEST) end = request.args.get("end", ()) if len(end) == 0: self.problemReport("invalid-end", "Missing end request-URI query parameter", responsecode.BAD_REQUEST) if len(end) > 1: self.problemReport("invalid-end", "Too many end request-URI query parameters", responsecode.BAD_REQUEST) elif len(end) == 1: try: if len(end[0]) != 20: raise ValueError() end = DateTime.parseText(end[0], fullISO=True) except ValueError: self.problemReport("invalid-end", "Invalid end request-URI query parameter value", responsecode.BAD_REQUEST) if end <= start: self.problemReport("invalid-end", "Invalid end request-URI query parameter value - earlier than start", responsecode.BAD_REQUEST) tzdata = self.timezones.getTimezone(tzid) if tzdata is None: self.problemReport("tzid-not-found", "Time zone identifier not found", responsecode.NOT_FOUND) # Now do the expansion (but use a cache to avoid re-calculating TZs) observances = self.expandcache.get((tzid, start, end), None) if observances is None: observances = tzexpandlocal(tzdata, start, end, utc_onset=True) self.expandcache[(tzid, start, end)] = observances # Turn into JSON result = { "dtstamp": self.timezones.dtstamp, "tzid": tzid, "observances": [ { "name": name, "onset": onset.getXMLText(), "utc-offset-from": utc_offset_from, "utc-offset-to": utc_offset_to, } for onset, utc_offset_from, utc_offset_to, name in observances ], } return JSONResponse(responsecode.OK, result, pretty=config.TimezoneService.PrettyPrintJSON)
def _addEvent(self): if not self._client.started: return succeed(None) calendars = self._calendarsOfType(caldavxml.calendar, "VEVENT") while calendars: calendar = self.random.choice(calendars) calendars.remove(calendar) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def doIt(self, txn): uid = raw_input("Owner UID/Name: ") start = raw_input("Start Time (UTC YYYYMMDDTHHMMSSZ or YYYYMMDD): ") if len(start) == 8: start += "T000000Z" end = raw_input("End Time (UTC YYYYMMDDTHHMMSSZ or YYYYMMDD): ") if len(end) == 8: end += "T000000Z" try: start = DateTime.parseText(start) except ValueError: print("Invalid start value") returnValue(None) try: end = DateTime.parseText(end) except ValueError: print("Invalid end value") returnValue(None) timerange = caldavxml.TimeRange(start=start.getText(), end=end.getText()) home = yield txn.calendarHomeWithUID(uid) if home is None: print("Could not find calendar home") returnValue(None) yield self.eventsForEachCalendar(home, uid, timerange)
def test_freebusy(self): """ Test that action=component works. """ yield self.createShare("user01", "puser01") calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar") yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1)) yield self.commitTransaction(0) fbstart = "{now:04d}0102T000000Z".format(**self.nowYear) fbend = "{now:04d}0103T000000Z".format(**self.nowYear) shared = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", name="shared-calendar") fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(DateTime.parseText(fbstart), DateTime.parseText(fbend)) organizer = recipient = (yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.theTransactionUnderTest(1))) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange) matchtotal = (yield freebusy.generateFreeBusyInfo([shared, ], fbinfo)) self.assertEqual(matchtotal, 1) self.assertEqual(fbinfo[0], [Period.parseText("{now:04d}0102T140000Z/PT1H".format(**self.nowYear)), ]) self.assertEqual(len(fbinfo[1]), 0) self.assertEqual(len(fbinfo[2]), 0) yield self.commitTransaction(1)
def test_purgeOldEvents(self): # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 13) # Actually remove total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, debug=True )) self.assertEquals(total, 13) # There should be no more left total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, debug=True )) self.assertEquals(total, 0)
def _initEvent(self): if not self._client.started: return succeed(None) # If it already exists, don't re-create calendar = self._calendarsOfType(caldavxml.calendar, "VEVENT")[0] if calendar.events: events = [ event for event in calendar.events.values() if event.url.endswith("event_to_update.ics") ] if events: return succeed(None) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration( seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) href = '%s%s' % (calendar.url, "event_to_update.ics") d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def _addEvent(self): # Don't perform any operations until the client is up and running if not self._client.started: return succeed(None) calendar = self._getRandomCalendarOfType('VEVENT') if not calendar: # No VEVENT calendars, so no new event... return succeed(None) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration( seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def _addAvailabilityComponent(self, component, lowerLimit, upperLimit): """ Add the specified master VAVAILABILITY Component to the instance list, expanding it within the supplied time range. VAVAILABILITY components are not recurring, they have an optional DTSTART and DTEND/DURATION defining a single time-range which may be bounded depending on the presence of the properties. If unbounded at one or both ends, we will set the time to 1/1/1900 in the past and 1/1/3000 in the future. @param component: the Component to expand @param limit: the end L{DateTime} for expansion """ start = component.getStartDateUTC() if start: lowerLimit, upperLimit = self._setupLimits(start, lowerLimit, upperLimit) if start is not None and start >= upperLimit: # If the availability is beyond the end of the range we want, ignore it return if start is None: start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) start = self.normalizeFunction(start) end = component.getEndDateUTC() if lowerLimit is not None and end is not None and end < lowerLimit: # If the availability is before the start of the range we want, ignore it return if end is None: end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) end = self.normalizeFunction(end) self.addInstance(Instance(component, start, end))
def initNextTrigger(self): # Do not bother if its completed if self.mAlarmStatus == definitions.eAlarm_Status_Completed: return self.mStatusInit = True # Look for trigger immediately preceeding or equal to utc now nowutc = DateTime.getNowUTC() # Init done counter self.mDoneCount = 0 # Determine the first trigger trigger = DateTime() self.getFirstTrigger(trigger) while self.mDoneCount < self.mRepeats: # See if next trigger is later than now next_trigger = trigger + self.mRepeatInterval if next_trigger > nowutc: break self.mDoneCount += 1 trigger = next_trigger # Check for completion if trigger == self.mLastTrigger or ( nowutc - trigger).getTotalSeconds() > 24 * 60 * 60: if self.mDoneCount == self.mRepeats: self.mAlarmStatus = definitions.eAlarm_Status_Completed return else: trigger = trigger + self.mRepeatInterval self.mDoneCount += 1 self.mNextTrigger = trigger
def parseSQLTimestampToPyCalendar(ts, withTimezone=None): """ Parse an SQL formated timestamp into a DateTime @param ts: the SQL timestamp @type ts: C{str} @return: L{DateTime} result """ if isinstance(ts, datetime): return DateTime( year=ts.year, month=ts.month, day=ts.day, hours=ts.hour, minutes=ts.minute, seconds=ts.second, tzid=withTimezone, ) else: # Format is "%Y-%m-%d %H:%M:%S" return DateTime( year=int(ts[0:4]), month=int(ts[5:7]), day=int(ts[8:10]), hours=int(ts[11:13]), minutes=int(ts[14:16]), seconds=int(ts[17:19]), tzid=withTimezone, )
def _addEvent(self): if not self._client.started: return succeed(None) calendars = self._calendarsOfType(caldavxml.calendar, "VEVENT") while calendars: calendar = self.random.choice(calendars) calendars.remove(calendar) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration( seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def __init__(self, parent=None): super(VAlarm, self).__init__(parent=parent) self.mAction = definitions.eAction_VAlarm_Display self.mTriggerAbsolute = False self.mTriggerOnStart = True self.mTriggerOn = DateTime() # Set duration default to 1 hour self.mTriggerBy = Duration() self.mTriggerBy.setDuration(60 * 60) # Does not repeat by default self.mRepeats = 0 self.mRepeatInterval = Duration() self.mRepeatInterval.setDuration(5 * 60) # Five minutes # Status self.mStatusInit = False self.mAlarmStatus = definitions.eAlarm_Status_Pending self.mLastTrigger = DateTime() self.mNextTrigger = DateTime() self.mDoneCount = 0 # Create action data self.mActionData = VAlarm.VAlarmDisplay("")
def actionExpand(self, request, tzid): """ Expand a timezone within specified start/end dates. """ if set(request.args.keys()) - set(("start", "end", "changedsince",)): self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST) start = request.args.get("start", ()) if len(start) == 0: self.problemReport("invalid-start", "Missing start request-URI query parameter", responsecode.BAD_REQUEST) if len(start) > 1: self.problemReport("invalid-start", "Too many start request-URI query parameters", responsecode.BAD_REQUEST) elif len(start) == 1: try: if len(start[0]) != 20: raise ValueError() start = DateTime.parseText(start[0], fullISO=True) except ValueError: self.problemReport("invalid-start", "Invalid start request-URI query parameter value", responsecode.BAD_REQUEST) end = request.args.get("end", ()) if len(end) == 0: self.problemReport("invalid-end", "Missing end request-URI query parameter", responsecode.BAD_REQUEST) if len(end) > 1: self.problemReport("invalid-end", "Too many end request-URI query parameters", responsecode.BAD_REQUEST) elif len(end) == 1: try: if len(end[0]) != 20: raise ValueError() end = DateTime.parseText(end[0], fullISO=True) except ValueError: self.problemReport("invalid-end", "Invalid end request-URI query parameter value", responsecode.BAD_REQUEST) if end <= start: self.problemReport("invalid-end", "Invalid end request-URI query parameter value - earlier than start", responsecode.BAD_REQUEST) tzdata = self.timezones.getTimezone(tzid) if tzdata is None: self.problemReport("tzid-not-found", "Time zone identifier not found", responsecode.NOT_FOUND) # Now do the expansion (but use a cache to avoid re-calculating TZs) observances = self.expandcache.get((tzid, start, end), None) if observances is None: observances = tzexpandlocal(tzdata, start, end, utc_onset=True) self.expandcache[(tzid, start, end)] = observances # Turn into JSON result = { "dtstamp": self.timezones.dtstamp, "tzid": tzid, "observances": [ { "name": name, "onset": onset.getXMLText(), "utc-offset-from": utc_offset_from, "utc-offset-to": utc_offset_to, } for onset, utc_offset_from, utc_offset_to, name in observances ], } return JSONResponse(responsecode.OK, result, pretty=config.TimezoneService.PrettyPrintJSON)
def _initEvent(self): if not self._client.started: return succeed(None) # If it already exists, don't re-create calendar = self._calendarsOfType(caldavxml.calendar, "VEVENT")[0] if calendar.events: events = [event for event in calendar.events.values() if event.url.endswith("event_to_update.ics")] if events: return succeed(None) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) href = '%s%s' % (calendar.url, "event_to_update.ics") d = self._client.addEvent(href, vcalendar) return self._newOperation("create", d)
def doPOSTExpand(self, request): """ Expand a timezone within specified start/end dates. """ tzid = request.args.get("tzid", ()) if len(tzid) != 1: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-timezone"), "Invalid tzid query parameter", )) tzid = tzid[0] try: tzdata = readTZ(tzid) except TimezoneException: raise HTTPError(ErrorResponse( responsecode.NOT_FOUND, (calendarserver_namespace, "timezone-available"), "Timezone not found", )) try: start = request.args.get("start", ()) if len(start) != 1: raise ValueError() start = DateTime.parseText(start[0]) except ValueError: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-start-date"), "Invalid start query parameter", )) try: end = request.args.get("end", ()) if len(end) != 1: raise ValueError() end = DateTime.parseText(end[0]) if end <= start: raise ValueError() except ValueError: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-end-date"), "Invalid end query parameter", )) # Now do the expansion (but use a cache to avoid re-calculating TZs) observances = self.cache.get((tzid, start, end), None) if observances is None: observances = tzexpand(tzdata, start, end) self.cache[(tzid, start, end)] = observances # Turn into XML result = customxml.TZData( *[customxml.Observance(customxml.Onset(onset), customxml.UTCOffset(utc_offset)) for onset, utc_offset in observances] ) return XMLResponse(responsecode.OK, result)
def _doRefresh(tzpath, xmlfile, tzdb, tzvers): """ Refresh data from IANA. """ print("Downloading latest data from IANA") if tzvers: path = "https://www.iana.org/time-zones/repository/releases/tzdata%s.tar.gz" % (tzvers,) else: path = "https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz" data = urllib.urlretrieve(path) print("Extract data at: %s" % (data[0])) rootdir = tempfile.mkdtemp() zonedir = os.path.join(rootdir, "tzdata") os.mkdir(zonedir) with tarfile.open(data[0], "r:gz") as t: t.extractall(zonedir) # Get the version from the Makefile try: makefile = open(os.path.join(zonedir, "Makefile")).read() lines = makefile.splitlines() for line in lines: if line.startswith("VERSION="): tzvers = line[8:].strip() break except IOError: pass if not tzvers: tzvers = DateTime.getToday().getText() print("Converting data (version: %s) at: %s" % (tzvers, zonedir,)) startYear = 1800 endYear = DateTime.getToday().getYear() + 10 Calendar.sProdID = "-//calendarserver.org//Zonal//EN" zonefiles = "northamerica", "southamerica", "europe", "africa", "asia", "australasia", "antarctica", "etcetera", "backward" parser = tzconvert() for file in zonefiles: parser.parse(os.path.join(zonedir, file)) parser.generateZoneinfoFiles(os.path.join(rootdir, "zoneinfo"), startYear, endYear, filterzones=()) print("Copy new zoneinfo to destination: %s" % (tzpath,)) z = FilePath(os.path.join(rootdir, "zoneinfo")) tz = FilePath(tzpath) z.copyTo(tz) print("Updating XML file at: %s" % (xmlfile,)) tzdb.readDatabase() tzdb.updateDatabase() print("Current total: %d" % (len(tzdb.timezones),)) print("Total Changed: %d" % (tzdb.changeCount,)) if tzdb.changeCount: print("Changed:") for k in sorted(tzdb.changed): print(" %s" % (k,)) versfile = os.path.join(os.path.dirname(xmlfile), "version.txt") print("Updating version file at: %s" % (versfile,)) with open(versfile, "w") as f: f.write(TimezoneCache.IANA_VERSION_PREFIX + tzvers)
def getEventDetails(event): detail = {} nowPyDT = DateTime.getNowUTC() nowDT = datetime.datetime.utcnow() oneYearInFuture = DateTime.getNowUTC() oneYearInFuture.offsetDay(365) component = yield event.component() mainSummary = component.mainComponent().propertyValue( "SUMMARY", u"<no title>") whenTrashed = event.whenTrashed() ago = nowDT - whenTrashed detail["summary"] = mainSummary detail["whenTrashed"] = agoString(ago) detail["recoveryID"] = event._resourceID if component.isRecurring(): detail["recurring"] = True detail["instances"] = [] instances = component.cacheExpandedTimeRanges(oneYearInFuture) instances = sorted(instances.instances.values(), key=lambda x: x.start) limit = 3 count = 0 for instance in instances: if instance.start >= nowPyDT: summary = instance.component.propertyValue( "SUMMARY", u"<no title>") location = locationString(instance.component) tzid = instance.component.getProperty( "DTSTART").parameterValue("TZID", None) dtstart = instance.start if tzid is not None: timezone = Timezone(tzid=tzid) dtstart.adjustTimezone(timezone) detail["instances"].append({ "summary": summary, "starttime": dtstart.getLocaleDateTime(DateTime.FULLDATE, False, True, dtstart.getTimezoneID()), "location": location }) count += 1 limit -= 1 if limit == 0: break else: detail["recurring"] = False dtstart = component.mainComponent().propertyValue("DTSTART") detail["starttime"] = dtstart.getLocaleDateTime( DateTime.FULLDATE, False, True, dtstart.getTimezoneID()) detail["location"] = locationString(component.mainComponent()) returnValue(detail)
def test_TimeFormatting24Hour(self): with translationTo('pig', localeDir=localeDir) as t: self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), "00:00") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), "12:00") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), "23:59") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), "06:05") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), "16:05")
def test_TimeFormattingAMPM(self): with translationTo('en', localeDir=localeDir) as t: self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), "12:00 AM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), "12:00 PM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), "11:59 PM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), "6:05 AM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), "4:05 PM")
def __init__(self, *children, **attributes): super(CalDAVTimeRangeElement, self).__init__(*children, **attributes) # One of start or end must be present if "start" not in attributes and "end" not in attributes: raise ValueError("One of 'start' or 'end' must be present in CALDAV:time-range") self.start = DateTime.parseText(attributes["start"]) if "start" in attributes else None self.end = DateTime.parseText(attributes["end"]) if "end" in attributes else None
def __init__(self, parent=None): super(VFreeBusy, self).__init__(parent=parent) self.mStart = DateTime() self.mHasStart = False self.mEnd = DateTime() self.mHasEnd = False self.mDuration = False self.mCachedBusyTime = False self.mSpanPeriod = None self.mBusyTime = None
def _invite(self): """ Try to add a new event, or perhaps remove an existing attendee from an event. @return: C{None} if there are no events to play with, otherwise a L{Deferred} which fires when the attendee change has been made. """ if not self._client.started: return succeed(None) # Find calendars which are eligible for invites calendars = self._calendarsOfType(caldavxml.calendar, "VEVENT") while calendars: # Pick one at random from which to try to create an event # to modify. calendar = self.random.choice(calendars) calendars.remove(calendar) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration( seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) vevent.addProperty(self._client._makeSelfOrganizer()) vevent.addProperty(self._client._makeSelfAttendee()) attendees = list(vevent.properties('ATTENDEE')) for _ignore in range(int(self._inviteeCountDistribution.sample())): try: self._addAttendee(vevent, attendees) except CannotAddAttendee: self._failedOperation("invite", "Cannot add attendee") return succeed(None) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addInvite(href, vcalendar) return self._newOperation("invite", d)
def test_pyCalendarTodatetime(self): """ dateops.pyCalendarTodatetime """ tests = ( (DateTime(2012, 4, 4, 12, 34, 56), datetime.datetime(2012, 4, 4, 12, 34, 56, tzinfo=dateutil.tz.tzutc())), (DateTime(2012, 12, 31), datetime.date(2012, 12, 31)), ) for pycal, result in tests: self.assertEqual(pyCalendarTodatetime(pycal), result)
def test_parseSQLTimestampToPyCalendar(self): """ dateops.parseSQLTimestampToPyCalendar """ tests = ( ("2012-04-04 12:34:56", DateTime(2012, 4, 4, 12, 34, 56)), ("2012-12-31 01:01:01", DateTime(2012, 12, 31, 1, 1, 1)), ) for sqlStr, result in tests: self.assertEqual(parseSQLTimestampToPyCalendar(sqlStr), result)
def testDuplicateInSet(self): s = set(( DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)), DateTime(2011, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)), )) self.assertTrue( DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) in s) self.assertFalse( DateTime(2011, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)) in s)
def test_pyCalendarToSQLTimestamp(self): """ dateops.pyCalendarToSQLTimestamp """ tests = ( (DateTime(2012, 4, 4, 12, 34, 56), datetime(2012, 4, 4, 12, 34, 56, tzinfo=None)), (DateTime(2012, 12, 31), date(2012, 12, 31)), ) for pycal, result in tests: self.assertEqual(pyCalendarToSQLTimestamp(pycal), result)
def test_truncatedDec(self): """ Custom VTZ valid from 2007. Daylight 2007 OK. """ TimezoneCache.create(empty=True) TimezoneCache.clear() self.doTest("TruncatedDec10.ics", DateTime(2007, 12, 10, 17, 0, 0, Timezone.UTCTimezone), DateTime(2007, 12, 10, 18, 0, 0, Timezone.UTCTimezone))
def _invite(self): """ Try to add a new event, or perhaps remove an existing attendee from an event. @return: C{None} if there are no events to play with, otherwise a L{Deferred} which fires when the attendee change has been made. """ if not self._client.started: return succeed(None) # Find calendars which are eligible for invites calendars = self._calendarsOfType(caldavxml.calendar, "VEVENT") while calendars: # Pick one at random from which to try to create an event # to modify. calendar = self.random.choice(calendars) calendars.remove(calendar) # Copy the template event and fill in some of its fields # to make a new event to create on the calendar. vcalendar = self._eventTemplate.duplicate() vevent = vcalendar.mainComponent() uid = str(uuid4()) dtstart = self._eventStartDistribution.sample() dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample()) vevent.replaceProperty(Property("CREATED", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC())) vevent.replaceProperty(Property("DTSTART", dtstart)) vevent.replaceProperty(Property("DTEND", dtend)) vevent.replaceProperty(Property("UID", uid)) rrule = self._recurrenceDistribution.sample() if rrule is not None: vevent.addProperty(Property(None, None, None, pycalendar=rrule)) vevent.addProperty(self._client._makeSelfOrganizer()) vevent.addProperty(self._client._makeSelfAttendee()) attendees = list(vevent.properties('ATTENDEE')) for _ignore in range(int(self._inviteeCountDistribution.sample())): try: self._addAttendee(vevent, attendees) except CannotAddAttendee: self._failedOperation("invite", "Cannot add attendee") return succeed(None) href = '%s%s.ics' % (calendar.url, uid) d = self._client.addInvite(href, vcalendar) return self._newOperation("invite", d)
def test_parseSQLDateToPyCalendar(self): """ dateops.parseSQLDateToPyCalendar """ tests = ( ("2012-04-04", DateTime(2012, 4, 4)), ("2012-12-31 00:00:00", DateTime(2012, 12, 31)), ) for sqlStr, result in tests: self.assertEqual(parseSQLDateToPyCalendar(sqlStr), result)
def getEventDetails(event): detail = {} nowPyDT = DateTime.getNowUTC() nowDT = datetime.datetime.utcnow() oneYearInFuture = DateTime.getNowUTC() oneYearInFuture.offsetDay(365) component = yield event.component() mainSummary = component.mainComponent().propertyValue("SUMMARY", u"<no title>") whenTrashed = event.whenTrashed() ago = nowDT - whenTrashed detail["summary"] = mainSummary detail["whenTrashed"] = agoString(ago) detail["recoveryID"] = event._resourceID if component.isRecurring(): detail["recurring"] = True detail["instances"] = [] instances = component.cacheExpandedTimeRanges(oneYearInFuture) instances = sorted(instances.instances.values(), key=lambda x: x.start) limit = 3 count = 0 for instance in instances: if instance.start >= nowPyDT: summary = instance.component.propertyValue("SUMMARY", u"<no title>") location = locationString(instance.component) tzid = instance.component.getProperty("DTSTART").parameterValue("TZID", None) dtstart = instance.start if tzid is not None: timezone = Timezone(tzid=tzid) dtstart.adjustTimezone(timezone) detail["instances"].append( { "summary": summary, "starttime": dtstart.getLocaleDateTime(DateTime.FULLDATE, False, True, dtstart.getTimezoneID()), "location": location, } ) count += 1 limit -= 1 if limit == 0: break else: detail["recurring"] = False dtstart = component.mainComponent().propertyValue("DTSTART") detail["starttime"] = dtstart.getLocaleDateTime(DateTime.FULLDATE, False, True, dtstart.getTimezoneID()) detail["location"] = locationString(component.mainComponent()) returnValue(detail)
def __init__(self, xml_element): super(TimeRange, self).__init__(xml_element) if xml_element is None: return # One of start or end must be present if "start" not in xml_element.attributes and "end" not in xml_element.attributes: raise ValueError("One of 'start' or 'end' must be present in CALDAV:time-range") self.start = DateTime.parseText(xml_element.attributes["start"]) if "start" in xml_element.attributes else None self.end = DateTime.parseText(xml_element.attributes["end"]) if "end" in xml_element.attributes else None self.tzinfo = None
def sort_for_display(e1, e2): s1 = e1.getMaster() s2 = e2.getMaster() # Check status first (convert None -> Needs action for tests) status1 = s1.self.mStatus status2 = s2.self.mStatus if status1 == definitions.eStatus_VToDo_None: status1 = definitions.eStatus_VToDo_NeedsAction if status2 == definitions.eStatus_VToDo_None: status2 = definitions.eStatus_VToDo_NeedsAction if status1 != status2: # More important ones at the top return status1 < status2 # At this point the status of each is the same # If status is cancelled sort by start time if s1.self.mStatus == definitions.eStatus_VToDo_Cancelled: # Older ones at the bottom return s1.mStart > s2.mStart # If status is completed sort by completion time if s1.self.mStatus == definitions.eStatus_VToDo_Completed: # Older ones at the bottom return s1.self.mCompleted > s2.self.mCompleted # Check due date exists if s1.mHasEnd != s2.mHasEnd: now = DateTime() now.setToday() # Ones with due dates after today below ones without due dates if s1.hasEnd(): return s1.mEnd <= now elif s2.hasEnd(): return now < s2.mEnd # Check due dates if present if s1.mHasEnd: if s1.mEnd != s2.mEnd: # Soonest dues dates above later ones return s1.mEnd < s2.mEnd # Check priority next if s1.self.mPriority != s2.self.mPriority: # Higher priority above lower ones return s1.self.mPriority < s2.self.mPriority # Just use start time - older ones at the top return s1.mStart < s2.mStart
def printEventDetails(event): nowPyDT = DateTime.getNowUTC() nowDT = datetime.datetime.utcnow() oneYearInFuture = DateTime.getNowUTC() oneYearInFuture.offsetDay(365) component = yield event.component() mainSummary = component.mainComponent().propertyValue("SUMMARY", u"<no title>") whenTrashed = event.whenTrashed() ago = nowDT - whenTrashed print(" Trashed {}:".format(agoString(ago))) if component.isRecurring(): print( " \"{}\" (repeating) Recovery ID = {}".format( mainSummary, event._resourceID ) ) print(" ...upcoming instances:") instances = component.cacheExpandedTimeRanges(oneYearInFuture) instances = sorted(instances.instances.values(), key=lambda x: x.start) limit = 3 count = 0 for instance in instances: if instance.start >= nowPyDT: summary = instance.component.propertyValue("SUMMARY", u"<no title>") location = locationString(instance.component) tzid = instance.component.getProperty("DTSTART").parameterValue("TZID", None) dtstart = instance.start if tzid is not None: timezone = Timezone(tzid=tzid) dtstart.adjustTimezone(timezone) print(" \"{}\" {} {}".format(summary, startString(dtstart), location)) count += 1 limit -= 1 if limit == 0: break if not count: print(" (none)") else: print( " \"{}\" (non-repeating) Recovery ID = {}".format( mainSummary, event._resourceID ) ) dtstart = component.mainComponent().propertyValue("DTSTART") location = locationString(component.mainComponent()) print(" {} {}".format(startString(dtstart), location))
def __init__(self, threshold, past): """ @param threshold: the size in bytes that will trigger a split @type threshold: C{int} @param past: number of days in the past where the split will occur @type past: C{int} """ self.threshold = threshold self.past = DateTime.getNowUTC() self.past.setHHMMSS(0, 0, 0) self.past.offsetDay(-past) self.now = DateTime.getNowUTC() self.now.setHHMMSS(0, 0, 0) self.now.offsetDay(-1)
def setUpCalendarStore(test): test.root = FilePath(test.mktemp()) test.root.createDirectory() storeRootPath = test.storeRootPath = test.root.child("store") calendarPath = storeRootPath.child("calendars").child("__uids__") calendarPath.parent().makedirs() storePath.copyTo(calendarPath) # Set year values to current year nowYear = DateTime.getToday().getYear() for home in calendarPath.child("ho").child("me").children(): if not home.basename().startswith("."): for calendar in home.children(): if not calendar.basename().startswith("."): for resource in calendar.children(): if resource.basename().endswith(".ics"): resource.setContent(resource.getContent() % {"now": nowYear}) testID = test.id() test.calendarStore = CalendarStore( storeRootPath, {"push": test.notifierFactory} if test.notifierFactory else {}, buildDirectory(), quota=deriveQuota(test), ) test.txn = test.calendarStore.newTransaction(testID + "(old)") assert test.calendarStore is not None, "No calendar store?"
def actionList(self, request): """ Return a list of all timezones known to the server. """ if set(request.args.keys()) - set(("changedsince",)): self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST) changedsince = request.args.get("changedsince", ()) if len(changedsince) > 1: self.problemReport("invalid-changedsince", "Too many changedsince request-URI query parameters", responsecode.BAD_REQUEST) if len(changedsince) == 1: # Validate a date-time stamp changedsince = changedsince[0] try: dt = DateTime.parseText(changedsince, fullISO=True) except ValueError: self.problemReport("invalid-changedsince", "Invalid changedsince request-URI query parameter value", responsecode.BAD_REQUEST) if not dt.utc(): self.problemReport("invalid-changedsince", "Invalid changedsince request-URI query parameter value - not UTC", responsecode.BAD_REQUEST) timezones = [] for tz in self.timezones.listTimezones(changedsince): timezones.append({ "tzid": tz.tzid, "last-modified": tz.dtstamp, "aliases": tz.aliases, }) result = { "dtstamp": self.timezones.dtstamp, "timezones": timezones, } return JSONResponse(responsecode.OK, result, pretty=config.TimezoneService.PrettyPrintJSON)
def initNextTrigger(self): # Do not bother if its completed if self.mAlarmStatus == definitions.eAlarm_Status_Completed: return self.mStatusInit = True # Look for trigger immediately preceeding or equal to utc now nowutc = DateTime.getNowUTC() # Init done counter self.mDoneCount = 0 # Determine the first trigger trigger = DateTime() self.getFirstTrigger(trigger) while self.mDoneCount < self.mRepeats: # See if next trigger is later than now next_trigger = trigger + self.mRepeatInterval if next_trigger > nowutc: break self.mDoneCount += 1 trigger = next_trigger # Check for completion if trigger == self.mLastTrigger or (nowutc - trigger).getTotalSeconds() > 24 * 60 * 60: if self.mDoneCount == self.mRepeats: self.mAlarmStatus = definitions.eAlarm_Status_Completed return else: trigger = trigger + self.mRepeatInterval self.mDoneCount += 1 self.mNextTrigger = trigger
def _updateEvent(self): """ Try to add a new attendee to an event, or perhaps remove an existing attendee from an event. @return: C{None} if there are no events to play with, otherwise a L{Deferred} which fires when the attendee change has been made. """ if not self._client.started: return succeed(None) # If it does not exist, try to create it calendar = self._calendarsOfType(caldavxml.calendar, "VEVENT")[0] if not calendar.events: return self._initEvent() events = [event for event in calendar.events.values() if event.url.endswith("event_to_update.ics")] if not events: return self._initEvent() event = events[0] # Add/update the ACKNOWLEDGED property component = event.component.mainComponent() component.replaceProperty(Property("ACKNOWLEDGED", DateTime.getNowUTC())) d = self._client.changeEvent(event.url) return self._newOperation("update", d)
def updateToCurrentYear(data): """ Update the supplied iCalendar data so that all dates are updated to the current year. """ nowYear = DateTime.getToday().getYear() return data % {"now": nowYear}
def doWork(self): try: home = (yield self.transaction.calendarHomeWithResourceID(self.homeResourceID)) resource = (yield home.objectResourceWithID(self.resourceID)) attendeeAddress = yield calendarUserFromCalendarUserUID(home.uid(), self.transaction) attendee = attendeeAddress.record.canonicalCalendarUserAddress() calendar = (yield resource.componentForUser()) organizer = calendar.validOrganizerForScheduling() # Deserialize "" as None changedRids = map(lambda x: DateTime.parseText(x) if x else None, self.changedRids.split(",")) if self.changedRids else None log.debug("ScheduleReplyWork - running for ID: {id}, UID: {uid}, attendee: {att}", id=self.workID, uid=calendar.resourceUID(), att=attendee) # We need to get the UID lock for implicit processing. yield NamedLock.acquire(self.transaction, "ImplicitUIDLock:%s" % (hashlib.md5(calendar.resourceUID()).hexdigest(),)) itipmsg = iTipGenerator.generateAttendeeReply(calendar, attendee, changedRids=changedRids) # Send scheduling message and process response response = (yield self.sendToOrganizer(home, "REPLY", itipmsg, attendee, organizer)) responses, all_delivered = self.extractSchedulingResponse((response,)) if not all_delivered: changed = yield self.handleSchedulingResponse(responses, calendar, False) if changed: yield resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ATTENDEE_ITIP_UPDATE) self._dequeued() except Exception, e: # FIXME: calendar may not be set here! log.debug("ScheduleReplyWork - exception ID: {id}, UID: '{uid}', {err}", id=self.workID, uid=calendar.resourceUID(), err=str(e)) raise
def doList(self, request): """ Return a list of all timezones known to the server. """ changedsince = request.args.get("changedsince", ()) if len(changedsince) > 1: raise HTTPError( JSONResponse( responsecode.BAD_REQUEST, {"error": "invalid-changedsince", "description": "Invalid changedsince query parameter"}, ) ) if len(changedsince) == 1: # Validate a date-time stamp changedsince = changedsince[0] try: dt = DateTime.parseText(changedsince) except ValueError: raise HTTPError( JSONResponse( responsecode.BAD_REQUEST, {"error": "invalid-changedsince", "description": "Invalid changedsince query parameter"}, ) ) if not dt.utc(): raise HTTPError(JSONResponse(responsecode.BAD_REQUEST, "Invalid changedsince query parameter value")) timezones = [] for tz in self.timezones.listTimezones(changedsince): timezones.append({"tzid": tz.tzid, "last-modified": tz.dtstamp, "aliases": tz.aliases}) result = {"dtstamp": self.timezones.dtstamp, "timezones": timezones} return JSONResponse(responsecode.OK, result)
def doRequest(self): """ Execute the actual HTTP request. """ now = DateTime.getNowUTC() href = joinURL(self.sessions[0].calendarHref, "put.ics") self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1,), "text/calendar")
def createNewDatabase(self): """ Create a new DB xml file from scratch by scanning zoneinfo. """ self.dtstamp = DateTime.getNowUTC().getXMLText() self._scanTZs("") self._dumpTZs()