diff --git a/hook.wsgi b/hook.wsgi index 740d30b031f5823c2fc886a6a15c05c603a0a45b..5306dfede92b75985856426cd7ba7d06c14599ee 100644 --- a/hook.wsgi +++ b/hook.wsgi @@ -4,7 +4,10 @@ import configparser import json import psycopg2 +import psycopg2.extras import traceback +import dateutil.parser +# import dateutil.tz ### Configuration ### @@ -21,22 +24,31 @@ def db_connect(): db_connection = psycopg2.connect( host='localhost', user=config['db']['user'], - passwd=config['db']['passwd'], - db=config['db']['name'], + password=config['db']['passwd'], + dbname=config['db']['name'], ) - db = db_conn.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor) + db = db_connection.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor) def db_query(query, args=()): if db is None: db_connect() try: db.execute(query, args) - # FIXME: Adapt for Postgres! - except MySQLdb.OperationalError: + except psycopg2.DatabaseError: # Reconnect if the connection died (timeout, server restart etc.) db_connect() db.execute(query, args) +### Utilities ### + +# FIXME: Move to shared code? + +def parse_time(iso_time, tz_name): + utc = dateutil.parser.isoparse(iso_time) + # tz = dateutil.tz.gettz(tz_name) + # return utc.astimezone(tz) + return utc + ### Application ### class HookApp: @@ -54,21 +66,82 @@ class HookApp: ]) return ["{} {}".format(code, msg)] - def run(self): - self.log(self.env) + def create_meeting(self, js): + payload = js["payload"] + object = payload["object"] + meeting_id = object["id"] + + type = object["type"] + if type != 2 and type != 8: + self.log(f"Meeting type {type} ignored") + return + + host_user_id = object["host_id"] + db_query("SELECT * FROM zoom_users WHERE user_id=%s", (host_user_id,)) + user = db.fetchone() + if user is None: + self.log(f"Meeting {meeting_id}: Host {host_user_id} not found in zoom_users") + + self.log(f"Meeting {meeting_id}: Planning") + db_query(""" + INSERT INTO zoom_meetings + (meeting_id, uuid, host_id, topic, type, start_time, duration) + VALUES (%s, %s, %s, %s, %s, %s, %s) + """, ( + meeting_id, + object['uuid'], + user.id, + object['topic'], + object['type'], + parse_time(object['start_time'], object['timezone']), + object['duration'], + )) + + db_connection.commit() + + def delete_meeting(self, js): + payload = js["payload"] + object = payload["object"] + meeting_id = object["id"] + + type = object["type"] + if type != 2 and type != 8: + self.log(f"Meeting type {type} ignored") + return + + self.log(f"Meeting {meeting_id}: Deleting") + db_query(""" + DELETE FROM zoom_meetings + WHERE meeting_id=%s AND start_time=%s AND duration=%s + """, ( + meeting_id, + parse_time(object['start_time'], object['timezone']), + object['duration'], + )) + + db_connection.commit() + def run(self): method = self.env['REQUEST_METHOD'] if method != 'POST': return self.http_error(405, 'Method not allowed', [('Allow', 'POST')]) - # FIXME: Check authorization - - self.log('Gotcha!') + if self.env.get('HTTP_AUTHORIZATION', '') != config['hooks']['verification_token']: + self.log('Verification token does not match!') + return self.http_error(401, 'Authorization failed') body = self.env['wsgi.input'].read() js = json.loads(body) self.log(js) + event = js["event"] +# if event == "meeting.created": +# self.create_meeting(js) +# elif event == "meeting.deleted": +# self.delete_meeting(js) +# else: +# self.log(f"Unknown event: {event}") + self.wsgi_start("204 No Content", []) return b""