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()
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()])
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))
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()
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()
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), )
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')
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.')
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")
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'])):] if not vevent['DESCRIPTION']: del vevent['DESCRIPTION'] lpts = str(vevent['LOCATION']).split(',') for i in reversed(list(range(len(lpts)))): loc = (' at ' + ','.join( lpts[:i])) + ' (' + vevent['DTSTART'].dt.strftime('%d %b %y') + ')' vevent['SUMMARY'] = vevent['SUMMARY'].replace(loc, '') return vevent out = Calendar() for component in orig.subcomponents: if component.name == 'VEVENT': component = fix_vevent(component) out.add_component(component) sys.stdout.buffer.write(out.to_ical())
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())
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()
out.add_component(c) if opts.category: if isinstance(ev.get('categories', ''), vText): ev['categories'] = [ev['categories']] ev.setdefault('categories', []).append(vText(opts.category)) if opts.status and not 'status' in ev: ev['status'] = opts.status.upper() out.add_component(ev) try: old = Calendar.from_ical(open(path, 'rb').read()) except IOError: old = None write = True else: write = hasChanged(old, out) if write: if not os.path.exists(path): added += 1 else: changed += 1 with open(path, 'wb') as f: f.write(out.to_ical()) porcelain.add(opts.outdir, [str(fname)]) if changed or added: porcelain.commit(opts.outdir, 'Processing %s. Updated: %d, new: %d.' % (opts.prefix, changed, added)) logger.info('Processed %s. Seen %d, updated %d, new %d', opts.prefix, seen, changed, added)
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'))
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')
#!/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()
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: f.write(c.to_ical()) logging.info('Wrote %s', path)
seen += 1 (old, todo, new, href, etag, ev) = utils.create_or_update_calendar_item( target_collection_url, "VEVENT", uid) out = Calendar() if import_url is not None: out['X-IMPORTED-FROM-URL'] = vUri(import_url) # If this is not an iTIP request, then make it one. if "METHOD" not in out and opts.invite: out["METHOD"] = "REQUEST" out.update(list(orig.items())) for c in other: out.add_component(c) if opts.category: if isinstance(ev.get('CATEGORIES', ''), vText): ev['CATEGORIES'] = [ev['CATEGORIES']] ev.setdefault('categories', []).append(vText(opts.category)) if opts.status and 'STATUS' not in ev: ev['STATUS'] = opts.status.upper() out.add_component(ev) write = hasChanged(old, out) if write: if old is None: added += 1 utils.add_member(target_collection_url, 'text/calendar', out.to_ical()) else: changed += 1 utils.put(href, 'text/calendar', out.to_ical(), if_match=[etag]) logger.info('Processed %s. Seen %d, updated %d, new %d', opts.prefix, seen, changed, added)
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'] lpts = unicode(vevent['LOCATION']).split(',') for i in reversed(range(len(lpts))): loc = (' at ' + ','.join(lpts[:i])) + ' (' + vevent['DTSTART'].dt.strftime('%d %b %y') + ')' vevent['SUMMARY'] = vevent['SUMMARY'].replace(loc, '') return vevent out = Calendar() for component in orig.subcomponents: if component.name == 'VEVENT': component = fix_vevent(component) out.add_component(component) sys.stdout.write(out.to_ical())