Mercurial > code > home > repos > gcalendarwatch
view gcalendarwatch.py @ 91:62caecb41dfd default tip
fix tag
author | drewp@bigasterisk.com |
---|---|
date | Fri, 03 Jan 2025 18:06:13 -0800 |
parents | f75b3a109b66 |
children |
line wrap: on
line source
""" read calendar from mongodb, return a few preset queries as RDF graphs gcalendarwatch.conf looks like this: { "mongo" : {"host" : "h1", "port" : 27017, "database" : "dbname"}, } """ import datetime import json import logging import re from typing import Sequence, cast import background_loop import pymongo.collection import pymongo.database from dateutil.tz import tzlocal from patchablegraph import PatchableGraph from patchablegraph.handler import GraphEvents, StaticGraph from pymongo import MongoClient from rdflib import Namespace from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import HTMLResponse from starlette.routing import Route from starlette_exporter import PrometheusMiddleware, handle_metrics from datetimemath import dayRange, limitDays from graphconvert import asGraph from localtypes import Conf, Record logging.basicConfig(level=logging.INFO) log = logging.getLogger() EV = Namespace("http://bigasterisk.com/event#") """ example: { 'id': 'l640999999999999999999999c', 'summary': 'sec.......', 'start': {'timeZone': 'America/Los_Angeles', 'dateTime': '2014-09-25T16:00:00-07:00'}, 'end': {'timeZone': 'America/Los_Angeles', 'dateTime': '2014-09-25T17:00:00-07:00'}, 'endTimeUnspecified': True, 'created': '2014-09-08T20:39:00.000Z', 'creator': {'self': True, 'displayName': '...', 'email': '...'}, 'etag': '"2829999999999000"', 'htmlLink': 'https://www.google.com/calendar/event?eid=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbEBt', 'iCalUID': 'l640998888888888888888888888888888com', 'kind': 'calendar#event', 'organizer': {'self': True, 'displayName': '...', 'email': '...'}, 'reminders': {'useDefault': True}, 'sequence': 0, 'status': 'confirmed', 'updated': '2014-09-17T04:28:56.997Z', }""" def filterStarred(recs: Sequence[Record], maxCount=15) -> list[Record]: recs = sorted(recs, key=lambda r: r['start']) out = [] for rec in recs: if m := re.search(r'(.*)\*\s*$', rec['title']): rec = rec.copy() rec['title'] = m.group(1) out.append(rec) if len(out) >= maxCount: break return out class SyncGraphsToMongo(object): """reads mongodb (that calsync wrote); edits graphs""" calendarsCollection: pymongo.collection.Collection eventsCollection: pymongo.collection.Collection def __init__(self, conf: Conf, db: pymongo.database.Database, agendaGraph: PatchableGraph, countdownGraph: PatchableGraph, currentEventsGraph: PatchableGraph): self.conf = conf self.eventsCollection = db.get_collection('test_gcalendar') self.calendarsCollection = db.get_collection('test_gcalendar_cals') self.agendaGraph = agendaGraph self.countdownGraph = countdownGraph self.currentEventsGraph = currentEventsGraph def _getEvents(self, t1: datetime.datetime, t2: datetime.datetime) -> list[Record]: if t1.tzinfo is None or t2.tzinfo is None: raise TypeError("tz-naive datetimes") return list(self.eventsCollection.find({"startTime": {"$gte": t1, "$lt": t2}}).sort([("startTime", 1)])) def updateGraphs(self, first_run): s, e = dayRange(120) currentRecords = self._getEvents(s, e) cals = list(self.calendarsCollection.find()) self.agendaGraph.setToGraph(asGraph(self.conf, cals, limitDays(currentRecords, days=2))) self.countdownGraph.setToGraph(asGraph(self.conf, cals, filterStarred(currentRecords, maxCount=15), extraClasses=[EV['CountdownEvent']])) now = datetime.datetime.now(tzlocal()) events = list(self.eventsCollection.find({"startTime": {"$lte": now}, "endTime": {"$gte": now}})) self.currentEventsGraph.setToGraph(asGraph(self.conf, cals=[], events=events, extraClasses=[EV['CurrentEvent']])) def main(): agendaGraph = PatchableGraph(label='agenda') # next few days countdownGraph = PatchableGraph(label='countdown') # next n of starred events currentEventsGraph = PatchableGraph(label='currentEvents') # events happening now conf = cast(Conf, json.load(open("gcalendarwatch.conf"))) m = conf['mongo'] db = MongoClient(m['host'], m['port'], tz_aware=True)[m['database']] sync = SyncGraphsToMongo(conf, db, agendaGraph, countdownGraph, currentEventsGraph) # todo: this should watch for mongodb edits, or get a signal from calsync background_loop.loop_forever(sync.updateGraphs, 5, metric_prefix="update_graphs") def getRoot(request: Request) -> HTMLResponse: return HTMLResponse(content=open("index.html").read()) moreNs = { "": "http://bigasterisk.com/event#", "cal": "http://bigasterisk.com/calendar/", "event": "http://bigasterisk.com/calendarEvent/", } app = Starlette(debug=True, routes=[ Route('/', getRoot), Route('/graph/calendar/upcoming', StaticGraph(agendaGraph, moreNs)), Route('/graph/calendar/upcoming/events', GraphEvents(agendaGraph)), Route('/graph/calendar/countdown', StaticGraph(countdownGraph, moreNs)), Route('/graph/calendar/countdown/events', GraphEvents(countdownGraph)), Route('/graph/currentEvents', StaticGraph(currentEventsGraph, moreNs)), Route('/graph/currentEvents/events', GraphEvents(currentEventsGraph)), ]) app.add_middleware(PrometheusMiddleware, group_paths=True, filter_unhandled_paths=True, app_name='gcalendarwatch') app.add_route("/metrics", handle_metrics) return app app = main()