diff gcalendarwatch.py @ 19:0af075b62e4a

support reread of a single cal. read fewer default days, since who knows what will happen
author drewp@bigasterisk.com
date Thu, 29 Oct 2020 23:47:02 -0700
parents a87969972d85
children 8c7af0d1b118
line wrap: on
line diff
--- a/gcalendarwatch.py	Thu Oct 29 23:45:46 2020 -0700
+++ b/gcalendarwatch.py	Thu Oct 29 23:47:02 2020 -0700
@@ -64,6 +64,10 @@
 }"""
 
 
+def feedFromCalId(conf, calId):
+    return conf['event_uri_ns'] + 'feed/' + calId
+
+
 def recordFromEv(conf: Dict, calId: str, ev: Dict):
 
     def dateOrTime(d):
@@ -73,7 +77,7 @@
 
     rec = {
         'uri': conf['event_uri_ns'] + ev['id'],
-        'feed': conf['event_uri_ns'] + 'feed/' + calId,
+        'feed': feedFromCalId(conf, calId),
         'title': ev.get('summary', '?'),
         'start': dateOrTime(ev['start']),
         'end': dateOrTime(ev['end']),
@@ -196,8 +200,10 @@
 
 class SyncToMongo(object):
     """reads gcal, writes to mongodb"""
+    collection: pymongo.collection.Collection
 
-    def __init__(self, conf, collection: pymongo.collection.Collection, agendaGraph: PatchableGraph, countdownGraph: PatchableGraph):
+    def __init__(self, conf, collection: pymongo.collection.Collection, agendaGraph: PatchableGraph,
+                 countdownGraph: PatchableGraph):
         self.conf = conf
         self.service = getCalendarService()
         self.collection = collection
@@ -205,12 +211,20 @@
         self.countdownGraph = countdownGraph
 
     @UPDATE.time()
-    def update(self, days=30 * 6):
+    def update(self, days=10, cal=None) -> int:
         start, end = dayRange(days)
-        self.removeEntries(start, end)
+        spec = {"startTime": {"$gte": start, "$lte": end}}
+        if cal is not None:
+            spec['feed'] = feedFromCalId(self.conf, cal)
+        idsFormerlyInRange = [doc['_id'] for doc in self.collection.find(spec)]
+        n = self.collection.delete_many(spec)
+        log.info(f'cleared {n} records before reread')
 
+        totalNew = 0
         currentRecords = []
         for calId in getFirstPageOfCalendars(self.service):
+            if cal and calId != cal:
+                continue
             print('read %s' % calId)
             events = self.service.events().list(
                 calendarId=calId,
@@ -224,13 +238,12 @@
             for ev in events['items']:
                 rec = recordFromEv(self.conf, calId, ev)
                 self.upsertMongo(rec)
+                if rec['uri'] not in idsFormerlyInRange:
+                    totalNew += 1
                 currentRecords.append(rec)
 
         self.updateGraphs(currentRecords)
-
-    def removeEntries(self, start, end):
-        for doc in list(self.collection.find({"startTime": {"$gte": start, "$lte": end}})):
-            self.collection.remove({'_id': doc['_id']})
+        return totalNew
 
     def upsertMongo(self, rec):
         if self.collection.find_one({"_id": rec['uri']}) is not None:
@@ -238,17 +251,19 @@
             # this is not yet noticing updates
             return []
         else:
-            log.debug("new records %s", rec)
+            log.debug("add record %s", rec)
             d = rec.copy()
             d['_id'] = d.pop('uri')
-            self.collection.insert(d)
+            self.collection.insert_one(d)
             return [rec]
 
     def updateGraphs(self, currentRecords):
         c = EV['gcalendar']
         currentRecords = list(currentRecords)
         self.agendaGraph.setToGraph([(s, p, o, c) for s, p, o in asGraph(limitDays(currentRecords, days=2))])
-        self.countdownGraph.setToGraph([(s, p, o, c) for s, p, o in asGraph(filterStarred(currentRecords, maxCount=15), extraClasses=[EV['CountdownEvent']])])
+        self.countdownGraph.setToGraph([
+            (s, p, o, c) for s, p, o in asGraph(filterStarred(currentRecords, maxCount=15), extraClasses=[EV['CountdownEvent']])
+        ])
 
 
 class ReadMongoEvents(object):
@@ -275,29 +290,34 @@
         self.scheduled = reactor.callLater(self.periodSec, self._updateLoop)
         self.events = None
 
-    def updateNow(self):
+    def updateNow(self, cal=None) -> int:
         self.scheduled.cancel()
-        self._updateLoop()
+        return self._updateLoop(cal)
 
-    def _updateLoop(self):
-        log.info("updating")
+    def _updateLoop(self, cal=None) -> int:
+        log.info(f"updating {cal or 'all'}")
         t1 = time.time()
         try:
-            self.sync.update()
+            n = self.sync.update(cal=cal)
         except Exception:
             traceback.print_exc()
             log.error("updated failed")
+            n = 0
         self.lastUpdateTime = t1
         self.everUpdated = True
         took = time.time() - t1
         self.scheduled = reactor.callLater(max(3, self.periodSec - took), self._updateLoop)
+        return n
 
 
 class PollNow(cyclone.web.RequestHandler):
 
     def post(self):
-        self.settings.poller.updateNow()
-        self.set_status(202)
+        cal = json.loads(self.request.body).get('cal', None) if self.request.body else None
+        n = self.settings.poller.updateNow(cal)
+        msg = f"found {n} new records"
+        log.info(msg)
+        self.write(msg.encode('utf8'))
 
 
 class Index(cyclone.web.RequestHandler):
@@ -325,8 +345,8 @@
         """
         arg = self.get_argument
         t1 = parse(arg('t1')) if arg('t1', default=None) else datetime.datetime.now().replace(hour=0, minute=0, second=0)
-        t2 = parse(arg('t2')) if arg('t2',
-                                     default=None) else datetime.datetime.now() + datetime.timedelta(days=int(arg('days')) if arg('days', default=None) else 2)
+        t2 = parse(arg('t2')) if arg('t2', default=None) else datetime.datetime.now() + datetime.timedelta(
+            days=int(arg('days')) if arg('days', default=None) else 2)
         if 0:
             self.set_header("content-type", "application/ld+json")
             self.write(asJsonLd(self.settings.read.getEvents(t1, t2)))