Fix timezone handling of `TemplateResponse`s for users with a custom timezone

The PR #9628 missed the cases, where a TemplateResponse is used, which
defers the rendering to a point outside the override_tz() context
manager. This change re-uses the existing handling for the user's
preferred language.

Fixes #10243
pull/10951/head
Stefan Hammer 2023-03-20 08:33:36 +01:00 zatwierdzone przez Sage Abdullah
rodzic 75a5dfaff7
commit 42cc12d449
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: EB1A33CC51CC0217
5 zmienionych plików z 119 dodań i 39 usunięć

Wyświetl plik

@ -6,6 +6,7 @@ Changelog
* Fix: Fix radio and checkbox elements shrinking when using a long label (Sage Abdullah)
* Fix: Fix select elements expanding beyond their container when using a long option label (Sage Abdullah)
* Fix: Fix timezone handling of `TemplateResponse`s for users with a custom timezone (Stefan Hammer, Sage Abdullah)
4.1.3 (13.03.2023)

Wyświetl plik

@ -15,3 +15,4 @@ depth: 1
* Fix radio and checkbox elements shrinking when using a long label (Sage Abdullah)
* Fix select elements expanding beyond their container when using a long option label (Sage Abdullah)
* Fix timezone handling of `TemplateResponse`s for users with a custom timezone (Stefan Hammer, Sage Abdullah)

Wyświetl plik

@ -1,17 +0,0 @@
# Wagtail 4.2.2 release notes
_Unreleased_
```{contents}
---
local:
depth: 1
---
```
## What's new
### Bug fixes
* Fix radio and checkbox elements shrinking when using a long label (Sage Abdullah)
* Fix select elements expanding beyond their container when using a long option label (Sage Abdullah)

Wyświetl plik

@ -182,29 +182,30 @@ def require_admin_access(view_func):
if preferred_language:
with override(preferred_language):
response = view_func(request, *args, **kwargs)
if hasattr(response, "render"):
# If the response has a render() method, Django treats it
# like a TemplateResponse, so we should do the same
# In this case, we need to guarantee that when the TemplateResponse
# is rendered, it is done within the override context manager
# or the user preferred_language will not be used
# (this could be replaced with simply rendering the TemplateResponse
# for simplicity but this does remove some of its middleware modification
# potential)
render = response.render
def overridden_render(response):
with override(preferred_language):
return render()
response.render = types.MethodType(
overridden_render, response
)
# decorate the response render method with the override context manager
return response
else:
return view_func(request, *args, **kwargs)
response = view_func(request, *args, **kwargs)
if hasattr(response, "render"):
# If the response has a render() method, Django treats it
# like a TemplateResponse, so we should do the same
# In this case, we need to guarantee that when the TemplateResponse
# is rendered, it is done within the override context manager
# or the user preferred_language/timezone will not be used
# (this could be replaced with simply rendering the TemplateResponse
# for simplicity but this does remove some of its middleware modification
# potential)
render = response.render
def overridden_render(response):
with override_tz(time_zone):
if preferred_language:
with override(preferred_language):
return render()
return render()
response.render = types.MethodType(overridden_render, response)
# decorate the response render method with the override context manager
return response
except PermissionDenied:
if request.headers.get("x-requested-with") == "XMLHttpRequest":

Wyświetl plik

@ -423,6 +423,100 @@ class TestPageEdit(TestCase, WagtailTestUtils):
"This publishing schedule will only take effect after you have published",
)
def test_edit_post_scheduled_custom_timezone(self):
# Set user's timezone to something different from the server timezone
UserProfile.objects.update_or_create(
user=self.user,
defaults={"current_time_zone": "Asia/Jakarta"},
)
post_data = {
"title": "I've been edited!",
"content": "Some content",
"slug": "hello-world",
"go_live_at": "2022-03-20 06:00",
}
edit_url = reverse("wagtailadmin_pages:edit", args=(self.child_page.id,))
response = self.client.post(edit_url, post_data, follow=True)
html = response.content.decode()
# Should be redirected to the edit page again
self.assertRedirects(response, edit_url, 302, 200)
child_page_new = SimplePage.objects.get(id=self.child_page.id)
# The page will still be live
self.assertTrue(child_page_new.live)
# A revision with approved_go_live_at should not exist
self.assertFalse(
Revision.page_revisions.filter(object_id=child_page_new.id)
.exclude(approved_go_live_at__isnull=True)
.exists()
)
# But a revision with go_live_at in their content json *should* exist
if settings.USE_TZ:
# The saved timestamp should be in UTC
self.assertTrue(
Revision.page_revisions.filter(
object_id=child_page_new.id,
content__go_live_at="2022-03-19T23:00:00Z",
).exists()
)
else:
# Without TZ support, just use the submitted timestamp as-is
self.assertTrue(
Revision.page_revisions.filter(
object_id=child_page_new.id,
content__go_live_at="2022-03-20T06:00:00",
).exists()
)
# Should show the draft go_live_at under the "Once published" label
# and should be in the user's timezone
self.assertContains(
response,
'<div class="w-label-3">Once published:</div>',
html=True,
count=1,
)
self.assertContains(
response,
'<span class="w-text-primary">Go-live:</span> March 20, 2022, 6 a.m.',
html=True,
count=1,
)
# Should show the "Edit schedule" button
self.assertTagInHTML(
'<button type="button" data-a11y-dialog-show="schedule-publishing-dialog">Edit schedule</button>',
html,
count=1,
allow_extra_attrs=True,
)
# Should show the dialog template pointing to the [data-edit-form] selector as the root
self.assertTagInHTML(
'<div id="schedule-publishing-dialog" class="w-dialog publishing" data-dialog-root-selector="[data-edit-form]">',
html,
count=1,
allow_extra_attrs=True,
)
# Should show the input with the correct value in the user's timezone
self.assertTagInHTML(
'<input type="text" name="go_live_at" value="2022-03-20 06:00">',
html,
count=1,
allow_extra_attrs=True,
)
self.assertContains(
response,
"This publishing schedule will only take effect after you have published",
)
def test_schedule_panel_without_publish_permission(self):
editor = self.create_user("editor", password="password")
editor.groups.add(Group.objects.get(name="Editors"))