Пример #1
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())
Пример #2
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
Пример #3
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}\'.')
Пример #4
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')
Пример #5
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)
Пример #6
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()
Пример #7
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()