def generate(dates, output_filename, *, name=None, description=None, uid=None): c = ical.Calendar() c.add("prodid", "-//electioncal.us generator//circuitpython.org//") c.add("version", "2.0") path_parts = output_filename.split("/") c.add( "url", ical.vUri("https://electioncal.us/" + "/".join(path_parts[1:-1]) + "/")) c.add("source", ical.vUri("https://electioncal.us/" + "/".join(path_parts[1:]))) # c.add('REFRESH-INTERVAL'VALUE=DURATION:P1W, value) if name: c.add("name", name) if description: c.add("description", description) if uid: c.add("uid", uid) last_modified = None for date in dates: event = ical.Event() event.add("summary", date["name"]) event.add("dtstart", ical.vDate(date["date"])) c.add_component(event) if description: c.add("last-modified", ical.vDate(date["date"])) with open(output_filename, "wb") as f: f.write(c.to_ical())
def export_ical(events): cal = Calendar() site = Site.objects.get_current() cal.add('prodid', '-//%s Events Calendar//%s//' % (site.name, site.domain)) cal.add('version', '2.0') site_token = site.domain.split('.') site_token.reverse() site_token = '.'.join(site_token) for event in events: ical_event = Event() ical_event.add('summary', event.title) ical_event.add('description', event.body) ical_event.add('dtstart', event.start_datetime) ical_event.add('dtend', event.end_datetime) ical_event.add('dtstamp', event.end_datetime) ical_event.add('url', vUri('http://' + site.domain + event.get_absolute_url())) ical_event['location'] = vText(event.location) ical_event['uid'] = '%d.event.events.%s' % (event.id, site_token) cal.add_component(ical_event) return cal
def generate_ical_event(event, now): cal_event = Event() cal_event.add('DTSTAMP', vDatetime(now)) cal_event.add('SEQUENCE', 0) cal_event.add('UID', 'event_{}@foss.events'.format(event['id'])) cal_event.add('summary', event['label']) cal_event.add('dtstart', vDate(event['start_date'])) cal_end_date = event['end_date'] + timedelta(days=1) cal_event.add('dtend', vDate(cal_end_date)) cal_event.add('location', event['readable_location']) cal_event.add('url', vUri(event['abs_details_url'])) description = event['description'] or '' description += '\n\n' if event['has_details']: description += 'Read everything about ' + event['label'] + ' in a nutshell on // foss.events: ' + event['abs_details_url'] + '\n\n' description += 'Official Homepage: ' + event['homepage'] + '\n\n' if event['osm_link']: description += 'Find your way: ' + event['osm_link'] + '\n' cal_event['description'] = remove_tags(description) if event['lat'] and event['lon']: cal_event['geo'] = vGeo([event['lat'], event['lon']]) return cal_event
def make_event(title, date, location, link, speaker): """Make an iCal `Event` object from the colloquium details.""" event = Event() event.add('summary', title) event.add('dtstart', date) event.add('dtend', date + timedelta(minutes=COLLOQ_LENGTH)) event['location'] = vText(location) event['uid'] = link event['description'] = vText(speaker or 'Colloquium') event['URL'] = vUri(link) return event
def show_calendarevent_ics_view(context, request): from icalendar import Calendar from icalendar import Event from icalendar import vUri from webob import Response calendar = Calendar() calendar.add('prodid', '-//KARL3//Event//') calendar.add('version', '2.0') calendar.add('method', 'PUBLISH') event = Event() event['uid'] = '%s:%s' % (context.__parent__.__parent__.__name__, context.docid) event.add('summary', context.title) if context.description: event.add('description', context.description) if context.location: event.add('location', context.location) event.add('dtstamp', context.modified) event.add('last-modified', context.modified) event.add('created', context.created) event.add('dtstart', context.startDate) event.add('dtend', context.endDate) contacts = [] if context.contact_name: contacts.append(context.contact_name) if context.contact_email: contacts.append(context.contact_email) if contacts: event.add('contact', ', '.join(contacts)) for name in context.attendees: if isinstance(name, unicode): name = name.encode('UTF-8') event.add('attendee', name) for f in context['attachments'].values(): attachment = vUri(model_url(f, request)) attachment.params['fmttype'] = f.mimetype event.add('attach', attachment) calendar.add_component(event) return Response(body=calendar.as_string(), content_type='text/calendar', charset='UTF8', )
def main(*, args): params = docopt.docopt( doc=__doc__.format( prog=__prog__, ), argv=args, help=True, version=__version__, options_first=False, ) assert params.pop("--help") == False assert params.pop("--version") == False dtstart = parse_dt(params.pop("START_DT_WITH_TIMEZONE")) dtend = parse_dt(params.pop("END_DT_WITH_TIMEZONE")) summary = params.pop("--summary") or "Event" description = params.pop("--description") or f"Generated By: {__product__}" url = params.pop("--url") attachments = params.pop("--attachment") output_path = params.pop("--output") assert not params, params print("Summary: {}" .format(summary)) print("Start: {:%c %z}".format(dtstart)) print("End: {:%c %z}".format(dtend)) print("Duration: {}" .format(dtend - dtstart)) print("Description: {}" .format(description)) print(file=sys.stderr) event = icalendar.Event() event.add("SUMMARY", icalendar.vText(summary)) event.add("DESCRIPTION", icalendar.vText(description)) event.add("DTSTART", icalendar.vDatetime(dtstart)) event.add("DTEND", icalendar.vDatetime(dtend)) if url is not None: event.add("URL", icalendar.vUri(url)) for path in attachments: add_attachment_to_calendar_event(event, path) calendar = icalendar.Calendar() #TODO:vruyr:bugs Verify with the standard. calendar.add("PRODID", f"-//{__product__}//vruyr.com//EN") calendar.add("VERSION", "2.0") calendar.add_component(event) with open(output_path, "wb") as fo: fo.write(calendar.to_ical())
def course_to_event(course): """Convert a Course into a icalendar event. :param course: a :class:`tradeschool.models.Course` to export as an Event :returns: :class:`icalendar.Event` """ return Event(**{ 'uid': vText(_build_uid_for_course(course)), 'created': vDatetime(course.created), 'description': vText(course.description), 'dtstart': vDatetime(course.start_time), 'dtend': vDatetime(course.end_time), 'last-mod': vDatetime(course.updated), 'dtstamp': vDatetime(datetime.datetime.now()), 'location': vText(_build_location_for_venue(course.venue)), 'summary': vText(course.title), 'url': vUri(course.course_view_url), })
def gen_calendar_data(events): c = Calendar() c.add("prodid", "-//Morton Feldman Forthcoming Performances//notimportant.org//") c.add("version", "2.0") c.add("X-WR-CALNAME", "Morton Feldman Forthcoming Performances") c.add("x-original-url", "http://feldman.notimportant.org/") c.add("method", "PUBLISH") for event in events: e = Event() e.add("summary", "Morton Feldman: %s" % event["venue"]) e.add("location", event["location"]) e.add("dtstart", event["date"].date()) e.add("url", vUri(event["source"])) e.add("uid", event["uid"]) e.add("description", get_event_desc(event)) c.add_component(e) return c
def generate_event_ical_files(events): for event in events: cal = Calendar() cal.add('prodid', '-//foss.events//foss.events//') cal.add('version', '1.3.3.7') cal_event = Event() cal_event.add('summary', event['label']) cal_event.add('dtstart', vDate(event['start_date'])) cal_end_date = event['end_date'] + timedelta(days=1) cal_event.add('dtend', vDate(cal_end_date)) cal_event.add('location', event['readable_location']) cal_event.add('url', vUri(event['abs_details_url'])) description = event['description'] or '' description += '\n\n' if event['has_details']: description += 'Read everything about ' + event[ 'label'] + ' in a nutshell on // foss.events: ' + event[ 'abs_details_url'] + '\n\n' description += 'Official Homepage: ' + event['homepage'] + '\n\n' if event['osm_link']: description += 'Find your way: ' + event['osm_link'] + '\n' cal_event['description'] = remove_tags(description) cal.add_component(cal_event) if event['lat'] and event['lon']: cal_event['geo'] = vGeo([event['lat'], event['lon']]) filepath = generate_event_ical_path(event) with open('build/' + filepath, 'wb') as f: f.write(cal.to_ical())
def create_ical_entry (e, request): event = icalendar.Event() # TODO should we generate an UUID when creating the event? uid = u'*****@*****.**' % (str(e.id)) event['uid'] = icalendar.vText(uid) event['dtstamp'] = icalendar.vDatetime(datetime.utcnow()) # The sequence field must be incremented each time the event is modifed. # The trick here is to subtract the create TS from the modify TS and # use the difference as sequence. sequence = 0 if e.date_time_created and e.date_time_modified: createTimestamp = time.mktime(e.get_date_time_created_utc().timetuple()) modifyTimestamp = time.mktime(e.get_date_time_modified_utc().timetuple()) sequence = modifyTimestamp - createTimestamp event['sequence'] = icalendar.vInt(sequence) + 1 # created and last-modified if e.date_time_created: event['created'] = icalendar.vDatetime(e.get_date_time_created_utc()) if e.date_time_modified: event['last-modified'] = icalendar.vDatetime(e.get_date_time_modified_utc()) # TENTATIVE, CONFIRMED, CANCELLED if e.canceled: event['status'] = icalendar.vText(u'CANCELLED') else: event['status'] = icalendar.vText(u'CONFIRMED') relative_url = e.get_absolute_url() absolute_url = request.build_absolute_uri(relative_url) event['url'] = icalendar.vUri(absolute_url) if e.title: event['summary'] = icalendar.vText(e.title) description = u'' if e.description: description += e.description if e.url: if len(description) > 0: description += u'\n\n' description += u'Event Webseite: ' + e.url if len(description) > 0: description += u'\n\n' description += u'Event bei Techism: ' + absolute_url event['description'] = icalendar.vText(description) if e.date_time_begin: event['dtstart'] = icalendar.vDatetime(e.get_date_time_begin_utc()) if e.date_time_end: event['dtend'] = icalendar.vDatetime(e.get_date_time_end_utc()) # geo value isn't used by iCal readers :-( # maybe a trick is to add the geo coordinates to the location field using the following format: # $latitude, $longitude ($name, $street, $city) if e.location: location = u'%s, %s, %s' % (e.location.name, e.location.street, e.location.city) event['location'] = icalendar.vText(location) if e.location and e.location.latitude and e.location.longitude: event['geo'] = icalendar.vGeo((e.location.latitude, e.location.longitude)) return event
def main(): with open('_data/routes.yml') as f: routes = yaml.load(f) with open('_data/schedule.yml') as f: sched = yaml.load(f) def lkup(uid): for r in routes: if r['id'] == uid: return r def dtstart(date, phase): time = datetime.strptime(phase['time'], '%H:%M') return datetime(date.year, date.month, date.day, time.hour, time.minute, 0, 0, tzinfo=pytz.timezone('America/Los_Angeles')) # ics timestamps must be utc now = datetime.now(pytz.utc) # NOTE: assumes events back-to-back on single day things = [] for run in sched: date = datetime.strptime(run['date'], '%Y-%m-%d') phases = run['plan'] if 'cancelled' in run.keys(): continue for i in range(len(phases)): phase = phases[i] if 'cancelled' in phase.keys(): continue if 'route_id' in phase.keys(): route = lkup(phase['route_id']) else: route = phase['route'] name = route['name'] gmap = route['map'] if 'map' in route else '' dist = route['dist'] if 'dist' in route else None event_name = f'{name} ({dist})' if dist else name start = dtstart(date, phase) if i < len(phases) - 1: end = dtstart(date, phases[i + 1]) else: delta = timedelta(0, 10 * 60 * round(dist if dist else 3)) end = start + delta uid = str(start) + '@raceconditionrunning.com' uid = uid.strip(' :-,;') things.append({ 'summary': event_name, 'dtstart': start, 'dtend': end, 'description': gmap, 'dtstamp': now, 'uid': uid }) # add brunch after other phases if i == len(phases) - 1 and dist > 0: bstart = end bend = bstart + timedelta(0, 90 * 60) buid = str(bstart) + '@raceconditionrunning.com' buid = buid.strip(' :-,;') things.append({ 'summary': 'Brunch', 'dtstart': bstart, 'dtend': bend, 'description': 'Post-run brunch!', 'dtstamp': now, 'uid': buid }) # add Tuesday and Thursday runs def previous_tuesday(datetime_date): while datetime_date.weekday() != 1: datetime_date -= timedelta(1) return datetime_date first_run = min( [datetime.strptime(r['date'], '%Y-%m-%d').date() for r in sched]) start = min(previous_tuesday(datetime.today().date()), previous_tuesday(first_run)) start = dtstart(start, {'time': '16:40'}) end = start + timedelta(0, 60 * 60) uid = '*****@*****.**' things.append({ 'summary': 'Short Run', 'dtstart': start, 'dtend': end, 'location': 'Meet outside CSE 2', 'description': 'Usually 4 miles on Tuesday, 2 miles on Wednesday, and 6 miles on Thursday.', 'dtstamp': now, 'uid': uid, 'rrule': { 'FREQ': 'WEEKLY', 'BYDAY': ['TU', 'WE', 'TH'] } }) cal = Calendar() for (k, v) in calHeader: if v.startswith('http'): cal.add(k, vUri(v)) else: cal.add(k, vText(v)) for x in things: e = Event() for k, v in x.items(): if isinstance(v, datetime): e.add(k, vDatetime(v)) elif isinstance(v, str) and v.startswith('http'): e.add(k, vUri(v)) elif k.lower() == 'rrule': # XXX: ugly hack e.add(k, v) else: e.add(k, vText(v)) cal.add_component(e) with open('rcc.ics', 'wb') as f: f.write(cal.to_ical())
def new_event(locale, dtstart=None, dtend=None, summary=None, timezone=None, allday=False, description=None, location=None, categories=None, repeat=None, until=None, alarms=None, url=None): """create a new event :param dtstart: starttime of that event :type dtstart: datetime :param dtend: end time of that event, if this is a *date*, this value is interpreted as being the last date the event is scheduled on, i.e. the VEVENT DTEND will be *one day later* :type dtend: datetime :param summary: description of the event, used in the SUMMARY property :type summary: unicode :param timezone: timezone of the event (start and end) :type timezone: pytz.timezone :param allday: if set to True, we will not transform dtstart and dtend to datetime :type allday: bool :param url: url of the event :type url: string :returns: event :rtype: icalendar.Event """ if dtstart is None: raise ValueError("no start given") if dtend is None: raise ValueError("no end given") if summary is None: raise ValueError("no summary given") if not allday and timezone is not None: dtstart = timezone.localize(dtstart) dtend = timezone.localize(dtend) event = icalendar.Event() event.add('dtstart', dtstart) event.add('dtend', dtend) event.add('dtstamp', dt.datetime.now()) event.add('summary', summary) event.add('uid', generate_random_uid()) # event.add('sequence', 0) if description: event.add('description', description) if location: event.add('location', location) if categories: event.add('categories', categories) if url: event.add('url', icalendar.vUri(url)) if repeat and repeat != "none": rrule = rrulefstr(repeat, until, locale, dtstart.tzinfo) event.add('rrule', rrule) if alarms: for alarm in alarms.split(","): alarm = alarm.strip() alarm_trig = -1 * guesstimedeltafstr(alarm) new_alarm = icalendar.Alarm() new_alarm.add('ACTION', 'DISPLAY') new_alarm.add('TRIGGER', alarm_trig) new_alarm.add('DESCRIPTION', description) event.add_component(new_alarm) return event
def make_ical(data, lang, old): caldata = TranslatedMap(data['calendar'], lang=lang) cal = Calendar() cal.add('prodid', 'yamlical.py') cal.add('version', '2.0') cal.add('method', 'PUBLISH') if 'name' in caldata: cal.add('name', caldata['name']) cal.add('x-wr-calname', caldata['name']) if 'description' in caldata: cal.add('description', caldata['description']) cal.add('x-wr-caldesc', caldata['description']) if 'url' in caldata: cal.add('url', caldata['url']) if 'published' in caldata: pubdata = TranslatedMap(caldata['published'], lang=lang) url = vUri(pubdata['url']) url.params['value'] = 'URI' cal.add('source', url) # Todo: make this come from calendar.published.refresh_interval. refresh_interval = vDuration(timedelta(days=1)) refresh_interval.params['VALUE'] = 'DURATION' cal.add('x-published-ttl', refresh_interval) cal.add('refresh-interval', refresh_interval) add_timezone(cal) if 'organizer' in caldata: organizer = vCalAddress(caldata['organizer']['uri']) organizer.params['cn'] = vText(caldata['organizer']['cn']) else: organizer = None for evdata_raw in data['events']: evdata = TranslatedMap(evdata_raw, lang=lang) if 'overlay' in evdata: apply_overlay(evdata, TranslatedMap(evdata['overlay'], lang=lang)) end = None # default if not specified if 'date' in evdata: # Calculate the start and end timestamps from time/endtime. date = arrow.get(evdata['date'], DATE_FORMATS).date() a_start = arrow.get(evdata['time'], TIME_FORMATS) start = datetime.combine(date, a_start.time()) if 'endtime' in evdata: a_end = arrow.get(evdata['endtime'], TIME_FORMATS) end = datetime.combine(date, a_end.time()) else: start = arrow.get(evdata['start'], DT_FORMATS) if 'end' in evdata: end = arrow.get(evdata['end'], DT_FORMATS) event = Event() uid = evdata.setdefault('uid', make_uid()) # Add uid if needed. event.add('uid', uid) event.add('dtstart', dt_ical(start)) if end: event.add('dtend', dt_ical(end)) event.add('summary', apply_template(evdata, 'title')) if 'location' in evdata: event.add('location', apply_template(evdata, 'location')) if 'url' in evdata: event.add('url', apply_template(evdata, 'url')) if 'description' in evdata: event.add('description', apply_template(evdata, 'description')) if organizer: event.add('organizer', organizer) if evdata.get('cancelled', False): event.add('status', 'CANCELLED') if old and uid in old and events_equal(event, old[uid]): event['DTSTAMP'] = old[uid]['DTSTAMP'] else: event.add('dtstamp', datetime.utcnow()) cal.add_component(event) return cal
def ical(request): ninety_days = datetime.utcnow() + timedelta(days=90) event_list = service.get_event_query_set().filter(date_time_begin__lte=ninety_days).order_by('date_time_begin') cal = icalendar.Calendar() cal['prodid'] = icalendar.vText(u'-//Techism//Techism//DE') cal['version'] = icalendar.vText(u'2.0') cal['x-wr-calname'] = icalendar.vText(u'Techism') cal['x-wr-caldesc'] = icalendar.vText(u'Techism - IT-Events in München') for e in event_list: event = icalendar.Event() # TODO should we generate an UUID when creating the event? uid = u'*****@*****.**' % (str(e.id)) event['uid'] = icalendar.vText(uid) event['dtstamp'] = icalendar.vDatetime(datetime.utcnow()) # The sequence field must be incremented each time the event is modifed. # The trick here is to subtract the create TS from the modify TS and # use the difference as sequence. sequence = 0 if e.date_time_created and e.date_time_modified: createTimestamp = time.mktime(e.get_date_time_created_utc().timetuple()) modifyTimestamp = time.mktime(e.get_date_time_modified_utc().timetuple()) sequence = modifyTimestamp - createTimestamp event['sequence'] = icalendar.vInt(sequence) # created and last-modified if e.date_time_created: event['created'] = icalendar.vDatetime(e.get_date_time_created_utc()) if e.date_time_modified: event['last-modified'] = icalendar.vDatetime(e.get_date_time_modified_utc()) # TENTATIVE, CONFIRMED, CANCELLED event['status'] = icalendar.vText(u'CONFIRMED') if e.title: event['summary'] = icalendar.vText(e.title) if e.description: event['description'] = icalendar.vText(e.description) if e.date_time_begin: event['dtstart'] = icalendar.vDatetime(e.get_date_time_begin_utc()) if e.date_time_end: event['dtend'] = icalendar.vDatetime(e.get_date_time_end_utc()) if e.url: relative_url = reverse('event-show', args=[e.id]) absolute_url = request.build_absolute_uri(relative_url) event['url'] = icalendar.vUri(absolute_url) # geo value isn't used by iCal readers :-( # maybe a trick is to add the geo coordinates to the location field using the following format: # $latitude, $longitude ($name, $street, $city) if e.location: location = u'%s, %s, %s' % (e.location.name, e.location.street, e.location.city) event['location'] = icalendar.vText(location) if e.location and e.location.latitude and e.location.longitude: event['geo'] = icalendar.vGeo((e.location.latitude, e.location.longitude)) cal.add_component(event) response = HttpResponse(cal.as_string()) response['Content-Type'] = 'text/calendar; charset=UTF-8' response['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate' response['Pragma'] = 'no-cache' response['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT' return response