def build(): try: cal = Calendar() dav = DAVClient(url) for calendar in dav.principal().calendars(): for event in calendar.events(): evcal = Calendar.from_ical(event.data) for e in evcal.walk(): if isinstance(e, Event): cal.add_component(e) return cal.to_ical().decode('utf-8') except OSError as e: print("caldav:{}: {}".format(name, e)) return None
def main(): url = getenv(URL_ENV) username = getenv(USER_ENV) password = getenv(PASS_ENV) if url is None: url = input('URL: ') if username is None: username = input('Username: '******'Password: '******'Invalid URL or credentials.') exit(1) start = getenv(START_ENV) end = getenv(END_ENV) try: start = datetime.fromisoformat(start) end = datetime.fromisoformat(end) except ValueError: print(f'Invalid {START_ENV} or {END_ENV} value.') exit(1) if start is None: default_start = datetime(date.today().year, 1, 1) start = timeinput( f'Start time [{default_start.strftime("%Y-%m-%d %H:%M")}]: ', default_start) if end is None: default_end = datetime(date.today().year + 1, 1, 1) end = timeinput( f'End time [{default_end.strftime("%Y-%m-%d %H:%M")}]: ', default_end) for cal in principal.calendars(): for ev in cal.date_search(start=start, end=end, expand=True): # expand recurring events write_event(cal.name, ev) with open(join(calendar_folder(cal.name), CAL_NAME_FILE), 'w') as f: # for importing f.write(cal.name) print(f'Exported events from calendar \'{cal.name}\'.')
def update_calendar(client: DAVClient, calendar_name: str, event: Event) -> None: """ Create or update an event in a calendar. """ principal = client.principal() try: calendar = principal.calendar(name=calendar_name) except caldav.error.NotFoundError: calendar = principal.make_calendar(name=calendar_name) # delete existing event, identified by URL if "url" in event: # pad search, otherwise it will return nothing existing_events = calendar.date_search( start=event["dtstart"].dt.date(), end=event["dtend"].dt.date() + timedelta(days=1), expand=False, ) for existing_event in existing_events: vevent = existing_event.vobject_instance.vevent if hasattr(vevent, "url") and vevent.url.value == event["url"]: _logger.info("Found existing event, deleting") existing_event.delete() # wrap in BEGIN:VCALENDAR component = Calendar() component.add("prodid", "-//Nefelibata Corp.//CalDAV Client//EN") component.add("version", "2.0") component.add("x-wr-calname", calendar_name) component.add_component(event) _logger.info("Creating event") calendar.save_event(component.to_ical())
def __init__( # pylint: disable=too-many-arguments self, root: Path, config: Config, url: str, username: str, password: str, calendar: str, **kwargs: Any): super().__init__(root, config, **kwargs) self.client = DAVClient(url=url, username=username, password=password) self.calendar = calendar
def main(): url = getenv(URL_ENV) username = getenv(USER_ENV) password = getenv(PASS_ENV) if url is None: url = input('URL: ') if username is None: username = input('Username: '******'Password: '******'Invalid URL or credentials.') exit(1) parent_folder = getcwd() for path in listdir(): if not (path.startswith(EXPORT_FOLDER_PREFIX) and isdir(path)): continue chdir(join(parent_folder, path)) try: with open(CAL_NAME_FILE, 'r') as f: cal_name = f.readline().strip() except FileNotFoundError: print( f'Found directory {path} which matches the export folder schema but does not contain a \ {CAL_NAME_FILE} file.') continue print(f'Importing calendar \'{cal_name}\'...') calendar = available_calendars.get(cal_name, principal.make_calendar(cal_name)) count = len(listdir()) for i, path in enumerate(listdir()): if path.endswith('.ics'): with open(path, 'r') as f: calendar.save_event(''.join(f.readlines())) print(f'\t{i}/{count}', end='\r')
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', type=bool, default=False, 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', default=None) parser.add_argument('remfile', nargs='?', default=expanduser('~/.reminders'), help='The Remind file to process (default: ~/.reminders)') args = parser.parse_args() rem = Remind(args.remfile) ldict = set(rem.get_uids()) try: (user, _, passwd) = netrc().authenticators(urlparse(args.davurl).netloc) except (IOError, TypeError): if not args.davuser: print "dav2rem: error: argument -u/--davuser is required" return 2 user = args.davuser if args.davpass: passwd = args.davpass else: passwd = getpass() client = DAVClient(args.davurl, username=user, password=passwd) principal = client.principal() calendar = principal.calendars()[0] 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] vevent.load() rem.append(vevent.data)
def __init__(self, calendar=None, url=None): if not config.CALENDAR_ACTIVE: return self.url = url if url is not None else config.CALENDAR_URL self.client = DAVClient(self.url) self.principal = None for _ in range(config.CALENDAR_MAX_REQUESTS): try: self.principal = self.client.principal() break except Exception as exc: print("Got exception {} from caldav, retrying".format( str(exc))) if self.principal is None: raise CalendarException( "Got {} CalDAV-error from the CalDAV server.".format( config.CALENDAR_MAX_REQUESTS)) if calendar is not None: self.calendar = self.get_calendar(calendar) else: self.calendar = calendar
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 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, })
class Client: def __init__(self, calendar=None, url=None): if not config.CALENDAR_ACTIVE: return self.url = url if url is not None else config.CALENDAR_URL self.client = DAVClient(self.url) self.principal = None for _ in range(config.CALENDAR_MAX_REQUESTS): try: self.principal = self.client.principal() break except Exception as exc: print("Got exception {} from caldav, retrying".format( str(exc))) if self.principal is None: raise CalendarException( "Got {} CalDAV-error from the CalDAV server.".format( config.CALENDAR_MAX_REQUESTS)) if calendar is not None: self.calendar = self.get_calendar(calendar) else: self.calendar = calendar def get_calendars(self): if not config.CALENDAR_ACTIVE: return for _ in range(config.CALENDAR_MAX_REQUESTS): try: return [ calendar.name for calendar in self.principal.calendars() ] except Exception as exc: print("Got exception {} from caldav, retrying".format( str(exc))) raise CalendarException( "Got {} CalDAV Errors from the CalDAV server.".format( config.CALENDAR_MAX_REQUESTS)) def get_calendar(self, calendar_name): candidates = self.principal.calendars() for calendar in candidates: if calendar.name == calendar_name: return calendar raise CalendarException("No calendar named {}.".format(calendar_name)) def set_event_at(self, begin, name, description): if not config.CALENDAR_ACTIVE: return candidates = [ Event.from_raw_event(raw_event) for raw_event in self.calendar.date_search( begin, begin + timedelta(hours=1)) ] candidates = [event for event in candidates if event.name == name] event = None if len(candidates) == 0: event = Event( None, name, description, begin, begin + timedelta(hours=config.CALENDAR_DEFAULT_DURATION)) vevent = self.calendar.add_event(event.to_vcal()) event.vevent = vevent else: event = candidates[0] event.set_description(description) event.vevent.save()
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", default=None) 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().decode("utf-8")) 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 = {} try: (user, _, passwd) = netrc().authenticators(urlparse(args.davurl).netloc) except (IOError, TypeError): if not args.davuser: print "rem2dav: error: argument -u/--davuser is required" return 2 user = args.davuser if args.davpass: passwd = args.davpass else: passwd = getpass() client = DAVClient(args.davurl, username=user, password=passwd) principal = client.principal() calendar = principal.calendars()[0] 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.viewkeys() & odict.viewkeys() rdict = {key: rdict[key] for key in intersect} else: rdict = {} local = ldict.viewkeys() - rdict.viewkeys() for uid in local: ncal = iCalendar() ncal.add(ldict[uid]) calendar.add_event(ncal.serialize()) if args.delete or args.old: remote = rdict.viewkeys() - ldict.viewkeys() for uid in remote: rdict[uid].delete()
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()