diff --git a/src/wuttjamaican/app.py b/src/wuttjamaican/app.py index 091ad06..0056cb8 100644 --- a/src/wuttjamaican/app.py +++ b/src/wuttjamaican/app.py @@ -862,7 +862,8 @@ class AppHandler: # pylint: disable=too-many-public-methods :returns: Text to display. """ - return humanize.naturaltime(value) + # TODO: this now assumes naive UTC value incoming... + return humanize.naturaltime(value, when=self.make_utc(tzinfo=False)) ############################## # getters for other handlers diff --git a/src/wuttjamaican/batch.py b/src/wuttjamaican/batch.py index 54c9ad7..733c48b 100644 --- a/src/wuttjamaican/batch.py +++ b/src/wuttjamaican/batch.py @@ -24,7 +24,6 @@ Batch Handlers """ -import datetime import os import shutil @@ -481,7 +480,7 @@ class BatchHandler(GenericHandler): # pylint: disable=too-many-public-methods result = self.execute( # pylint: disable=assignment-from-none batch, user=user, progress=progress, **kwargs ) - batch.executed = datetime.datetime.now() + batch.executed = self.app.make_utc() batch.executed_by = user return result diff --git a/src/wuttjamaican/db/alembic/versions/b59a34266288_drop_time_zones.py b/src/wuttjamaican/db/alembic/versions/b59a34266288_drop_time_zones.py new file mode 100644 index 0000000..c78e547 --- /dev/null +++ b/src/wuttjamaican/db/alembic/versions/b59a34266288_drop_time_zones.py @@ -0,0 +1,186 @@ +"""drop time zones + +Revision ID: b59a34266288 +Revises: efdcb2c75034 +Create Date: 2025-12-14 19:10:11.627188 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +import wuttjamaican.db.util +from sqlalchemy.dialects import postgresql +from wuttjamaican.util import make_utc + +# revision identifiers, used by Alembic. +revision: str = "b59a34266288" +down_revision: Union[str, None] = "efdcb2c75034" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + + # upgrade.created + op.add_column("upgrade", sa.Column("created_new", sa.DateTime(), nullable=True)) + upgrade = sa.sql.table( + "upgrade", + sa.sql.column("uuid"), + sa.sql.column("created"), + sa.sql.column("created_new"), + ) + cursor = op.get_bind().execute(upgrade.select()) + for row in cursor.fetchall(): + op.get_bind().execute( + upgrade.update() + .where(upgrade.c.uuid == row.uuid) + .values({"created_new": make_utc(row.created)}) + ) + op.drop_column("upgrade", "created") + op.alter_column( + "upgrade", + "created_new", + new_column_name="created", + nullable=False, + existing_type=sa.DateTime(), + existing_nullable=True, + ) + + # upgrade.executed + op.add_column("upgrade", sa.Column("executed_new", sa.DateTime(), nullable=True)) + upgrade = sa.sql.table( + "upgrade", + sa.sql.column("uuid"), + sa.sql.column("executed"), + sa.sql.column("executed_new"), + ) + cursor = op.get_bind().execute(upgrade.select()) + for row in cursor.fetchall(): + if row.executed: + op.get_bind().execute( + upgrade.update() + .where(upgrade.c.uuid == row.uuid) + .values({"executed_new": make_utc(row.executed)}) + ) + op.drop_column("upgrade", "executed") + op.alter_column( + "upgrade", + "executed_new", + new_column_name="executed", + existing_type=sa.DateTime(), + existing_nullable=True, + ) + + # user_api_token.created + op.add_column( + "user_api_token", sa.Column("created_new", sa.DateTime(), nullable=True) + ) + user_api_token = sa.sql.table( + "user_api_token", + sa.sql.column("uuid"), + sa.sql.column("created"), + sa.sql.column("created_new"), + ) + cursor = op.get_bind().execute(user_api_token.select()) + for row in cursor.fetchall(): + op.get_bind().execute( + user_api_token.update() + .where(user_api_token.c.uuid == row.uuid) + .values({"created_new": make_utc(row.created)}) + ) + op.drop_column("user_api_token", "created") + op.alter_column( + "user_api_token", + "created_new", + new_column_name="created", + nullable=False, + existing_type=sa.DateTime(), + existing_nullable=True, + ) + + +def downgrade() -> None: + + # user_api_token.created + op.add_column( + "user_api_token", + sa.Column("created_old", sa.DateTime(timezone=True), nullable=True), + ) + user_api_token = sa.sql.table( + "user_api_token", + sa.sql.column("uuid"), + sa.sql.column("created"), + sa.sql.column("created_old"), + ) + cursor = op.get_bind().execute(user_api_token.select()) + for row in cursor.fetchall(): + op.get_bind().execute( + user_api_token.update() + .where(user_api_token.c.uuid == row.uuid) + .values({"created_old": row.created}) + ) + op.drop_column("user_api_token", "created") + op.alter_column( + "user_api_token", + "created_old", + new_column_name="created", + nullable=False, + existing_type=sa.DateTime(timezone=True), + existing_nullable=True, + ) + + # upgrade.executed + op.add_column( + "upgrade", sa.Column("executed_old", sa.DateTime(timezone=True), nullable=True) + ) + upgrade = sa.sql.table( + "upgrade", + sa.sql.column("uuid"), + sa.sql.column("executed"), + sa.sql.column("executed_old"), + ) + cursor = op.get_bind().execute(upgrade.select()) + for row in cursor.fetchall(): + if row.executed: + op.get_bind().execute( + upgrade.update() + .where(upgrade.c.uuid == row.uuid) + .values({"executed_old": row.executed}) + ) + op.drop_column("upgrade", "executed") + op.alter_column( + "upgrade", + "executed_old", + new_column_name="executed", + existing_type=sa.DateTime(timezone=True), + existing_nullable=True, + ) + + # upgrade.created + op.add_column( + "upgrade", sa.Column("created_old", sa.DateTime(timezone=True), nullable=True) + ) + upgrade = sa.sql.table( + "upgrade", + sa.sql.column("uuid"), + sa.sql.column("created"), + sa.sql.column("created_old"), + ) + cursor = op.get_bind().execute(upgrade.select()) + for row in cursor.fetchall(): + op.get_bind().execute( + upgrade.update() + .where(upgrade.c.uuid == row.uuid) + .values({"created_old": row.created}) + ) + op.drop_column("upgrade", "created") + op.alter_column( + "upgrade", + "created_old", + new_column_name="created", + nullable=False, + existing_type=sa.DateTime(timezone=True), + existing_nullable=True, + ) diff --git a/src/wuttjamaican/db/model/auth.py b/src/wuttjamaican/db/model/auth.py index 5bb4c45..2a48369 100644 --- a/src/wuttjamaican/db/model/auth.py +++ b/src/wuttjamaican/db/model/auth.py @@ -39,14 +39,13 @@ So a user's permissions are "inherited" from the role(s) to which they belong. """ -import datetime - import sqlalchemy as sa from sqlalchemy import orm from sqlalchemy.ext.associationproxy import association_proxy from wuttjamaican.db.util import uuid_column, uuid_fk_column from wuttjamaican.db.model.base import Base +from wuttjamaican.util import make_utc class Role(Base): # pylint: disable=too-few-public-methods @@ -343,9 +342,9 @@ class UserAPIToken(Base): # pylint: disable=too-few-public-methods ) created = sa.Column( - sa.DateTime(timezone=True), + sa.DateTime(), nullable=False, - default=datetime.datetime.now, + default=make_utc, doc=""" Date/time when the token was created. """, diff --git a/src/wuttjamaican/db/model/batch.py b/src/wuttjamaican/db/model/batch.py index ad2ef3c..c9ab097 100644 --- a/src/wuttjamaican/db/model/batch.py +++ b/src/wuttjamaican/db/model/batch.py @@ -34,6 +34,7 @@ from sqlalchemy.ext.orderinglist import ordering_list from wuttjamaican.db.model.base import uuid_column from wuttjamaican.db.model.auth import User from wuttjamaican.db.util import UUID +from wuttjamaican.util import make_utc class BatchMixin: @@ -223,9 +224,7 @@ class BatchMixin: status_code = sa.Column(sa.Integer(), nullable=True) status_text = sa.Column(sa.String(length=255), nullable=True) - created = sa.Column( - sa.DateTime(timezone=True), nullable=False, default=datetime.datetime.now - ) + created = sa.Column(sa.DateTime(), nullable=False, default=make_utc) created_by_uuid = sa.Column(UUID(), nullable=False) @declared_attr @@ -238,7 +237,7 @@ class BatchMixin: cascade_backrefs=False, ) - executed = sa.Column(sa.DateTime(timezone=True), nullable=True) + executed = sa.Column(sa.DateTime(), nullable=True) executed_by_uuid = sa.Column(UUID(), nullable=True) @declared_attr @@ -428,8 +427,5 @@ class BatchRowMixin: # pylint: disable=too-few-public-methods status_text = sa.Column(sa.String(length=255), nullable=True) modified = sa.Column( - sa.DateTime(timezone=True), - nullable=True, - default=datetime.datetime.now, - onupdate=datetime.datetime.now, + sa.DateTime(), nullable=True, default=make_utc, onupdate=make_utc ) diff --git a/src/wuttjamaican/db/model/upgrades.py b/src/wuttjamaican/db/model/upgrades.py index 7c94d3f..ae035bb 100644 --- a/src/wuttjamaican/db/model/upgrades.py +++ b/src/wuttjamaican/db/model/upgrades.py @@ -24,14 +24,13 @@ Upgrade Model """ -import datetime - import sqlalchemy as sa from sqlalchemy import orm from wuttjamaican.enum import UpgradeStatus from wuttjamaican.db.util import uuid_column, uuid_fk_column from wuttjamaican.db.model.base import Base +from wuttjamaican.util import make_utc class Upgrade(Base): # pylint: disable=too-few-public-methods @@ -44,9 +43,9 @@ class Upgrade(Base): # pylint: disable=too-few-public-methods uuid = uuid_column() created = sa.Column( - sa.DateTime(timezone=True), + sa.DateTime(), nullable=False, - default=datetime.datetime.now, + default=make_utc, doc=""" When the upgrade record was created. """, @@ -98,7 +97,7 @@ class Upgrade(Base): # pylint: disable=too-few-public-methods ) executed = sa.Column( - sa.DateTime(timezone=True), + sa.DateTime(), nullable=True, doc=""" When the upgrade was executed. diff --git a/tests/test_app.py b/tests/test_app.py index 5a84db1..936d79d 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -571,7 +571,7 @@ app_title = WuttaTest now = datetime.datetime.now() result = self.app.render_time_ago(now) self.assertEqual(result, "now") - humanize.naturaltime.assert_called_once_with(now) + humanize.naturaltime.assert_called_once() def test_get_person(self): people = self.app.get_people_handler()