def get(self, format): events = Event.all().filter("status IN", ["approved", "canceled"]).order("start_time") if format == "ics": cal = Calendar() for event in events: cal.add_component(event.to_ical()) self.response.headers["content-type"] = "text/calendar" self.response.out.write(cal.as_string()) elif format == "json": self.response.headers["content-type"] = "application/json" events = map(lambda x: x.to_dict(summarize=True), Event.get_approved_list()) self.response.out.write(simplejson.dumps(events)) elif format == "rss": url_base = "http://" + self.request.headers.get("host", "events.hackerdojo.com") rss = PyRSS2Gen.RSS2( title="Hacker Dojo Events Feed", link=url_base, description="Upcoming events at the Hacker Dojo in Mountain View, CA", lastBuildDate=datetime.now(), items=[ PyRSS2Gen.RSSItem( title=event.name, link=url_base + event_path(event), description=event.details, guid=url_base + event_path(event), pubDate=event.updated, ) for event in events ], ) self.response.headers["content-type"] = "application/xml" self.response.out.write(rss.to_xml())
def _make_icalendar(): ical = ICalendar() ical.add('prodid', '-//Ross Laird/mezzanine-events//NONSGML V{0}//EN'.format(__version__)) #'-//Ross Laird Events//' ical.add('version', '2.0') # version of the format, not the product! return ical
def get_ical(self): cal = Calendar() adate = self.start_date for shift in self.shifts: event = Event() if shift not in self.definitions: print('WARNING: Unknown shift: {}'.format(shift), file=sys.stderr) times = None else: if self.definitions[shift]: times = [self.definitions[shift]['start'], self.definitions[shift]['end']] else: times = None if times is not None: starttime = time(int(times[0][:2]), int(times[0][2:4]), tzinfo=self.timezone) event.add('dtstart', datetime.combine(adate, starttime)) if int(times[0]) > int(times[1]): enddate = adate + timedelta(1) else: enddate = adate endtime = time(int(times[1][:2]), int(times[1][2:4]), tzinfo=self.timezone) event.add('dtend', datetime.combine(enddate, endtime)) if 'title' in self.definitions[shift]: event['summary'] = self.definitions[shift]['title'] cal.add_component(event) adate += timedelta(1) return cal.to_ical()
def talk_ics(slug): cal = Calendar() cal.add('prodid', '-//PyCon Canada 2016//2016.pycon.ca') cal.add('version', '2.0') if slug == 'schedule': schedule = get_data_file('schedule.json') # TODO: This should be refactored. for day in schedule.get('days'): for slot in day.get('entries'): if slot.get('talks'): for room, talk in slot.get('talks').iteritems(): if talk: cal.add_component(event_ics(talk)) else: cal.add_component(event_ics(slug)) headers = { 'Content-Disposition': 'attachment;filename={0}.ics'.format(slug) } return Response(response=cal.to_ical(), status=200, mimetype='text/calendar', headers=headers)
def new(self, cal, uri, event): if not cal: print "creating new calendar" cal = Calendar() cal['prodid'] = myProduct.prodid cal['version'] = myProduct.version if uri == "" or uri == None: import os uri = os.path.join(os.path.expanduser("~"), ".gdesklets", "gdesklets-calendar" + os.extsep + "ics") print "creating new file %s" % uri # Add the event to the calendar cal.add_component(event) try: tmp_cal_string = cal.as_string() except ValueError, error: print "ValueError in %s: \"%s\"\n" % (uri, error) print "This is a python issue, but could be solved in the icalendar package." print "Work around it by removing the offending dates in %s ." % uri return
def make_anc_ical(request, anc=None): # Collect future meetings and sort after collating meetings across ANCs. now = datetime.datetime.now() meetings = [] for mtganc, mtgs in meeting_data.items(): if anc != None and mtganc.lower() != anc: continue for mtgdate, mtginfo in sorted(mtgs['meetings'].items()): mtgdate = dateutil.parser.parse(mtgdate) if mtgdate < now: continue meetings.append( (mtgdate, mtganc, mtginfo) ) meetings.sort() # Make ical. from icalendar import Calendar, Event cal = Calendar() for mtgdate, mtganc, mtginfo in meetings: if mtginfo.get("status") == "invalid": continue event = Event() event.add('dtstart', mtgdate) event['summary'] = "ANC %s Meeting" % mtganc event['description'] = "See ANCFinder.org for details: http://ancfinder.org/%s" % mtganc event['location'] = '; '.join(mtginfo[k] for k in ('building', 'address', 'root') if mtginfo.get(k)) event['link'] = mtginfo.get("link") cal.add_component(event) return HttpResponse(cal.to_ical(), "text/calendar" if "mime" not in request.GET else "text/plain")
class TTParser: _cal = Calendar() def __init__(self): self._cal = Calendar() self._cal.add('prodid', '-//University of Lincoln//Room TimeTable ICal Accessor//') self._cal.add('version', '2.0') self._baseUrl = "http://stafftimetables.lincoln.ac.uk/V2/UL/Reports/" def ical(self): d = date.today() for x in range(0, self._range): try: self.add_day(d + timedelta(x)) except Exception as ex: logging.getLogger(__name__).warning( 'failed to add_day for ' + str(d + timedelta(x)) + ': ' + str(type(ex)) + ': ' + ex.message) return self._cal.to_ical() def create_event(self, name, room, the_day, time): tv = time.replace(' ', '').replace(':', '-').split('-') dBegin = datetime(the_day.year, the_day.month, the_day.day, int(tv[0]), int(tv[1]), tzinfo=self._tz_london) dEnd = datetime(the_day.year, the_day.month, the_day.day, int(tv[2]), int(tv[3]), tzinfo=self._tz_london) event = Event() event.add('summary', name) event.add('dtstart', dBegin) event.add('dtend', dEnd) event['location'] = vText(room) return event
def index(): cfg = load_config('config.json') calendar = Calendar() calendar['prodid'] = '-//worker-perlence//Worker calendar' calendar['version'] = '2.0' calendar['x-wr-calname'] = 'Worker calendar' for day, shift in workdays(cfg['FORMULA'], cfg['FIRST_DAY']): if shift == '0': continue event = Event() event.add('uid', 'WORKER-DAY-' + day.isoformat()) event.add('dtstamp', datetime.now()) event.add('dtstart', day) event.add('dtend', day + timedelta(days=1)) event.add('summary', cfg['SUMMARY'][shift]) event['dtstamp'].to_ical() event['dtstart'].to_ical() event['dtend'].to_ical() calendar.add_component(event) data = calendar.to_ical() cache_bust = md5(data).hexdigest()[:7] response = make_response(data) response.headers['Content-Type'] = 'text/calendar;charset=utf-8' response.headers['Content-Disposition'] = ( 'inline; filename="worker-day-%s.ics"' % cache_bust) return response
def __init__(self, ical_string, start_date, end_date, new_events): self.ical = Calendar.from_string(ical_string) self.simpl_ical = Calendar() self.new_events = new_events self.new_events.sort(key=lambda x: x.duration, reverse=True) self.start_date = start_date - start_date%30 + 30 self.end_date = end_date - end_date%30 + 30
def update_event(self, username, uid, event_name, start_timestamp, quantity): """ Update the info about a specific event on the user calendar. :param username: username of the calendar to insert the event. :param uid: UID tha identifies the event in the calendar. :param event_name: Event name. :param start_timestamp: The date where the event are scheduled. :param quantity: The quantity reserved. :return: Keyword 'OK' """ cal = Calendar() cal['version'] = "2.0" cal['prodid'] = "//Radicale//NONSGML Radicale Server//EN" event = Event() event['uid'] = uid event['dtstart'] = vDatetime(datetime.fromtimestamp(start_timestamp)).to_ical() event['summary'] = event_name event['description'] = 'Quantity: ' + str(quantity) event['x-radicale-name'] = str(uid) + '.ics' cal.add_component(event) headers = {'Content-Type': 'text/calendar', 'charset': 'utf-8'} self.client.put(self.url + username + '/calendar.ics/' + str(uid) + '.ics', cal.to_ical(), headers) return 'OK'
def get_course_calendar(user, course_key_string): try: from icalendar import Calendar, Event except ImportError: logging.error('Calendar module not installed') return course_key = CourseKey.from_string(course_key_string) checked = ['course', 'vertical', 'sequential'] items = modulestore().get_items(course_key) hour = timedelta(hours=1) cal = Calendar() for num, item in enumerate(items): if not item.category in checked: continue if not item.graded: continue if not has_access(user, 'load', item, course_key=item.location.course_key): continue if not item.due: continue if item.category != 'course': format = item.format or item.get_parent().format else: format = 'course' url = u'http://{}{}'.format(settings.SITE_NAME, _reverse_usage(item)) event = Event() summary = u'Type: {}; Name: {}({})'.format(format, item.display_name, url).encode('utf-8') event.add('summary', summary) event.add('dtstart', item.due - hour) event.add('dtend', item.due) cal.add_component(event) text = cal.to_ical().decode('utf-8') return text
def calendar(username): access_token = request.args.get("access_token") try: data = urlopen("https://www.beeminder.com/api/v1/users/%s/goals.json?access_token=%s"%(username, access_token)).read() data = json.loads(data.decode(encoding='UTF-8')) except HTTPError: return error_page() cal = Calendar() cal.add('prodid', '-//Beeminder calendar//tevp.net//') cal.add('version', '2.0') cal.add('X-WR-CALNAME', 'Beeminder Calendar for %s'%username) for goal in data: start = datetime.fromtimestamp(goal["losedate"]) startdate = start.date() if start.hour <=4: # Assume that times before 4am are effectively "yesterday" startdate -= timedelta(days = 1) enddate = startdate + timedelta(days = 1) title = goal["title"] event = Event() event.add('summary', "%s fail day" % title) event.add('dtstart', startdate) event.add('dtend', enddate) event.add('last-modified', datetime.now()) event['uid'] = hashlib.md5(title.encode() + str(startdate).encode()).hexdigest() cal.add_component(event) resp = make_response(cal.to_ical()) resp.headers["Content-Type"] = "text/Calendar" resp.headers["Cache-Control"] = "no-cache, must-revalidate" resp.headers["Expires"] = "Sat, 26 Jul 1997 05:00:00 GMT" return resp
def build_calendar(issues, ics_path): cal = Calendar() for i in issues: event = Event() if "Full" in str(i.status): summary = "[COMPLET] " + i.subject else: summary = i.subject event.add('summary', summary) event.add('description', i.description) event['uid'] = i.id for c in i.custom_fields: if c.id == 20: # 20 is 'debut' start_time = str(c.value).replace(':', '')+"00" if c.id == 21: # 21 is 'fin' end_time = str(c.value).replace(':', '')+"00" event['dtstart'] = i.due_date.replace('/','')+"T"+start_time event['dtend'] = i.due_date.replace('/','')+"T"+end_time event['dtstamp'] = vDatetime(now).to_ical() organizer = vCalAddress('MAILTO:[email protected]') organizer.params['cn'] = vText('Les fruits défendus') event['organizer'] = organizer event['location'] = vText('Montréal, QC') cal.add_component(event) f = open(ics_path, 'wb') f.write(cal.to_ical()) f.close()
def ical_event_delete(task, name=None): from icalendar import Calendar # Note removes duplicates if name is None: name = task.name calendarname = task.group() stat = False client, calendar = calendar_load(calendarname) events = calendar.events() for event in events: if str(event).endswith('/'): continue try: event.load() except: error('Failed to load caldav event: ' + name) continue data = Calendar().from_ical(event.get_data()) for component in data.walk(): if component.name == "VTODO": if component.get('summary') == name: if not universe.dry: event.delete() report(colour.red + ' removed caldav event: ' + name + ' (calendar: ' + calendarname + ')' + colour.end) stat = True return stat
def XtestBla(self): from icalendar import Calendar c = Calendar() c['description']=u'Paragraph one\n\nParagraph two' output = c.to_ical() self.assertEqual(output, "BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\r\n \r\n Paragraph two\r\nEND:VCALENDAR\r\n")
def export_ics(self): events = Event.get_recent_past_and_future() url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com') cal = Calendar() for event in events: iev = CalendarEvent() iev.add('summary', event.name if event.status == 'approved' else event.name + ' (%s)' % event.status.upper()) # make verbose description with empty fields where information is missing ev_desc = '__Status: %s\n__Member: %s\n__Type: %s\n__Estimated size: %s\n__Info URL: %s\n__Fee: %s\n__Contact: %s, %s\n__Rooms: %s\n\n__Details: %s\n\n__Notes: %s' % ( event.status, event.owner(), event.type, event.estimated_size, event.url, event.fee, event.contact_name, event.contact_phone, event.roomlist(), event.details, event.notes) # then delete the empty fields with a regex ev_desc = re.sub(re.compile(r'^__.*?:[ ,]*$\n*',re.M),'',ev_desc) ev_desc = re.sub(re.compile(r'^__',re.M),'',ev_desc) ev_url = url_base + event_path(event) iev.add('description', ev_desc + '\n--\n' + ev_url) iev.add('url', ev_url) if event.start_time: iev.add('dtstart', event.start_time.replace(tzinfo=pytz.timezone('US/Pacific'))) if event.end_time: iev.add('dtend', event.end_time.replace(tzinfo=pytz.timezone('US/Pacific'))) cal.add_component(iev) return 'text/calendar', cal.as_string()
def export_calendar_for_user(cal_user_id=None, filename="export"): """ Create and export iCalendar file with the meetings of the chosen user :param cal_user_id: User ID to create calendar for :param filename: Filename for the ics file :return: ics file wrapped in a response """ if cal_user_id is None: # Defaults to current user cal_user_id = current_user.id meeting_list = Meeting.get_user_meetings(cal_user_id) tz = timezone(app.config['TIMEZONE']) cal = Calendar() for meeting in meeting_list: event = Event() event.add('summary', meeting.title) event.add('dtstart', tz.localize(meeting.start_time)) event.add('dtend', tz.localize(meeting.end_time)) event.add('description', u'Møte generert av %s. Antall deltakere: %s. ' % (app.config['APP_NAME'], meeting.participant_count)) cal.add_component(event) export = StringIO.StringIO() export.writelines(cal.to_ical()) export.seek(0) return send_file(export, attachment_filename=filename + '.ics', as_attachment=True)
def get(self, format): events = Event.all().filter('status IN', ['approved', 'canceled']).order('start_time') if format == 'ics': cal = Calendar() for event in events: cal.add_component(event.to_ical()) self.response.headers['content-type'] = 'text/calendar' self.response.out.write(cal.as_string()) elif format == 'json': self.response.headers['content-type'] = 'application/json' events = map(lambda x: x.to_dict(summarize=True), Event.get_approved_list()) self.response.out.write(simplejson.dumps(events)) elif format =='rss': url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com') rss = PyRSS2Gen.RSS2( title = "Hacker Dojo Events Feed", link = url_base, description = "Upcoming events at the Hacker Dojo in Mountain View, CA", lastBuildDate = datetime.now(), items = [PyRSS2Gen.RSSItem( title = event.name, link = url_base + event_path(event), description = event.details, guid = url_base + event_path(event), pubDate = event.updated, ) for event in events] ) self.response.headers['content-type'] = 'application/xml' self.response.out.write(rss.to_xml())
class TTParser: _cal = Calendar() _tz_london = timezone('Europe/London') # the start date has to be the first Monday of the teaching period _start_date = date(2015, 9, 14) _range = 51 * 7 def __init__(self): self._cal = Calendar() self._cal.add('prodid', '-//University of Lincoln//TimeTable//') self._cal.add('version', '2.0') self._baseUrl = "http://stafftimetables.lincoln.ac.uk/V2/UL/Reports/" def ical(self, lecturer): for x in range(0, self._range): #for x in range(49, 70): try: self.query(self._start_date + timedelta(x), lecturer) except Exception as ex: logging.getLogger(__name__).warning( 'failed to add_day for ' + str(self._start_date + timedelta(x)) + ': ' + str(type(ex)) + ': ' + ex.message) return self._cal.to_ical() def create_event(self, name, room, the_day, dBegin, dEnd): event = Event() event.add('summary', name) event.add('dtstart', dBegin) event.add('dtend', dEnd) event['location'] = vText(room) return event
def _make_ics(event, etime): cal = Calendar() cal.add("prodid", "N1-send-availability-package") cal.add("version", "2.0") cal.add("method", "REQUEST") # also have PUBLISH or CANCEL evt = Event() evt.add("summary", event.title) evt.add("location", event.location) evt.add("description", event.description) evt.add("dtstart", etime.start.replace(tzinfo=pytz.UTC)) evt.add("dtend", etime.end.replace(tzinfo=pytz.UTC)) evt.add("dtstamp", datetime.now(pytz.UTC)) evt["uid"] = "{timestamp}/{email}".format( timestamp=time.mktime(datetime.now(pytz.UTC).timetuple()), email=event.organizer.email ) evt.add("priority", 5) organizer = vCalAddress("MAILTO:{}".format(event.organizer.email)) organizer.params["cn"] = vText(event.organizer.name) organizer.params["role"] = vText("CHAIR") evt["organizer"] = organizer for attendee in event.attendees: atnd = vCalAddress("MAILTO:{}".format(attendee.email)) atnd.params["cn"] = vText(attendee.name) atnd.params["ROLE"] = vText("REQ-PARTICIPANT") evt.add("attendee", atnd, encode=0) cal.add_component(evt) return cal.to_ical()
def generate_icalendar_event(event_id): """Takes an event id and returns the event in iCal format""" cal = Calendar() event = icalendar.Event() matching_event = Event.query.get(event_id) if matching_event is None: return api_response(status_code=404, error='Event') event.add('summary', matching_event.name) event.add('geo', (matching_event.latitude, matching_event.longitude)) event.add('location', matching_event.location_name) event.add('color', matching_event.color) event.add('dtstart', matching_event.start_time) event.add('dtend', matching_event.end_time) event.add('logo', matching_event.logo) event.add('email', matching_event.email) event.add('description', matching_event.description) event.add('url', matching_event.event_url) cal.add_component(event) #Saving ical in file filename = "event_calendar/event-calendar-" + str(event_id) + ".ics" f = open(os.path.join(os.path.realpath('.') + '/static/', filename), 'wb') f.write(cal.to_ical()) f.close() return api_response( data=jsonify(calendar=str(cal.to_ical), filename=filename), status_code=event_status_code(event_id), error='Event' )
def handle(self, *args, **options): url = args[0] cal_data = requests.get(url).content cal = Calendar().from_ical(cal_data) events = cal.walk('vevent') Event.objects.filter(from_ics=True).delete() for event in events: end_time = event.get('dtend') if not end_time or not isinstance(end_time.dt, datetime.datetime): continue start_time = event.get('dtstart').dt.replace(year=2014) end_time = event.get('dtend').dt.replace(year=2014) name = event.get('summary') description = event.get('description') location = event.get('location') if description: description = smart_truncate(description, MAX_DESCRIPTION_LENGTH) new = Event.objects.create( name=unicode(name), location=unicode(location) if location else None, description=unicode(description) if description else None, start_time=start_time, end_time=end_time, is_featured=False, from_ics=True, )
def makeCal(outputFile, inputFeed): cal = Calendar() menuRSS = feedparser.parse(inputFeed) for item in menuRSS["entries"]: title = item["title_detail"]["value"].split() jour = title[0] service = title[1] date = datetime.strptime(title[2], "%d/%m/%Y") description = item["summary_detail"]["value"].replace('<br />', '') ev = Event() if not ((jour=="Vendredi" and service=="soir") or jour=="Samedi" or jour=="Dimanche"): ev.add('summary', 'menu RU') if service == "midi": ev.add('dtstart', datetime(date.year,date.month,date.day,11,30,0,tzinfo=timezone("Europe/Paris"))) ev.add('dtend', datetime(date.year,date.month,date.day,13,0,0,tzinfo=timezone("Europe/Paris"))) elif service == "soir": ev.add('dtstart', datetime(date.year,date.month,date.day,18,30,0,tzinfo=timezone("Europe/Paris"))) ev.add('dtend', datetime(date.year,date.month,date.day,20,0,0,tzinfo=timezone("Europe/Paris"))) ev.add('description', description) cal.add_component(ev) f = open(outputFile, 'wb') f.write(cal.to_ical()) f.close()
def favourites_ical(): code = request.args.get('token', None) user = None if code: user = User.get_by_checkin_code(app.config.get('FEED_SECRET_KEY'), str(code)) if not current_user.is_anonymous: user = current_user if not user: abort(404) schedule = _get_scheduled_proposals(request.args, override_user=user) title = 'EMF {} Favourites for {}'.format(event_start().year, user.name) cal = Calendar() cal.add('summary', title) cal.add('X-WR-CALNAME', title) cal.add('X-WR-CALDESC', title) cal.add('version', '2.0') for event in schedule: if not event['is_fave']: continue cal_event = Event() cal_event.add('uid', event['id']) cal_event.add('summary', event['title']) cal_event.add('description', event['description']) cal_event.add('location', event['venue']) cal_event.add('dtstart', event['start_date']) cal_event.add('dtend', event['end_date']) cal.add_component(cal_event) return Response(cal.to_ical(), mimetype='text/calendar')
class CalRessource(dict): def __init__(self, name, ressouce_path, color='normal', ressource_type="local"): self.ressouce_path = ressouce_path self.ressource_type = ressource_type self.color = COLOR_DICT[color] self.name = name if self.ressource_type == 'webressource': try: webcalendar = urlopen(ressouce_path) self.ical = Calendar.from_ical(webcalendar.read()) except IOError: self.ical = Calendar() elif self.ressource_type == 'local': with open(self.ressouce_path, 'rb') as cal_file: self.ical = Calendar.from_ical(cal_file.read()) for component in self.ical.walk(): if component.name == 'VEVENT': iso_date = component['DTSTART'].dt.isoformat().split('T')[0] if not iso_date in self.keys(): self[iso_date] = [component] else: self[iso_date].append(component) def save(self): if not self.ressource_type == 'webressource': with open(self.ressouce_path, 'w') as ressource_file: ressource_file.write(self.ical.to_ical())
def generate_ical(object): cal = Calendar() cal['PRODID'] = 'Kawaz' cal['VERSION'] = '2.0' site = Site.objects.get(pk=settings.SITE_ID) event = CalEvent() event['summary'] = object.title event['description'] = object.body event['class'] = 'PUBLIC' if object.pub_state == 'public' else 'PRIVATE' if object.category: event['categories'] = object.category.label event['dtstamp'] = vDatetime(object.created_at) if object.place: event['location'] = object.place event['dtstart'] = vDatetime(object.period_start).to_ical() if object.period_end: event['dtend'] = vDatetime(object.period_end).to_ical() def create_vaddress(user): va = vCalAddress('MAILTO:{}'.format(user.email)) va.params['cn'] = vText(user.nickname) va.params['ROLE'] = vText(user.role) return va organizer = create_vaddress(object.organizer) event['organizer'] = organizer event['URL'] = 'http://{}{}'.format(site.domain, object.get_absolute_url()) for attendee in object.attendees.all(): event.add('attendee', create_vaddress(attendee), encode=0) cal.add_component(event) return cal
def gen_ical(courses): cal = Calendar() cal["version"] = "2.0" cal[ "prodid" ] = "-//Zhejiang University//LIU Dongyuan//ZH" # *mandatory elements* where the prodid can be changed, see RFC 5445 for course in courses: for lesson in course["lessons"]: weeks = lesson["weeks"] for recur in weeks: event = Event() event.add("summary", unify_brackets(course["name"])) offset_days = lesson["day"] - 1 + 7 * (int(recur) - 1) offset = timedelta(days=offset_days) classdate = week_start + offset start = lesson_time[lesson["start"]]["start"] end = lesson_time[lesson["end"]]["end"] event.add("dtstart", datetime.combine(classdate, start)) event.add("dtend", datetime.combine(classdate, end)) event.add("location", lesson["location"]) event.add("description", u"教师:" + course["teacher"]) event["uid"] = str(uuid1()) + "@ZJU" cal.add_component(event) return cal.to_ical()
def to_ical(course_list): """This function takes all the data parsed and returns an icalendar.""" ical = Calendar() current_tz = timezone("America/Montreal") for courses in course_list: for course in courses: bydays = course.datetime_day.split(',') for byday in bydays: entry_ical = Event() entry_ical.add('summary', course.summary) entry_ical.add('description', course.description) entry_ical.add('location', course.location) dtstart = parser.parse( course.datetime_start).replace(tzinfo=current_tz) entry_ical.add('dtstart', dtstart) dtend = parser.parse( course.datetime_end).replace(tzinfo=current_tz) entry_ical.add('dtend', dtend) until = parser.parse( course.datetime_until).replace(tzinfo=current_tz) entry_ical.add('rrule', {'freq': 'weekly', 'until': until, 'byday': byday}) ical.add_component(entry_ical) return ical
def send_file(request): from icalendar import Calendar, Event as Ev from datetime import datetime import pytz import time cal = Calendar() cal.add('prodid','//Delteps//OurCalendarObjectHackFmi') cal.add('version','2.0') cal.add('method','publish') i = 0 for ev in Event.objects.all(): event = Ev() event.add('summary',ev.subject.name) event.add('dtstart',ev.date_start) event.add('dtend', ev.date_end) event.add('dtstamp',datetime.now()) event['uid']=ev.subject.name+'/'+str(i) i = i+1 cal.add_component(event) icalstream = cal.to_ical() response = HttpResponse(icalstream, mimetype='text/calendar') response['Filename'] = 'filename.ics' response['Content-Disposition'] = 'attachment; filename=filename.ics' return response
def main(): args = parse_command_line() start = dateutil.parser.parse(args.start).date() end = dateutil.parser.parse(args.end).date() days = list(args.days) with file(args.schedule, 'rt') as f: schedule = yaml.load(f) if args.template is not None: with open(args.template,'rt') as f: t = Template(f.read()) if args.ical is not None: cal = Calendar() cal.add('prodid', '-//MicahSherr@Georgetown//make-syllabus//') cal.add('version', '2.0') if args.course is not None: cal.add('X-WR-CALNAME', args.course) holidays = parse_holidays( args.holidays ) if args.template is not None and args.header is not None: with open(args.header,'rt') as h: print h.read() if args.starttime is not None and args.endtime is not None: st = dateutil.parser.parse(args.starttime).time() et = dateutil.parser.parse(args.endtime).time() day_count = (end - start).days + 1 class_num = 0 for single_date in (start + datetime.timedelta(n) for n in range(day_count)): class_info = dict() day_of_week = str(single_date.weekday()) if day_of_week in days: if single_date in holidays: class_info['lec_num'] = "-" class_info['lec_date'] = single_date class_info['description'] = 'No class' class_info['noclass'] = True else: # not a holiday; we have class. if class_num < len(schedule): class_info = schedule[class_num] class_num = class_num + 1 class_info['lec_num'] = class_num class_info['lec_date'] = single_date if args.template is not None: print t.render(class_info) if args.ical is not None and single_date not in holidays: event = make_ical_event(single_date,st,et,class_info,args) cal.add_component(event) if args.template is not None and args.footer is not None: with open(args.footer,'rt') as f: print f.read() if args.ical is not None: with open(args.ical,'wb') as o: o.write(cal.to_ical())
def __init__(self): self.cal = Calendar()
def main(r, filename): data = open(filename, 'rb') #opens a file to read gets from controller.py newStart = datetime.strptime(r, "%m/%d/%Y").date( ) # strips the input string for the specific month day and year values #print(newStart) minDate = date( 9999, 12, 31 ) # the maximum possible allowed date all start dates have to be less than this date daysList = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"] startDateList = [] endDateList = [] #eventSummaryList = [] #eventDescriptionList = [] tzvalue = "" cal = Calendar.from_ical(data.read()) rrules = [] for component in cal.walk(): if component.name == 'VCALENDAR': tzvalue = component.get('X-WR-TIMEZONE') break for event in cal.walk('vevent'): start = event.get('dtstart').dt startDateList.append(start) rrule = event.get('rrule') rrules.append(rrule) print(type(rrule)) if (isinstance(start, datetime)): newStartDate = date(start.year, start.month, start.day) else: newStartDate = start #print('type newStartDate', type(newStartDate)) #print('type startDate', type(start)) #print('type minDate', type(minDate)) if (newStartDate < minDate): minDate = newStartDate end = event.get('dtend').dt endDateList.append(end) newStartDateList = [] newEndDateList = [] print("minDate", minDate) print("new start", newStart) dayOffset = differ_days(minDate, newStart) print("offset", dayOffset) size = len(startDateList) print('size', size) for i in range(0, size): startDate = startDateList[i] # adds the number of offset days to generate a new start date newStartDate = startDate + timedelta(days=dayOffset) endDate = endDateList[i] newEndDate = endDate + timedelta(days=dayOffset) newStartDateList.append(newStartDate) newEndDateList.append(newEndDate) count = 0 rruleCount = 0 bigFile = "" for i in range(0, size): print(i, startDateList[i], newStartDateList[i], endDateList[i], newEndDateList[i]) seenVEVENT = False with open(filename) as f: with open("answers.ics", "w") as f1: for line in f: # copies the file into another file line by line if the line contains a DTSTART or DTEND then the date will be replaced # also writes the file to a long string so that it can be returned and a user will have the opportunity to either copy and paste or download the file if "BEGIN:VEVENT" in line: seenVEVENT = True if "RRULE" in line and seenVEVENT: temp = line if 'BYDAY' in line: oldPart = temp[0:-3] oldDay = temp[-3:-1] val = daysList.index(oldDay) val += dayOffset val %= 7 newPart = daysList[val] bigFile += oldPart + newPart + '\n' f1.write(oldPart + newPart + '\n') continue if "DTSTART;VALUE" in line and seenVEVENT: f1.write("DTSTART;VALUE=DATE:" + newStartDateList[count].strftime("%Y%m%d") + "\n") bigFile += "DTSTART;VALUE=DATE:" + \ newStartDateList[count].strftime("%Y%m%d")+"\n" elif "DTSTART;TZID" in line and seenVEVENT: f1.write("DTSTART;TZID=" + tzvalue + ":" + newStartDateList[count].strftime("%Y%m%d") + 'T' + newStartDateList[count].strftime("%H%M%S") + '\n') bigFile += "DTSTART;TZID="+tzvalue+":" + \ newStartDateList[count].strftime( "%Y%m%d")+'T'+newStartDateList[count].strftime("%H%M%S")+'\n' elif "DTSTART:" in line and seenVEVENT: f1.write("DTSTART:" + newStartDateList[count].strftime("%Y%m%d") + 'T' + newStartDateList[count].strftime("%H%M%S") + 'Z' + "\n") bigFile += "DTSTART:" + \ newStartDateList[count].strftime( "%Y%m%d") + 'T'+newStartDateList[count].strftime("%H%M%S")+'Z'+"\n" elif "DTEND;VALUE" in line and seenVEVENT: f1.write("DTEND;VALUE=DATE:" + newEndDateList[count].strftime("%Y%m%d") + "\n") bigFile += "DTEND;VALUE=DATE:" + \ newEndDateList[count].strftime("%Y%m%d")+"\n" count += 1 elif 'DTEND;TZID' in line and seenVEVENT: f1.write('DTEND;TZID=' + tzvalue + ':' + newEndDateList[count].strftime('%Y%m%d') + 'T' + newEndDateList[count].strftime('%H%M%S') + '\n') bigFile += 'DTEND;TZID='+tzvalue+':' + \ newEndDateList[count].strftime( '%Y%m%d')+'T'+newEndDateList[count].strftime('%H%M%S')+'\n' count += 1 elif "DTEND:" in line and seenVEVENT: f1.write("DTEND:" + newEndDateList[count].strftime("%Y%m%d") + 'T' + newEndDateList[count].strftime("%H%M%S") + 'Z' + "\n") bigFile += "DTEND:" + newEndDateList[count].strftime( "%Y%m%d") + 'T' + newEndDateList[count].strftime( "%H%M%S") + 'Z' + "\n" count += 1 else: f1.write(line) bigFile += line f.close() f1.close() if os.path.exists(filename): os.remove(filename) return bigFile
def ical_feed(request, variant, secret_id): if variant not in ('due', 'waiting'): return HttpResponseNotFound() try: store = models.TaskStore.objects.get(secret_id=secret_id) except: return HttpResponseNotFound() if not store.ical_enabled: return HttpResponseNotFound() if variant == 'due': calendar_title = "Tasks Due" task_filter = { 'due.any': None, 'status': 'pending', } field = 'due' elif variant == 'waiting': calendar_title = "Tasks Waiting" task_filter = { 'status': 'waiting', } field = 'wait' tasks = store.client.filter_tasks(task_filter) calendar = Calendar() calendar.add('version', '2.0') calendar.add('prodid', '-//inthe.am//ical.%s//' % variant) calendar.add('X-WR-CALNAME', calendar_title) for task in tasks: if field not in task: continue event = Event() event.add('uid', task['uuid']) event.add('dtstart', task[field].date()) event.add('dtend', task[field].date() + datetime.timedelta(days=1)) event.add('dtstamp', task.get('modified', task['entry'])) event.add('summary', task['description']) calendar.add_component(event) return HttpResponse( calendar.to_ical(), content_type='text/calendar', )
"February": 2, "March": 3, "April": 4, "May": 5, "June": 6, "July": 7, "August": 8, "September": 9, "October": 10, "November": 11, "December": 12, }.get(month_name, 0) # Create the calendar object and add necessary stuff cal = Calendar() cal.add("prodid", "-//My calendar product//mxm.dk//") cal.add("version", "2.0") # Loop through 30 euroleague pages containing the games for i in range(4, 35): link = ("http://www.euroleague.net/main/results?gamenumber=" + str(i) + "&phasetypecode=RS&seasoncode=E2019") myteam = "Zalgiris Kaunas" # Extract html from the page html = requests.get(link) html.encoding = "utf-8" # Create soup object from the html text soup = BeautifulSoup(html.text, features="lxml")
from icalendar import Calendar, Event, Alarm from datetime import datetime, timedelta from pytz import UTC # timezone import csv contact_file = "mycontacts.csv" ics_export_file = "birthday.ics" alert_begin = 8 alert_end = 10 cal = Calendar() cal.add("prodid", "Birthday-Calendar") cal.add("version", "1.0") def openContacts(): with open(contact_file, newline="") as csvfile: reader = csv.DictReader(csvfile) for row in reader: if (row["Birthday"] != ""): print(row["Name"], row["Birthday"]) year = row["Birthday"][0:4] month = row["Birthday"][5:7] day = row["Birthday"][8:9] # sometimes google saves the birthday of your # contacts like this # --.01-01 # this is why we change the undifined value to 2000 format_time = row["Birthday"].replace("--", "-").replace( " ", "2000") format_time = format_time.split("-")
class Team(object): """ Object that has all team attributes. The information is sent from Competition where it has the visibility of the Standings table. It parses every row and it gets the data per each column. """ Row = namedtuple('Row', [ 'position', 'name', 'played_games', 'won_games', 'tie_games', 'lost_games', 'goals', 'diff', 'points' ]) def __init__(self, competition_instance, team_details, division): self.logger = logging.getLogger('{base}.{suffix}'.format( base=LOGGER_BASENAME, suffix=self.__class__.__name__)) self.session = competition_instance.session self.competition = competition_instance self._populate(Team.Row(*[info.text for info in team_details])) self._calendar = None self.division = division def _populate(self, team_details): """ It gets the row from standingstable for the requested Team and then it gets the index accordingly to every column. :param team_details: BFS object """ try: self.position = team_details.position self.name = team_details.name.encode('utf-8').strip() self.played_games = team_details.played_games self.won_games = team_details.won_games self.tie_games = team_details.tie_games self.lost_games = team_details.lost_games self.goals = team_details.goals self.diff = team_details.diff self.points = team_details.points except AttributeError: self.logger.exception("Got an exception while populating a team") @property def matches(self): """ Gets all matches for a Team :return: list of Match objects """ return [ match for match in self.competition.matches if self.name in match.title ] @property def events(self): """ :return: list of Event objects for all the matches that a Team is part of """ return [match.event for match in self.matches] @property def calendar(self): """ Generates a RFC2445 (iCalendar) for all the Events that a Team has :return: Calendar string """ if not self._calendar: self._calendar = Calendar() for event in self.events: self._calendar.add_component(event) return self._calendar
class Competition(object): """ Gets competitions from location, url and name. Object that has all attributes for a competition """ def __init__(self, footy_instance, url): self._logger = logging.getLogger('{base}.{suffix}'.format( base=LOGGER_BASENAME, suffix=self.__class__.__name__)) self.session = footy_instance.session self._populate(url) self._teams = [] self._matches = [] self._calendar = None self._soup = None def _populate(self, url): """ Fills class variables that are passed from the main page """ try: self.url = url except KeyError: self._logger.exception("Got an exception in Competition") @property def teams(self): """ Gets all teams that are in a competition. The teams are retrieved from each row in the standings table :return: list of Team objects """ if not self._teams: standings = self._get_table('banner') division = standings.h2.text for teams in standings.find_all('tr'): team = teams.find_all('td') if team: self._teams.append(Team(self, team, division)) return self._teams @property def matches(self): """ Gets all matches that are in a competition The matches are retrieved from all the Rounds :return: list of Match objects """ if not self._matches: match_tables = self._get_table('previous-matches') for matches in match_tables.find_all('tr'): match = matches.find_all('td') if match: self._matches.append(Match(self, match)) return self._matches def _get_table(self, section_attr): """ Gets according section tag This is used for teams and matches :param section_attr: name of the section id attribute :return: BFS object """ if not self._soup: competition_page = self.session.get(self.url) self._soup = Bfs(competition_page.text, "html.parser") return self._soup.find('section', {'id': '{}'.format(section_attr)}) @property def calendar(self): """ Generates a RFC2445 (iCalendar) for all the matches in a competition :return: Calendar string """ if not self._calendar: self._calendar = Calendar() for team in self.teams: for event in team.events: self._calendar.add_component(event) return self._calendar
from icalendar import Calendar, Event from pprint import pprint events = {} with open('events.en.ics', 'r') as f: cal = Calendar.from_ical(f.read()) for component in cal.walk(): if component.name == "VEVENT": evs = [] desc = str(component.get('description')) evs = desc.split(', ') if len(evs) > 2: evs[-1] = evs[-1].split('and ')[-1] else: evs = desc.split(' and ') events.append({component.get('dtstart').dt: evs}) pprint(events)
def events_from_ics(namespace, calendar, ics_str): try: cal = Calendar.from_ical(ics_str) except ValueError: raise MalformedEventError() events = [] for component in cal.walk(): if component.name == "VEVENT": start = component.get('dtstart').dt end = component.get('dtend').dt title = component.get('summary') description = str(component.get('description')) if isinstance(start, datetime): all_day = False else: all_day = True start = datetime.combine(start, datetime.min.time()) end = datetime.combine(end, datetime.min.time()) reccur = component.get('rrule') if reccur: reccur = reccur.to_ical() else: reccur = '' participants = [] for attendee in component.get('attendee'): email = str(attendee) # strip mailto: if it exists if email.startswith('mailto:'): email = email[7:] try: name = attendee.params['CN'] except KeyError: name = None status_map = { 'NEEDS-ACTION': 'noreply', 'ACCEPTED': 'yes', 'DECLINED': 'no', 'TENTATIVE': 'maybe' } status = 'noreply' try: a_status = attendee.params['PARTSTAT'] status = status_map[a_status] except KeyError: pass notes = None try: guests = attendee.params['X-NUM-GUESTS'] notes = "Guests: {}".format(guests) except KeyError: pass participants.append({ 'email_address': email, 'name': name, 'status': status, 'notes': notes, 'guests': [] }) location = component.get('location') organizer = component.get('organizer') if (organizer): organizer = str(organizer) if organizer.startswith('mailto:'): organizer = organizer[7:] uid = str(component.get('uid')) event = Event(namespace=namespace, calendar=calendar, uid=uid, provider_name='ics', raw_data=component.to_ical(), title=title, description=description, location=location, reminders=str([]), recurrence=reccur, start=start, end=end, busy=True, all_day=all_day, read_only=True, source='local', participants=participants) events.append(event) return events
def main(infile=None): # The skipinitialspace option eliminates leading # spaces and reduces blank cells to '' while the clean_spaces # function gets rid of trailing spaces. try: if infile == None: start_dir = '~/' if isdir(expanduser("~/Desktop")): start_dir = '~/Desktop/' msg = 'Please select the .csv file to be converted to .ics' infile = easygui.fileopenbox(msg=msg, title="", default=expanduser(start_dir), filetypes=["*.csv"]) reader_builder = list( csv.DictReader(open(infile, 'U'), skipinitialspace=True)) # For testing comment 4 lines above (2 x if / else) and use this: # reader_builder = list(csv.DictReader(open('path_to_tester.csv', 'rb'), skipinitialspace = True)) except Exception as e: logger.exception(e) easygui.msgbox( "Looks like there was an error opening the file, didn't even make it to the conversion part. Sorry!" ) sys.exit(1) # Filter out events with empty subjects, a required element # for a calendar event. # Code found here: http://bit.ly/Z4Pg4h reader_builder[:] = [d for d in reader_builder if d.get('Subject') != ''] headers = reader_builder[0].keys() logger.debug('reader_builder[0].keys(): {}'.format(headers)) check_headers(headers) reader = clean_spaces(reader_builder) # Start calendar file cal = Calendar() cal.add('prodid', 'n8henrie.com') cal.add('version', '2.0') # Write the clean list of dictionaries to events. rownum = 0 try: for row in reader: event = Event() event.add('summary', row['Subject']) try: check_dates_and_times(start_date=row.get('Start Date'), start_time=row.get('Start Time'), end_date=row.get('End Date'), end_time=row.get('End Time'), all_day=row.get('All Day Event'), subject=row.get('Subject')) except DateTimeError as e: sys.exit(e) # If marked as an "all day event," ignore times. # If start and end date are the same # or if end date is blank default to a single 24-hour event. if row.get('All Day Event') != None and row['All Day Event'].lower( ) == 'true': # All-day events will not be marked as 'busy' event.add('transp', 'TRANSPARENT') event.add( 'dtstart', datetime.strptime(row['Start Date'], '%m/%d/%Y').date()) if row.get('End Date') in ['', None]: event.add( 'dtend', (datetime.strptime(row['Start Date'], '%m/%d/%Y') + timedelta(days=1)).date()) else: event.add('dtend', (datetime.strptime(row['End Date'], '%m/%d/%Y') + timedelta(days=1)).date()) # Continue processing events not marked as "all day" events. else: # Events with times should be 'busy' by default event.add('transp', 'OPAQUE') # Get rid of spaces # Note: Must have both start and end times if not all_day, already checked row['Start Time'] = row['Start Time'].replace(' ', '') row['End Time'] = row['End Time'].replace(' ', '') # Allow either 24 hour time or 12 hour + am/pm if row['Start Time'][-2:].lower() in ['am', 'pm']: event.add( 'dtstart', datetime.strptime( row['Start Date'] + row['Start Time'], '%m/%d/%Y%I:%M%p')) else: event.add( 'dtstart', datetime.strptime( row['Start Date'] + row['Start Time'], '%m/%d/%Y%H:%M')) # Allow blank end dates (assume same day) if row.get('End Date') in ['', None]: row['End Date'] = row['Start Date'] if row['End Time'][-2:].lower() in ['am', 'pm']: event.add( 'dtend', datetime.strptime(row['End Date'] + row['End Time'], '%m/%d/%Y%I:%M%p')) else: event.add( 'dtend', datetime.strptime(row['End Date'] + row['End Time'], '%m/%d/%Y%H:%M')) if row.get('Description'): event.add('description', row['Description']) if row.get('Location'): event.add('location', row['Location']) event.add('dtstamp', datetime.replace(datetime.now(), tzinfo=LocalTimezone())) event['uid'] = str(randint(1, 10**30)) + datetime.now().strftime( '%Y%m%dT%H%M%S') + '___n8henrie.com' cal.add_component(event) rownum += 1 except Exception, e: if rownum > 0: easygui.msgbox( 'I had a problem with an event. I think I might have gotten through about {0} events and had trouble with an event with subject: {1}. Sorry!' .format(rownum, row['Subject'])) logger.exception(e) elif rownum == 0: easygui.msgbox( 'Looks like I didn\'t even get through the first event. Sorry!' ) logger.exception(e) else: easygui.msgbox( 'Somehow it looks like I processed negative events... that shouldn\'t have happened. Sorry!' ) logger.exception(e) sys.exit(2)
def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): """ Query the events occurring in a given time range. :param content: iCal URL/file content as String :param start: start date for search, default today :param end: end date for search :param default_span: default query length (one week) :return: events as list """ if not start: start = now() if not end: end = start + default_span if not content: raise ValueError("Content is invalid!") calendar = Calendar.from_ical(content) # Keep track of the timezones defined in the calendar timezones = {} # Parse non standard timezone name if "X-WR-TIMEZONE" in calendar: x_wr_timezone = str(calendar["X-WR-TIMEZONE"]) timezones[x_wr_timezone] = get_timezone(x_wr_timezone) for c in calendar.walk("VTIMEZONE"): name = str(c["TZID"]) try: timezones[name] = c.to_tz() except IndexError: # This happens if the VTIMEZONE doesn't # contain start/end times for daylight # saving time. Get the system pytz # value from the name as a fallback. timezones[name] = timezone(name) # If there's exactly one timezone in the file, # assume it applies globally, otherwise UTC if len(timezones) == 1: cal_tz = get_timezone(list(timezones)[0]) else: cal_tz = UTC start = normalize(start, cal_tz) end = normalize(end, cal_tz) found = [] recurrence_ids = [] # Skip dates that are stored as exceptions. exceptions = {} for component in calendar.walk(): if component.name == "VEVENT": e = create_event(component, cal_tz) if "RECURRENCE-ID" in component: recurrence_ids.append( (e.uid, component["RECURRENCE-ID"].dt, e.sequence) ) if "EXDATE" in component: # Deal with the fact that sometimes it's a list and # sometimes it's a singleton exlist = [] if isinstance(component["EXDATE"], list): exlist = component["EXDATE"] else: exlist.append(component["EXDATE"]) for ex in exlist: exdate = ex.to_ical().decode("UTF-8") exceptions[exdate[0:8]] = exdate # Attempt to work out what timezone is used for the start # and end times. If the timezone is defined in the calendar, # use it; otherwise, attempt to load the rules from pytz. start_tz = None end_tz = None if e.start.tzinfo != UTC: if str(e.start.tzinfo) in timezones: start_tz = timezones[str(e.start.tzinfo)] else: start_tz = e.start.tzinfo if e.end.tzinfo != UTC: if str(e.end.tzinfo) in timezones: end_tz = timezones[str(e.end.tzinfo)] else: end_tz = e.end.tzinfo # If we've been passed or constructed start/end values # that are timezone naive, but the actual appointment # start and end times are in a timezone, convert start # and end to have a timezone. Otherwise, python will # raise an exception for comparing timezone naive # and offset-aware values. if e.start.tzinfo and not start.tzinfo: start = normalize(start, e.start.tzinfo) if e.start.tzinfo and not end.tzinfo: end = normalize(end, e.start.tzinfo) duration = e.end - e.start if e.recurring: # Unfold recurring events according to their rrule rule = parse_rrule(component, cal_tz) [after] = adjust_timezone(component, [start - duration], start_tz) [end] = adjust_timezone(component, [end], start_tz) for dt in rule.between(after, end, inc=True): if start_tz is None: # Shrug. If we couldn't work out the timezone, it is what it is. ecopy = e.copy_to(dt, e.uid) else: # Recompute the start time in the current timezone *on* the # date of *this* occurrence. This handles the case where the # recurrence has crossed over the daylight savings time boundary. naive = datetime( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second ) dtstart = normalize(naive, tz=start_tz) ecopy = e.copy_to(dtstart, e.uid) # We're effectively looping over the start time, we might need # to adjust the end time too, but don't have it's recurred value. # Make sure it's adjusted by constructing it from the meeting # duration. Pro: it'll be right. Con: if it was in a different # timezone from the start time, we'll have lost that. ecopy.end = dtstart + duration exdate = "%04d%02d%02d" % ( ecopy.start.year, ecopy.start.month, ecopy.start.day, ) if exdate not in exceptions: found.append(ecopy) elif e.end >= start and e.start <= end: exdate = "%04d%02d%02d" % (e.start.year, e.start.month, e.start.day) if exdate not in exceptions: found.append(e) # Filter out all events that are moved as indicated by the recurrence-id prop return [ event for event in found if e.sequence is None or not (event.uid, event.start, e.sequence) in recurrence_ids ]
def orderFromUs(request): if request.method == 'POST': form = OrderForm(request.POST) if (form.is_valid()): orderer = form.cleaned_data['orderer'] ordererEmail = form.cleaned_data['ordererEmail'] phoneNumber = form.cleaned_data['phoneNumber'] association = form.cleaned_data['association'] numberOfCoffee = form.cleaned_data['numberOfCoffee'] numberOfTea = form.cleaned_data['numberOfTea'] numberOfSoda = form.cleaned_data['numberOfSoda'] numberOfKlagg = form.cleaned_data['numberOfKlagg'] numberOfJochen = form.cleaned_data['numberOfJochen'] numberOfMinijochen = form.cleaned_data['numberOfMinijochen'] numberOfPastasalad = form.cleaned_data['numberOfPastasalad'] pickup = form.cleaned_data['pickup'] date = form.cleaned_data['date'] def extend_sub_types(sub_types): return [(field_name, label, form.cleaned_data[f"numberOf{field_name.title()}"]) for field_name, label in sub_types] order_fields = ( ("kaffe", numberOfCoffee, None), ("te", numberOfTea, None), ("läsk/vatten", numberOfSoda, None), ("klägg", numberOfKlagg, None), ("Jochen", numberOfJochen, extend_sub_types(form.JOCHEN_TYPES)), ("Mini Jochen", numberOfMinijochen, extend_sub_types(form.MINI_JOCHEN_TYPES)), ("pastasallad", numberOfPastasalad, extend_sub_types(form.PASTA_SALAD_TYPES)), ) subject = f'[Beställning {date.strftime("%Y-%m-%d")} | {orderer} - {association}]' from_email = '*****@*****.**' to = '*****@*****.**' html_content = render_to_string("baljan/email/order.html", { "data": form.cleaned_data, "order_fields": order_fields, }) htmlpart = MIMEText(html_content.encode('utf-8'), 'html', 'UTF-8') msg = EmailMultiAlternatives(subject, "", from_email, [to], headers={'Reply-To': ordererEmail}) msg.attach(htmlpart) description_lines = [ f"Namn: {orderer}", f"Telefon: {phoneNumber}", f"Email: {ordererEmail}", "", ] + [ f"Antal {name}: {count}" for name, count, _ in order_fields if count ] + ["", "Mer detaljerad information hittas i mailet."] calendar_description = "\n".join(description_lines) start, end = time(0, 0), time(0, 0) if pickup == '0': # Morgon start, end = time(7, 30), time(8, 0) if pickup == '1': # Lunch start, end = time(12, 15), time(13, 0) if pickup == '2': # Eftermiddag start, end = time(16, 15), time(17, 0) tz = pytz.timezone(settings.TIME_ZONE) cal = Calendar() cal.add('prodid', '-//Baljan Cafesys//baljan.org//') cal.add('version', '2.0') cal.add('calscale', "GREGORIAN") cal.add('method', 'REQUEST') event = Event() event.add("summary", subject) event.add('dtstart', datetime.combine(date, start, tz)) event.add('dtend', datetime.combine(date, end, tz)) event.add('dtstamp', datetime.now(tz)) event.add("uid", f"{uuid.uuid4()}@baljan.org") event.add("description", calendar_description) event.add("location", "Baljan") event.add("status", "CONFIRMED") cal.add_component(event) msg.attach('event.ics', cal.to_ical(), 'text/calendar') msg.send() messages.add_message(request, messages.SUCCESS, _("Thank you!")) return HttpResponseRedirect("bestallning") else: form = OrderForm() return render(request, 'baljan/orderForm.html', { 'form': form, })
# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Copyright 2014 <Dominique DERRIER> from icalendar import Event, Calendar from datetime import datetime import pytz cal = Calendar() evt = Event() cal['X-CALENDARSERVER-ACCESS'] = "CONFIDENTIAL" # CONFIDENTIAL | PUBLIC #evt.add('dtstart',datetime(2014,04,29,20,0,0,tzinfo=pytz.timezone('America/Montreal'))) #evt.add('dtend',datetime(2014,04,29,21,0,0,tzinfo=pytz.timezone('America/Montreal'))) #evt.add('summary','Evenement secret') #evt.add('description','Generated Evenement') # #cal.add_component(evt) #evt2=Event() #evt2.add('summary','Multiple Day') #evt2.add('dtstart;VALUE=DATE','20140429')
def get_week_cal(self): '''Extracts the weekly calendar from the ical urls on the config file''' logger.info('Getting week calendar') today = datetime.datetime.utcnow().date() next_week = today + datetime.timedelta(7) week_cal = Calendar() week_cal.add('x-wr-calname', "Weekly Combined Calendar") urls = self.get_cal_urls() for url in urls: logger.debug(url) try: # Error avoider: Tries to read the calendar several times attempts = 0 while attempts < 5: if attempts < 4: try: req = requests.get(url) attempts = 5 except: attempts += 1 else: req = requests.get(url) attempts = 5 # Error avoider finished if req.status_code != 200: logger.error("Error {} fetching {}: {}".format( url, req.status_code, req.text)) continue cal = Calendar.from_ical(req.text) for event in cal.walk("VEVENT"): end = event.get('dtend') if end: WEEK_EVENT = False if hasattr(end.dt, 'date'): date = end.dt.date() else: date = end.dt if date >= today and date < next_week: WEEK_EVENT = True elif 'RRULE' in event: try: rrule = event['RRULE'] until = rrule.get('until')[0] if today < until.date(): # Only weekly repeated events are supported if 'WEEKLY' in rrule.get('freq')[0]: WEEK_EVENT = True except Exception as error: logger.error(("{} rrule\n" + error).format( sys._getframe().f_code.co_name)) if WEEK_EVENT: copied_event = Event() for attr in event: if type(event[attr]) is list: for element in event[attr]: copied_event.add(attr, element) else: copied_event.add(attr, event[attr]) week_cal.add_component(copied_event) except Exception as error: # Add counter to avoid false errors logger.warning('Invalid calendar, removing\n' + url + '\n' + error) self.remove_cal_url(url) for chat_id in self.state.chat_id_list: self.state.bot.sendMessage( chat_id, 'Removed invalid calendar url:\n' + url) logger.info('Got calendars') return week_cal
#!/usr/bin/env python3 from icalendar import Calendar, Event from datetime import datetime from pytz import UTC openFile = open('example.ics', 'rb') openCalendar = Calendar.from_ical(openFile.read()) for component in openCalendar.walk(): if component.name == "VEVENT" and component.get( 'summary') is not None and component.get( 'description') is not None and 'food' in str( component.get('description')): # print("Event==================================") # print("Event: " + component.get('summary')) # print("Description: " + component.get('description')) # print("Location: " + component.get('location')) start = component.get('dtstart') end = component.get('dtend') startdt = start.dt startstr = startdt.strftime('%Y-%m-%d-%H-%M-%S') enddt = end.dt endstr = enddt.strftime('%Y-%m-%d-%H-%M-%S') openFile.close() print(startstr) print(endstr)
if fn.endswith(".ics")) data = ((os.stat(path), path) for path in data) # regular files, insert creation date data = ((stat[ST_CTIME], path) for stat, path in data if S_ISREG(stat[ST_MODE])) file = sorted(data, reverse=True)[0][1] try: g = open(file, 'rb') o = open('C:\\Users\\Alice\\Desktop\\birthdays.txt', 'wb') except IOError: print "Could not open file! Please close Excel!" gcal = Calendar.from_ical(g.read()) current_date = datetime.now().__str__().split()[0] i = 0 people = [] for component in gcal.walk(): if component.name == "VEVENT": persone_date = component.get('dtstart').__dict__['dt'].__str__() if persone_date == current_date: uid = component.get('uid').split('@')[0] uid = uid[1:] link = 'https://www.facebook.com/profile.php?id=' link = link + uid name = component.get('summary').split()[0] simbol = ':*' if name[len(name) - 1] == 'a' else ':)' lma = 'La multi ani, ' + name + '! ' + simbol people.append((link, lma))
def write_calendar(summary: str, start: datetime, end: datetime, description: str, location: str, oponent_info: str): calname = "ltc-herren1-" + datetime.strftime(start, "%Y%m%d") + ".ics" t_cal = Calendar() t_cal.add('prodid', '-//LTC Herren 1 Kalender//ltc-scraper.py by Bartosz Swiatek//') t_cal.add('version', '2.0') t_cal.add('method', 'request') event = Event() event.add('uid', uuid.uuid4().hex) event.add('summary', summary) event.add('dtstart', start) event.add('dtend', end) event.add('description', description) event.add('last-modified', datetime.now()) event.add('dtstamp', datetime.now()) event.add('location', location) event.add('comment', oponent_info) alarm = Alarm() alarm.add('action', 'DISPLAY') alarm.add('TRIGGER;RELATED=START', '-P1D') alarm.add('description', 'Erinnerung zum Punktspiel') event.add_component(alarm) t_cal.add_component(event) cal.add_component(event) cwd = os.getcwd() f = open(os.path.join(cwd, calname), 'wb') f.write(t_cal.to_ical()) f.close() del alarm del event del t_cal
def isschoolcalendar(self, zone, day, month, year): try: zoneok = str(zone.upper()) except: return "Wrong Zone (must be A, B or C)" if len(zoneok) > 1: return "Wrong Zone (must be A, B or C)" if zoneok not in ["A", "B", "C"]: return "Wrong Zone (must be A, B or C)" else: URL = "http://media.education.gouv.fr/ics/Calendrier_Scolaire_Zone_" + zoneok + ".ics" try: ics = urlopen(URL) cal = Calendar.from_ical(ics.read()) except: return "Data offline" #datenow = datetime.now() #year = datenow.year #month = datenow.month #month = 9 #day = datenow.day #day = 26 today = date(year, month, day) startspring = u"Vacances d'\xe9t\xe9" endspring = u"Rentr\xe9e scolaire des \xe9l\xe8ves" springd2 = None springd3 = None for event in cal.walk('vevent'): start = event.get('dtstart') convertstart = start.to_ical() stringconvertstart = str(convertstart) startdecode = time.strptime(str(convertstart), '%Y%m%d') end = event.get('dtend') summary = event.get('summary') yearstart = startdecode[0] monthstart = startdecode[1] daystart = startdecode[2] d2 = date(yearstart, monthstart, daystart) d3 = None description = summary.to_ical().decode('utf-8') if str(year) in convertstart: if startspring in summary: if d2 is not None: springd2 = d2 if endspring in summary: if d2 is not None: springd3 = d2 comparestart = "" compareend = "" if springd2: comparestart = springd2 < today if springd3: compareend = today < springd3 if comparestart and compareend: description = startspring.encode('utf-8') return str(description) if end: convertend = end.to_ical() enddecode = time.strptime(str(convertend), '%Y%m%d') stringconvertend = str(convertend) yearend = enddecode[0] monthend = enddecode[1] dayend = enddecode[2] d3 = date(yearend, monthend, dayend) if d2 < today < d3: return description else: pass
def _update(self, provider, update): self.provider = provider self.path = provider.get('config', {}).get('path', None) if not self.path: logger.warn( 'File Feeding Service {} is configured without path. Please check the configuration' .format(provider['name'])) return [] registered_parser = self.get_feed_parser(provider) for filename in get_sorted_files(self.path, sort_by=FileSortAttributes.created): try: last_updated = None file_path = os.path.join(self.path, filename) if os.path.isfile(file_path): stat = os.lstat(file_path) last_updated = datetime.fromtimestamp(stat.st_mtime, tz=utc) if self.is_latest_content(last_updated, provider.get('last_updated')): if isinstance(registered_parser, NTBEventXMLFeedParser): logger.info('Ingesting xml events') with open(file_path, 'rb') as f: xml = ElementTree.parse(f) parser = self.get_feed_parser( provider, xml.getroot()) item = parser.parse(xml.getroot(), provider) elif isinstance(registered_parser, IcsTwoFeedParser): logger.info('Ingesting ics events') with open(file_path, 'rb') as f: cal = Calendar.from_ical(f.read()) parser = self.get_feed_parser(provider, cal) item = parser.parse(cal, provider) else: logger.info('Ingesting events with unknown parser') parser = self.get_feed_parser(provider, file_path) item = parser.parse(file_path, provider) self.after_extracting(item, provider) self.move_file(self.path, filename, provider=provider, success=True) if isinstance(item, list): yield item else: yield [item] else: self.move_file(self.path, filename, provider=provider, success=True) except Exception as ex: if last_updated and self.is_old_content(last_updated): self.move_file(self.path, filename, provider=provider, success=False) raise ParserError.parseFileError( '{}-{}'.format(provider['name'], self.NAME), filename, ex, provider) push_notification('ingest:update')
import os import uuid from pathlib import Path home = str(Path.home()) url = "https://tvbb.liga.nu/cgi-bin/WebObjects/nuLigaTENDE.woa/wa/groupPage?championship=TVBB+Sommer+2021&group=1635442" xpath = "//*[@id='content-row2']/table[2]" before_xpath = "//*[@id='content-row2']/table[2]/tbody/tr[" datetime_xpath = "]/td[2]" host_xpath = "]/td[4]" guest_xpath = "]/td[5]" club = "Lichtenberger Tennisclub" cal = Calendar() cal.add('prodid', '-//LTC Herren 1 Kalender//ltc-scraper.py by Bartosz Swiatek//') cal.add('version', '2.0') calendarname = "ltc-herren1-full.ics" options = Options() options.headless = True # driver = webdriver.Firefox(options=options, executable_path=home+'/bin/geckodriver') # second_driver = webdriver.Firefox(options=options, executable_path=home+'/bin/geckodriver') driver = webdriver.Chrome(options=options, executable_path=home + '/bin/chromedriver') second_driver = webdriver.Chrome(options=options, executable_path=home + '/bin/chromedriver') driver.get(url)
def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): """ Query the events occurring in a given time range. :param content: iCal URL/file content as String :param start: start date for search, default today :param end: end date for search :param default_span: default query length (one week) :return: events as list """ if not start: start = now() if not end: end = start + default_span if not content: raise ValueError('Content is invalid!') calendar = Calendar.from_ical(content) # Keep track of the timezones defined in the calendar timezones = {} for c in calendar.walk('VTIMEZONE'): name = str(c['TZID']) timezones[name] = c.to_tz() # If there's exactly one timezone in the file, # assume it applies globally, otherwise UTC if len(timezones) == 1: cal_tz = gettz(list(timezones)[0]) else: cal_tz = UTC start = normalize(start, cal_tz) end = normalize(end, cal_tz) found = [] # Skip dates that are stored as exceptions. exceptions = {} for component in calendar.walk(): if component.name == "VEVENT": e = create_event(component) if ('EXDATE' in component): # Deal with the fact that sometimes it's a list and # sometimes it's a singleton exlist = [] if isinstance(component['EXDATE'], list): exlist = component['EXDATE'] else: exlist.append(component['EXDATE']) for ex in exlist: exdate = ex.to_ical().decode("UTF-8") exceptions[exdate[0:8]] = exdate # Attempt to work out what timezone is used for the start # and end times. If the timezone is defined in the calendar, # use it; otherwise, attempt to load the rules from pytz. start_tz = None end_tz = None # Ignore all-day apointments, they aren't really in a timezone. if not e.all_day: if e.start.tzinfo != UTC: if str(e.start.tzinfo) in timezones: start_tz = timezones[str(e.start.tzinfo)] else: try: start_tz = timezone(str(e.start.tzinfo)) except: pass if e.end.tzinfo != UTC: if str(e.end.tzinfo) in timezones: end_tz = timezones[str(e.end.tzinfo)] else: try: end_tz = timezone(str(e.end.tzinfo)) except: pass duration = e.end - e.start if e.recurring: # Unfold recurring events according to their rrule rule = parse_rrule(component, cal_tz) dur = e.end - e.start for dt in rule.between(start - dur, end, inc=True): if start_tz is None: # Shrug. If we coudln't work out the timezone, it is what it is. ecopy = e.copy_to(dt, e.uid) else: # Recompute the start time in the current timezone *on* the # date of *this* occurrence. This handles the case where the # recurrence has crossed over the daylight savings time boundary. naive = datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) dtstart = start_tz.localize(naive) ecopy = e.copy_to(dtstart, e.uid) # We're effectively looping over the start time, we might need # to adjust the end time too, but don't have it's recurred value. # Make sure it's adjusted by constructing it from the meeting # duration. Pro: it'll be right. Con: if it was in a different # timezone from the start time, we'll have lost that. ecopy.end = dtstart + duration exdate = "%04d%02d%02d" % (ecopy.start.year, ecopy.start.month, ecopy.start.day) if exdate not in exceptions: found.append(ecopy) elif e.end >= start and e.start <= end: exdate = "%04d%02d%02d" % (e.start.year, e.start.month, e.start.day) if exdate not in exceptions: found.append(e) return found
def test__close(self, ical_writer, fact, path): """Make sure the calendar is actually written do disk before file is closed.""" ical_writer.write_report((fact, )) with open(path, 'rb') as fobj: result = Calendar.from_ical(fobj.read()) assert result.walk()
def main(): time_zone = pytz.timezone('Asia/Shanghai') semesters = get_semesters_to_json() if semesters == -1: print('Program met some wrong, please wait and try again.') exit(1) print('Semesters:') semesters_dict = parse_semesters_json_to_dict(semesters) for semester in semesters: print(semester['Code'], '->', semester['Name']) selester_selected = input( 'Please select a semester (Just need enter the number before arrow):') if not semesters_dict.__contains__(selester_selected): print('Please select a correct semester!') exit(1) username = input('Please input your JiDaTong username:'******'Please input your JiDaTong password:'******'Please input first day of term(Format: Year-month-day):') sid = get_jmu_sid(username, password) if sid == -1: print('Your username or password is error, please try again.') exit(1) print('Your JiDaTong sid is:', sid) schedule_json = get_schedule_to_json(sid, selester_selected) if schedule_json == -1: print('Program met some wrong, please wait and try again.') exit(1) name = schedule_json['Name'] class_name = schedule_json['className'] courses = schedule_json['courses'] calendar = Calendar() calendar.add('prodid', '-//My calendar product//mxm.dk//') calendar.add('version', '2.0') for course in courses: course_in_day_of_week = int(course['couDayTime']) # 课程在星期几 course_take_weeks = get_course_take_weeks(course['allWeek']) course_begin_time, course_end_time = get_course_take_time( course['coudeTime']) for week in course_take_weeks: course_date = get_course_date(first_day_date_str, course_in_day_of_week, week) event = Event() event.add('summary', course['couName']) event.add( 'dtstart', datetime.datetime(course_date.year, course_date.month, course_date.day, course_begin_time[0], course_begin_time[1], course_begin_time[2], tzinfo=time_zone)) event.add( 'dtend', datetime.datetime(course_date.year, course_date.month, course_date.day, course_end_time[0], course_end_time[1], course_end_time[2], tzinfo=time_zone)) event.add( 'dtstamp', datetime.datetime(course_date.year, course_date.month, course_date.day, course_begin_time[0], course_begin_time[1], course_begin_time[2], tzinfo=time_zone)) event.add('location', course['couRoom']) calendar.add_component(event) output_file_name = '{} - {}.ics'.format(class_name, name) output_file = open(output_file_name, 'wb') output_file.write(calendar.to_ical()) output_file.close() print('Success write your calendar to', output_file_name)
def calendar_add(caldav_conn, args): cal = Calendar() cal.add('prodid', '-//{author_short}//{product}//{language}'.format(author_short=__author_short__, product=__product__, language=args.language)) cal.add('version', '2.0') event = Event() ## TODO: timezone ## read timestamps from arguments event_spec = args.event_time.split('+') print(event_spec) if len(event_spec)>3: raise ValueError('Invalid event time "%s" - can max contain 2 plus-signs' % args.event_time) elif len(event_spec)==3: event_time = '%s+%s' % tuple(event_spec[0:2]) event_duration = event_spec[2] elif len(event_spec)==2 and not event_spec[1][-1:] in time_units: event_time = '%s+%s' % tuple(event_spec[0:2]) event_duration = '1h' elif len(event_spec)==2: event_time = '%s' % event_spec[0] event_duration = event_spec[1] else: event_time = event_spec[0] event_duration = '1h' ## TODO: error handling event_duration_secs = int(event_duration[:-1]) * time_units[event_duration[-1:]] dtstart = dateutil.parser.parse(event_spec[0]) if args.whole_day: if event_spec[1][-1:] != 'd': raise ValueError('Duration of whole-day event must be multiple of 1d') duration = int(event_spec[1][:-1]) dtstart = dateutil.parser.parse(event_spec[0]) dtend = dtstart + timedelta(days=duration) event.add('dtstart', _date(dtstart.date())) event.add('dtend', _date(dtend.date())) else: event.add('dtstart', dtstart) ## TODO: handle duration and end-time as options. default 3600s by now. event.add('dtend', dtstart + timedelta(0,event_duration_secs)) event.add('dtstamp', _now()) uid = uuid.uuid1() event.add('uid', str(uid)) for attr in vcal_txt_one: if attr == 'summary': continue val = getattr(args, 'set_'+attr) if val: event.add(attr, val) for attr in vcal_txt_many: val = getattr(args, 'set_'+attr) if val: vals = val.split(',') event.add(attr, vals) event.add('summary', ' '.join(args.summary)) if args.alarm is not None: alarm = create_alarm(' '.join(args.summary), parse_time_delta(args.alarm)) event.add_component(alarm) cal.add_component(event) #print(cal.to_ical()) _calendar_addics(caldav_conn, cal.to_ical(), uid, args) print(uid)
for cours in self.liste_cours: if d_now < cours.debut: # Car dans l'ordre chronologique dans .ics delta = cours.debut - d_now hours = delta.seconds // 3600 minutes = (delta.seconds - hours * 3600) // 60 print("\nProchain cours dans ", str(hours), "h", str(minutes), '\n') return cours return -1 # Pas de prochain cours def afficher_cours(self): for cours in self.liste_cours: cours.afficher() cal = open("D:\\Python_WS\\20200916173359.ics", 'rb') lc = Cours_Semaine() gcal = Calendar.from_ical(cal.read()) for component in gcal.walk(): if component.name == "VEVENT": c = Cours(component.get("DESCRIPTION"), component.get("DTSTART").dt, component.get("DTEND").dt, component.get("DURATION").dt, component.get("LOCATION")) lc.ajouter_cours(c) cal.close() lc.prochain_cours().afficher()
def get_caldav(choices: List[Choice], current_poll: Poll, user: BitpollUser, request): # calendar stuff events2 = [] if not settings.CALENDAR_ENABLED or not (user.is_authenticated and current_poll.type == 'datetime' and choices): for choice in choices: events2.append([]) return events2 start = choices[0].date end = choices[-1].date # experimental: fetch calendar(s) events = [] for calendar_obj in user.davcalendar_set.all(): cache_key = "calendar_{}_events_{}-{}".format(calendar_obj.id, start, end).replace(' ', '_') events_calendar = cache.get(cache_key) if events_calendar is None: events_calendar = [] try: calendar = DavCalendar(client=DAVClient(calendar_obj.url), url=calendar_obj.url) appointments = calendar.date_search(start, end) for appointment in appointments: ical = Calendar.from_ical(appointment.data) for event in ical.walk(): if event.name == "VEVENT": try: if "DTEND" in event: end = event.decoded('DTEND') else: duration = event.decoded("DURATION") if isinstance(duration, list): duration = duration[ 0] # todo: use all elements?? what does it mean if there are more than one element? end = event.decoded('DTSTART') + duration events_calendar.append({ "DTSTART": event.decoded('DTSTART'), "DTEND": end, "NAME": event.get('summary').title(), }) except (AttributeError, ValueError, TypeError) as e: # we ignore the event we can not parse, but send it to sentry try: from raven.contrib.django.raven_compat.models import client client.captureException() except Exception: # if the sending of the error does fail we ignore it pass cache.set(cache_key, events_calendar) except AuthorizationError as e: messages.warning( request, ugettext_lazy( 'Could not access your calendar "%s" due to an authorization error' % calendar_obj.name)) events += events_calendar for choice in choices: ev_tmp = [] for event in events: if isinstance(event['DTSTART'], type(choice.date)): # datetime if event['DTSTART'] <= choice.date and event[ 'DTEND'] >= choice.date: ev_tmp.append(event) else: # dates if event['DTSTART'] <= choice.date.date() <= event['DTEND']: ev_tmp.append(event) events2.append(ev_tmp) return events2
def main(): args = parse_args() conn = sqlite3.connect(args.dbpath) us_west_start = datetime(2014, 6, 28) us_west_end = datetime(2014, 9, 24) us_east_start = datetime(2018, 8, 1) tz_tw = pytz.timezone('Asia/Taipei') tz_us_west = pytz.timezone('US/Pacific') tz_us_east = pytz.timezone('US/Eastern') cmd = '''SELECT activities.name, categories.name, start_time, end_time FROM activities, categories, facts WHERE facts.activity_id = activities.id AND activities.category_id = categories.id ORDER BY facts.start_time''' cals = [] cal = Calendar() curr_cnt = 0 cnt_us_west = cnt_us_east = cnt_tw = 0 for row in conn.execute(cmd): start_time = datetime.strptime(row[-2], '%Y-%m-%d %H:%M:%S') if us_west_end >= start_time >= us_west_start: tz = tz_us_west cnt_us_west += 1 elif start_time >= us_east_start: tz = tz_us_east cnt_us_east += 1 else: tz = tz_tw cnt_tw += 1 end_time = datetime(*time.strptime(row[-1], '%Y-%m-%d %H:%M:%S')[:6], tzinfo=tz) start_time = datetime(*time.strptime(row[-2], '%Y-%m-%d %H:%M:%S')[:6], tzinfo=tz) name = row[0] category = row[1] event = Event() event.add('summary', '%s (%s)' % (name, category)) event.add('dtstart', start_time) event.add('dtend', end_time) cal.add_component(event) # limit calendar size curr_cnt += 1 if curr_cnt >= args.limit: cals.append(cal) cal = Calendar() curr_cnt = 0 os.makedirs(args.outdir, exist_ok=True) for idx, cal in enumerate(cals): with open(os.path.join(args.outdir, 'cal-%04d.ics' % idx), 'w') as outfile: outfile.write(cal.to_ical().decode('utf8').replace('\r\n', '\n').strip()) conn.close()
def events_from_ics(namespace, calendar, ics_str): try: cal = iCalendar.from_ical(ics_str) except (ValueError, IndexError, KeyError): raise MalformedEventError() events = dict(invites=[], rsvps=[]) # See: https://tools.ietf.org/html/rfc5546#section-3.2 calendar_method = None for component in cal.walk(): if component.name == "VCALENDAR": calendar_method = component.get('method') if component.name == "VTIMEZONE": tzname = component.get('TZID') assert tzname in timezones_table,\ "Non-UTC timezone should be in table" if component.name == "VEVENT": # Make sure the times are in UTC. try: original_start = component.get('dtstart').dt original_end = component.get('dtend').dt except AttributeError: raise MalformedEventError("Event lacks start and/or end time") start = original_start end = original_end original_start_tz = None all_day = False if isinstance(start, datetime) and isinstance(end, datetime): tzid = str(original_start.tzinfo) if tzid in timezones_table: original_start_tz = timezones_table[tzid] if original_start.tzinfo is None: tzid = component.get('dtstart').params.get('TZID', None) assert tzid in timezones_table,\ "Non-UTC timezone should be in table" corresponding_tz = timezones_table[tzid] original_start_tz = corresponding_tz local_timezone = pytz.timezone(corresponding_tz) original_start = local_timezone.localize(original_start) if original_end.tzinfo is None: tzid = component.get('dtend').params.get('TZID', None) assert tzid in timezones_table,\ "Non-UTC timezone should be in table" corresponding_tz = timezones_table[tzid] local_timezone = pytz.timezone(corresponding_tz) original_end = local_timezone.localize(original_end) # Now that we have tz-aware datetimes, convert them to UTC start = original_start.astimezone(pytz.UTC) end = original_end.astimezone(pytz.UTC) elif isinstance(start, date) and isinstance(end, date): all_day = True start = arrow.get(start) end = arrow.get(end) assert isinstance(start, type(end)), "Start and end should be of "\ "the same type" # Get the last modification date. # Exchange uses DtStamp, iCloud and Gmail LAST-MODIFIED. component_dtstamp = component.get('dtstamp') component_last_modified = component.get('last-modified') last_modified = None if component_dtstamp is not None: # This is one surprising instance of Exchange doing # the right thing by giving us an UTC timestamp. Also note that # Google calendar also include the DtStamp field, probably to # be a good citizen. if component_dtstamp.dt.tzinfo is not None: last_modified = component_dtstamp.dt else: raise NotImplementedError("We don't support arcane Windows" " timezones in timestamps yet") elif component_last_modified is not None: # Try to look for a LAST-MODIFIED element instead. # Note: LAST-MODIFIED is always in UTC. # http://www.kanzaki.com/docs/ical/lastModified.html last_modified = component_last_modified.dt title = None summaries = component.get('summary', []) if not isinstance(summaries, list): summaries = [summaries] if summaries != []: title = " - ".join(summaries) description = component.get('description') if description is not None: description = unicode(description) event_status = component.get('status') if event_status is not None: event_status = event_status.lower() else: # Some providers (e.g: iCloud) don't use the status field. # Instead they use the METHOD field to signal cancellations. method = component.get('method') if method and method.lower() == 'cancel': event_status = 'cancelled' elif calendar_method and calendar_method.lower() == 'cancel': # So, this particular event was not cancelled. Maybe the # whole calendar was. event_status = 'cancelled' else: # Otherwise assume the event has been confirmed. event_status = 'confirmed' assert event_status in EVENT_STATUSES recur = component.get('rrule') if recur: recur = "RRULE:{}".format(recur.to_ical()) participants = [] organizer = component.get('organizer') organizer_name = None organizer_email = None if organizer: organizer_email = unicode(organizer) if organizer_email.lower().startswith('mailto:'): organizer_email = organizer_email[7:] if 'CN' in organizer.params: organizer_name = organizer.params['CN'] owner = formataddr([organizer_name, organizer_email.lower()]) else: owner = None is_owner = False if owner is not None and ( namespace.account.email_address == canonicalize_address(organizer_email)): is_owner = True attendees = component.get('attendee', []) # the iCalendar python module doesn't return a list when # there's only one attendee. Go figure. if not isinstance(attendees, list): attendees = [attendees] for attendee in attendees: email = unicode(attendee) # strip mailto: if it exists if email.lower().startswith('mailto:'): email = email[7:] try: name = attendee.params['CN'] except KeyError: name = None status_map = { 'NEEDS-ACTION': 'noreply', 'ACCEPTED': 'yes', 'DECLINED': 'no', 'TENTATIVE': 'maybe' } status = 'noreply' try: a_status = attendee.params['PARTSTAT'] status = status_map[a_status] except KeyError: pass notes = None try: guests = attendee.params['X-NUM-GUESTS'] notes = u"Guests: {}".format(guests) except KeyError: pass participants.append({ 'email': email.lower(), 'name': name, 'status': status, 'notes': notes, 'guests': [] }) location = component.get('location') uid = str(component.get('uid')) sequence_number = int(component.get('sequence', 0)) # Some services (I'm looking at you, http://www.foogi.me/) # don't follow the spec and generate icalendar files with # ridiculously big sequence numbers. Truncate them to fit in # our db. if sequence_number > 2147483647: sequence_number = 2147483647 event = Event(namespace=namespace, calendar=calendar, uid=uid, provider_name='ics', raw_data=component.to_ical(), title=title, description=description, location=location, reminders=str([]), recurrence=recur, start=start, end=end, busy=True, all_day=all_day, read_only=True, owner=owner, is_owner=is_owner, last_modified=last_modified, original_start_tz=original_start_tz, source='local', status=event_status, sequence_number=sequence_number, participants=participants) # We need to distinguish between invites/updates/cancellations # and RSVPs. if calendar_method == 'REQUEST' or calendar_method == 'CANCEL': events['invites'].append(event) elif calendar_method == 'REPLY': events['rsvps'].append(event) return events
class Match(object): """ Object that has all attributes for a given match The information is sent from Competition where it has the visibility of the Matches table. It parses every row and it gets the data per each column. """ Row = namedtuple( 'Row', ['datetime', 'location', 'title', 'score', 'referee', 'motm', 'info']) def __init__(self, competition_instance, match_details): self.logger = logging.getLogger('{base}.{suffix}'.format( base=LOGGER_BASENAME, suffix=self.__class__.__name__)) self._populate(Match.Row(*[detail.text for detail in match_details])) self.competitions = competition_instance self._calendar = None self._visiting_team = None self._visiting_team_goals = None self._home_team = None self._home_team_goals = None self.event = FootyEvent(self.datetime, self.title, self.location, self.info) def _populate(self, match_details): """ It gets the row from matchtable for the requested Team and then it gets the value accordingly to every column. :param info: BFS object """ try: self.datetime = self.__string_to_datetime(match_details.datetime) self.location = match_details.location self.title = match_details.title.encode('utf-8') self.score = match_details.score self.referee = match_details.referee self.motm = match_details.motm self.info = match_details.info except AttributeError: self.logger.exception("Got an exception while populating a match") @property def visiting_team(self): """ :return: Visiting team name in a match """ if not self._visiting_team: self._visiting_team = self._get_team(home_team=False) return self._visiting_team @property def home_team(self): """ :return: Home team name in a match """ if not self._home_team: self._home_team = self._get_team() return self._home_team def _get_team(self, home_team=True): """ Method that gets the teams in a match and it determines whether it is the home or visiting one. - True: Home team - False: Visiting team :param home_team: Boolean :return: home/visiting team name """ home, visiting = self.title.split(' - ') match = home.strip() if not home_team: match = visiting.strip() team = next( (team for team in self.competitions.teams if team.name == match), None) return team def _get_match_goals(self, home_team_goals=True): """ Method that gets the score in a match and it determines whether result is for the home or visiting team. - True: Home team goals - False: Visiting team goals :param home_team_goals: Boolean :return: home/visiting goals for a team """ try: # Match not started (-:-) home, visiting = self.score.split(':') except ValueError: # Played match (0 - 0) home, visiting = self.score.split('-') score = home.strip() if not home_team_goals: score = visiting.strip() return score @property def home_team_goals(self): """ :return: home team goals in a match """ if not self._home_team_goals: self._home_team_goals = self._get_match_goals() return self._home_team_goals @property def visiting_team_goals(self): """ :return: visiting team goals in a match """ if not self._visiting_team_goals: self._visiting_team_goals = self._get_match_goals( home_team_goals=False) return self._visiting_team_goals @property def calendar(self): """ Generates a RFC2445 (iCalendar) for a match :return: Calendar string """ if not self._calendar: self._calendar = Calendar() self._calendar.add_component(self.event) return self._calendar @staticmethod def __string_to_datetime(datetime_string): """ Converts date and time string into a datetime object :param datetime_string: 05.09.2017 21:30 :return: datetime object """ datetime_object = None try: datetime_object = parse(date_string=datetime_string, date_formats=['%d.%m.%Y %H:%M'], settings={'TIMEZONE': 'Europe/Amsterdam'}) except AttributeError: LOGGER.exception("Couldn't parse this datetime.") return datetime_object
try: args = cgi.parse_qs(os.getenv("QUERY_STRING")) except AttributeError: print "No courses defined" sys.exit() pass scraperwiki.utils.httpresponseheader('Content-Type', 'text/calendar') sourcescraper = 'course_listings' scraperwiki.sqlite.attach(sourcescraper) data = scraperwiki.sqlite.select('* from swdata WHERE course_code IN (' + getCourses(args['courses'][0]) + ')') cal = Calendar() cal.add('version', '2.0') cal.add('prodid', '-//ScraperWiki MB//SOAS Course Listings//EN') cal.add('X-WR-CALNAME', 'SOAS Course Listings') cal.add('X-WR-TIMEZONE', 'Europe/London') cal.add('X-ORIGINAL-URL', 'https://scraperwiki.com/scrapers/course_listings/') for ev in data: # if it's in the request... day_adder = {"Mon": 0, "Tue": 1, "Wed": 2, "Thu": 3, "Fri": 4} dates = [] if (ev['term'] == "Term 1"): dates = [{ "start_date": "2012-10-01",