diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6324c9e0e8..b95ac40703 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -45,6 +45,7 @@ Changelog * Fix: Ensure that document search results count shows the correct all matches, not the paginate total (Andy Chosak) * 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) * Docs: Add code block to make it easier to understand contribution docs (Suyash Singh) * Docs: Add new "Icons" page for icons customisation and reuse across the admin interface (Coen van der Kamp) * Docs: Fix broken formatting for MultiFieldPanel / FieldRowPanel permission kwarg docs (Matt Westcott) @@ -85,6 +86,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.2.1 (13.03.2023) @@ -260,6 +262,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) diff --git a/docs/releases/4.1.4.md b/docs/releases/4.1.4.md index a9d5daf0f5..2a20066d10 100644 --- a/docs/releases/4.1.4.md +++ b/docs/releases/4.1.4.md @@ -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) diff --git a/docs/releases/4.2.2.md b/docs/releases/4.2.2.md index 76eb413b11..21c2356940 100644 --- a/docs/releases/4.2.2.md +++ b/docs/releases/4.2.2.md @@ -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) diff --git a/docs/releases/5.0.md b/docs/releases/5.0.md index 9fdb57925f..3da0889ef5 100644 --- a/docs/releases/5.0.md +++ b/docs/releases/5.0.md @@ -59,6 +59,7 @@ Support for adding custom validation logic to StreamField blocks has been formal * Ensure that document search results count shows the correct all matches, not the paginate total (Andy Chosak) * 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) ### Documentation diff --git a/wagtail/admin/auth.py b/wagtail/admin/auth.py index ca6a3d7b96..15648b7adf 100644 --- a/wagtail/admin/auth.py +++ b/wagtail/admin/auth.py @@ -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": diff --git a/wagtail/admin/tests/pages/test_edit_page.py b/wagtail/admin/tests/pages/test_edit_page.py index a8fe389e8d..c4327415cb 100644 --- a/wagtail/admin/tests/pages/test_edit_page.py +++ b/wagtail/admin/tests/pages/test_edit_page.py @@ -444,6 +444,100 @@ class TestPageEdit(WagtailTestUtils, TestCase): "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, + '