import caldav import vobject import copy # ugh from cStringIO import StringIO from datetime import datetime, timedelta, date from dateutil import zoneinfo from flask import Flask, g, json, make_response app = Flask('hs_cal') app.config.from_pyfile('config.cfg') server = app.config['SERVER'] location = app.config['CALENDAR'] tz = zoneinfo.gettz(app.config['TIMEZONE']) @app.before_request def connect(): client = caldav.DAVClient(server) g.calendar = caldav.Calendar(client, server + location) def shift_date(event, rec_dtstart): orig_st = event.dtstart.value orig_et = event.dtend.value duration = orig_et - orig_st event.dtstart.value = rec_dtstart event.dtend.value = rec_dtstart + duration # shim-o-rama def expand_recurrences(event, start, end): rrs = event.getrruleset() print event.__dict__ if rrs: return [fix_date(copy.deepcopy(event), dts) for dts in rrs.between(start, end, inc=True)] else: return [event] def objectify_event(event): def nullable(event, attr): a = getattr(event, attr, None) return a and a.value return dict((attr, nullable(event, attr)) for attr in ['summary', 'description', 'dtstart', 'dtend', 'categories']) def jsonify_events(events): def encode(o): if isinstance(o, datetime) : return o.strftime('%d/%m/%Y %H:%M') if isinstance(o, date): return o.strftime('%d/%m/%Y') raise TypeError(type(o)) return make_response(json.dumps(dict(events=events), default=encode, indent=app.config.get('INDENT'))) @app.route('/') def get_events_range(start=None, end=None): start = start or datetime.today() if not end or (end - start).days > 31: end = start + timedelta(days=31) start = start.replace(tzinfo=tz) end = end.replace(tzinfo=tz) res = [] for event in g.calendar.date_search(start, end): vev = event.instance.vevent res.extend(expand_recurrences(vev, start, end)) return jsonify_events(map(objectify_event, res)) @app.route('/from//to//') def range_query(start, end): fstring = '%d-%m-%Y' return get_events_range(datetime.strptime(start, fstring), datetime.strptime(end, fstring)) if __name__ == '__main__': app.debug = True app.run()