Beispiel #1
0
 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
Beispiel #2
0
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}\'.')
Beispiel #3
0
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())
Beispiel #4
0
    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
Beispiel #5
0
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')
Beispiel #6
0
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)
Beispiel #7
0
 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
Beispiel #8
0
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))
Beispiel #9
0
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,
    })
Beispiel #10
0
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()
Beispiel #11
0
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()
Beispiel #12
0
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
Beispiel #13
0
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()