예제 #1
0
 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)
     ])
예제 #2
0
 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)
예제 #3
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))
예제 #4
0
    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))
예제 #5
0
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
예제 #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', 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)
예제 #7
0
 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
예제 #8
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,
    })
예제 #9
0
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
예제 #10
0
 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)
예제 #11
0
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
예제 #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
예제 #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()