diff --git a/invenio_banners/records/models.py b/invenio_banners/records/models.py index c9238d1..a3fe6e7 100644 --- a/invenio_banners/records/models.py +++ b/invenio_banners/records/models.py @@ -8,7 +8,7 @@ """Models.""" -from datetime import datetime +from datetime import datetime, timezone import sqlalchemy as sa from flask import current_app @@ -36,7 +36,11 @@ class BannerModel(db.Model, Timestamp): category = db.Column(db.String(20), nullable=False) """Category of the message, for styling messages per category.""" - start_datetime = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) + start_datetime = db.Column( + db.DateTime, + nullable=False, + default=lambda: datetime.now(timezone.utc).replace(tzinfo=None), + ) """Start date and time (UTC), can be immediate or delayed.""" end_datetime = db.Column(db.DateTime, nullable=True) @@ -90,7 +94,7 @@ def delete(cls, banner): @classmethod def get_active(cls, url_path): """Return active banners.""" - now = datetime.utcnow() + now = datetime.now(timezone.utc).replace(tzinfo=None) query = ( db.session.query(cls) @@ -130,7 +134,7 @@ def search(cls, search_params, filters): @classmethod def disable_expired(cls): """Disable any old still active messages to keep everything clean.""" - now = datetime.utcnow() + now = datetime.now(timezone.utc).replace(tzinfo=None) query = ( db.session.query(cls) diff --git a/invenio_banners/services/schemas.py b/invenio_banners/services/schemas.py index 27c9dde..6b50a18 100644 --- a/invenio_banners/services/schemas.py +++ b/invenio_banners/services/schemas.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # Copyright (C) 2022-2023 CERN. +# Copyright (C) 2024 Graz University of Technology. # # Invenio-Banners is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -22,7 +23,11 @@ class BannerSchema(BaseRecordSchema): category = fields.String(required=True, metadata={"default": "info"}) start_datetime = fields.DateTime( required=True, - metadata={"default": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")}, + metadata={ + "default": datetime.now(timezone.utc) + .replace(tzinfo=None) + .strftime("%Y-%m-%d %H:%M:%S") + }, ) end_datetime = fields.DateTime(allow_none=True) active = fields.Boolean(required=True, metadata={"default": True}) diff --git a/tests/records/test_disable.py b/tests/records/test_disable.py index ec0fbd8..3622603 100644 --- a/tests/records/test_disable.py +++ b/tests/records/test_disable.py @@ -1,43 +1,49 @@ # -*- coding: utf-8 -*- # # Copyright (C) 2023 CERN. +# Copyright (C) 2024 Graz University of Technology. # # Invenio-Banners is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. """Test disable expired.""" -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from invenio_banners.records.models import BannerModel + +def _now(): + return datetime.now(timezone.utc).replace(tzinfo=None) + + banners = { "valid": { "message": "valid", "url_path": "/valid", "category": "warning", - "end_datetime": datetime.utcnow() + timedelta(days=1), + "end_datetime": _now() + timedelta(days=1), "active": True, }, "everywhere": { "message": "everywhere", "url_path": None, "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "sub_records_only": { "message": "sub_records_only", "url_path": "/resources/sub", "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "expired": { "message": "expired", "url_path": "/expired", "category": "info", - "end_datetime": datetime.utcnow() - timedelta(days=1), + "end_datetime": _now() - timedelta(days=1), "active": True, }, } diff --git a/tests/records/test_models.py b/tests/records/test_models.py index afd95be..d2bc3b0 100644 --- a/tests/records/test_models.py +++ b/tests/records/test_models.py @@ -1,67 +1,73 @@ # -*- coding: utf-8 -*- # # Copyright (C) 2020-2023 CERN. +# Copyright (C) 2024 Graz University of Technology. # # Invenio-Banners is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. """Test models.""" -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import pytest from invenio_banners.records.models import BannerModel from invenio_banners.services.errors import BannerNotExistsError + +def _now(): + return datetime.now(timezone.utc).replace(tzinfo=None) + + banners = { "valid": { "message": "valid", "url_path": "/valid", "category": "info", - "end_datetime": datetime.utcnow() + timedelta(days=1), + "end_datetime": _now() + timedelta(days=1), "active": True, }, "everywhere": { "message": "everywhere", "url_path": None, "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "with_end_datetime": { "message": "with_end_datetime", "url_path": "/with_end_datetime", "category": "info", - "end_datetime": datetime.utcnow() - timedelta(days=1), + "end_datetime": _now() - timedelta(days=1), "active": True, }, "records_only": { "message": "records_only", "url_path": "/resources", "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "sub_records_only": { "message": "sub_records_only", "url_path": "/resources/sub", "category": "warning", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "disabled": { "message": "disabled", "url_path": "/disabled", "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": False, }, "expired": { "message": "expired", "url_path": "/expired", "category": "warning", - "end_datetime": datetime.utcnow() - timedelta(days=1), + "end_datetime": _now() - timedelta(days=1), "active": True, }, } diff --git a/tests/resources/test_resources.py b/tests/resources/test_resources.py index e0f76e5..98ba1d6 100644 --- a/tests/resources/test_resources.py +++ b/tests/resources/test_resources.py @@ -7,7 +7,7 @@ # under the terms of the MIT License; see LICENSE file for more details. """Banner resource tests.""" -from datetime import date, datetime, timedelta +from datetime import date, datetime, timedelta, timezone import pytest from invenio_db import db @@ -15,6 +15,11 @@ from invenio_banners.records import BannerModel + +def _now(): + return datetime.now(timezone.utc).replace(tzinfo=None) + + banners = { "banner0": { "message": "banner0", @@ -22,9 +27,7 @@ "category": "info", "active": True, "start_datetime": date(2022, 7, 20).strftime("%Y-%m-%d %H:%M:%S"), - "end_datetime": (datetime.utcnow() - timedelta(days=20)).strftime( - "%Y-%m-%d %H:%M:%S" - ), + "end_datetime": (_now() - timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S"), }, "banner1": { "message": "banner1", @@ -32,9 +35,7 @@ "category": "info", "active": True, "start_datetime": date(2022, 7, 20).strftime("%Y-%m-%d %H:%M:%S"), - "end_datetime": (datetime.utcnow() + timedelta(days=20)).strftime( - "%Y-%m-%d %H:%M:%S" - ), + "end_datetime": (_now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S"), }, "banner2": { "message": "banner2", @@ -42,9 +43,7 @@ "category": "other", "active": False, "start_datetime": date(2022, 12, 15).strftime("%Y-%m-%d %H:%M:%S"), - "end_datetime": (datetime.utcnow() + timedelta(days=10)).strftime( - "%Y-%m-%d %H:%M:%S" - ), + "end_datetime": (_now() + timedelta(days=10)).strftime("%Y-%m-%d %H:%M:%S"), }, "banner3": { "message": "banner3", @@ -52,9 +51,7 @@ "category": "warning", "active": True, "start_datetime": date(2023, 1, 20).strftime("%Y-%m-%d %H:%M:%S"), - "end_datetime": (datetime.utcnow() + timedelta(days=30)).strftime( - "%Y-%m-%d %H:%M:%S" - ), + "end_datetime": (_now() + timedelta(days=30)).strftime("%Y-%m-%d %H:%M:%S"), }, } @@ -138,7 +135,7 @@ def test_update_banner(client, admin, headers): admin.login(client) new_data = { - "start_datetime": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), + "start_datetime": _now().strftime("%Y-%m-%d %H:%M:%S"), "active": True, "message": "New banner message", "category": "info", @@ -162,7 +159,7 @@ def test_disable_expired_after_update_action(client, admin, headers): admin.login(client) new_data = { - "start_datetime": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), + "start_datetime": _now().strftime("%Y-%m-%d %H:%M:%S"), "active": True, "message": "New banner message", "category": "info", diff --git a/tests/services/test_services.py b/tests/services/test_services.py index 6cc9214..85fc747 100644 --- a/tests/services/test_services.py +++ b/tests/services/test_services.py @@ -8,7 +8,7 @@ """Service level tests for Banners.""" -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import pytest from invenio_db import db @@ -18,15 +18,18 @@ from invenio_banners.records import BannerModel from invenio_banners.services.errors import BannerNotExistsError + +def _now(): + return datetime.now(timezone.utc).replace(tzinfo=None) + + banners = { "active": { "message": "active", "url_path": "/active", "category": "info", - "start_datetime": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), - "end_datetime": (datetime.utcnow() + timedelta(days=1)).strftime( - "%Y-%m-%d %H:%M:%S" - ), + "start_datetime": _now().strftime("%Y-%m-%d %H:%M:%S"), + "end_datetime": (_now() + timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S"), "active": True, }, "inactive": { @@ -39,28 +42,28 @@ "message": "other", "url_path": "/other", "category": "warning", - "end_datetime": datetime.utcnow() + timedelta(days=5), + "end_datetime": _now() + timedelta(days=5), "active": True, }, "expired": { "message": "expired", "url_path": "/expired", "category": "info", - "end_datetime": datetime.utcnow() - timedelta(days=1), + "end_datetime": _now() - timedelta(days=1), "active": True, }, "sub_records_only": { "message": "sub_records_only", "url_path": "/resources/sub", "category": "warning", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, "records_only": { "message": "records_only", "url_path": "/resources", "category": "info", - "start_datetime": datetime.utcnow() - timedelta(days=1), + "start_datetime": _now() - timedelta(days=1), "active": True, }, } @@ -90,7 +93,7 @@ def test_update_banner(app, superuser_identity): new_data = { "active": True, - "start_datetime": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), + "start_datetime": _now().strftime("%Y-%m-%d %H:%M:%S"), "message": "New banner message", "category": "info", } diff --git a/tests/test_macro.py b/tests/test_macro.py index e661773..750080e 100644 --- a/tests/test_macro.py +++ b/tests/test_macro.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- # # Copyright (C) 2020-2023 CERN. +# Copyright (C) 2024 Graz University of Technology. # # Invenio-Banners is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. """Test views.""" -from datetime import datetime +from datetime import datetime, timezone import pytest from flask import url_for @@ -23,7 +24,7 @@ def _create_banner(message, category, url_path=None): "message": message, "category": category, "url_path": url_path, - "start_datetime": datetime.utcnow(), + "start_datetime": datetime.now(timezone.utc).replace(tzinfo=None), "active": True, } )