From af744b2b5160119d841df4988900a3d12420991f Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Tue, 24 Mar 2020 13:23:00 +0100
Subject: [PATCH] Fetch: Refresh a single meeting

---
 TODO                   |   1 +
 hook/fetch-meetings.py | 123 ++++++++++++++++++++++++++++++-----------
 2 files changed, 91 insertions(+), 33 deletions(-)

diff --git a/TODO b/TODO
index 89926a9..3274cb0 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,7 @@
 DB:
 - Trigger na "last modified" u meetingů
 - indexy
+- vazby: on delete cascade
 
 Hook:
 - Adjust number of workers
diff --git a/hook/fetch-meetings.py b/hook/fetch-meetings.py
index fbdf86d..f74ab76 100755
--- a/hook/fetch-meetings.py
+++ b/hook/fetch-meetings.py
@@ -9,9 +9,7 @@ import psycopg2.extras
 import time
 import dateutil.parser
 import sys
-
-verbose = True
-very_verbose = True
+import argparse
 
 config = configparser.ConfigParser()
 config.read('zoom.ini')
@@ -26,28 +24,18 @@ def parse_time(iso_time):
     return dateutil.parser.isoparse(iso_time)
 
 
-def add_recurring(mid, meet):
-    time.sleep(0.2)
-    resp = client.meeting.get(host_id = meet['host_id'], id = meet['id'])
+def get_meeting(host_id, meeting_id):
+    resp = client.meeting.get(host_id=host_id, id=meeting_id)
     resp.raise_for_status()
     details = json.loads(resp.content)
-    if very_verbose:
+    if debug:
         pprint(details)
+    return details
 
-    for occ in details["occurrences"]:
-        db.execute("""
-                INSERT INTO zoom_schedule
-                (mid, occurrence_id, start_time, duration)
-                VALUES (%s, %s, %s, %s)
-            """, (
-                mid,
-                occ['occurrence_id'],
-                parse_time(occ['start_time']),
-                occ['duration'],
-            ))
 
+def insert_meeting(uid, meet):
+    meeting_id = meet["id"]
 
-def add_meeting(uid, meet):
     db.execute("""
             INSERT INTO zoom_meetings
             (meeting_id, uuid, host_uid, topic, type)
@@ -63,12 +51,26 @@ def add_meeting(uid, meet):
     meeting_row = db.fetchone()
     mid = meeting_row.mid
 
-    mtype = meet['type']
-    if mtype == 8:
-        # Recurring meetings: need to ask for the list of occurrences
-        add_recurring(mid, meet)
+    print(f"Meeting {meeting_id}: Creating")
+
+    if 'occurrences' in meet:
+        # Recurrent meetings have a list of occurrences
+        for occ in meet["occurrences"]:
+            occ_id = occ['occurrence_id']
+            print(f"Meeting {meeting_id}.{occ_id}: Scheduling")
+            db.execute("""
+                    INSERT INTO zoom_schedule
+                    (mid, occurrence_id, start_time, duration)
+                    VALUES (%s, %s, %s, %s)
+                """, (
+                    mid,
+                    occ_id,
+                    parse_time(occ['start_time']),
+                    occ['duration'],
+                ))
     elif 'start_time' in meet:
         # Other meetings usually have a starting time
+        print(f"Meeting {meeting_id}: Scheduling")
         db.execute("""
                 INSERT INTO zoom_schedule
                 (mid, occurrence_id, start_time, duration)
@@ -80,6 +82,18 @@ def add_meeting(uid, meet):
                 meet['duration'],
             ))
 
+    return mid
+
+
+def add_meeting(uid, meet):
+    mtype = meet['type']
+    if mtype == 8:
+        # Recurring meetings: need to ask for the list of occurrences
+        time.sleep(0.2)
+        meet = get_meeting(meet['host_id'], meet['id'])
+
+    insert_meeting(uid, meet)
+
 
 def get_meetings(uid, user_id):
     page_id = 1
@@ -88,14 +102,13 @@ def get_meetings(uid, user_id):
     total_rec = 0
 
     while page_id <= num_pages:
-        if verbose:
-            print(f"Fetching meetings for user {user_id}: page {page_id} of {num_pages}")
+        print(f"Fetching meetings for user {user_id}: page {page_id} of {num_pages}")
 
         resp = client.meeting.list(user_id = user_id, type = 'scheduled', page_number = page_id)
         resp.raise_for_status()
 
         meeting_list = json.loads(resp.content)
-        if very_verbose:
+        if debug:
             pprint(meeting_list)
 
         num_pages = meeting_list['page_count']
@@ -111,12 +124,56 @@ def get_meetings(uid, user_id):
     assert total_rec == expected_rec, "Unexpected number of records, probably because of race condition"
 
 
-db.execute('DELETE FROM zoom_schedule')
-db.execute('DELETE FROM zoom_meetings')
+def fetch_all():
+    db.execute('DELETE FROM zoom_schedule')
+    db.execute('DELETE FROM zoom_meetings')
+
+    db.execute("SELECT * FROM zoom_users")
+    users = db.fetchall()
+    for u in users:
+        get_meetings(u.uid, u.user_id)
 
-db.execute("SELECT * FROM zoom_users")
-users = db.fetchall()
-for u in users:
-    get_meetings(u.uid, u.user_id)
+    db_conn.commit()
 
-db_conn.commit()
+
+def fetch_single(user_email, meeting_id):
+    db.execute("SELECT * FROM zoom_users WHERE email=%s", (user_email,))
+    user_row = db.fetchone()
+    if user_row is None:
+        print(f"E-mail {user_email} not found", file=sys.stderr)
+        sys.exit(1)
+    uid = user_row.uid
+
+    db.execute("SELECT * FROM zoom_meetings WHERE meeting_id=%s", (meeting_id,))
+    meeting_row = db.fetchone()
+    if meeting_row is not None:
+        assert meeting_row.host_uid == uid, "Mismatched user ID"
+        print(f"Deleting previous records on meeting {meeting_id}")
+        db.execute("DELETE FROM zoom_schedule WHERE mid=%s", (meeting_row.mid,))
+        db.execute("DELETE FROM zoom_meetings WHERE mid=%s", (meeting_row.mid,))
+
+    meet = get_meeting(user_row.user_id, meeting_id)
+    insert_meeting(uid, meet)
+
+    db_conn.commit()
+
+
+argp = argparse.ArgumentParser(description="Fetch meeting data from Zoom API")
+argp.add_argument('--all', action='store_const', const=True, default=False, help="re-fetch all meetings")
+argp.add_argument('--user', metavar='EMAIL', help='fetch meetings hosted by a given user')
+argp.add_argument('--meeting', type=int, metavar='ID', help='fetch a single meeting (requires --user)')
+argp.add_argument('--debug', action='store_const', const=True, default=False, help="enable debugging dumps")
+
+args = argp.parse_args()
+debug = args.debug
+
+if args.all:
+    fetch_all()
+elif args.meeting is not None:
+    if args.user is None:
+        argp.error("--meeting requires --user")
+    fetch_single(args.user, args.meeting)
+elif args.user is not None:
+    raise NotImplementedError
+else:
+    print("Nothing to do.")
-- 
GitLab