def testSetCalendarProperties(self): c = self.principal.make_calendar(name="Yep", cal_id=self.testcal_id) assert_not_equal(c.url, None) props = c.get_properties([dav.DisplayName(), ]) assert_equal("Yep", props[dav.DisplayName.tag]) # Creating a new calendar with different ID but with existing name # - fails on zimbra only. # This is OK to fail. if 'zimbra' in str(c.url): assert_raises(Exception, self.principal.make_calendar, "Yep", self.testcal_id2) else: # This may fail, and if it fails, add an exception to the test # (see the "if" above) cc = self.principal.make_calendar("Yep", self.testcal_id2) cc.delete() c.set_properties([dav.DisplayName("hooray"), ]) props = c.get_properties([dav.DisplayName(), ]) assert_equal(props[dav.DisplayName.tag], "hooray") # Creating a new calendar with different ID and old name, this should # work, shouldn't it? # ... ouch, now it fails with a 409 on zimbra (it didn't fail # earlier) if not 'zimbra' in str(c.url): cc = self.principal.make_calendar( name="Yep", cal_id=self.testcal_id2).save() assert_not_equal(cc.url, None) cc.delete()
def testSetCalendarProperties(self): c = self.principal.make_calendar(name="Yep", cal_id=testcal_id) assert_not_equal(c.url, None) props = c.get_properties([ dav.DisplayName(), ]) assert_equal("Yep", props[dav.DisplayName.tag]) ## Creating a new calendar with different ID but with existing name - fails on zimbra only. ## This is OK to fail. if 'zimbra' in str(c.url): assert_raises(Exception, self.principal.make_calendar, "Yep", testcal_id2) c.set_properties([ dav.DisplayName("hooray"), ]) props = c.get_properties([ dav.DisplayName(), ]) assert_equal(props[dav.DisplayName.tag], "hooray") ## Creating a new calendar with different ID and old name - should never fail cc = self.principal.make_calendar(name="Yep", cal_id=testcal_id2).save() assert_not_equal(cc.url, None) cc.delete()
def calendars(self): if not hasattr(self, '_calendars'): calendars = self.principal.calendars() self._calendars = {} for calendar in calendars: p = calendar.get_properties([ dav.DisplayName(), ]) if p: calname = p[dav.DisplayName().tag] self._calendars[calname] = calendar return self._calendars
def children(self, type=None): """ List children, using a propfind (resourcetype) on the parent object, at depth = 1. """ c = [] depth = 1 properties = {} props = [dav.ResourceType(), dav.DisplayName()] response = self._query_properties(props, depth) properties = self._handle_prop_response( response=response, props=props, type=type, what='tag') for path in list(properties.keys()): resource_type = properties[path][dav.ResourceType.tag] resource_name = properties[path][dav.DisplayName.tag] if resource_type == type or type is None: # TODO: investigate the RFCs thoroughly - why does a "get # members of this collection"-request also return the # collection URL itself? # And why is the strip_trailing_slash-method needed? # The collection URL should always end with a slash according # to RFC 2518, section 5.2. if (self.url.strip_trailing_slash() != self.url.join(path).strip_trailing_slash()): c.append((self.url.join(path), resource_type, resource_name)) return c
def create_calendar(client, parent, name, id=None): """ Create a new calendar with display name `name` in `parent`. """ path = None if id is None: id = str(uuid.uuid1()) name = dav.DisplayName(name) cal = cdav.CalendarCollection() coll = dav.Collection() + cal type = dav.ResourceType() + coll prop = dav.Prop() + [type, name] set = dav.Set() + prop mkcol = dav.Mkcol() + set q = etree.tostring(mkcol.xmlelement(), encoding="utf-8", xml_declaration=True) path = url.join(parent.url.path, id) r = client.mkcol(path, q) if r.status == 201: path = url.make(parent.url, path) else: raise error.MkcolError(r.raw) return (id, path)
def update_calendar(self, calendar): """Update an existing calendar.""" remote_cal = self.client.calendar(calendar.encoded_path) remote_cal.set_properties([ dav.DisplayName(calendar.name), ical.CalendarColor(calendar.color) ])
def handle_cal_list(self, message): self.please_wait() principal = self.caldav_.principal() calendars = principal.calendars() listcals = list() totalCalendars = len(calendars) # There is at least one calendar. if totalCalendars > 0: for calendar in calendars: tnameRaw = calendar.get_properties([ dav.DisplayName(), ]) tname = tnameRaw[dav.DisplayName.tag] listcals.append(tname) cals = ", ".join(listcals) self.speak_dialog('cal.list.calendars', data={ "totalCalendars": totalCalendars, "calendars": cals }, expect_response=False) # There is no calendar. else: self.speak_dialog('cal.list.calendars.none', expect_response=False)
def Caldav(self): # Verbinding maken met CalDav agenda client = caldav.DAVClient(self.config["url"]) principal = client.principal() calendars = principal.calendars() first_all = True # Lus door de beschikbare agenda's heen for calendar in calendars: # Zoek de naam hiervan op calendar_name = calendar.get_properties([ dav.DisplayName(), ])["{DAV:}displayname"] # Alleen doorgaan indien de agenda in de 'calendars' config regel staat if calendar_name in self.config["calendars"]: first = True now = f.Now(self.config_full) # Evenementen voor vandaag zoeken, met een beetje buffer terug in de tijd. results = calendar.date_search(now - timedelta(hours=2), now + timedelta(days=1)) for vevent in results: event = Event(client=client, url=vevent.url) event.load() # Oke.. in de documentatie niks over hoe hier een nette string van te maken # En in het object zelf zit ook niet echt een functie daarvoor, los van __str()__ start = event.instance.vevent.dtstart.__str__() summary = event.instance.vevent.summary.__str__() # Zo kan het ook. summary = summary.replace("<SUMMARY{}", "")[:-1] # Dit komt binnen: <DTSTART{'X-VOBJ-ORIGINAL-TZID': ['Europe/Amsterdam']} # Dus split op } en dan de eerste verwijderen, en het > teken achteraan verwijderen start = parse(''.join(start.split("}")[1:])[:-1]) # Eerste event in deze agenda? Toon de agenda naam if first: # Niet de eerste agenda? Extra witregel if not first_all: self.text += "<br/>" self.text += "<h3>" + calendar_name + "</h3>" first = False first_all = False # Event samenvatting (tijd + omschijving) toevoegen aan de text dt = "%A %H:%M" if (calendar_name.lower().find("birthday") >= 0 or calendar_name.lower().find("verjaardag") >= 0): dt = "%A" self.text += "{0} {1}<br/>".format(start.strftime(dt), summary) if not first_all: self.hasText = True
def get_named_calendar(self, name): if len(self.calendars) > 0: for calendar in self.calendars: properties = calendar.get_properties([dav.DisplayName()]) display_name = properties["{DAV:}displayname"] if display_name == name: return calendar return None
def get_named_calendar(self, name): if len(self.calendars) > 0: for calendar in self.calendars: if calendar.get_properties([ dav.DisplayName(), ])['{DAV:}displayname'] == name: return calendar return None
def _create(self, name=None, id=None, supported_calendar_component_set=None): """ Create a new calendar with display name `name` in `parent`. """ if id is None: id = str(uuid.uuid1()) self.id = id path = self.parent.url.join(id) self.url = path # TODO: mkcalendar seems to ignore the body on most servers? # at least the name doesn't get set this way. # zimbra gives 500 (!) if body is omitted ... prop = dav.Prop() if name: display_name = dav.DisplayName(name) prop += [ display_name, ] if supported_calendar_component_set: sccs = cdav.SupportedCalendarComponentSet() for scc in supported_calendar_component_set: sccs += cdav.Comp(scc) prop += sccs set = dav.Set() + prop mkcol = cdav.Mkcalendar() + set r = self._query(root=mkcol, query_method='mkcalendar', url=path, expected_return_value=201) # COMPATIBILITY ISSUE # name should already be set, but we've seen caldav servers failing # on setting the DisplayName on calendar creation # (DAViCal, Zimbra, ...). Doing an attempt on explicitly setting the # display name using PROPPATCH. if name: try: self.set_properties([display_name]) except: try: current_display_name = self.get_properties([display_name]) if current_display_name != name: logging.warning( "caldav server not complient with RFC4791. unable to set display name on calendar. Wanted name: \"%s\" - gotten name: \"%s\". Ignoring." % (name, current_display_name)) except: logging.warning( "calendar server does not support display name on calendar? Ignoring", exc_info=True)
def newClient(): client = caldav.DAVClient("https://sogo.inoio.de/SOGo/dav/public/loesungsraum/Calendar/personal/") principal = client.principal() calendars = principal.calendars() if len(calendars) > 0: calendar = calendars[0] print "Using calendar", calendar print "Renaming" calendar.set_properties([dav.DisplayName("Test calendar"),]) print calendar.get_properties([dav.DisplayName(),]) event = calendar.add_event(vcal) print "Event", event, "created" print "Looking for events in 2010-05" results = calendar.date_search( datetime(2010, 5, 1), datetime(2010, 6, 1)) for event in results: print "Found", event
def __init__(self, **kwargs): super(CalDav, self).__init__(**kwargs) self.window = kwargs.get("window", 60 * 60 * 24 * 7) self.client = caldav.DAVClient(kwargs["url"], username=kwargs["user"], password=kwargs["password"]) self.principal = self.client.principal() self.all_calendars = dict([ (calendar.get_properties([dav.DisplayName()])["{DAV:}displayname"], calendar) for calendar in self.principal.calendars() ]) #print(self.all_calendars) self.calendars = [ self.all_calendars[name] for name in kwargs["calendars"] ]
def connect(self): client = caldav.DAVClient(self._calendar_url, username=self._user, password=self._password) principal = client.principal() calendars = principal.calendars() matched_calendar = None for calendar in calendars: calendar_displayname_property_dict = calendar.get_properties([ dav.DisplayName(), ]) value_list = list(calendar_displayname_property_dict.values()) name = value_list[0] if self._calendar_name == name: matched_calendar = calendar break if matched_calendar: self._caldav_object = matched_calendar
# In[33]: principal = client.principal() # In[34]: calendars = principal.calendars() # In[35]: if len(calendars) > 0: calendar = calendars[0] print ("Using calendar", calendar) print ("Renaming") calendar.set_properties([dav.DisplayName("Test calendar"),]) print (calendar.get_properties([dav.DisplayName(),])) event = calendar.add_event(vcal) print ("Event", event, "created") print ("Ищу события в 2019 году") results = calendar.date_search( datetime(2019, 12, 1), datetime(2020,1, 1)) for event in results: print ("Found", event)
def testBackwardCompatibility(self): """ Tobias Brox has done some API changes - but this thing should still be backward compatible. """ if not 'backwards_compatibility_url' in self.server_params: return caldav = DAVClient(self.server_params['backwards_compatibility_url']) principal = Principal( caldav, self.server_params['backwards_compatibility_url']) c = Calendar(caldav, name="Yep", parent=principal, id=testcal_id).save() assert_not_equal(c.url, None) c.set_properties([ dav.DisplayName("hooray"), ]) props = c.get_properties([ dav.DisplayName(), ]) assert_equal(props[dav.DisplayName.tag], "hooray") cc = Calendar(caldav, name="Yep", parent=principal).save() assert_not_equal(cc.url, None) cc.delete() e = Event(caldav, data=ev1, parent=c).save() assert_not_equal(e.url, None) ee = Event(caldav, url=url.make(e.url), parent=c) ee.load() assert_equal(e.instance.vevent.uid, ee.instance.vevent.uid) r = c.date_search(datetime(2006, 7, 13, 17, 00, 00), datetime(2006, 7, 15, 17, 00, 00)) assert_equal(e.instance.vevent.uid, r[0].instance.vevent.uid) assert_equal(len(r), 1) all = c.events() assert_equal(len(all), 1) e2 = Event(caldav, data=ev2, parent=c).save() assert_not_equal(e.url, None) tmp = c.event("*****@*****.**") assert_equal(e2.instance.vevent.uid, tmp.instance.vevent.uid) r = c.date_search(datetime(2007, 7, 13, 17, 00, 00), datetime(2007, 7, 15, 17, 00, 00)) assert_equal(len(r), 1) e.data = ev2 e.save() r = c.date_search(datetime(2007, 7, 13, 17, 00, 00), datetime(2007, 7, 15, 17, 00, 00)) for e in r: print(e.data) assert_equal(len(r), 1) e.instance = e2.instance e.save() r = c.date_search(datetime(2007, 7, 13, 17, 00, 00), datetime(2007, 7, 15, 17, 00, 00)) for e in r: print(e.data) assert_equal(len(r), 1)
def test_xml_parsing(self): """ DAVResponse has quite some code to parse the XML received from the server. This test contains real XML received from various caldav servers, and the expected result from the parse methods. """ xml = """ <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/</href> <propstat> <prop> <current-user-principal xmlns="DAV:"> <href xmlns="DAV:">/17149682/principal/</href> </current-user-principal> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus> """ expected_result = { '/': { '{DAV:}current-user-principal': '/17149682/principal/' } } assert_equal( MockedDAVResponse(xml).expand_simple_props( props=[dav.CurrentUserPrincipal()]), expected_result) xml = """ <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/17149682/principal/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav"> <href xmlns="DAV:">https://p62-caldav.icloud.com:443/17149682/calendars/</href> </calendar-home-set> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus>""" expected_result = { '/17149682/principal/': { '{urn:ietf:params:xml:ns:caldav}calendar-home-set': 'https://p62-caldav.icloud.com:443/17149682/calendars/' } } assert_equal( MockedDAVResponse(xml).expand_simple_props( props=[cdav.CalendarHomeSet()]), expected_result) xml = """ <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/</href> <propstat> <prop> <current-user-principal xmlns="DAV:"> <href xmlns="DAV:">/17149682/principal/</href> </current-user-principal> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus>""" expected_result = { '/': { '{DAV:}current-user-principal': '/17149682/principal/' } } assert_equal( MockedDAVResponse(xml).expand_simple_props( props=[dav.CurrentUserPrincipal()]), expected_result) xml = """ <multistatus xmlns="DAV:"> <response> <href>/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/</href> <propstat> <prop> </prop> <status>HTTP/1.1 200 OK</status> </propstat> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav"/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> </response> <response> <href>/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/20010712T182145Z-123401%40example.com.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VEVENT UID:[email protected] DTSTAMP:20060712T182145Z DTSTART:20060714T170000Z DTEND:20060715T040000Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR </calendar-data> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus> """ expected_result = { '/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/': { '{urn:ietf:params:xml:ns:caldav}calendar-data': None }, '/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/[email protected]': { '{urn:ietf:params:xml:ns:caldav}calendar-data': 'BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Example Corp.//CalDAV Client//EN\nBEGIN:VEVENT\nUID:[email protected]\nDTSTAMP:20060712T182145Z\nDTSTART:20060714T170000Z\nDTEND:20060715T040000Z\nSUMMARY:Bastille Day Party\nEND:VEVENT\nEND:VCALENDAR\n' } } assert_equal( MockedDAVResponse(xml).expand_simple_props( props=[cdav.CalendarData()]), expected_result) xml = """ <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/17149682/calendars/</href> <propstat> <prop> <resourcetype xmlns="DAV:"> <collection/> </resourcetype> <displayname xmlns="DAV:">Ny Test</displayname> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> <response xmlns="DAV:"> <href>/17149682/calendars/06888b87-397f-11eb-943b-3af9d3928d42/</href> <propstat> <prop> <resourcetype xmlns="DAV:"> <collection/> <calendar xmlns="urn:ietf:params:xml:ns:caldav"/> </resourcetype> <displayname xmlns="DAV:">calfoo3</displayname> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> <response xmlns="DAV:"> <href>/17149682/calendars/inbox/</href> <propstat> <prop> <resourcetype xmlns="DAV:"> <collection/> <schedule-inbox xmlns="urn:ietf:params:xml:ns:caldav"/> </resourcetype> </prop> <status>HTTP/1.1 200 OK</status> </propstat> <propstat> <prop> <displayname xmlns="DAV:"/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> </response> <response xmlns="DAV:"> <href>/17149682/calendars/testcalendar-e2910e0a-feab-4b51-b3a8-55828acaa912/</href> <propstat> <prop> <resourcetype xmlns="DAV:"> <collection/> <calendar xmlns="urn:ietf:params:xml:ns:caldav"/> </resourcetype> <displayname xmlns="DAV:">Yep</displayname> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus> """ expected_result = { '/17149682/calendars/': { '{DAV:}resourcetype': ['{DAV:}collection'], '{DAV:}displayname': 'Ny Test' }, '/17149682/calendars/06888b87-397f-11eb-943b-3af9d3928d42/': { '{DAV:}resourcetype': [ '{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}calendar' ], '{DAV:}displayname': 'calfoo3' }, '/17149682/calendars/inbox/': { '{DAV:}resourcetype': [ '{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}schedule-inbox' ], '{DAV:}displayname': None }, '/17149682/calendars/testcalendar-e2910e0a-feab-4b51-b3a8-55828acaa912/': { '{DAV:}resourcetype': [ '{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}calendar' ], '{DAV:}displayname': 'Yep' } } assert_equal( MockedDAVResponse(xml).expand_simple_props( props=[dav.DisplayName()], multi_value_props=[dav.ResourceType()]), expected_result) xml = """ <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/</href> <propstat> <prop> <getetag xmlns="DAV:">"kkkgopik"</getetag> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> <response xmlns="DAV:"> <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/1761bf8c-6363-11eb-8fe4-74e5f9bfd8c1.ics</href> <propstat> <prop> <getetag xmlns="DAV:">"kkkgorwx"</getetag> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> <response xmlns="DAV:"> <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/20010712T182145Z-123401%40example.com.ics</href> <propstat> <prop> <getetag xmlns="DAV:">"kkkgoqqu"</getetag> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> <sync-token>HwoQEgwAAAh4yw8ntwAAAAAYAhgAIhUIopml463FieB4EKq9+NSn04DrkQEoAA==</sync-token> </multistatus> """ expected_results = { '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/': { '{DAV:}getetag': '"kkkgopik"', '{urn:ietf:params:xml:ns:caldav}calendar-data': None }, '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/1761bf8c-6363-11eb-8fe4-74e5f9bfd8c1.ics': { '{DAV:}getetag': '"kkkgorwx"', '{urn:ietf:params:xml:ns:caldav}calendar-data': None }, '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/[email protected]': { '{DAV:}getetag': '"kkkgoqqu"', '{urn:ietf:params:xml:ns:caldav}calendar-data': None } }
def receive(dbcal, calendar): rs_touched = set() ev_touched = set() rs_updated = rs_created = rs_deleted = 0 count_update = 0 count_new = 0 count_deleted = 0 #~ print "Using calendar", calendar props = calendar.get_properties([dav.DisplayName()]) dbcal.name = props[dav.DisplayName().tag] dbcal.save() from_date = dbcal.start_date if not from_date: from_date = datetime.datetime.now() - datetime.timedelta(days=365) until_date = datetime.datetime.now() + datetime.timedelta(days=365) #~ from_date = aware(from_date) #~ until_date = aware(until_date) #~ print from_date.tzinfo, until_date.tzinfo #~ raise Exception("20110823") results = calendar.date_search(from_date, until_date) if results: for comp in results: #~ if len(list(comp.instance.getChildren())) != 1: #~ raise Exception("comp.instance.getChildren() is %s" % list(comp.instance.getChildren())) dblogger.info( "Got calendar component <<<\n%s\n>>>", prettyPrint(comp.instance)) if comp.instance.vevent: event = comp.instance.vevent if isinstance(event, RecurringComponent): """ in a google calendar, all events are parsed to a RecurringComponent. if event.rruleset is None we consider them non recurrent. """ uid = event.uid.value dtstart = event.dtstart.value get_kw = {} set_kw = {} get_kw.update(uid=uid) set_kw.update(summary=event.summary.value) #~ dblogger.info("TRANSPARENCE IS %r", event.transp.value) location_name = event.location.value if location_name: qs = Place.objects.filter(name__iexact=location_name) if qs.count() == 0: pl = Place(name=location_name) pl.full_clean() pl.save() dblogger.info("Auto-created location %s", pl) else: pl = qs[0] if qs.count() > 1: dblogger.warning( "Found more than 1 Place for location %r", location_name) set_kw.update(place=pl) else: set_kw.update(place=None) if event.transp.value == 'TRANSPARENT': set_kw.update(transparent=True) else: set_kw.update(transparent=False) set_kw.update(description=event.description.value) set_kw.update(calendar=dbcal) #~ set_kw.update(location=event.location.value) #~ kw.update(dtend=event.dtend.value) dblogger.info("It's a RecurringComponent") if event.rruleset: try: obj = RecurrenceSet.objects.get(uid=uid) assert obj.calendar == dbcal rs_updated += 1 except RecurrenceSet.DoesNotExist as e: #~ except Exception, e: obj = RecurrenceSet(uid=uid) obj.calendar = dbcal obj.user = dbcal.user rs_created += 1 #~ raise Exception("20110823 must save rrule, rdate etc... %s" % type(event.rrule_list)) obj.rrules = '\n'.join( [r.value for r in event.rrule_list]) #~ obj.exrules = '\n'.join([r.value for r in event.exrule_list]) #~ obj.rdates = '\n'.join([r.value for r in event.rdate_list]) #~ obj.exdates = '\n'.join([r.value for r in event.exdate_list]) obj.summary = event.summary.value obj.description = event.description.value setkw(obj, **dt2kw(dtstart, 'start')) obj.full_clean() obj.save() dblogger.info("Saved %s", obj) rs_touched.add(obj.pk) set_kw.update(rset=obj) if getattr(dtstart, 'tzinfo', False): dtlist = event.rruleset.between( aware(from_date), aware(until_date)) else: dtlist = event.rruleset.between( from_date, until_date) dblogger.info("rrulset.between() --> %s", dtlist) else: dtlist = [dtstart] dblogger.info("No rruleset") duration = event.dtend.value - dtstart for dtstart in dtlist: dtend = dtstart + duration get_kw = dt2kw(dtstart, 'start', **get_kw) set_kw = dt2kw(dtend, 'end', **set_kw) try: obj = Event.objects.get(**get_kw) count_update += 1 except Event.DoesNotExist as e: #~ except Exception, e: obj = Event(**get_kw) obj.user = dbcal.user count_new += 1 setkw(obj, **set_kw) obj.full_clean() obj.save() dblogger.info("Saved %s", obj) ev_touched.add(obj.pk) else: raise Exception( "comp.instance.vevent is a %s (expected VEvent)" % type(event)) else: raise Exception( "Got unhandled component %s" % comp.instance.prettyPrint()) #~ print "children:", [c for c in comp.instance.getChildren()] #~ raise StopIteration qs = dbcal.event_set.exclude(id__in=ev_touched) count_deleted = qs.count() qs.delete() # note: doesn't call delete methods of individual objects qs = dbcal.recurrenceset_set.exclude(id__in=rs_touched) rs_deleted = qs.count() qs.delete() # note: doesn't call delete methods of individual objects dblogger.info( "--> Created %d, updated %d, deleted %s Events", count_new, count_update, count_deleted) dblogger.info( "--> Created %d, updated %d, deleted %s RecurrenceSets", rs_created, rs_updated, rs_deleted)
def _create(self, name, id=None): """ Create a new calendar with display name `name` in `parent`. """ if id is None: id = str(uuid.uuid1()) self.id = id path = self.parent.url.join(id) self.url = path ## TODO: mkcalendar seems to ignore the body on most servers? ## at least the name doesn't get set this way. ## zimbra gives 500 (!) if body is omitted ... if name: display_name = dav.DisplayName(name) cal = cdav.CalendarCollection() coll = dav.Collection() + cal type = dav.ResourceType() + coll prop = dav.Prop() + [type,] if name: prop += [display_name,] set = dav.Set() + prop mkcol = cdav.Mkcalendar() + set q = etree.tostring(mkcol.xmlelement(), encoding="utf-8", xml_declaration=True) r = self.client.mkcalendar(path, q) if r.status != 201: raise error.MkcalendarError(r.raw) if name: try: self.set_properties([display_name]) except: self.delete() raise ## Special hack for Zimbra! The calendar we've made exists at ## the specified URL, and we can do operations like ls, even ## PUT an event to the calendar. Zimbra will enforce that the ## event uuid matches the event url, and return either 201 or ## 302 - but alas, try to do a GET towards the event and we ## get 404! But turn around and replace the calendar ID with ## the calendar name in the URL and hey ... it works! ## TODO: write test cases for calendars with non-trivial ## names and calendars with names already matching existing ## calendar urls and ensure they pass. zimbra_url = self.parent.url.join(name) try: ret = self.client.request(zimbra_url) if ret.status == 404: raise error.NotFoundError ## insane server self.url = zimbra_url except error.NotFoundError: ## sane server pass
def _create(self, name, id=None, supported_calendar_component_set=None): """ Create a new calendar with display name `name` in `parent`. """ if id is None: id = str(uuid.uuid1()) self.id = id path = self.parent.url.join(id) self.url = path # TODO: mkcalendar seems to ignore the body on most servers? # at least the name doesn't get set this way. # zimbra gives 500 (!) if body is omitted ... # ehm ... this element seems non-existent in the RFC? # Breaks with baikal, too ... # cal = cdav.CalendarCollection() # coll = dav.Collection() # + cal # also breaks on baikal, # # and probably not needed? # type = dav.ResourceType() ## probably not needed? prop = dav.Prop() # + [type,] if name: display_name = dav.DisplayName(name) prop += [display_name, ] if supported_calendar_component_set: sccs = cdav.SupportedCalendarComponentSet() for scc in supported_calendar_component_set: sccs += cdav.Comp(scc) prop += sccs set = dav.Set() + prop mkcol = cdav.Mkcalendar() + set r = self._query(root=mkcol, query_method='mkcalendar', url=path, expected_return_value=201) # COMPATIBILITY ISSUE # name should already be set, but we've seen caldav servers failing # on setting the DisplayName on calendar creation # (DAViCal, Zimbra, ...). Better to be explicit. if name: try: self.set_properties([display_name]) except: self.delete() raise # Special hack for Zimbra! The calendar we've made exists at # the specified URL, and we can do operations like ls, even # PUT an event to the calendar. Zimbra will enforce that the # event uuid matches the event url, and return either 201 or # 302 - but alas, try to do a GET towards the event and we # get 404! But turn around and replace the calendar ID with # the calendar name in the URL and hey ... it works! # TODO: write test cases for calendars with non-trivial # names and calendars with names already matching existing # calendar urls and ensure they pass. zimbra_url = self.parent.url.join(name) try: ret = self.client.request(zimbra_url) if ret.status == 404: raise error.NotFoundError # special hack for radicale. # It will happily accept any calendar-URL without returning 404. ret = self.client.request(self.parent.url.join( 'ANYTHINGGOESHEREthisshouldforsurereturn404')) if ret.status == 404: # insane server self.url = zimbra_url except error.NotFoundError: # sane server pass
def from_remote_calendar(cls, remote_calendar): props = remote_calendar.get_properties([dav.DisplayName(),]) return (Calendar(props[dav.DisplayName.tag], remote_calendar.id))
def get_events_from_caldav( url, calendar_name ): client = caldav.DAVClient(url) principal = client.principal() calendars = principal.calendars() for calendar in calendars: if "{'{DAV:}displayname': '"+calendar_name+"'}" == str(calendar.get_properties([dav.DisplayName(),])): print ("Using calendar: " + str(calendar)) loaded_events = 0 startdate = datetime.datetime.now() - dateutil.relativedelta.relativedelta(years = 1) enddate = startdate + dateutil.relativedelta.relativedelta(months=1) while startdate < datetime.datetime.now() + dateutil.relativedelta.relativedelta(years = 3): print("time: " + str(startdate) + " - " + str(enddate)) for event in calendar.date_search(startdate,enddate): eventlist.append(event.data) loaded_events = loaded_events + 1 startdate = enddate enddate = startdate + dateutil.relativedelta.relativedelta(months=1) return
def add_events_to_caldav( url, calendar_name ): client = caldav.DAVClient(url) principal = client.principal() calendars = principal.calendars() for calendar in calendars: if "{'{DAV:}displayname': '"+calendar_name+"'}" == str(calendar.get_properties([dav.DisplayName(),])): print ("Using calendar: " + str(calendar)) total_events = len(eventlist) saved_events = 0 for event in eventlist: try: calendar.add_event(event) print("saved event " + str(saved_events) + " of " + str(total_events) + " events") saved_events = saved_events + 1 except: print("An exception occurred") print(event) f = open("join_calendars.log", "a") f.write("##############################################") f.write(event) f.close() return
def _create(self, name, id=None, supported_calendar_component_set=None): """ Create a new calendar with display name `name` in `parent`. """ if id is None: id = str(uuid.uuid1()) self.id = id path = self.parent.url.join(id) self.url = path ## TODO: mkcalendar seems to ignore the body on most servers? ## at least the name doesn't get set this way. ## zimbra gives 500 (!) if body is omitted ... cal = cdav.CalendarCollection() coll = dav.Collection() + cal type = dav.ResourceType() + coll prop = dav.Prop() + [ type, ] if name: display_name = dav.DisplayName(name) prop += [ display_name, ] if supported_calendar_component_set: sccs = cdav.SupportedCalendarComponentSet() for scc in supported_calendar_component_set: sccs += cdav.Comp(scc) prop += sccs set = dav.Set() + prop mkcol = cdav.Mkcalendar() + set r = self._query(root=mkcol, query_method='mkcalendar', url=path, expected_return_value=201) if name: try: self.set_properties([display_name]) except: self.delete() raise ## Special hack for Zimbra! The calendar we've made exists at ## the specified URL, and we can do operations like ls, even ## PUT an event to the calendar. Zimbra will enforce that the ## event uuid matches the event url, and return either 201 or ## 302 - but alas, try to do a GET towards the event and we ## get 404! But turn around and replace the calendar ID with ## the calendar name in the URL and hey ... it works! ## TODO: write test cases for calendars with non-trivial ## names and calendars with names already matching existing ## calendar urls and ensure they pass. zimbra_url = self.parent.url.join(name) try: ret = self.client.request(zimbra_url) if ret.status == 404: raise error.NotFoundError ## insane server self.url = zimbra_url except error.NotFoundError: ## sane server pass
username = "******" password = "******" calendar_names = ["Müll", "Family", "Privat"] final_url = "https://" + username + ":" + password + "@" + url client = caldav.DAVClient(final_url) principal = client.principal() calendars = principal.calendars() caldata_today = [] caldata_tomorrow = [] if len(calendars) > 0: for i in range(0, len(calendars) - 1): calendar_displayname = str(calendars[i].get_properties([ dav.DisplayName(), ])) #print(calendar_displayname) for calendar_name in calendar_names: if calendar_displayname.find(calendar_name) > 0: calendar = calendars[i] html_today = '<table>' html_tomorrow = '<table>' searchdate = date.today() #print("Termine heute:",date(searchdate.year, searchdate.month, searchdate.day)) results = calendar.date_search( date(searchdate.year, searchdate.month, searchdate.day), date(searchdate.year, searchdate.month, searchdate.day + 1)) for event in results: ev = event
# print(" Name: %-20s URL: %s" % (c.name, c.url)) # else: # print("your principal has no calendars") # regExp_dtstart = re.compile('(0-9){8}') # regExp_dtstart = re.compile('(20100729)') # DTSTART;TZID=Asia/Seoul:20100729T100000 # DTEND;TZID=Asia/Seoul:20100729T110000 KST = timezone('Asia/Seoul') now = utc.localize(datetime.utcnow()).astimezone(KST).strftime('%Y%m%d') if len(calendars) > 0: for calendar in calendars: properties = calendar.get_properties([dav.DisplayName(), ]) display_name = properties['{DAV:}displayname'] # 캘린더명 가져오기 # print(properties) if display_name != '내 캘린더':continue # all_events = calendar.events() for event in calendar.events(): data = get_vevent_data(event) dtstart = data.get('dtstart').dt.strftime('%Y%m%d') dtend = data.get('dtend').dt.strftime('%Y%m%d') # if type(dtstart.dt) == type(date.today()) :continue # print(type(dtstart.dt)) # print(dtend.dt) print(display_name, dtstart, now, dtend) if not dtstart <= now <= dtend: continue print(display_name, data, '===============>', data.get('summary'))
def testCalendar(self): c = Calendar(self.caldav, name="Yep", parent=self.principal, id=testcal_id).save() assert_not_equal(c.url, None) # TODO: fail #props = c.get_properties([DAVDisplayName(),]) #assert_equal("Yep", props[DAVDisplayName.tag]) c.set_properties([ dav.DisplayName("hooray"), ]) props = c.get_properties([ dav.DisplayName(), ]) assert_equal(props[dav.DisplayName.tag], "hooray") print c cc = Calendar(self.caldav, name="Yep", parent=self.principal).save() assert_not_equal(cc.url, None) cc.delete() e = Event(self.caldav, data=ev1, parent=c).save() assert_not_equal(e.url, None) print e, e.data ee = Event(self.caldav, url=url.make(e.url), parent=c) ee.load() assert_equal(e.instance.vevent.uid, ee.instance.vevent.uid) r = c.date_search(datetime(2006, 7, 13, 17, 00, 00), datetime(2006, 7, 15, 17, 00, 00)) assert_equal(e.instance.vevent.uid, r[0].instance.vevent.uid) for e in r: print e.data assert_equal(len(r), 1) all = c.events() assert_equal(len(all), 1) e2 = Event(self.caldav, data=ev2, parent=c).save() assert_not_equal(e.url, None) tmp = c.event("*****@*****.**") assert_equal(e2.instance.vevent.uid, tmp.instance.vevent.uid) r = c.date_search(datetime(2006, 7, 13, 17, 00, 00), datetime(2006, 7, 15, 17, 00, 00)) for e in r: print e.data assert_equal(len(r), 1) e.data = ev2 e.save() r = c.date_search(datetime(2006, 7, 13, 17, 00, 00), datetime(2006, 7, 15, 17, 00, 00)) for e in r: print e.data assert_equal(len(r), 1)
def main(): parser = argparse.ArgumentParser() parser.add_argument('-i', metavar='FILE_NAME', help='Input JSON file with appointments', required=True) parser.add_argument('-o', metavar='FILE_NAME', help='Output ICS file') parser.add_argument('--caldav', metavar='CALDAV_URL', help='URL of the CALDAV server') parser.add_argument('-p', '--person_name', metavar='NAME', help='Name to append to calendar entries') args = parser.parse_args() if not args.o and not url: print ('Provide -o command line argument for file output or CALDAV_URL environment variable ' + 'for CalDAV output') parser.print_help() sys.exit(1) appointments = None with open(args.i) as f: appointments = json.load(f) # Generate vcal events from appointments icalendars = [] all_events = Calendar() for appointment in appointments: cal = Calendar() location = get_location(appointment['clinicName']) dt = dateutil.parser.parse(appointment['appointmentDate']) tz = pytz.timezone('Europe/Warsaw') local = dt.replace(tzinfo=tz) event = Event() #event['methdo'] event['uid'] = '{0}@medicover.pl'.format(appointment['id']) event['dtstart'] = vDatetime(local) event['dtend'] = vDatetime(local + datetime.timedelta(minutes=appointment['duration'])) event['dtstamp'] = vDatetime(now) event['summary'] = vText(appointment['specializationName']) summary = appointment['specializationName'] if args.person_name: summary += u' – {0}'.format(args.person_name) event['summary'] = vText(summary) event['description'] = vText(u'{0}, {1}'.format( appointment['specializationName'], appointment['doctorName'])) event['class'] = 'private' if location: event['location'] = vText(u'{0}, {1}, {2}'.format(appointment['clinicName'], location['address'], location['cityname'])) geocode = location['geocode'] if geocode: event['geo'] = '{0};{1}'.format(*geocode['geo']) else: event['location'] = appointment['clinicName'] cal.add_component(event) icalendars.append(cal) all_events.add_component(event) # Write calendar to file. if args.o: print 'Writing ' + args.o output_file = open(args.o, 'w') output_file.write(all_events.to_ical()) # Write calendar to CalDAV. if url: client = caldav.DAVClient(url) principal = client.principal() calendars = principal.calendars() for calendar in calendars: name = calendar.get_properties([dav.DisplayName(),])['{DAV:}displayname'] if name == 'Medicover': for cal in icalendars: print cal.to_ical() event = calendar.add_event(cal.to_ical()) print 'Event', event, 'created'
config = configparser.ConfigParser() config.read(['config.dist.ini', 'config.ini']) print("SevDesk API-Token: " + config.get("sevdesk", "apikey")) print("Zeige alle Rechnungen an:") params = {'token': config.get("sevdesk", "apikey"), 'limit': 1000, 'offset': 0} response = requests.get('https://my.sevdesk.de/api/v1/Invoice', params=params) if response.ok: jsonResponse = response.json() for invoice in jsonResponse['objects']: print(invoice) calDavUrl = config.get('calendar', 'url') print("Benuzte URL: %s" % calDavUrl) client = caldav.DAVClient(calDavUrl, None, config.get('calendar', 'user'), config.get('calendar', 'pass')) principal = client.principal() calendars = principal.calendars() print(calendars) for cal in calendars: calendar_name = cal.get_properties([dav.DisplayName() ])['{DAV:}displayname'] section_name = 'calendar_' + calendar_name.replace(' ', '_') if section_name in config.sections(): print("Price for %s: %.2f €" % (calendar_name, float(config.get(section_name, 'price')))) for event in cal.events(): print("Ereignis: %s" % event) else: print("Calendar %s is not matched" % calendar_name)