From e7926952b3dc89ec8d4a1c5f1c77908c36a3709b Mon Sep 17 00:00:00 2001 From: Viet Than Date: Mon, 11 Sep 2023 02:45:17 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=A6=20Database=20Change:=20convert=20c?= =?UTF-8?q?reated=20utc=20to=20datetimez=20for=20viewers=20(#697)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * passed the test * this works better * Remove commented-out code. * Remove commented-out code. --------- Co-authored-by: Ben Rog-Wilhelm --- files/classes/views.py | 14 ++--- files/routes/users.py | 5 +- ...d682a_change_to_datetimez_table_viewers.py | 53 +++++++++++++++++++ 3 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 migrations/versions/2023_09_08_02_14_46_bcfaec0d682a_change_to_datetimez_table_viewers.py diff --git a/files/classes/views.py b/files/classes/views.py index 18ad428d7..7cbbc581e 100644 --- a/files/classes/views.py +++ b/files/classes/views.py @@ -2,6 +2,7 @@ import time from sqlalchemy import * from sqlalchemy.orm import relationship +from sqlalchemy.sql.functions import now from files.classes.base import Base from files.helpers.lazy import lazy @@ -13,17 +14,18 @@ class ViewerRelationship(Base): user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True) - last_view_utc = Column(Integer, nullable=False) + last_view_datetimez = Column(DateTime(timezone=True), nullable=False, server_default=now()) Index('fki_view_viewer_fkey', viewer_id) viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id", viewonly=True) - def __init__(self, **kwargs): - if 'last_view_utc' not in kwargs: - kwargs['last_view_utc'] = int(time.time()) - - super().__init__(**kwargs) + @property + def last_view_utc(self): + """ + the last view timestamp in UTC seconds. Milliseconds are truncated/rounded down. + """ + return int(self.last_view_datetimez.timestamp()) @property @lazy diff --git a/files/routes/users.py b/files/routes/users.py index 8c42348e2..92470ccd9 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -2,6 +2,7 @@ import io import math import time from collections import Counter +from datetime import datetime from urllib.parse import urlparse import gevent @@ -633,7 +634,7 @@ def following(v, username): @auth_required def visitors(v): if v.admin_level < 2 and not v.patron: return render_template("errors/patron.html", v=v) - viewers=sorted(v.viewers, key = lambda x: x.last_view_utc, reverse=True) + viewers=sorted(v.viewers, key = lambda x: x.last_view_datetimez, reverse=True) return render_template("viewers.html", v=v, viewers=viewers) @@ -651,7 +652,7 @@ def u_username(username, v=None): if v and v.id != u.id and (u.patron or u.admin_level > 1): view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none() - if view: view.last_view_utc = int(time.time()) + if view: view.last_view_datetimez = datetime.utcnow() else: view = ViewerRelationship(viewer_id=v.id, user_id=u.id) g.db.add(view) diff --git a/migrations/versions/2023_09_08_02_14_46_bcfaec0d682a_change_to_datetimez_table_viewers.py b/migrations/versions/2023_09_08_02_14_46_bcfaec0d682a_change_to_datetimez_table_viewers.py new file mode 100644 index 000000000..129e8055a --- /dev/null +++ b/migrations/versions/2023_09_08_02_14_46_bcfaec0d682a_change_to_datetimez_table_viewers.py @@ -0,0 +1,53 @@ +"""Change to datetimez table viewers + +Revision ID: bcfaec0d682a +Revises: a2fce4808e1d +Create Date: 2023-09-08 02:14:46.989072+00:00 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.sql.functions import now + + +# revision identifiers, used by Alembic. +revision = 'bcfaec0d682a' +down_revision = 'a2fce4808e1d' +branch_labels = None +depends_on = None + +table_name = 'viewers' +from_column = 'last_view_utc' +to_column = 'last_view_datetimez' + + +def upgrade(): + op.add_column(table_name, sa.Column(to_column, sa.DateTime(timezone=True), nullable=True, server_default=now())) + op.execute(f""" + UPDATE {table_name} + SET {to_column} = + CASE + WHEN {from_column} > 0 THEN + (timestamp 'epoch' + {from_column} * interval '1 second') at time zone 'utc' + ELSE NULL + END + """) + op.alter_column(table_name, to_column, nullable=False) + op.drop_column(table_name, from_column) + + +def downgrade(): + """ + Downgrade will truncate the milliseconds. + """ + op.add_column(table_name, sa.Column(from_column, sa.Integer(), server_default=sa.text('0'), nullable=True)) + op.execute(f""" + UPDATE {table_name} + SET {from_column} = + COALESCE( + EXTRACT(EPOCH FROM {to_column})::integer, + 0 + ) + """) + op.alter_column(table_name, from_column, nullable=False) + op.drop_column(table_name, to_column) \ No newline at end of file