diff --git a/plugins/backups/api/routes.py b/plugins/backups/api/routes.py index dba92ad..6eb54cd 100644 --- a/plugins/backups/api/routes.py +++ b/plugins/backups/api/routes.py @@ -12,6 +12,9 @@ because requiring the app server to mount the SFLD share would turn a permissions slip into an unexplained empty download. """ +from datetime import timezone +from zoneinfo import ZoneInfo + from flask import Blueprint, current_app, request, Response from flask_jwt_extended import jwt_required @@ -22,15 +25,42 @@ from shopdb.api import ( ) from ..models import BackupRevision +from ..models.backup import _utciso from ..services.registry import REGISTRY, getkind backups_bp = Blueprint('backups', __name__) +_DEFAULTTZ = 'America/New_York' + + +def _sitezone(): + """Site-configured IANA zone (settings key site_timezone). + + Same lookup the notifications plugin uses. A stored timestamp is UTC, so + anything rendered server-side has to be converted or it shows the wrong + wall clock for the site - four hours out at West Jefferson. + """ + from shopdb.api import Setting + row = Setting.query.filter_by(key='site_timezone').first() + name = row.value if row and row.value else _DEFAULTTZ + try: + return ZoneInfo(name) + except Exception: + return ZoneInfo(_DEFAULTTZ) + + def _label(revision): - """Panel list title: kind-agnostic, readable at a glance.""" + """Panel list title: kind-agnostic, readable at a glance. + + Rendered in the SITE zone, not UTC: this string is baked server-side and + the client cannot correct it afterwards. + """ when = revision.collectedat or revision.createdat - stamp = when.strftime('%Y-%m-%d %H:%M') if when else 'unknown time' + if not when: + return 'unknown time' + local = when.replace(tzinfo=timezone.utc).astimezone(_sitezone()) + stamp = local.strftime('%Y-%m-%d %H:%M') if revision.sourcefilename: return '{} - {}'.format(stamp, revision.sourcefilename) return stamp @@ -129,8 +159,7 @@ def asset_info(assetid): revision.payload, assetid, partmarkertypes=current_app.config.get('BACKUPS_PARTMARKER_TYPES')) data['backuprevisionid'] = revision.backuprevisionid - data['collectedat'] = (revision.collectedat.isoformat() - if revision.collectedat else None) + data['collectedat'] = _utciso(revision.collectedat) return success_response(data) diff --git a/plugins/backups/frontend/views/BackupHistory.vue b/plugins/backups/frontend/views/BackupHistory.vue index b2286e9..625e689 100644 --- a/plugins/backups/frontend/views/BackupHistory.vue +++ b/plugins/backups/frontend/views/BackupHistory.vue @@ -95,7 +95,8 @@