Reflect timezone in Object Details; Fix latest IAM bucket policy bugs

This commit is contained in:
2026-01-14 22:47:29 +08:00
parent 956d17a649
commit 7a494abb96
3 changed files with 17 additions and 7 deletions

View File

@@ -41,8 +41,14 @@ from .storage import ObjectStorage, StorageError
ui_bp = Blueprint("ui", __name__, template_folder="../templates", url_prefix="/ui") ui_bp = Blueprint("ui", __name__, template_folder="../templates", url_prefix="/ui")
def _format_datetime_display(dt: datetime) -> str: def _format_datetime_display(dt: datetime, display_tz: str | None = None) -> str:
"""Format a datetime for display using the configured timezone.""" """Format a datetime for display using the configured timezone.
Args:
dt: The datetime to format
display_tz: Optional timezone string. If not provided, reads from current_app.config.
"""
if display_tz is None:
display_tz = current_app.config.get("DISPLAY_TIMEZONE", "UTC") display_tz = current_app.config.get("DISPLAY_TIMEZONE", "UTC")
if display_tz and display_tz != "UTC": if display_tz and display_tz != "UTC":
try: try:
@@ -52,7 +58,7 @@ def _format_datetime_display(dt: datetime) -> str:
dt = dt.astimezone(tz) dt = dt.astimezone(tz)
except (KeyError, ValueError): except (KeyError, ValueError):
pass pass
return dt.strftime("%b %d, %Y %H:%M") return dt.isoformat()
@@ -587,6 +593,7 @@ def stream_bucket_objects(bucket_name: str):
tags_template = url_for("ui.object_tags", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER") tags_template = url_for("ui.object_tags", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER")
copy_template = url_for("ui.copy_object", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER") copy_template = url_for("ui.copy_object", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER")
move_template = url_for("ui.move_object", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER") move_template = url_for("ui.move_object", bucket_name=bucket_name, object_key="KEY_PLACEHOLDER")
display_tz = current_app.config.get("DISPLAY_TIMEZONE", "UTC")
def generate(): def generate():
meta_line = json.dumps({ meta_line = json.dumps({
@@ -632,7 +639,7 @@ def stream_bucket_objects(bucket_name: str):
"key": obj.key, "key": obj.key,
"size": obj.size, "size": obj.size,
"last_modified": obj.last_modified.isoformat(), "last_modified": obj.last_modified.isoformat(),
"last_modified_display": _format_datetime_display(obj.last_modified), "last_modified_display": _format_datetime_display(obj.last_modified, display_tz),
"etag": obj.etag, "etag": obj.etag,
}) + "\n" }) + "\n"

View File

@@ -136,6 +136,7 @@
tr.dataset.key = obj.key; tr.dataset.key = obj.key;
tr.dataset.size = obj.size; tr.dataset.size = obj.size;
tr.dataset.lastModified = obj.lastModified || obj.last_modified; tr.dataset.lastModified = obj.lastModified || obj.last_modified;
tr.dataset.lastModifiedDisplay = obj.lastModifiedDisplay || obj.last_modified_display || new Date(obj.lastModified || obj.last_modified).toLocaleString();
tr.dataset.etag = obj.etag; tr.dataset.etag = obj.etag;
tr.dataset.previewUrl = obj.previewUrl || obj.preview_url; tr.dataset.previewUrl = obj.previewUrl || obj.preview_url;
tr.dataset.downloadUrl = obj.downloadUrl || obj.download_url; tr.dataset.downloadUrl = obj.downloadUrl || obj.download_url;
@@ -1792,7 +1793,7 @@
previewKey.textContent = row.dataset.key; previewKey.textContent = row.dataset.key;
previewSize.textContent = formatBytes(Number(row.dataset.size)); previewSize.textContent = formatBytes(Number(row.dataset.size));
previewModified.textContent = row.dataset.lastModified; previewModified.textContent = row.dataset.lastModifiedDisplay || row.dataset.lastModified;
previewEtag.textContent = row.dataset.etag; previewEtag.textContent = row.dataset.etag;
downloadButton.href = row.dataset.downloadUrl; downloadButton.href = row.dataset.downloadUrl;
downloadButton.classList.remove('disabled'); downloadButton.classList.remove('disabled');

View File

@@ -1520,7 +1520,7 @@
</div> </div>
{% endif %} {% endif %}
{% if can_edit_policy %} {% if can_manage_lifecycle %}
<div class="tab-pane fade {{ 'show active' if active_tab == 'lifecycle' else '' }}" id="lifecycle-pane" role="tabpanel" aria-labelledby="lifecycle-tab" tabindex="0"> <div class="tab-pane fade {{ 'show active' if active_tab == 'lifecycle' else '' }}" id="lifecycle-pane" role="tabpanel" aria-labelledby="lifecycle-tab" tabindex="0">
{% if not lifecycle_enabled %} {% if not lifecycle_enabled %}
<div class="alert alert-warning d-flex align-items-start mb-4" role="alert"> <div class="alert alert-warning d-flex align-items-start mb-4" role="alert">
@@ -1679,7 +1679,9 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
{% if can_manage_cors %}
<div class="tab-pane fade {{ 'show active' if active_tab == 'cors' else '' }}" id="cors-pane" role="tabpanel" aria-labelledby="cors-tab" tabindex="0"> <div class="tab-pane fade {{ 'show active' if active_tab == 'cors' else '' }}" id="cors-pane" role="tabpanel" aria-labelledby="cors-tab" tabindex="0">
<div class="row g-4"> <div class="row g-4">
<div class="col-lg-8"> <div class="col-lg-8">