Example #1
0
 def test_extract_vtodo(self):
     event1 = Calendar.from_ical(EXAMPLE_VEVENT1)
     todo1 = Calendar.from_ical(EXAMPLE_VTODO1)
     self.assertEqual([todo1.subcomponents[0]],
                      list(
                          filters.extract_vtodos([('foo.ics', event1),
                                                  ('bar.ics', todo1)])))
Example #2
0
def create_or_update_calendar_item(collection_url, component_name, uid):
    """Create or update a calendar item by UID.

    :param collection_url: URL of collection to search in
    :param component_name: Component name (VTODO, VEVENT, etc)
    :param uid: UID value
    :return: (href, etag, old, new), where old and new are Calendar items
        New items will have the first three elements set to None
    """
    try:
        (href, etag, old) = get_by_uid(collection_url, component_name, uid)
    except KeyError:
        etag = None
        props = {'UID': uid}
        todo = component_factory[component_name](**props)
        old = None
        href = None
        new = Calendar()
        new.add_component(todo)
    else:
        new = Calendar.from_ical(old.to_ical())
        for component in old.subcomponents:
            if component.name == component_name:
                todo = component
                break
    return (old, new, href, etag, todo)
Example #3
0
    def test_repr(self):
        """Test correct class representation.
        """
        from icalendar.cal import Component, Calendar, Event

        component = Component()
        component['key1'] = 'value1'

        self.assertTrue(
            re.match(r"Component\({u?'KEY1': 'value1'}\)", str(component)))

        calendar = Calendar()
        calendar['key1'] = 'value1'

        self.assertTrue(
            re.match(r"VCALENDAR\({u?'KEY1': 'value1'}\)", str(calendar)))

        event = Event()
        event['key1'] = 'value1'

        self.assertTrue(re.match(r"VEVENT\({u?'KEY1': 'value1'}\)",
                                 str(event)))

        # Representation of nested Components
        nested = Component(key1='VALUE1')
        nested.add_component(component)
        calendar.add_component(event)
        nested.add_component(calendar)

        self.assertTrue(
            re.match(
                r"Component\({u?'KEY1': 'VALUE1'}, Component\({u?'KEY1': 'value1'}\), VCALENDAR\({u?'KEY1': 'value1'}, VEVENT\({u?'KEY1': 'value1'}\)\)\)",  # nopep8
                str(nested)))
Example #4
0
    async def report(self, environ, body, resources_by_hrefs,
                     properties, base_href, base_resource, depth):
        requested = None
        for el in body:
            if el.tag == '{urn:ietf:params:xml:ns:caldav}time-range':
                requested = el
            else:
                raise AssertionError("unexpected XML element")
        tz = get_calendar_timezone(base_resource)

        def tzify(dt):
            return as_tz_aware_ts(dt, tz).astimezone(pytz.utc)
        (start, end) = _parse_time_range(requested)
        assert start.tzinfo
        assert end.tzinfo
        ret = ICalendar()
        ret['VERSION'] = '2.0'
        ret['PRODID'] = PRODID
        fb = FreeBusy()
        fb['DTSTAMP'] = vDDDTypes(tzify(datetime.datetime.now()))
        fb['DTSTART'] = vDDDTypes(start)
        fb['DTEND'] = vDDDTypes(end)
        fb['FREEBUSY'] = [item async for item in iter_freebusy(
            webdav.traverse_resource(base_resource, base_href, depth),
            start, end, tzify)]
        ret.add_component(fb)
        return webdav.Response(status='200 OK', body=[ret.to_ical()])
Example #5
0
 def extractEqual(self, incal_str, outcal_str):
     incal = ICalendar.from_ical(incal_str)
     expected_outcal = ICalendar.from_ical(outcal_str)
     outcal = ICalendar()
     caldav.extract_from_calendar(incal, outcal, self.requested)
     self.assertEqual(expected_outcal.to_ical().decode(),
                      outcal.to_ical().decode(),
                      ET.tostring(self.requested))
Example #6
0
 def extractEqual(self, incal_str, outcal_str):
     incal = ICalendar.from_ical(incal_str)
     expected_outcal = ICalendar.from_ical(outcal_str)
     outcal = ICalendar()
     outcal = caldav.extract_from_calendar(incal, self.requested)
     self.maxDiff = None
     self.assertMultiLineEqual(
         expected_outcal.to_ical().decode(),
         outcal.to_ical().decode(),
         ET.tostring(self.requested),
     )
Example #7
0
 def get_value_ext(self, base_href, resource, el, environ, requested):
     if len(requested) == 0:
         serialized_cal = b''.join(resource.get_body())
     else:
         c = ICalendar()
         calendar = calendar_from_resource(resource)
         if calendar is None:
             raise KeyError
         extract_from_calendar(calendar, c, requested)
         serialized_cal = c.to_ical()
     # TODO(jelmer): Don't hardcode encoding
     el.text = serialized_cal.decode('utf-8')
Example #8
0
def ls(bdt,
       pve=7,
       cmt=False,
       fp=os.path.expanduser('~/.cal.dat'),
       comm=False,
       exp=True,
       eli=0,
       evo=False):
    entries = Entries(bdt=bdt, fp=fp, comm=comm, exp=exp)
    pvs = ""
    if pve > 0:
        if isinstance(fp, StringIO): fp.seek(0)
        pvd = bdt[0] + dt.timedelta(days=-(bdt[0].day - 2) + 30)
        pvs = repr(Entries(bdt=(None, pvd), fp=fp, exp=False))
    if pvs:
        pvs = "%s%s" % (pvd.strftime("\n %B --\n"), '\n'.join(
            pvs.split('\n')[:pve]))
    else:
        pvs = ""
    if evo:
        return repr(entries) + pvs
    cal = Calendar(bdt[0], bdt if len(bdt) > 1 else (bdt[0], ), entries)
    if eli:
        entries.limit(eli)
    return nextTo(cal, repr(entries) + pvs)
Example #9
0
	def getEvent(self, title):
		cal = Calendar.from_ical(self.getCalendarText())
		countdownEvent = None
		for component in cal.subcomponents:
			if "SUMMARY" in component.keys() and component["SUMMARY"] == title:
				countdownEvent = component
		return countdownEvent
Example #10
0
 def calendar(self):
     if self._calendar is None:
         try:
             self._calendar = Calendar.from_ical(b''.join(self.content))
         except ValueError:
             raise InvalidFileContents(self.content_type, self.content)
     return self._calendar
Example #11
0
def get_by_uid(url, component, uid, depth='1'):
    uidprop = ET.Element('{urn:ietf:params:xml:ns:caldav}calendar-data')
    uidprop.set('name', 'UID')
    dataprop = ET.Element('{urn:ietf:params:xml:ns:caldav}calendar-data')
    ret = caldav.calendar_query(
        url,
        props=[uidprop, dataprop, '{DAV:}getetag'],
        depth=depth,
        filter=caldav.comp_filter(
            "VCALENDAR",
            caldav.comp_filter(
                component,
                caldav.prop_filter(
                    "UID", caldav.text_match(text=uid, collation="i;octet")))))

    for (href, status, propstat) in ret:
        if status == 'HTTP/1.1 404 Not Found':
            raise KeyError(uid)
        etag = None
        data = None
        for prop, prop_status in propstat:
            if prop.tag == '{urn:ietf:params:xml:ns:caldav}calendar-data':
                data = prop.text
            if prop.tag == '{DAV:}getetag':
                etag = prop.text
        assert data is not None, "data missing for %r" % href
        return (href, etag, Calendar.from_ical(data))
    raise KeyError(uid)
Example #12
0
def StripStamps(c):
    if c is None:
        return None
    c = Calendar.from_ical(c.to_ical())
    for sc in c.subcomponents:
        if 'DTSTAMP' in sc:
            del sc['DTSTAMP']
    return c.to_ical()
Example #13
0
 def getEvent(self, title):
     calendarText = self.__getCalendarText()
     cal = Calendar.from_ical(calendarText)
     countdownEvent = None
     for component in cal.subcomponents:
         if "SUMMARY" in component.keys() and component["SUMMARY"] == title:
             countdownEvent = component
     return countdownEvent
Example #14
0
def generate_ics(showings, location):
    calendar = Calendar()
    caplocation = location.capitalize()
    calendar.add('prodid', '-//BFiCal %s Calendar//bfical.com//' % caplocation)
    calendar.add('version', '2.0')

    for showing in showings:
        if showing.master_location == location:
            calevent = CalEvent()
            if showing.ident:
                calevent.add('uid', '*****@*****.**' % showing.ident)
            else:
                calevent.add('uid', '*****@*****.**' % int(time.time()))
            calevent.add('summary', showing.parent().name)
            calevent.add('description', showing.parent().precis)
            calevent.add('location', '%s, BFI %s, London' % (showing.location, caplocation))
            calevent.add('dtstart', showing.start.replace(tzinfo=GB_TZ).astimezone(pytz.utc))
            calevent.add('dtend', showing.end.replace(tzinfo=GB_TZ).astimezone(pytz.utc))
            calevent.add('url', showing.parent().src_url)
            calevent.add('sequence', int(time.time())) # TODO - fix
            #calevent.add('dtstamp', datetime.datetime.now())

            calendar.add_component(calevent)

    return calendar
Example #15
0
def events():
    cal = Calendar.from_ical(requests.get('http://api.meetup.com/noisebridge/upcoming.ical').text)
    events = []
    for event in cal.walk('vevent'):
        events.append({
            'start': event.decoded('dtstart'),
            'title': event.decoded('summary')
        })
    return jsonify(events=events)
Example #16
0
def do_import(username, password, calendar, server, ics_url):
    base_url = CALDAVURL % (server, username, calendar)

    # fetch events from target cal
    target_fetch_url = '%s?export' % base_url
    r = requests.get(target_fetch_url, auth=(username, password))
    r.raise_for_status()
    try:
        target_cal = Calendar.from_ical(r.text)
    except ValueError as e:
        print('Warning: Could not parse iCal (%s)' % target_fetch_url,
              file=sys.stderr)
        print(e, file=sys.stderr)
        return

    existing_uids = [e['UID'].to_ical() for e in target_cal.walk('VEVENT')]

    # fetch webcal
    sourceRequest = requests.get(ics_url)
    sourceRequest.encoding = 'utf-8'
    sourceContent = sourceRequest.text
    c = Calendar.from_ical(sourceContent)

    # import webcal
    imported_uids = []
    for e in c.walk('VEVENT'):
        uid = bytes.decode(e['UID'].to_ical())
        uid.replace('\'', '')
        uid.replace('/', 'slash')
        cal = Calendar()
        cal.add_component(e)
        r = requests.put(
            '%s/%s.ics' % (base_url, uid),
            data=cal.to_ical(),
            auth=(username, password),
            headers={'content-type': 'text/calendar; charset=UTF-8'})
        if r.status_code == 500 and r'Sabre\VObject\Recur\NoInstancesException' in r.text:
            # ignore the NoInstancesException
            print('Warning: No valid instances: %s' % uid, file=sys.stdout)
        elif r.status_code == 201 or r.status_code == 204:
            print('Imported: %s (%d)' % (uid, r.status_code), file=sys.stdout)
            imported_uids.append(uid)
        else:
            r.raise_for_status()

    # remove events not in webcal
    for uid in existing_uids:
        if not uid in imported_uids:
            r = requests.delete('%s/%s.ics' % (base_url, uid),
                                auth=(username, password))
            if r.status_code == 204:
                print('Deleted %s' % uid, file=sys.stdout)
                # ignore 404 - not found (seems to be a manually created event)
            elif r.status_code == 404:
                pass
            else:
                r.raise_for_status()
Example #17
0
def get_all_calendars(url, depth=None, filter=None):
    for (href, status, propstat) in caldav.calendar_query(
            url,
        ['{DAV:}getetag', '{urn:ietf:params:xml:ns:caldav}calendar-data'],
            filter):
        data = None
        for prop, prop_status in propstat:
            if prop.tag == '{urn:ietf:params:xml:ns:caldav}calendar-data':
                data = prop.text
        assert data is not None, "data missing for %r" % href
        yield href, Calendar.from_ical(data)
Example #18
0
    def test_repr(self):
        """Test correct class representation.
        """
        from icalendar.cal import Component, Calendar, Event

        component = Component()
        component['key1'] = 'value1'

        self.assertTrue(
            re.match(r"Component\({u?'KEY1': u?'value1'}\)", str(component))
        )

        calendar = Calendar()
        calendar['key1'] = 'value1'

        self.assertTrue(
            re.match(r"VCALENDAR\({u?'KEY1': u?'value1'}\)", str(calendar))
        )

        event = Event()
        event['key1'] = 'value1'

        self.assertTrue(
            re.match(r"VEVENT\({u?'KEY1': u?'value1'}\)", str(event))
        )

        # Representation of nested Components
        nested = Component(key1='VALUE1')
        nested.add_component(component)
        calendar.add_component(event)
        nested.add_component(calendar)

        self.assertTrue(
            re.match(
                r"Component\({u?'KEY1': u?'VALUE1'}, "
                r"Component\({u?'KEY1': u?'value1'}\), "
                r"VCALENDAR\({u?'KEY1': u?'value1'}, "
                r"VEVENT\({u?'KEY1': u?'value1'}\)\)\)",
                str(nested)
            )
        )
Example #19
0
def do_import(username, password, calendar, server, ics_url):
  base_url = CALDAVURL % (server, username, calendar)

  # fetch events from target cal
  target_fetch_url = '%s?export' % base_url
  r = requests.get(target_fetch_url, auth=(username, password))
  r.raise_for_status()
  try:
    target_cal = Calendar.from_ical(r.text)
  except ValueError as e:
    print('Warning: Could not parse iCal (%s)' % target_fetch_url,
          file=sys.stderr)
    print(e, file=sys.stderr)
    return

  existing_uids = []
  for e in target_cal.walk('VEVENT'):
    uid = bytes.decode(e['UID'].to_ical()).replace('\'', '').replace('/', 'slash')
    existing_uids.append(uid)

  # fetch webcal
  sourceRequest = requests.get(ics_url)
  sourceRequest.encoding = 'utf-8'
  sourceContent = sourceRequest.text
  c = Calendar.from_ical(sourceContent)

  # import webcal
  imported_uids = []
  for e in c.walk('VEVENT'):
    uid = bytes.decode(e['UID'].to_ical())
    uid.replace('\'','')
    uid.replace('/','slash')
    cal = Calendar()
    cal.add_component(e)
    r = requests.put('%s/%s.ics' % (base_url, uid),
                     data=cal.to_ical(),
                     auth=(username, password),
                     headers={'content-type':'text/calendar; charset=UTF-8'}
                     )
    if r.status_code == 500 and r'Sabre\VObject\Recur\NoInstancesException' in r.text:
      # ignore the NoInstancesException
      print('Warning: No valid instances: %s' % uid, file=sys.stdout)
    elif r.status_code == 201 or r.status_code == 204:
      print('Imported: %s (%d)' % (uid, r.status_code), file=sys.stdout)
      imported_uids.append(uid)
    else:
      r.raise_for_status()

  # remove events not in webcal
  for uid in existing_uids:
    if not uid in imported_uids:
      r = requests.delete('%s/%s.ics' % (base_url, uid),
                          auth=(username, password))
      if r.status_code == 204:
        print('Deleted %s' % uid, file=sys.stdout)
        # ignore 404 - not found (seems to be a manually created event)
      elif r.status_code == 404:
        pass
      else:
        r.raise_for_status()
Example #20
0
    def setUp(self):
        self.icalReader = ICalReader()

        self.calendarData = DBCalendarData()
        self.calendarData.ownerId = 'dummyOwner'
        self.calendarData.ownerType = STUDENT_OWNER_TYPE
        self.calendarData.accessPermissions = PUBLIC_PERMISSION
        self.calendarData.calendarData = Calendar().to_ical()

        self.dummyTask = DBTask()
        self.dummyTask.displayName = "dummyTaskDisplayName"
        self.dummyTask.name = "dummyTaskName"
        self.dummyTask.taskId = "dummyTaskId"
Example #21
0
def gather_icalendars(dirs):
    """Find all the ics files in a directory, yield components.

    :param dirs: List of directories to browse
    :return: Iterator over components found
    """
    for bp in dirs:
        for n in os.listdir(bp):
            p = os.path.join(bp, n)
            if not p.endswith(".ics"):
                continue

            yield Calendar.from_ical(open(p, 'r').read())
Example #22
0
def do_import(username, password, calendar, server, ics_url):
  base_url = CALDAVURL % (server, username, calendar)

  # fetch events from target cal
  target_fetch_url = '%s?export' % base_url
  r = requests.get(target_fetch_url, auth=(username, password))
  r.raise_for_status()
  try:
    target_cal = Calendar.from_ical(r.text)
  except ValueError as e:
    print('Warning: Could not parse iCal (%s)' % target_fetch_url,
          file=sys.stderr)
    print(e, file=sys.stderr)
    return

  existing_uids = [e['UID'].to_ical() for e in target_cal.walk('VEVENT')]

  # replace markers
  today = date.today()
  ics_url = ics_url.replace('###YEAR###', today.strftime("%Y"))
  ics_url = ics_url.replace('###YEAR+1###', date(today.year + 1, today.month, today.day).strftime("%Y"))
  print('Used ics_url: %s' % (ics_url))

  # fetch webcal
  c = Calendar.from_ical(requests.get(ics_url).text)

  # import webcal
  imported_uids = []
  for e in c.walk('VEVENT'):
    uid = e['UID'].to_ical()
    cal = Calendar()
    cal.add_component(e)
    r = requests.put('%s/%s.ics' % (base_url, uid),
                     data=cal.to_ical(),
                     auth=(username, password),
                     headers={'content-type':'text/calendar; charset=UTF-8'}
                     )
    if r.status_code == 500 and 'Sabre\VObject\Recur\NoInstancesException' in r.text:
      # ignore the NoInstancesException
      print('Warning: No valid instances: %s' % uid, file=sys.stdout)
    elif r.status_code == 201 or r.status_code == 204:
      print('Imported: %s (%d)' % (uid, r.status_code), file=sys.stdout)
      imported_uids.append(uid)
    else:
      r.raise_for_status()

  # remove events not in webcal
  for uid in existing_uids:
    if not uid in imported_uids:
      r = requests.delete('%s/%s.ics' % (base_url, uid),
                          auth=(username, password))
      if r.status_code == 204:
        print('Deleted %s' % uid, file=sys.stdout)
        # ignore 404 - not found (seems to be a manually created event)
      elif r.status_code == 404:
        pass
      else:
        r.raise_for_status()
Example #23
0
def do_import(username, password, calendar, server, ics_url, ics_username, ics_password):
    logging.info('  Working with calendar %s...' % calendar)
    base_url = CALDAVURL % (server, username, calendar)

    target_fetch_url = '%s?export' % base_url
    r = requests.get(target_fetch_url, auth=(username, password))
    r.raise_for_status()
    try:
        target_cal = Calendar.from_ical(r.text)
    except ValueError as e:
        logging.error('    Warning: Could not parse iCal (%s)' % target_fetch_url)
        logging.error(e)
        return

    existing_uids = [bytes.decode(e['UID'].to_ical()).replace('\'', '').replace('/', 'slash') for e in target_cal.walk('VEVENT')]

    sourceRequest = requests.get(ics_url, auth=(ics_username, ics_password))
    sourceRequest.encoding = 'utf-8'
    sourceContent = sourceRequest.text
    c = Calendar.from_ical(sourceContent)

    distant_uids = [bytes.decode(e['UID'].to_ical()).replace('\'', '').replace('/', 'slash') for e in c.walk('VEVENT')]

    imported_uids = []
    for e in c.walk('VEVENT'):
        uid = bytes.decode(e['UID'].to_ical()).replace('\'', '').replace('/', 'slash')
        name = bytes.decode(e['SUMMARY'].to_ical())
        if uid not in existing_uids:
            cal = Calendar()
            cal.add_component(e)
            r = requests.put('%s/%s.ics' % (base_url, uid),
                             data=cal.to_ical(),
                             auth=(username, password),
                             headers={'content-type': 'text/calendar; charset=UTF-8'}
                             )
            if r.status_code == 500 and r'Sabre\VObject\Recur\NoInstancesException' in r.text:
                logging.warning('   No valid instances: %s (%s)' % (uid, name))
            elif r.status_code == 201 or r.status_code == 204:
                logging.info('   Imported: %s (%s)' % (uid, name))
                imported_uids.append(uid)
            else:
                r.raise_for_status()

    for euid in existing_uids:
        if not euid in distant_uids:
            r = requests.delete('%s/%s.ics' % (base_url, euid), auth=(username, password))
        if r.status_code == 204:
            logging.info('Deleted %s' % euid)
        elif r.status_code == 404:
            pass
        else:
            r.raise_for_status()
    logging.info('  Done.')
Example #24
0
    def import_events(self, source):
        Event.objects.filter(source=source).delete()
        iCalEvent.ignore_exceptions = False
        Alarm.ignore_exceptions = True

        with source.sourcefile.file as feedfile:
            cal = Calendar.from_ical(feedfile.read())
            # Some icalendar feed choose to use X-WR-TIMEZONE to denote the timezone of the creator of the feed.
            # Although there is some argument out there, [1] this should be used to define the timezone of any
            # events that don't are not UTC and don't have a TZID reference. The icalendar library does not
            # Use this property but since this is a shared calendar system we have to use it at the point of
            # sharing, ie when the date is unpacked from the feed.
            #
            # 1 http://blog.jonudell.net/2011/10/17/x-wr-timezone-considered-harmful/
            try:
                default_timezone = pytz.timezone(cal.get('X-WR-TIMEZONE'))
            except:
                default_timezone = None  # Unless we put TZ support into the UI to allow users to set their timezone, this is the best we can do.
            metadata = source.metadata
            for k, _ in cal.iteritems():
                metadata[k.lower()] = self._get_value(cal, k, default_timezone)
            events = []
            for e in cal.walk('VEVENT'):
                dstart = e.decoded('DTSTART')
                dend = e.decoded('DTEND')
                starttz = default_timezone if dstart.tzinfo is None else dstart.tzinfo
                endtz = default_timezone if dstart.tzinfo is None else dstart.tzinfo

                event = Event(start=DateConverter.to_datetime(
                    dstart, defaultzone=default_timezone),
                              end=DateConverter.to_datetime(
                                  dend, defaultzone=default_timezone),
                              starttz=starttz,
                              endtz=endtz,
                              location=self._safe_get(e, "LOCATION", ""),
                              title=self._safe_get(e, "SUMMARY", ""),
                              uid=self._safe_get(e, "UID", ""),
                              source=source)
                metadata = event.metadata
                for k, _ in e.iteritems():
                    metadata[k.lower()] = self._get_value(
                        e, k, default_timezone)

                metadata['x-allday'] = DateConverter.is_date(
                    e.decoded('DTSTART'))
                events.append(event)
            source.save()
            Event.objects.bulk_create(events)
            Event.after_bulk_operation()
            return len(events)
Example #25
0
def generate_calendar(request):
    """http://codespeak.net/icalendar/"""

    cal = Calendar()
    cal.add("prodid", "-//Club Connect//ericleong.me//")
    cal.add("version", "2.0")
    posts = Post.objects.order_by("-created")

    cal["X-WR-CALNAME"] = "Club Connect Events"
    cal["X-PUBLISH-TTL"] = "PT12H"
    cal["CALSCALE"] = "GREGORIAN"
    cal["METHOD"] = "PUBLISH"

    # TODO: separate out private events using a private URL?
    # TODO: switch to using EDT
    for post in posts:
        if post.start_time:
            # Make sure we have a time
            event = Event()
            event.add("summary", vText(post.title))
            event.add("dtstart", post.start_time)
            event.add("dtend", post.end_time if post.end_time else post.start_time)
            # event.add('dtstamp', datetime(2005,4,4,0,10,0,tzinfo=UTC))
            event["uid"] = vText(post.id)
            event["organizer"] = vText(post.author.username)
            event["description"] = vText(post.description)
            event["url"] = vUri(post.get_absolute_url())

            if post.location:
                if post.location.room:
                    event["location"] = vText("%s (%s)" % (post.location.name, post.location.room))
                else:
                    event["location"] = vText(post.location.name)

            for commit in post.committed.all():
                attendee = vCalAddress("MAILTO:" + commit.email)
                name = (
                    ([commit.first_name, commit.last_name])
                    if (commit.first_name and commit.last_name)
                    else commit.username
                )
                attendee.params["cn"] = vText(name)
                event.add("attendee", attendee, encode=0)

            cal.add_component(event)

    return HttpResponse(cal.to_ical().replace("\n", "\r\n"), content_type="text/calendar")
Example #26
0
def sync_events(sender, instance, created, **kwargs):
    '''
  Synchronizes events for the saved calendar.
  '''
    for gevent in instance.get_events():
        # get or create this event in the DB
        event, created = Event.objects.get_or_create(uri=gevent.id.text)
        # update title and description
        event.title = gevent.title.text
        event.description = gevent.content.text
        if gevent.where:
            event.where = gevent.where[0].value_string
        event.save()

        stale_occurrences = []
        if gevent.recurrence and gevent.recurrence.text:
            # manage recurrences (if any)
            recurrence_ical_data = 'BEGIN:VCALENDAR\n%s\nEND:VCALENDAR' % gevent.recurrence.text
            parsed_recurrence = Calendar.from_ical(recurrence_ical_data)
            start_time = parsed_recurrence['DTSTART'].dt
            end_time = parsed_recurrence['DTEND'].dt
            rrules = dict(parsed_recurrence['RRULE'])
            # add a default count to rrule to bound it unless a bound is specified
            if not (('COUNT' in rrules) or ('UNTIL' in rrules)):
                rrules['count'] = 52
            occurrence_pks = event.add_occurrences(start_time, end_time,
                                                   **rrules)
            stale_occurrences = event.occurrence_set.exclude(
                pk__in=occurrence_pks)
        elif gevent.when:
            # otherwise just do a single-occurrence event
            occurrence_pks = event.add_occurrences(gevent.when[0].start_time,
                                                   gevent.when[0].end_time)
            stale_occurrences = event.occurrence_set.exclude(
                pk__in=occurrence_pks)

        # Clear out any stale occurrences.
        # Note:  only occurrences with end times in the future will be removed,
        # since past occurrences may have data already associated with them.
        for occurrence in stale_occurrences:
            if occurrence.end_time > timezone.now():
                occurrence.delete()
Example #27
0
def sync_events(sender, instance, created, **kwargs):
  '''
  Synchronizes events for the saved calendar.
  '''
  for gevent in instance.get_events():
    # get or create this event in the DB
    event, created = Event.objects.get_or_create(uri=gevent.id.text)
    # update title and description
    event.title = gevent.title.text
    event.description = gevent.content.text
    if gevent.where:
      event.where = gevent.where[0].value_string
    event.save()
    
    stale_occurrences = []
    if gevent.recurrence and gevent.recurrence.text:
      # manage recurrences (if any)
      recurrence_ical_data = 'BEGIN:VCALENDAR\n%s\nEND:VCALENDAR' % gevent.recurrence.text
      parsed_recurrence = Calendar.from_ical(recurrence_ical_data)
      start_time = parsed_recurrence['DTSTART'].dt
      end_time = parsed_recurrence['DTEND'].dt
      rrules = dict(parsed_recurrence['RRULE'])
      # add a default count to rrule to bound it unless a bound is specified
      if not (('COUNT' in rrules) or ('UNTIL' in rrules)):
        rrules['count'] = 52
      occurrence_pks = event.add_occurrences(start_time, end_time, **rrules)
      stale_occurrences = event.occurrence_set.exclude(pk__in=occurrence_pks)
    elif gevent.when:
      # otherwise just do a single-occurrence event
      occurrence_pks = event.add_occurrences(gevent.when[0].start_time, gevent.when[0].end_time)
      stale_occurrences = event.occurrence_set.exclude(pk__in=occurrence_pks)
    
    # Clear out any stale occurrences.
    # Note:  only occurrences with end times in the future will be removed,
    # since past occurrences may have data already associated with them.
    for occurrence in stale_occurrences:
      if occurrence.end_time > timezone.now():
        occurrence.delete()
Example #28
0
def icsout(inp):
    from icalendar.cal import Calendar, Event
    from hashlib import sha1
    inp = os.path.expanduser(inp)
    cal = Calendar()
    cal.add('prodid', '-//ccal.py 0.5//niij.org//')
    cal.add('version', '2.0')

    entries = Entries(every=True, comm=True)
    for entry in entries:
        event = Event()
        event.add('summary', entry.desc)
        event.add('dtstart', entry.dt)
        event.add('dtend', entry.dt + dt.timedelta(days=1))
        event.add('dtstamp', dt.datetime.now())
        uid = "%s%s%s %s" % (entry.dt.year, entry.dt.month, entry.dt.day,
                             entry.desc)
        event.add('uid', sha1(uid.encode('utf-8')).hexdigest())
        if (entry.comm):
            event.add('description', entry.comm.strip())
        cal.add_component(event)
    print(cal.to_ical().decode('utf-8'))
    sys.exit(0)
    def fetch_calendar(self, force_xml=False, force_ics=False):
        "Fetches the calendar data from an XML/.ics resource in preperation for parsing."
        cal_data = None
        if self.xml_url:
            cal_data = urlopen(self.xml_url)
        elif self.ics_url:
            cal_data = urlopen(self.ics_url)
        elif self.xml_file:
            cal_data = open(self.xml_file, "rb")
        elif self.ics_file:
            cal_data = open(self.ics_file, "rb")
        else:
            raise UnboundLocalError("No calendar url or file path has been set.")

        cal_str = cal_data.read()
        cal_data.close()

        if (self.xml_url or self.xml_file) and not force_ics:
            self.calendar = BeautifulStoneSoup(_normalize(cal_str, True))
        elif (self.ics_url or self.ics_file) and not force_xml:
            self.calendar = Calendar.from_ical(cal_str)

        return self.calendar
    def fetch_calendar(self, force_xml=False, force_ics=False):
        "Fetches the calendar data from an XML/.ics resource in preperation for parsing."
        cal_data = None
        if self.xml_url:
            cal_data = urlopen(self.xml_url)
        elif self.ics_url:
            cal_data = urlopen(self.ics_url)
        elif self.xml_file:
            cal_data = open(self.xml_file, "rb")
        elif self.ics_file:
            cal_data = open(self.ics_file, "rb")
        else:
            raise UnboundLocalError("No calendar url or file path has been set.")

        cal_str = cal_data.read()
        cal_data.close()

        if (self.xml_url or self.xml_file) and not force_ics:
            self.calendar = BeautifulStoneSoup(_normalize(cal_str, True))
        elif (self.ics_url or self.ics_file) and not force_xml:
            self.calendar = Calendar.from_string(cal_str)

        return self.calendar
Example #31
0
def expand_calendar_rrule(incal, start, end):
    outcal = Calendar()
    if incal.name != 'VCALENDAR':
        raise AssertionError(
            'called on file with root component %s' % incal.name)
    for field in incal:
        outcal[field] = incal[field]
    known = {}
    for insub in incal.subcomponents:
        if 'RECURRENCE-ID' in insub:
            ts = insub['RECURRENCE-ID'].dt
            utcts = asutc(ts)
            known[utcts] = insub
    for insub in incal.subcomponents:
        if insub.name == 'VTIMEZONE':
            continue
        if 'RECURRENCE-ID' in insub:
            continue
        if 'RRULE' in insub:
            for outsub in _expand_rrule_component(insub, start, end, known):
                outcal.add_component(outsub)
        else:
            outcal.add_component(insub)
    return outcal
Example #32
0
def add(request):
    def submit_form(form):
        return render_to_response("add.html", {"form": form}, context_instance=RequestContext(request))

    if request.method == "GET":
        if not request.user.is_authenticated():
            pass  # Ask the user if the want to sign on

        data = {}
        if "url" in request.GET:
            data.update({"url": request.GET["url"]})

        day = datetime.today()
        if "day" in request.GET:
            if request.GET["day"] != "":
                day = request.GET["day"]  # Javascript hands you Tue May 20 1990
                data.update({"date": day})
            else:
                data.update({"date": day.strftime("%a %b %d %Y")})
        else:
            data.update({"date": day.strftime("%a %b %d %Y")})

        start_time = datetime.today()
        start_time = start_time.strftime("%H:%M")
        if "start_time" in request.GET:
            if request.GET["start_time"] != "":
                start_time = request.GET["start_time"]

        data.update({"start_time": start_time})

        if "end_time" in request.GET:
            end_time = request.GET["end_time"]
            if end_time != "null":
                data.update({"end_time": end_time})

        data.update({"mail": "outlook"})

        form = EventForm(data)
        return submit_form(form)

    # Form was returned with data
    if request.method == "POST":
        form = EventForm(request.POST)
        if not form.is_valid():
            return submit_form(form)

        title = form.cleaned_data["title"]
        date = form.cleaned_data["date"]
        start_time = form.cleaned_data["start_time"]
        end_time = form.cleaned_data["end_time"]
        url = form.cleaned_data["url"]
        describe = form.cleaned_data["describe"]
        address = form.cleaned_data["address"]
        mail = form.cleaned_data["mail"]

        latitude = None
        longitude = None

        if address != u"":
            local = geocode(address)
            if local != None:
                if "address" in local:
                    address = local["address"]

                if "latitude" in local and "longitude" in local:
                    latitude = local["latitude"]
                    longitude = local["longitude"]

        # If they move the pointer to be more specific override address
        """
        if form.data['lati'] and form.data['lngi']:
            latitude = form.data['lati']
            longitude = form.data['lngi']
        """
        event = EventModel(
            title=title,
            date=date,
            start_time=start_time,
            end_time=end_time,
            address=address,
            longitude=longitude,
            latitude=latitude,
            description=describe,
            url=url,
        )
        # Save this event
        event.save()

        # Make sure you save the event before connecting it to a user
        if request.user.is_authenticated():
            event.connect(request.user)

        # Ical or Outlook iCal file
        if mail == "outlook" or mail == "ical":
            # Create the iCal file
            cal = Calendar()
            cal.add("version", "2.0")
            cal.add("prodid", "-//Microsoft Corporation//Windows Calendar 1.0//EN")
            cal.add("method", "PUBLISH")

            event = Event()
            event.add("summary", describe)
            if start_time != None:
                dt = datetime.combine(date, start_time)
            else:
                dt = date
            event.add("dtstart", dt)
            event.add("dtstamp", dt)

            if end_time != None:
                de = datetime.combine(date, end_time)
                event.add("dtend", de)

            g = (latitude, latitude)
            event.add("geo", g)
            event.add("location", address)

            uid = date.isoformat() + "@wenzit.net"
            event.add("UID", uid)
            event.add("url", url)
            cal.add_component(event)

            f = open("schedule.ics", "wb")
            f.write(cal.as_string())
            f.close()

            response = HttpResponse(cal.as_string(), mimetype="text/calendar")
            response["Content-Disposition"] = "attachment; filename=schedule.ics"

            return response

        # Send the event to google
        elif mail == "google":
            response = "http://www.google.com/calendar/event?action=TEMPLATE"
            response += "&text=" + urllib.quote_plus(title)

            if start_time != None:
                ds = datetime.combine(date, start_time)
            else:
                ds = date

            if end_time != None:
                de = datetime.combine(date, end_time)
                response += "&dates=" + vDatetime(ds).ical() + "/" + vDatetime(de).ical()
            else:
                response += "&dates=" + vDatetime(ds).ical()

            response += "&details=" + urllib.quote_plus(title)
            response += "&location=" + urllib.quote_plus(address)
            response += "&sprop=" + urllib.quote_plus(url)
            return HttpResponseRedirect(response)

        # Send the event to Yahoo
        if mail == "yahoo":
            response = "http://calendar.yahoo.com/?v=60"
            response += "&TITLE=" + urllib.quote_plus(title)

            ds = datetime.combine(date, start_time)
            if end_time:
                de = datetime.combine(date, end_time)
                dur = de - ds
                hrs, left = divmod(dur.seconds, 3600)
                mins, secs = divmod(left, 60)
                dur = "%02d%02d" % (hrs, mins)
            else:
                dur = ""

            response += "&ST=" + vDatetime(ds).ical()
            response += "&DUR=" + dur

            response += "&in_loc=" + urllib.quote_plus(address)
            response += "&DESC=" + urllib.quote_plus(title)
            response += "&URL=" + urllib.quote_plus(url)
            return HttpResponseRedirect(response)
Example #33
0
def get_pytz_from_text(tztext):
    tzid = extract_tzid(ICalendar.from_ical(tztext))
    return pytz.timezone(tzid)
Example #34
0
if status is not None:
    props['status'] = status
if location is not None:
    props['location'] = vText(location)
if opts.url:
    props['url'] = vUri(opts.url)
if description is not None:
    props['summary'] = vText(description)
if dtend is not None:
    props['dtend'] = vDate(dtend.date())
if duration is not None:
    props['duration'] = vDuration(duration)

ev = Event(**props)

c = Calendar()
c.add_component(ev)

md5 = hashlib.md5()
md5.update(c.to_ical())

uid = md5.hexdigest()

props['UID'] = uid

fname = uid + '.ics'
path = os.path.join(opts.outputdir, fname)
porcelain.add(opts.outputdir, path)
porcelain.commit(opts.outputdir, 'Add %s.' % description)

with open(path, 'w') as f:
Example #35
0
    def test_cal_Component(self):
        from icalendar.cal import Component, Calendar, Event
        from icalendar import prop

        # A component is like a dictionary with extra methods and attributes.
        c = Component()
        c.name = 'VCALENDAR'

        # Every key defines a property.A property can consist of either a
        # single item. This can be set with a single value...
        c['prodid'] = '-//max m//icalendar.mxm.dk/'
        self.assertEqual(c, Calendar({'PRODID':
                                      '-//max m//icalendar.mxm.dk/'}))

        # or with a list
        c['ATTENDEE'] = ['Max M', 'Rasmussen']
        self.assertEqual(
            c,
            Calendar({
                'ATTENDEE': ['Max M', 'Rasmussen'],
                'PRODID': '-//max m//icalendar.mxm.dk/'
            }))

        ### ADD MULTIPLE VALUES TO A PROPERTY

        # if you use the add method you don't have to considder if a value is
        # a list or not.
        c = Component()
        c.name = 'VEVENT'

        # add multiple values at once
        c.add('attendee', ['*****@*****.**', '*****@*****.**'])

        # or add one per line
        c.add('attendee', '*****@*****.**')
        c.add('attendee', '*****@*****.**')

        # add again multiple values at once to very concatenaton of lists
        c.add('attendee', ['*****@*****.**', '*****@*****.**'])

        self.assertEqual(
            c,
            Event({
                'ATTENDEE': [
                    prop.vCalAddress('*****@*****.**'),
                    prop.vCalAddress('*****@*****.**'),
                    prop.vCalAddress('*****@*****.**'),
                    prop.vCalAddress('*****@*****.**'),
                    prop.vCalAddress('*****@*****.**'),
                    prop.vCalAddress('*****@*****.**')
                ]
            }))

        ###

        # You can get the values back directly ...
        c.add('prodid', '-//my product//')
        self.assertEqual(c['prodid'], prop.vText(u'-//my product//'))

        # ... or decoded to a python type
        self.assertEqual(c.decoded('prodid'), b'-//my product//')

        # With default values for non existing properties
        self.assertEqual(c.decoded('version', 'No Version'), 'No Version')

        c.add('rdate', [datetime(2013, 3, 28), datetime(2013, 3, 27)])
        self.assertTrue(isinstance(c.decoded('rdate'), prop.vDDDLists))

        # The component can render itself in the RFC 2445 format.
        c = Component()
        c.name = 'VCALENDAR'
        c.add('attendee', 'Max M')
        self.assertEqual(
            c.to_ical(),
            b'BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n')

        # Components can be nested, so You can add a subcompont. Eg a calendar
        # holds events.
        e = Component(summary='A brief history of time')
        e.name = 'VEVENT'
        e.add('dtend', '20000102T000000', encode=0)
        e.add('dtstart', '20000101T000000', encode=0)
        self.assertEqual(
            e.to_ical(), b'BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n' +
            b'DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r' +
            b'\nEND:VEVENT\r\n')

        c.add_component(e)
        self.assertEqual(c.subcomponents, [
            Event({
                'DTEND': '20000102T000000',
                'DTSTART': '20000101T000000',
                'SUMMARY': 'A brief history of time'
            })
        ])

        # We can walk over nested componentes with the walk method.
        self.assertEqual([i.name for i in c.walk()], ['VCALENDAR', 'VEVENT'])

        # We can also just walk over specific component types, by filtering
        # them on their name.
        self.assertEqual([i.name for i in c.walk('VEVENT')], ['VEVENT'])

        self.assertEqual([i['dtstart'] for i in c.walk('VEVENT')],
                         ['20000101T000000'])

        # We can enumerate property items recursively with the property_items
        # method.
        self.assertEqual(c.property_items(),
                         [('BEGIN', b'VCALENDAR'),
                          ('ATTENDEE', prop.vCalAddress('Max M')),
                          ('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'),
                          ('DTSTART', '20000101T000000'),
                          ('SUMMARY', 'A brief history of time'),
                          ('END', b'VEVENT'), ('END', b'VCALENDAR')])

        # We can also enumerate property items just under the component.
        self.assertEqual(c.property_items(recursive=False),
                         [('BEGIN', b'VCALENDAR'),
                          ('ATTENDEE', prop.vCalAddress('Max M')),
                          ('END', b'VCALENDAR')])

        sc = c.subcomponents[0]
        self.assertEqual(sc.property_items(recursive=False),
                         [('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'),
                          ('DTSTART', '20000101T000000'),
                          ('SUMMARY', 'A brief history of time'),
                          ('END', b'VEVENT')])

        # Text fields which span multiple mulitple lines require proper
        # indenting
        c = Calendar()
        c['description'] = u'Paragraph one\n\nParagraph two'
        self.assertEqual(
            c.to_ical(),
            b'BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two'
            + b'\r\nEND:VCALENDAR\r\n')

        # INLINE properties have their values on one property line. Note the
        # double quoting of the value with a colon in it.
        c = Calendar()
        c['resources'] = 'Chair, Table, "Room: 42"'
        self.assertEqual(c, Calendar({'RESOURCES':
                                      'Chair, Table, "Room: 42"'}))

        self.assertEqual(
            c.to_ical(),
            b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n' +
            b'END:VCALENDAR\r\n')

        # The inline values must be handled by the get_inline() and
        # set_inline() methods.
        self.assertEqual(c.get_inline('resources', decode=0),
                         [u'Chair', u'Table', u'Room: 42'])

        # These can also be decoded
        self.assertEqual(c.get_inline('resources', decode=1),
                         [b'Chair', b'Table', b'Room: 42'])

        # You can set them directly ...
        c.set_inline('resources', ['A', 'List', 'of', 'some, recources'],
                     encode=1)
        self.assertEqual(c['resources'], 'A,List,of,"some, recources"')

        # ... and back again
        self.assertEqual(c.get_inline('resources', decode=0),
                         ['A', 'List', 'of', 'some, recources'])

        c['freebusy'] = '19970308T160000Z/PT3H,19970308T200000Z/PT1H,'\
                        + '19970308T230000Z/19970309T000000Z'
        self.assertEqual(c.get_inline('freebusy', decode=0), [
            '19970308T160000Z/PT3H', '19970308T200000Z/PT1H',
            '19970308T230000Z/19970309T000000Z'
        ])

        freebusy = c.get_inline('freebusy', decode=1)
        self.assertTrue(isinstance(freebusy[0][0], datetime))
        self.assertTrue(isinstance(freebusy[0][1], timedelta))
Example #36
0
def add(request):
    def submit_form(form):
        return render_to_response('add.html', {'form': form},
                                  context_instance=RequestContext(request))

    if request.method == 'GET':
        if not request.user.is_authenticated():
            pass  # Ask the user if the want to sign on

        data = {}
        if 'url' in request.GET:
            data.update({'url': request.GET['url']})

        day = datetime.today()
        if 'day' in request.GET:
            if request.GET['day'] != "":
                day = request.GET[
                    'day']  # Javascript hands you Tue May 20 1990
                data.update({'date': day})
            else:
                data.update({'date': day.strftime('%a %b %d %Y')})
        else:
            data.update({'date': day.strftime('%a %b %d %Y')})

        start_time = datetime.today()
        start_time = start_time.strftime('%H:%M')
        if 'start_time' in request.GET:
            if request.GET['start_time'] != '':
                start_time = request.GET['start_time']

        data.update({'start_time': start_time})

        if 'end_time' in request.GET:
            end_time = request.GET['end_time']
            if end_time != 'null':
                data.update({'end_time': end_time})

        data.update({'mail': 'outlook'})

        form = EventForm(data)
        return submit_form(form)

    # Form was returned with data
    if request.method == 'POST':
        form = EventForm(request.POST)
        if not form.is_valid():
            return submit_form(form)

        title = form.cleaned_data['title']
        date = form.cleaned_data['date']
        start_time = form.cleaned_data['start_time']
        end_time = form.cleaned_data['end_time']
        url = form.cleaned_data['url']
        describe = form.cleaned_data['describe']
        address = form.cleaned_data['address']
        mail = form.cleaned_data['mail']

        latitude = None
        longitude = None

        if address != u'':
            local = geocode(address)
            if local != None:
                if 'address' in local:
                    address = local['address']

                if 'latitude' in local and 'longitude' in local:
                    latitude = local['latitude']
                    longitude = local['longitude']

        # If they move the pointer to be more specific override address
        """
        if form.data['lati'] and form.data['lngi']:
            latitude = form.data['lati']
            longitude = form.data['lngi']
        """
        event = EventModel(title=title,
                           date=date,
                           start_time=start_time,
                           end_time=end_time,
                           address=address,
                           longitude=longitude,
                           latitude=latitude,
                           description=describe,
                           url=url)
        # Save this event
        event.save()

        # Make sure you save the event before connecting it to a user
        if request.user.is_authenticated():
            event.connect(request.user)

        # Ical or Outlook iCal file
        if mail == 'outlook' or mail == 'ical':
            # Create the iCal file
            cal = Calendar()
            cal.add('version', '2.0')
            cal.add('prodid',
                    '-//Microsoft Corporation//Windows Calendar 1.0//EN')
            cal.add('method', 'PUBLISH')

            event = Event()
            event.add('summary', describe)
            if start_time != None:
                dt = datetime.combine(date, start_time)
            else:
                dt = date
            event.add('dtstart', dt)
            event.add('dtstamp', dt)

            if end_time != None:
                de = datetime.combine(date, end_time)
                event.add('dtend', de)

            g = (latitude, latitude)
            event.add('geo', g)
            event.add('location', address)

            uid = date.isoformat() + '@wenzit.net'
            event.add('UID', uid)
            event.add('url', url)
            cal.add_component(event)

            f = open('schedule.ics', 'wb')
            f.write(cal.as_string())
            f.close()

            response = HttpResponse(cal.as_string(), mimetype='text/calendar')
            response[
                'Content-Disposition'] = 'attachment; filename=schedule.ics'

            return response

        # Send the event to google
        elif mail == 'google':
            response = "http://www.google.com/calendar/event?action=TEMPLATE"
            response += "&text=" + urllib.quote_plus(title)

            if start_time != None:
                ds = datetime.combine(date, start_time)
            else:
                ds = date

            if end_time != None:
                de = datetime.combine(date, end_time)
                response += "&dates=" + vDatetime(ds).ical()+ \
                            '/'+vDatetime(de).ical()
            else:
                response += "&dates=" + vDatetime(ds).ical()

            response += "&details=" + urllib.quote_plus(title)
            response += "&location=" + urllib.quote_plus(address)
            response += "&sprop=" + urllib.quote_plus(url)
            return HttpResponseRedirect(response)

        # Send the event to Yahoo
        if mail == 'yahoo':
            response = 'http://calendar.yahoo.com/?v=60'
            response += '&TITLE=' + urllib.quote_plus(title)

            ds = datetime.combine(date, start_time)
            if end_time:
                de = datetime.combine(date, end_time)
                dur = de - ds
                hrs, left = divmod(dur.seconds, 3600)
                mins, secs = divmod(left, 60)
                dur = '%02d%02d' % (hrs, mins)
            else:
                dur = ''

            response += '&ST=' + vDatetime(ds).ical()
            response += '&DUR=' + dur

            response += '&in_loc=' + urllib.quote_plus(address)
            response += '&DESC=' + urllib.quote_plus(title)
            response += '&URL=' + urllib.quote_plus(url)
            return HttpResponseRedirect(response)
Example #37
0
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

ch = logging.StreamHandler(sys.stderr)
ch.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(levelname)s: %(message)s')
ch.setFormatter(formatter)

logger.addHandler(ch)

parser = optparse.OptionParser("fix-songkick")
opts, args = parser.parse_args()

url = args[0]
orig = Calendar.from_ical(urllib.urlopen(url).read())

TRACKING_PREFIX = u"You’re tracking this event.\n\n"
GOING_PREFIX = u"You’re going.\n\n"

def fix_vevent(vevent):
    status = None
    if unicode(vevent['DESCRIPTION']).startswith(TRACKING_PREFIX):
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(TRACKING_PREFIX):]
    if unicode(vevent['DESCRIPTION']).startswith(GOING_PREFIX):
        vevent['STATUS'] = 'CONFIRMED'
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(GOING_PREFIX):]
    if unicode(vevent['DESCRIPTION']).startswith(unicode(vevent['URL'])):
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(unicode(vevent['URL'])):]
    if not vevent['DESCRIPTION']:
        del vevent['DESCRIPTION']
Example #38
0
logging.info('Inbox URL: %s', inbox_url)

if opts.invite:
    target_collection_url = inbox_url
else:
    target_collection_url = opts.url

try:
    import_url = args[0]
except IndexError:
    f = sys.stdin.buffer
    import_url = None
else:
    f = urllib.request.urlopen(import_url)

orig = Calendar.from_ical(f.read())

other = []
items = {}
for component in orig.subcomponents:
    if component.name in ('VEVENT', 'VTODO'):
        try:
            items[component['UID']] = component
        except KeyError:
            raise KeyError('missing UID for %s in %s' % (component.name, url))
    else:
        other.append(component)

seen = 0
changed = 0
added = 0
Example #39
0
    duration = datetime.timedelta(1)


props = {
    'categories': opts.categories.split(','),
    'dtstart': vDate(dtstart.date()),
    'created': vDatetime(datetime.datetime.now()),
    'class': 'PUBLIC',
    }
if status is not None:
    props['status'] = status
if location is not None:
    props['location'] = vText(location)
if opts.event_url:
    props['url'] = vUri(opts.event_url)
if description is not None:
    props['summary'] = vText(description)
if dtend is not None:
    props['dtend'] = vDate(dtend.date())
if duration is not None:
    props['duration'] = vDuration(duration)

uid = str(uuid.uuid1())
props['UID'] = uid
ev = Event(**props)

c = Calendar()
c.add_component(ev)

utils.add_member(opts.url, 'text/calendar', c.to_ical())
Example #40
0
                'start': start,
                'duration': duration,
                'label': ''
            }
            events.append(event)
    return events


def global_label(events, label):
    for event in events:
        event['label'] = label


events = []
with open('calendar.ics', 'r') as cal_file:
    cal = Calendar.from_ical(cal_file.read())
    new_events = calendar_to_events(cal)
    global_label(new_events, 'personal')
    events.extend(new_events)

with open('school.ics', 'r') as cal_file:
    cal = Calendar.from_ical(cal_file.read())
    new_events = calendar_to_events(cal)
    global_label(new_events, 'school')
    events.extend(new_events)

with open('sleep.ics', 'r') as cal_file:
    cal = Calendar.from_ical(cal_file.read())
    new_events = calendar_to_events(cal)
    global_label(new_events, 'sleep')
    events.extend(new_events)
Example #41
0
formatter = logging.Formatter('%(levelname)s: %(message)s')
ch.setFormatter(formatter)

logger.addHandler(ch)

parser = optparse.OptionParser("fix-songkick")
opts, args = parser.parse_args()

try:
    url = args[0]
except IndexError:
    f = sys.stdin.buffer
else:
    f = urllib.request.urlopen(url)

orig = Calendar.from_ical(f.read())

TRACKING_PREFIX = "You’re tracking this event.\n\n"
GOING_PREFIX = "You’re going.\n\n"


def fix_vevent(vevent):
    status = None
    if str(vevent['DESCRIPTION']).startswith(TRACKING_PREFIX):
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(TRACKING_PREFIX):]
        vevent['STATUS'] = 'TENTATIVE'
    if str(vevent['DESCRIPTION']).startswith(GOING_PREFIX):
        vevent['STATUS'] = 'CONFIRMED'
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(GOING_PREFIX):]
    if str(vevent['DESCRIPTION']).startswith(str(vevent['URL'])):
        vevent['DESCRIPTION'] = vevent['DESCRIPTION'][len(str(vevent['URL'])):]
def do_import(username, password, calendar, server, ics_url):
  base_url = CALDAVURL % (server, username, calendar)

  # fetch events from target cal
  target_fetch_url = '%s?export' % base_url
  r = requests.get(target_fetch_url, auth=(username, password))
  r.raise_for_status()
  try:
    target_cal = Calendar.from_ical(r.text)
  except ValueError as e:
    print('Warning: Could not parse iCal (%s)' % target_fetch_url,
          file=sys.stderr)
    print(e, file=sys.stderr)
    return

  existing_uids = [e['UID'].to_ical() for e in target_cal.walk('VEVENT')]

  # fetch webcal
  if ics_url.startswith('file://'):
    # Special handling for file:// URLs: substring to strip the file:// prefix,
    # then read it using normal file-reading functionality.
    sourceFile = open(ics_url[7:], 'r')
    sourceContent = sourceFile.read()
    sourceFile.close()
  else:
    sourceRequest = requests.get(ics_url)
    sourceRequest.encoding = 'utf-8'
    sourceContent = sourceRequest.text
    
  c = Calendar.from_ical(sourceContent)

  # import webcal
  imported_uids = []
  for e in c.walk('VEVENT'):
    uid = e['UID'].to_ical()
    cal = Calendar()
    cal.add_component(e)
    r = requests.put('%s/%s.ics' % (base_url, uid),
                     data=cal.to_ical(),
                     auth=(username, password),
                     headers={'content-type':'text/calendar; charset=UTF-8'}
                     )
    if r.status_code == 500 and 'Sabre\VObject\Recur\NoInstancesException' in r.text:
      # ignore the NoInstancesException
      print('Warning: No valid instances: %s' % uid, file=sys.stdout)
    elif r.status_code == 201 or r.status_code == 204:
      print('Imported: %s (%d)' % (uid, r.status_code), file=sys.stdout)
      imported_uids.append(uid)
    else:
      r.raise_for_status()

  # remove events not in webcal
  for uid in existing_uids:
    if not uid in imported_uids:
      r = requests.delete('%s/%s.ics' % (base_url, uid),
                          auth=(username, password))
      if r.status_code == 204:
        print('Deleted %s' % uid, file=sys.stdout)
        # ignore 404 - not found (seems to be a manually created event)
      elif r.status_code == 404:
        pass
      else:
        r.raise_for_status()
Example #43
0
ch.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(levelname)s: %(message)s')
ch.setFormatter(formatter)

logger.addHandler(ch)

parser = optparse.OptionParser("split")
parser.add_option("--prefix", dest="prefix", default="unknown", help="Filename prefix")
parser.add_option("--outdir", dest="outdir", default=".", help="Output directory path")
parser.add_option('--category', dest='category', default=None, help="Category to add.")
parser.add_option('--status', dest='status', type="choice", choices=["", "tentative", "confirmed"], default=None, help="Status to set.")
opts, args = parser.parse_args()

url = args[0]
orig = Calendar.from_ical(urllib.urlopen(url).read())

other = []
items = {}
for component in orig.subcomponents:
    try:
        uid = component['UID']
    except KeyError:
        md5 = hashlib.md5()
        md5.update(component.to_ical())
        component['UID'] = uid = md5.hexdigest()
    if component.name in ('VEVENT', 'VTODO'):
        items[uid] = component
    else:
        other.append(component)
Example #44
0
#!/usr/bin/python

from icalendar.cal import Calendar, FreeBusy
import optparse
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

from dystros import utils

parser = optparse.OptionParser("travel")
collection_set_options = utils.CollectionSetOptionGroup(parser)
parser.add_option_group(collection_set_options)
opts, args = parser.parse_args()

collections = utils.CollectionSet.from_options(opts)
vevents = collections.iter_vevents()

out = Calendar()
freebusy = FreeBusy()
for vevent in vevents:
    freebusy['UID'] = vevent['UID']
    freebusy['DTSTART'] = vevent['DTSTART']
    freebusy['DTEND'] = vevent['DTEND']
    out.add_component(freebusy)

print out.to_ical()
Example #45
0
def create_cal_from_classes(dfs_list, class_list: List[str],
                            semester_selector: str):
    assert (semester_selector[0:2] == "WS" and len(semester_selector)
            == 7) or (semester_selector[0:2] == "SS"
                      and len(semester_selector) == 4)

    academic_year_url = academic_year_base_url.replace(
        "%year%",
        f"20{int(semester_selector[2:4]) - 1}-{int(semester_selector[2:4])}"
        if semester_selector[0:2] == "SS" else
        f"20{semester_selector[2:7].replace('/', '-')}")

    fp = urllib.request.urlopen(academic_year_url)
    mybytes = fp.read()
    html_doc2 = mybytes.decode("utf8")
    fp.close()

    academic_year = Calendar.from_ical(html_doc2)

    semester_date_spans = []
    recess_date_spans = []

    for component in academic_year.walk():
        if component.name == 'VEVENT':
            if component['summary'].startswith(
                    expand_semester(semester_selector)):
                semester_date_spans.append(
                    (component['DTSTART'].dt, component['DTEND'].dt))

            if any(r.lower() in component['summary'].lower() for r in recess):
                recess_date_spans.append(
                    (component['DTSTART'].dt, component['DTEND'].dt))

    weekdates_semester = []

    for start_date, end_date in semester_date_spans:
        delta = end_date - start_date
        for i in range(delta.days + 1):
            day = start_date + timedelta(days=i)
            if not day.weekday() == SATURDAY and not day.weekday() == SUNDAY:
                weekdates_semester.append(day)

    recess_dates_semester = []

    for start_date, end_date in recess_date_spans:
        delta = end_date - start_date
        for i in range(delta.days + 1):
            day = start_date + timedelta(days=i)
            if not day.weekday() == SATURDAY and not day.weekday() == SUNDAY:
                recess_dates_semester.append(day)

    cal = Calendar()
    cal.add("version", 2.0)
    cal.add("prodid", "-//flmann.de//timetable//DE")
    cal.add('x-wr-calname', "Stundenplan")
    cal.add('x-wr-caldesc', "Stundenplan TU Dresden ET")
    cal.add('x-wr-timezone', "Europe/Berlin")

    tzc = Timezone()
    tzc.add('tzid', 'Europe/Berlin')
    tzc.add('x-lic-location', 'Europe/Berlin')

    tzs = TimezoneStandard()
    tzs.add('tzname', 'CET')
    tzs.add('dtstart', datetime(1970, 10, 25, 3, 0, 0))
    tzs.add('rrule', {'freq': 'yearly', 'bymonth': 10, 'byday': '-1su'})
    tzs.add('TZOFFSETFROM', timedelta(hours=2))
    tzs.add('TZOFFSETTO', timedelta(hours=1))

    tzd = TimezoneDaylight()
    tzd.add('tzname', 'CEST')
    tzd.add('dtstart', datetime(1970, 3, 29, 2, 0, 0))
    tzs.add('rrule', {'freq': 'yearly', 'bymonth': 3, 'byday': '-1su'})
    tzd.add('TZOFFSETFROM', timedelta(hours=1))
    tzd.add('TZOFFSETTO', timedelta(hours=2))

    tzc.add_component(tzs)
    tzc.add_component(tzd)
    cal.add_component(tzc)

    dates_added = set()

    for dfs in dfs_list:
        timetable = dfs[1].values.tolist()
        index = 2

        for i, row in enumerate(timetable):
            if i == 0:
                continue
            for j, cell in enumerate(row):
                if j == 0 or isinstance(cell, float):
                    continue

                time_info = timetable[i][0]
                weekday_tt = timetable[0][j]

                classes = dfs[index].values.tolist()

                for c in classes:
                    lecturer, name, room, *_ = c[0].split(seperator)
                    odd_even, time_start, time_end = time_info.split(seperator)

                    print(f"{name=} {name in class_list}")

                    if not name in class_list:
                        continue

                    time_start_hour, time_start_minutes = [
                        int(x) for x in time_start.split(COLON)
                    ]
                    time_end_hour, time_end_minutes = [
                        int(x) for x in time_end.split(COLON)
                    ]

                    if odd_even == "1.WO":
                        week_mod = 1
                    elif odd_even == "2.WO":
                        week_mod = 0
                    else:
                        print(f"Error. Invalid odd_even identifier {odd_even}")
                        exit()

                    id = f"{c[0]}{time_info}"
                    if id in dates_added:
                        continue
                    dates_added.add(id)

                    for day in weekdates_semester:
                        _, weeknumber, weekday = day.isocalendar()
                        if not weekday - 1 == WEEKDAYS[weekday_tt.lower()]:
                            continue
                        if not weeknumber % 2 == week_mod:
                            continue
                        if any([
                                d.day == day.day and d.month == day.day
                                and d.year == day.year
                                for d in recess_dates_semester
                        ]):
                            continue

                        e = Event()
                        e.add('summary', name)
                        e.add(
                            'dtstart',
                            datetime(day.year,
                                     day.month,
                                     day.day,
                                     time_start_hour,
                                     time_start_minutes,
                                     0,
                                     tzinfo=pytz.timezone("Europe/Berlin")))
                        e.add(
                            'dtend',
                            datetime(day.year,
                                     day.month,
                                     day.day,
                                     time_end_hour,
                                     time_end_minutes,
                                     0,
                                     tzinfo=pytz.timezone("Europe/Berlin")))
                        e.add('dtstamp', datetime.now())
                        e.add('uid', uuid.uuid4())
                        e.add('location', room)
                        e.add('description', f"Dozent: {flip_name(lecturer)}")

                        cal.add_component(e)

                index += 1

    return cal.to_ical().decode('utf-8').replace('\n\n',
                                                 '\n').replace('\r\n', '\n')
Example #46
0
def main():
    semester_selector = "WS20/21"
    # semester_selector = "SS20"

    group_selector = "EuiDE-9-NT1"

    assert (semester_selector[0:2] == "WS" and len(semester_selector)
            == 7) or (semester_selector[0:2] == "SS"
                      and len(semester_selector) == 4)

    timetable_url = timetable_base_url.replace("%semester%",
                                               semester_selector).replace(
                                                   "%group%", group_selector)
    academic_year_url = academic_year_base_url.replace(
        "%year%",
        f"20{int(semester_selector[2:4]) - 1}-{int(semester_selector[2:4])}"
        if semester_selector[0:2] == "SS" else
        f"20{semester_selector[2:7].replace('/', '-')}")

    fp = urllib.request.urlopen(timetable_url)
    mybytes = fp.read()
    html_doc = mybytes.decode("utf-8").replace("<BR>", seperator)
    fp.close()

    fp = urllib.request.urlopen(academic_year_url)
    mybytes = fp.read()
    html_doc2 = mybytes.decode("utf8")
    fp.close()

    academic_year = Calendar.from_ical(html_doc2)

    semester_date_spans = []
    recess_date_spans = []

    for component in academic_year.walk():
        if component.name == 'VEVENT':
            if component['summary'].startswith(
                    expand_semester(semester_selector)):
                semester_date_spans.append(
                    (component['DTSTART'].dt, component['DTEND'].dt))

            if any(r.lower() in component['summary'].lower() for r in recess):
                recess_date_spans.append(
                    (component['DTSTART'].dt, component['DTEND'].dt))

    weekdates_semester = []

    for start_date, end_date in semester_date_spans:
        delta = end_date - start_date
        for i in range(delta.days + 1):
            day = start_date + timedelta(days=i)
            if not day.weekday() == SATURDAY and not day.weekday() == SUNDAY:
                weekdates_semester.append(day)

    recess_dates_semester = []

    for start_date, end_date in recess_date_spans:
        delta = end_date - start_date
        for i in range(delta.days + 1):
            day = start_date + timedelta(days=i)
            if not day.weekday() == SATURDAY and not day.weekday() == SUNDAY:
                recess_dates_semester.append(day)

    dfs = pd.read_html(html_doc)
    dfs = [
        df.applymap(lambda x: x.replace(u"\xa0", u" ")
                    if isinstance(x, str) else x) for df in dfs
    ]

    timetable = dfs[1].values.tolist()

    cal = Calendar()

    index = 2

    class_list = []
    for i, row in enumerate(timetable):
        if i == 0:
            continue
        for j, cell in enumerate(row):
            if j == 0 or isinstance(cell, float):
                continue
            classes = dfs[index].values.tolist()

            for c in classes:
                print(c[0])
                lecturer, name, room, *_ = c[0].split(seperator)
                if not name in class_list:
                    class_list.append(name)
            index += 1

    print("[")
    for c in class_list:
        print(f"    \"{c}\",")
    print("]")

    index = 2

    for i, row in enumerate(timetable):
        if i == 0:
            continue
        for j, cell in enumerate(row):
            if j == 0 or isinstance(cell, float):
                continue

            time_info = timetable[i][0]
            weekday_tt = timetable[0][j]

            classes = dfs[index].values.tolist()

            for c in classes:
                lecturer, name, room, *_ = c[0].split(seperator)
                odd_even, time_start, time_end = time_info.split(seperator)

                time_start_hour, time_start_minutes = [
                    int(x) for x in time_start.split(COLON)
                ]
                time_end_hour, time_end_minutes = [
                    int(x) for x in time_end.split(COLON)
                ]

                if odd_even == "1.WO":
                    week_mod = 1
                elif odd_even == "2.WO":
                    week_mod = 0
                else:
                    print(f"Error. Invalid odd_even identifier {odd_even}")
                    exit()

                for day in weekdates_semester:
                    _, weeknumber, weekday = day.isocalendar()

                    if not weekday - 1 == WEEKDAYS[weekday_tt.lower()]:
                        continue
                    if not weeknumber % 2 == week_mod:
                        continue
                    if any([
                            d.day == day.day and d.month == day.day
                            and d.year == day.year
                            for d in recess_dates_semester
                    ]):
                        continue

                    e = Event()
                    e.add('summary', name)
                    e.add(
                        'dtstart',
                        datetime(day.year,
                                 day.month,
                                 day.day,
                                 time_start_hour,
                                 time_start_minutes,
                                 0,
                                 tzinfo=pytz.timezone("Europe/Berlin")))
                    e.add(
                        'dtstart',
                        datetime(day.year,
                                 day.month,
                                 day.day,
                                 time_end_hour,
                                 time_end_minutes,
                                 0,
                                 tzinfo=pytz.timezone("Europe/Berlin")))
                    e.add('location', room)
                    e.add('description', f"Dozent: {flip_name(lecturer)}")

                    cal.add_component(e)

            index += 1

    print(cal.to_ical().decode('utf-8'))

    with open('my.ics', 'w', encoding='utf-8') as f:
        f.write(cal.to_ical().decode('utf-8'))