def update_calendar(self, calendar): """Update an existing calendar.""" remote_cal = Calendar(self.client, calendar.encoded_path) remote_cal.set_properties([ dav.DisplayName(calendar.name), ical.CalendarColor(calendar.color) ])
def __init__(self, username, password, calendar=None): """Constructor.""" super(Caldav_Backend, self).__init__(calendar) server_url = smart_str( param_tools.get_global_parameter("server_location")) self.client = caldav.DAVClient( server_url, username=username, password=password) if self.calendar: self.remote_cal = Calendar(self.client, calendar.encoded_path)
def main(): """Command line tool to download from CalDAV to Remind""" parser = ArgumentParser(description='Command line tool to download from CalDAV to Remind') parser.add_argument('-d', '--delete', action='store_true', help='Delete old events') parser.add_argument('-r', '--davurl', required=True, help='The URL of the CalDAV server') parser.add_argument('-u', '--davuser', help='The username for the CalDAV server') parser.add_argument('-p', '--davpass', help='The password for the CalDAV server') parser.add_argument('-i', '--insecure', action='store_true', help='Ignore SSL certificate') parser.add_argument('remfile', nargs='?', default=expanduser('~/.reminders'), help='The Remind file to process (default: ~/.reminders)') args = parser.parse_args() # create empty file if it does not exist open(args.remfile, 'a') rem = Remind(args.remfile) ldict = set(rem.get_uids()) if args.davuser and args.davpass: user = args.davuser passwd = args.davpass else: try: (user, _, passwd) = netrc().authenticators(urlparse(args.davurl).netloc) except (IOError, TypeError): if not args.davuser: print('dav2rem: Error, argument -u/--davuser or netrc is required') return 1 user = args.davuser try: from keyring import get_password passwd = get_password(urlparse(args.davurl).netloc, user) except ImportError: passwd = None if not passwd: passwd = getpass() client = DAVClient(args.davurl, username=user, password=passwd, ssl_verify_cert=not args.insecure) calendar = Calendar(client, args.davurl) rdict = {splitext(basename(event.canonical_url))[0].replace('%40', '@'): event for event in calendar.events()} if args.delete: local = ldict - rdict.keys() for uid in local: rem.remove(uid) remote = rdict.keys() - ldict for uid in remote: vevent = rdict[uid] rem.append_vobject(readOne(vevent.data))
def create(calendar: caldav.Calendar, summary: str, description: str = ""): ics = [ "BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//Dashboard//CalDAV Client//EN", "BEGIN:VTODO", "UID:{}@dashboard.selfcoders.com".format(uuid.uuid4()), "DTSTAMP:{}".format(datetime.datetime.now().astimezone(tz=timezone("UTC")).strftime("%Y%m%dT%H%M%SZ")), "SUMMARY:{}".format(escape_ical_string(summary)), "DESCRIPTION:{}".format(escape_ical_string(description)), "END:VTODO", "END:VCALENDAR" ] calendar.add_todo("\n".join(ics))
def convert(calD: caldav.Calendar, clear: bool) -> List[Event]: results = calD.events(baikal=True) events = [] for subcalendar in results: cal = Calendar.from_ical(subcalendar._data) for component in cal.walk(): if component.name == "VEVENT": event = __processEvent(component, clear) events.append(event) return events
def main(): """Command line tool to download from CalDAV to Remind""" parser = ArgumentParser(description='Command line tool to download from CalDAV to Remind') parser.add_argument('-d', '--delete', action='store_true', help='Delete old events') parser.add_argument('-r', '--davurl', required=True, help='The URL of the CalDAV server') parser.add_argument('-u', '--davuser', help='The username for the CalDAV server') parser.add_argument('-p', '--davpass', help='The password for the CalDAV server') parser.add_argument('-i', '--insecure', action='store_true', help='Ignore SSL certificate') parser.add_argument('remfile', nargs='?', default=expanduser('~/.reminders'), help='The Remind file to process (default: ~/.reminders)') args = parser.parse_args() # create empty file if it does not exist open(args.remfile, 'a') rem = Remind(args.remfile) ldict = set(rem.get_uids()) if args.davuser and args.davpass: user = args.davuser passwd = args.davpass else: try: (user, _, passwd) = netrc().authenticators(urlparse(args.davurl).netloc) except (IOError, TypeError): if not args.davuser: print 'dav2rem: Error, argument -u/--davuser or netrc is required' return 1 user = args.davuser try: from keyring import get_password passwd = get_password(urlparse(args.davurl).netloc, user) except ImportError: passwd = None if not passwd: passwd = getpass() client = DAVClient(args.davurl, username=user, password=passwd, ssl_verify_cert=not args.insecure) calendar = Calendar(client, args.davurl) rdict = {splitext(basename(event.canonical_url))[0].replace('%40', '@'): event for event in calendar.events()} if args.delete: local = ldict - rdict.viewkeys() for uid in local: rem.remove(uid) remote = rdict.viewkeys() - ldict for uid in remote: vevent = rdict[uid] rem.append(vevent.data)
def update_event(self, uid, original_data): """Update an existing event.""" data = dict(original_data) url = "{}/{}.ics".format(self.remote_cal.url.geturl(), uid) cal = self.remote_cal.event_by_url(url) orig_evt = cal.vobject_instance.vevent if "title" in data: orig_evt.summary.value = data["title"] if data.get("allDay"): data["start"] = data["start"].date() data["end"] = data["end"].date() if "start" in data: del orig_evt.contents["dtstart"] orig_evt.add("dtstart").value = data["start"] if "end" in data: del orig_evt.contents["dtend"] orig_evt.add("dtend").value = data["end"] if "description" in data: if "description" in orig_evt.contents: orig_evt.description.value = data["description"] else: orig_evt.add("description").value = data["description"] if "attendees" in data: if "attendee" in orig_evt.contents: del orig_evt.contents["attendee"] for attdef in data.get("attendees", []): attendee = orig_evt.add('attendee') attendee.value = "MAILTO:{}".format(attdef["email"]) attendee.params["CN"] = [attdef["display_name"]] attendee.params["ROLE"] = ['REQ-PARTICIPANT'] if "calendar" in data and self.calendar.pk != data["calendar"].pk: # Calendar has been changed, remove old event first. self.remote_cal.client.delete(url) remote_cal = Calendar(self.client, data["calendar"].encoded_path) url = "{}/{}.ics".format(remote_cal.url.geturl(), uid) else: remote_cal = self.remote_cal remote_cal.add_event(cal.instance) return uid
def change_calendar(request, calendar_id: int = None): if calendar_id: calendar = get_object_or_404(DavCalendar, id=calendar_id, user=request.user) form = DavCalendarForm(request.POST, instance=calendar, user=request.user) else: form = DavCalendarForm(request.POST, user=request.user) if form.is_valid(): caldav_obj = form.save(commit=False) old_calendars = DavCalendar.objects.filter(user=request.user).exclude(id=calendar_id) exists = False # This is necessary as the urls are encrypted in the DB and can't filtered wherefore for old_calendar in old_calendars: if old_calendar.id != calendar_id and old_calendar.url == caldav_obj.url: exists = True break if not exists: try: calendar = Calendar(client=DAVClient(caldav_obj.url), url=caldav_obj.url) calendar.date_search(now(), now() + timedelta(hours=1)) caldav_obj.user = request.user caldav_obj.save() return redirect('settings') except Exception as e: form.add_error(None, ugettext_lazy("Error getting Calendar: {}".format(str(e)))) else: form.add_error(None, ugettext_lazy("This calendar is already configured")) elif 'delete' in request.POST: obj = get_object_or_404(DavCalendar, id=request.POST['delete'], user=request.user) obj.delete() return redirect('settings') return TemplateResponse(request, "caldav/caldav.html", { 'calendar_form': form, 'calendars': DavCalendar.objects.filter(user=request.user), 'calendar_id': calendar_id, 'edit': calendar_id is not None, })
def _get_calendar_events(settings: calview.settings.FrozenSettings, calendar: caldav.Calendar) -> list: """Connect to calDAV and get relevant events. Quits with exit code (1), if connection can't be established. Args: settings: full settings calendar: the calendar to query Returns: List of relevant, unloaded events; needs to be interpreted for further use. Raises: SystemExit: If connection can't be established (indirectly via calview.helper.quitter) """ try: relevant_events = calendar.date_search(start=settings.start_date, end=settings.end_date) except caldav.lib.error.AuthorizationError as not_authorized: logmsg = ('Wrong password / connection settings. Please ' 'check section [CONNECTION], variable user, ' 'server, calendar_url. You set them to: "%s", "%s"' ' and "%s" in: "%s". Exiting (1)') logging.critical(logmsg, settings.user, settings.server, settings.calendar_url, settings.settings_file) logging.debug('Caught: %s', not_authorized) quitmsg = 'Connection failed: Wrong password?' calview.helper.quitter(settings, quitmsg) except caldav.lib.error.NotFoundError as not_found: logmsg = ('Calendar / Server not found. Does it exist? Please ' 'check section [CONNECTION], variable calendar_url ' 'and variable server. You set them to: "%s" and "%s"' ' in: "%s". Exiting (1)') logging.critical(logmsg, settings.calendar_url, settings.server, settings.settings_file) logging.debug('Caught: %s', not_found) calview.helper.quitter(settings, 'Calendar / Server not found.') return relevant_events
def calendar(): url = config.get("general", "calendar_url") username = config.get("general", "calendar_username") password = config.get("general", "calendar_password") client = caldav.DAVClient(url, username=username, password=password) return Calendar(client, url)
class Caldav_Backend(CalendarBackend): """CalDAV calendar backend.""" def __init__(self, username, password, calendar=None): """Constructor.""" super(Caldav_Backend, self).__init__(calendar) server_url = smart_str( param_tools.get_global_parameter("server_location")) self.client = caldav.DAVClient( server_url, username=username, password=password) if self.calendar: self.remote_cal = Calendar(self.client, calendar.encoded_path) def _serialize_event(self, event): """Convert a vevent to a dictionary.""" vevent = event.vobject_instance.vevent description = ( vevent.description.value if "description" in vevent.contents else "" ) result = { "id": vevent.uid.value, "title": vevent.summary.value, "color": self.calendar.color, "description": description, "calendar": self.calendar, "attendees": [] } if isinstance(vevent.dtstart.value, datetime.datetime): all_day = False start = vevent.dtstart.value end = vevent.dtend.value else: tz = timezone.get_current_timezone() all_day = True start = tz.localize( datetime.datetime.combine( vevent.dtstart.value, datetime.time.min)) end = tz.localize( datetime.datetime.combine( vevent.dtend.value, datetime.time.min)) result.update({ "allDay": all_day, "start": start, "end": end }) if "attendee" in vevent.contents: for attendee in vevent.contents["attendee"]: email = ( attendee.value .replace("mailto:", "") .replace("MAILTO:", "") ) result["attendees"].append({ "display_name": attendee.params.get("CN")[0], "email": email }) return result def create_calendar(self, url): """Create a new calendar.""" self.client.mkcalendar(url) def update_calendar(self, calendar): """Update an existing calendar.""" remote_cal = Calendar(self.client, calendar.encoded_path) remote_cal.set_properties([dav.DisplayName(calendar.name), ical.CalendarColor(calendar.color)]) def create_event(self, data): """Create a new event.""" uid = uuid.uuid4() cal = vobject.iCalendar() cal.add("vevent") cal.vevent.add("uid").value = str(uid) cal.vevent.add("summary").value = data["title"] if not data["allDay"]: cal.vevent.add("dtstart").value = data["start"] cal.vevent.add("dtend").value = data["end"] else: cal.vevent.add("dtstart").value = data["start"].date() cal.vevent.add("dtend").value = data["end"].date() self.remote_cal.add_event(cal) return uid def update_event(self, uid, original_data): """Update an existing event.""" data = dict(original_data) url = "{}/{}.ics".format(self.remote_cal.url.geturl(), uid) cal = self.remote_cal.event_by_url(url) orig_evt = cal.vobject_instance.vevent if "title" in data: orig_evt.summary.value = data["title"] if data.get("allDay"): data["start"] = data["start"].date() data["end"] = data["end"].date() if "start" in data: del orig_evt.contents["dtstart"] orig_evt.add("dtstart").value = data["start"] if "end" in data: del orig_evt.contents["dtend"] orig_evt.add("dtend").value = data["end"] if "description" in data: if "description" in orig_evt.contents: orig_evt.description.value = data["description"] else: orig_evt.add("description").value = data["description"] if "attendees" in data: if "attendee" in orig_evt.contents: del orig_evt.contents["attendee"] for attdef in data.get("attendees", []): attendee = orig_evt.add('attendee') attendee.value = "MAILTO:{}".format(attdef["email"]) attendee.params["CN"] = [attdef["display_name"]] attendee.params["ROLE"] = ['REQ-PARTICIPANT'] if "calendar" in data and self.calendar.pk != data["calendar"].pk: # Calendar has been changed, remove old event first. self.remote_cal.client.delete(url) remote_cal = Calendar(self.client, data["calendar"].encoded_path) url = "{}/{}.ics".format(remote_cal.url.geturl(), uid) else: remote_cal = self.remote_cal remote_cal.add_event(cal.instance) return uid def get_event(self, uid): """Retrieve and event using its uid.""" url = "{}/{}.ics".format(self.remote_cal.url.geturl(), uid) event = self.remote_cal.event_by_url(url) return self._serialize_event(event) def get_events(self, start, end): """Retrieve a list of events.""" orig_events = self.remote_cal.date_search(start, end) events = [] for event in orig_events: events.append(self._serialize_event(event)) return events def delete_event(self, uid): """Delete an event using its uid.""" url = "{}/{}.ics".format(self.remote_cal.url.geturl(), uid) self.remote_cal.client.delete(url) def import_events(self, fp): """Import events from file.""" content = smart_str(fp.read()) counter = 0 for cal in vobject.base.readComponents(content): for event in cal.vevent_list: ical = vobject.iCalendar() ical.add(event) self.remote_cal.add_event(ical.serialize()) counter += 1 return counter
def get_caldav(choices: List[Choice], current_poll: Poll, user: BitpollUser, request): # calendar stuff events2 = [] if not settings.CALENDAR_ENABLED or not (user.is_authenticated and current_poll.type == 'datetime' and choices): for choice in choices: events2.append([]) return events2 start = choices[0].date end = choices[-1].date # experimental: fetch calendar(s) events = [] for calendar_obj in user.davcalendar_set.all(): cache_key = "calendar_{}_events_{}-{}".format(calendar_obj.id, start, end).replace(' ', '_') events_calendar = cache.get(cache_key) if events_calendar is None: events_calendar = [] try: calendar = DavCalendar(client=DAVClient(calendar_obj.url), url=calendar_obj.url) appointments = calendar.date_search(start, end) for appointment in appointments: ical = Calendar.from_ical(appointment.data) for event in ical.walk(): if event.name == "VEVENT": try: if "DTEND" in event: end = event.decoded('DTEND') else: duration = event.decoded("DURATION") if isinstance(duration, list): duration = duration[ 0] # todo: use all elements?? what does it mean if there are more than one element? end = event.decoded('DTSTART') + duration events_calendar.append({ "DTSTART": event.decoded('DTSTART'), "DTEND": end, "NAME": event.get('summary').title(), }) except (AttributeError, ValueError, TypeError) as e: # we ignore the event we can not parse, but send it to sentry try: from raven.contrib.django.raven_compat.models import client client.captureException() except Exception: # if the sending of the error does fail we ignore it pass cache.set(cache_key, events_calendar) except AuthorizationError as e: messages.warning( request, ugettext_lazy( 'Could not access your calendar "%s" due to an authorization error' % calendar_obj.name)) events += events_calendar for choice in choices: ev_tmp = [] for event in events: if isinstance(event['DTSTART'], type(choice.date)): # datetime if event['DTSTART'] <= choice.date and event[ 'DTEND'] >= choice.date: ev_tmp.append(event) else: # dates if event['DTSTART'] <= choice.date.date() <= event['DTEND']: ev_tmp.append(event) events2.append(ev_tmp) return events2
def main(): """Command line tool to upload a Remind file to CalDAV""" parser = ArgumentParser( description='Command line tool to upload a Remind file to CalDAV') parser.add_argument( '-z', '--zone', default='Europe/Berlin', help='Timezone of Remind file (default: Europe/Berlin)') parser.add_argument( '-s', '--startdate', type=lambda s: parse(s).date(), default=date.today() - timedelta(weeks=12), help='Start offset for remind call (default: -12 weeks)') parser.add_argument( '-m', '--month', type=int, default=15, help= 'Number of month to generate calendar beginning wit stadtdate (default: 15)' ) parser.add_argument('-d', '--delete', action='store_true', help='Delete old events') parser.add_argument('-r', '--davurl', required=True, help='The URL of the CalDAV server') parser.add_argument('-u', '--davuser', help='The username for the CalDAV server') parser.add_argument('-p', '--davpass', help='The password for the CalDAV server') parser.add_argument('-i', '--insecure', action='store_true', help='Ignore SSL certificate') parser.add_argument( 'infile', nargs='?', default=expanduser('~/.reminders'), help='The Remind file to process (default: ~/.reminders)') parser.add_argument( '-o', '--old', default=None, help= 'The old reference Remind file (entries not in the current one will be deleted from dav)' ) args = parser.parse_args() zone = gettz(args.zone) # Manually set timezone name to generate correct ical files # (python-vobject tests for the zone attribute) zone.zone = args.zone if args.infile == '-': remind = Remind(args.infile, zone, args.startdate, args.month) vobject = remind.stdin_to_vobject(stdin.read()) else: remind = Remind(args.infile, zone, args.startdate, args.month) vobject = remind.to_vobject() if hasattr(vobject, 'vevent_list'): ldict = {event.uid.value: event for event in vobject.vevent_list} else: ldict = {} if args.davuser and args.davpass: user = args.davuser passwd = args.davpass else: try: (user, _, passwd) = netrc().authenticators(urlparse(args.davurl).netloc) except (IOError, TypeError): if not args.davuser: print( 'rem2dav: Error, argument -u/--davuser or netrc is required' ) return 1 user = args.davuser try: from keyring import get_password passwd = get_password(urlparse(args.davurl).netloc, user) except ImportError: passwd = None if not passwd: passwd = getpass() client = DAVClient(args.davurl, username=user, password=passwd, ssl_verify_cert=not args.insecure) calendar = Calendar(client, args.davurl) rdict = { splitext(basename(event.canonical_url))[0].replace('%40', '@'): event for event in calendar.events() } if args.old: old = Remind(args.old, zone, args.startdate, args.month) old_vobject = old.to_vobject() if hasattr(old_vobject, 'vevent_list'): odict = { event.uid.value: event for event in old_vobject.vevent_list } intersect = rdict.keys() & odict.keys() rdict = {key: rdict[key] for key in intersect} else: rdict = {} local = ldict.keys() - rdict.keys() for uid in local: ncal = iCalendar() ncal.add(ldict[uid]) calendar.add_event(ncal.serialize()) if args.delete or args.old: remote = rdict.keys() - ldict.keys() for uid in remote: rdict[uid].delete()