diff --git a/app/templates/main.html b/app/templates/main.html index 51f513b8a87a1d8948b001232a1b349c08d4f95e..552babf43f278fff505ed164a73d099d59d30ef8 100644 --- a/app/templates/main.html +++ b/app/templates/main.html @@ -28,6 +28,14 @@ .meeting:hover { background-color: #aaaaff; } + .collision { + border: 1px solid red; + font-size: smaller; + background-color: #ffcccc; + } + .collision:hover { + background-color: #ffaaaa; + } </style> </head> @@ -60,7 +68,7 @@ <div class=hour style='position: absolute; left: {{ h.x }}px; top: {{ h.y }}px; width: {{ h.w }}px; height: {{ h.h }}px;'></div> {% endfor %} {% for m in g.meetings %} - <div class=meeting style='position: absolute; left: {{ m.x }}px; top: {{ m.y }}px; width: {{ m.w }}px; height: {{ m.h }}px;' title='{{ m.topic|e }}'> + <div class={{ "collision" if m.coll else "meeting" }} style='position: absolute; left: {{ m.x }}px; top: {{ m.y }}px; width: {{ m.w }}px; height: {{ m.h }}px;' title='{{ m.start + "–" + m.end + ": " + m.topic|e }}'> {{ m.start }} – {{ m.end }} </div> {% endfor %} diff --git a/app/zoom.py b/app/zoom.py index 2c471e01c46a1acd60d70a8dd790ca0cda9d1c8f..159769933ab54a275f87143f0f284c1f6eebd47f 100644 --- a/app/zoom.py +++ b/app/zoom.py @@ -3,7 +3,10 @@ from flask import Flask, render_template, request, g import psycopg2 import psycopg2.extras import time +from datetime import datetime import sys +import dateutil +import dateutil.tz ### Flask app object ### @@ -42,11 +45,14 @@ def db_query(query, args=()): ### Schedule ### def get_date(): + """Return a datetime object corresponding to the start of the given date.""" try: d = request.args.get('date', "") - return time.strptime(d, "%Y-%m-%d") + dt = datetime.strptime(d, "%Y-%m-%d") except ValueError: - return time.localtime() + dt = datetime.today() + tz = dateutil.tz.tzlocal() + return dt.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=tz) rooms = [ ('Z1', 'zoom-1@d3s.mff.cuni.cz'), @@ -62,11 +68,8 @@ rooms = [ @app.route('/') def main_page(): dt = get_date() - date = time.strftime("%Y-%m-%d", dt) - # FIXME: Broken time zones!!! - t = time.mktime(dt) - g.date = date - g.dow = time.strftime("%A", dt) + g.date = dt.strftime("%Y-%m-%d") + g.dow = dt.strftime("%A") hours_arg = request.args.get("hours", "") if hours_arg in ["0", "1"]: @@ -107,23 +110,28 @@ def main_page(): SELECT m.meeting_id, m.topic, m.start_time, m.duration, u.email, u.full_name FROM zoom_meetings m JOIN zoom_users u ON u.id = m.host_id - WHERE start_time >= DATE %s - INTERVAL '1 day' - AND start_time < DATE %s + INTERVAL '1 day' + WHERE m.start_time >= DATE %s - INTERVAL '1 day' + AND m.start_time < DATE %s + INTERVAL '1 day' + ORDER BY u.email, m.start_time """, - (date, date)) + (dt, dt)) g.meetings = [] + prev_room_i = -1 + prev_end_t = None for r in db.fetchall(): i = email_to_room_index.get(r.email, -1) if i < 0: continue - start_t = int(r.start_time.timestamp()) + # Datetime in the DB is in UTC, but psycopg2 interprets it as local time + start_dt = r.start_time.replace(tzinfo=dateutil.tz.tz.tzutc()) + start_t = int(start_dt.timestamp()) end_t = start_t + r.duration*60 - rel_start = start_t - t - hour_min*3600 + rel_start = start_t - dt.timestamp() - hour_min*3600 rel_end = rel_start + r.duration*60 start = max(0, int(rel_start)) end = min(num_hours * 3600, int(rel_end)) - app.logger.debug("Meeting: %s start=%s end=%s room_i=%s", r, start, end, i) + app.logger.debug("Meeting: %s start_t=%s start=%s end=%s room_i=%s", r, start_t, start, end, i) if start < end: g.meetings.append({ "x": i * room_box_width + 4, @@ -133,6 +141,9 @@ def main_page(): "start": time.strftime("%H:%M", time.localtime(start_t)), "end": time.strftime("%H:%M", time.localtime(end_t)), "topic": r.topic, + "coll": (i == prev_room_i and start_t < prev_end_t), }) + prev_room_i = i + prev_end_t = end_t return render_template('main.html')