mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-03-16 22:10:28 +00:00
Add a per-user timezone setting
This commit is contained in:
parent
c82b6835a0
commit
e43ea79747
15 changed files with 207 additions and 5 deletions
|
|
@ -6,6 +6,7 @@ Changelog
|
|||
|
||||
* Add `HelpPanel` to add HTML within an edit form (Keving Chung)
|
||||
* Added API endpoint for finding pages by HTML path (Karl Hobley)
|
||||
* Added time zone setting to account preferences (David Moore)
|
||||
* Persist tab hash in URL to allow direct navigation to tabs in the admin interface (Ben Weatherman)
|
||||
* Animate the chevron icon when opening sub-menus in the admin (Carlo Ascani)
|
||||
* Look through the target link and target page slug (in addition to the old slug) when searching for redirects in the admin (Michael Harrison)
|
||||
|
|
|
|||
|
|
@ -296,6 +296,7 @@ Contributors
|
|||
* Tim Kamanin
|
||||
* Sergey Fedoseev
|
||||
* Harm Zeinstra
|
||||
* David Moore
|
||||
|
||||
Translators
|
||||
===========
|
||||
|
|
|
|||
|
|
@ -426,6 +426,22 @@ Date and DateTime inputs
|
|||
|
||||
Specifies the date and datetime format to be used in input fields in the Wagtail admin. The format is specified in `Python datetime module syntax <https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior>`_, and must be one of the recognised formats listed in the ``DATE_INPUT_FORMATS`` or ``DATETIME_INPUT_FORMATS`` setting respectively (see `DATE_INPUT_FORMATS <https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-DATE_INPUT_FORMATS>`_).
|
||||
|
||||
.. _WAGTAIL_USER_TIME_ZONES:
|
||||
|
||||
Time zones
|
||||
----------
|
||||
|
||||
Logged-in users can choose their current time zone for the admin interface in the account settings. If is no time zone selected by the user, then ``TIME_ZONE`` will be used.
|
||||
(Note that time zones are only applied to datetime fields, not to plain time or date fields. This is a Django design decision.)
|
||||
|
||||
The list of time zones is by default the common_timezones list from pytz.
|
||||
It is possible to override this list via the ``WAGTAIL_USER_TIME_ZONES`` setting.
|
||||
If there is zero or one time zone permitted, the account settings form will be hidden.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
WAGTAIL_USER_TIME_ZONES = ['America/Chicago', 'Australia/Sydney', 'Europe/Rome']
|
||||
|
||||
.. _WAGTAILADMIN_PERMITTED_LANGUAGES:
|
||||
|
||||
Admin languages
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@ API lookup by page path
|
|||
|
||||
The API now includes an endpoint for finding pages by path; see :ref:`apiv2_finding_pages_by_path`. This feature was developed by Karl Hobley.
|
||||
|
||||
|
||||
User time zone setting
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Users can now set their current time zone through the Account Settings menu, which will then be reflected in date / time fields throughout the admin (such as go-live / expiry dates). The list of available time zones can be configured via the :ref:`WAGTAIL_USER_TIME_ZONES <WAGTAIL_USER_TIME_ZONES>` setting. This feature was developed by David Moore.
|
||||
|
||||
|
||||
Other features
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -33,6 +33,7 @@ install_requires = [
|
|||
"Unidecode>=0.04.14,<1.0",
|
||||
"Willow>=1.1,<1.2",
|
||||
"requests>=2.11.1,<3.0",
|
||||
"l18n",
|
||||
]
|
||||
|
||||
# Testing dependencies
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
from django.contrib.auth.views import redirect_to_login as auth_redirect_to_login
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import activate as activate_tz
|
||||
from django.utils.translation import activate as activate_lang
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
import l18n
|
||||
from wagtail.admin import messages
|
||||
|
||||
|
||||
|
|
@ -24,7 +26,11 @@ def require_admin_access(view_func):
|
|||
|
||||
if user.has_perms(['wagtailadmin.access_admin']):
|
||||
if hasattr(user, 'wagtail_userprofile'):
|
||||
activate_lang(user.wagtail_userprofile.get_preferred_language())
|
||||
language = user.wagtail_userprofile.get_preferred_language()
|
||||
l18n.set_language(language)
|
||||
activate_lang(language)
|
||||
time_zone = user.wagtail_userprofile.get_current_time_zone()
|
||||
activate_tz(time_zone)
|
||||
return view_func(request, *args, **kwargs)
|
||||
|
||||
if not request.is_ajax():
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block titletag %}{% trans "Set Time Zone" %}{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "Set Time Zone" as prefs_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=prefs_str %}
|
||||
|
||||
<div class="nice-padding">
|
||||
<form action="{% url 'wagtailadmin_account_current_time_zone' %}" method="POST" novalidate>
|
||||
{% csrf_token %}
|
||||
<ul class="fields">
|
||||
{% for field in form %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
<li class="submit"><input type="submit" value="{% trans 'Update' %}" class="button" /></li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import pytz
|
||||
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
|
|
@ -6,7 +8,8 @@ from django.core import mail
|
|||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.admin.utils import WAGTAILADMIN_PROVIDED_LANGUAGES, get_available_admin_languages
|
||||
from wagtail.admin.utils import (
|
||||
WAGTAILADMIN_PROVIDED_LANGUAGES, get_available_admin_languages, get_available_admin_time_zones)
|
||||
from wagtail.tests.utils import WagtailTestUtils
|
||||
from wagtail.users.models import UserProfile
|
||||
|
||||
|
|
@ -403,6 +406,67 @@ class TestAccountSection(TestCase, WagtailTestUtils):
|
|||
response = self.client.post(reverse('wagtailadmin_account'))
|
||||
self.assertNotContains(response, 'Language Preferences')
|
||||
|
||||
def test_current_time_zone_view(self):
|
||||
"""
|
||||
This tests that the current time zone view responds with an index page
|
||||
"""
|
||||
# Get account page
|
||||
response = self.client.get(reverse('wagtailadmin_account_current_time_zone'))
|
||||
|
||||
# Check that the user received an account page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailadmin/account/current_time_zone.html')
|
||||
|
||||
# Page should contain a 'Set Time Zone' title
|
||||
self.assertContains(response, "Set Time Zone")
|
||||
|
||||
def test_current_time_zone_view_post(self):
|
||||
"""
|
||||
This posts to the current time zone view and checks that the
|
||||
user profile is updated
|
||||
"""
|
||||
# Post new values to the current time zone page
|
||||
post_data = {
|
||||
'current_time_zone': 'Pacific/Fiji'
|
||||
}
|
||||
response = self.client.post(reverse('wagtailadmin_account_current_time_zone'), post_data)
|
||||
|
||||
# Check that the user was redirected to the account page
|
||||
self.assertRedirects(response, reverse('wagtailadmin_account'))
|
||||
|
||||
profile = UserProfile.get_for_user(get_user_model().objects.get(pk=self.user.pk))
|
||||
|
||||
# Check that the current time zone is stored
|
||||
self.assertEqual(profile.current_time_zone, 'Pacific/Fiji')
|
||||
|
||||
def test_unset_current_time_zone(self):
|
||||
# Post new values to the current time zone page
|
||||
post_data = {
|
||||
'current_time_zone': ''
|
||||
}
|
||||
response = self.client.post(reverse('wagtailadmin_account_current_time_zone'), post_data)
|
||||
|
||||
# Check that the user was redirected to the account page
|
||||
self.assertRedirects(response, reverse('wagtailadmin_account'))
|
||||
|
||||
profile = UserProfile.get_for_user(get_user_model().objects.get(pk=self.user.pk))
|
||||
|
||||
# Check that the current time zone are stored
|
||||
self.assertEqual(profile.current_time_zone, '')
|
||||
|
||||
@override_settings(WAGTAIL_USER_TIME_ZONES=['Africa/Addis_Ababa', 'America/Argentina/Buenos_Aires'])
|
||||
def test_available_admin_time_zones_with_permitted_time_zones(self):
|
||||
self.assertListEqual(get_available_admin_time_zones(),
|
||||
['Africa/Addis_Ababa', 'America/Argentina/Buenos_Aires'])
|
||||
|
||||
def test_available_admin_time_zones_by_default(self):
|
||||
self.assertListEqual(get_available_admin_time_zones(), pytz.common_timezones)
|
||||
|
||||
@override_settings(WAGTAIL_USER_TIME_ZONES=['Europe/London'])
|
||||
def test_not_show_options_if_only_one_time_zone_is_permitted(self):
|
||||
response = self.client.post(reverse('wagtailadmin_account'))
|
||||
self.assertNotContains(response, 'Set Time Zone')
|
||||
|
||||
|
||||
class TestAccountManagementForNonModerator(TestCase, WagtailTestUtils):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ urlpatterns = [
|
|||
account.language_preferences,
|
||||
name='wagtailadmin_account_language_preferences'
|
||||
),
|
||||
url(
|
||||
r'^account/current_time_zone/$',
|
||||
account.current_time_zone,
|
||||
name='wagtailadmin_account_current_time_zone'
|
||||
),
|
||||
url(r'^logout/$', account.LogoutView.as_view(), name='wagtailadmin_logout'),
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from functools import wraps
|
||||
import pytz
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
|
|
@ -53,6 +54,10 @@ def get_available_admin_languages():
|
|||
return getattr(settings, 'WAGTAILADMIN_PERMITTED_LANGUAGES', WAGTAILADMIN_PROVIDED_LANGUAGES)
|
||||
|
||||
|
||||
def get_available_admin_time_zones():
|
||||
return getattr(settings, 'WAGTAIL_USER_TIME_ZONES', pytz.common_timezones)
|
||||
|
||||
|
||||
def get_object_usage(obj):
|
||||
"Returns a queryset of pages that link to a particular object"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ from django.utils.translation import activate
|
|||
|
||||
from wagtail.admin import forms
|
||||
from wagtail.core import hooks
|
||||
from wagtail.users.forms import EmailForm, NotificationPreferencesForm, PreferredLanguageForm
|
||||
from wagtail.users.forms import (
|
||||
CurrentTimeZoneForm, EmailForm, NotificationPreferencesForm, PreferredLanguageForm)
|
||||
from wagtail.users.models import UserProfile
|
||||
from wagtail.utils.loading import get_custom_form
|
||||
|
||||
|
|
@ -168,6 +169,22 @@ def language_preferences(request):
|
|||
})
|
||||
|
||||
|
||||
def current_time_zone(request):
|
||||
if request.method == 'POST':
|
||||
form = CurrentTimeZoneForm(request.POST, instance=UserProfile.get_for_user(request.user))
|
||||
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("Your preferences have been updated."))
|
||||
return redirect('wagtailadmin_account')
|
||||
else:
|
||||
form = CurrentTimeZoneForm(instance=UserProfile.get_for_user(request.user))
|
||||
|
||||
return render(request, 'wagtailadmin/account/current_time_zone.html', {
|
||||
'form': form,
|
||||
})
|
||||
|
||||
|
||||
class LoginView(auth_views.LoginView):
|
||||
template_name = 'wagtailadmin/login.html'
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
|||
BlockElementHandler, ExternalLinkElementHandler, HorizontalRuleHandler,
|
||||
InlineStyleElementHandler, ListElementHandler, ListItemElementHandler, PageLinkElementHandler)
|
||||
from wagtail.admin.search import SearchArea
|
||||
from wagtail.admin.utils import get_available_admin_languages, user_has_any_page_permission
|
||||
from wagtail.admin.utils import (
|
||||
get_available_admin_languages, get_available_admin_time_zones,
|
||||
user_has_any_page_permission)
|
||||
from wagtail.admin.views.account import password_management_enabled
|
||||
from wagtail.admin.viewsets import viewsets
|
||||
from wagtail.admin.widgets import Button, ButtonWithDropdownFromHook, PageListingButton
|
||||
|
|
@ -244,6 +246,16 @@ def register_account_preferred_language_preferences(request):
|
|||
}
|
||||
|
||||
|
||||
@hooks.register('register_account_menu_item')
|
||||
def register_account_current_time_zone(request):
|
||||
if len(get_available_admin_time_zones()) > 1:
|
||||
return {
|
||||
'url': reverse('wagtailadmin_account_current_time_zone'),
|
||||
'label': _('Current Time Zone'),
|
||||
'help_text': _('Choose your current time zone.'),
|
||||
}
|
||||
|
||||
|
||||
@hooks.register('register_rich_text_features')
|
||||
def register_core_features(features):
|
||||
# Hallo.js
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
|
|
@ -12,7 +13,8 @@ from django.template.loader import render_to_string
|
|||
from django.utils.html import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.admin.utils import get_available_admin_languages
|
||||
import l18n
|
||||
from wagtail.admin.utils import get_available_admin_languages, get_available_admin_time_zones
|
||||
from wagtail.admin.widgets import AdminPageChooser
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.models import (
|
||||
|
|
@ -399,3 +401,20 @@ class EmailForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = ("email", )
|
||||
|
||||
|
||||
class CurrentTimeZoneForm(forms.ModelForm):
|
||||
def _get_time_zone_choices():
|
||||
time_zones = [(tz, str(l18n.tz_fullnames.get(tz, tz)))
|
||||
for tz in get_available_admin_time_zones()]
|
||||
time_zones.sort(key=itemgetter(1))
|
||||
return BLANK_CHOICE_DASH + time_zones
|
||||
|
||||
current_time_zone = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=_get_time_zone_choices
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = UserProfile
|
||||
fields = ("current_time_zone",)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.0.4 on 2018-04-07 01:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailusers', '0006_userprofile_prefered_language'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='current_time_zone',
|
||||
field=models.CharField(default='', help_text='Select your current time zone', max_length=40, verbose_name='current time zone'),
|
||||
),
|
||||
]
|
||||
|
|
@ -33,6 +33,13 @@ class UserProfile(models.Model):
|
|||
default=''
|
||||
)
|
||||
|
||||
current_time_zone = models.CharField(
|
||||
verbose_name=_('current time zone'),
|
||||
max_length=40,
|
||||
help_text=_("Select your current time zone"),
|
||||
default=''
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_for_user(cls, user):
|
||||
return cls.objects.get_or_create(user=user)[0]
|
||||
|
|
@ -40,6 +47,9 @@ class UserProfile(models.Model):
|
|||
def get_preferred_language(self):
|
||||
return self.preferred_language or settings.LANGUAGE_CODE
|
||||
|
||||
def get_current_time_zone(self):
|
||||
return self.current_time_zone or settings.TIME_ZONE
|
||||
|
||||
def __str__(self):
|
||||
return self.user.get_username()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue