diff --git a/wagtail/wagtailadmin/templatetags/wagtailadmin_nav.py b/wagtail/wagtailadmin/templatetags/wagtailadmin_nav.py index 8768d1c8f..566845678 100644 --- a/wagtail/wagtailadmin/templatetags/wagtailadmin_nav.py +++ b/wagtail/wagtailadmin/templatetags/wagtailadmin_nav.py @@ -61,7 +61,7 @@ def main_nav(context): if user.has_module_perms('auth'): menu_items.append( - MenuItem('Users', urlresolvers.reverse('verdantusers_index'), classnames='icon icon-user', order=600) + MenuItem('Users', urlresolvers.reverse('wagtailusers_index'), classnames='icon icon-user', order=600) ) for fn in hooks.get_hooks('construct_main_menu'): diff --git a/wagtail/wagtailusers/__init__.py b/wagtail/wagtailusers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailusers/forms.py b/wagtail/wagtailusers/forms.py new file mode 100644 index 000000000..509f5ad8b --- /dev/null +++ b/wagtail/wagtailusers/forms.py @@ -0,0 +1,101 @@ +from django import forms +from django.contrib.auth.models import User +from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm +from django.utils.translation import ugettext_lazy as _ + + +# extend Django's UserCreationForm with an 'is_superuser' field +class UserCreationForm(BaseUserCreationForm): + is_superuser = forms.BooleanField(label=_("Administrator"), required=False, + help_text=_("If ticked, this user has the ability to manage user accounts.") + ) + first_name = forms.CharField(required=True) + last_name = forms.CharField(required=True) + email = forms.EmailField(required=True) + + class Meta: + model = User + fields = ("username", "email", "first_name", "last_name", "is_superuser", "groups") + widgets = { + 'groups': forms.CheckboxSelectMultiple + } + + def save(self, commit=True): + user = super(UserCreationForm, self).save(commit=False) + + # users can access django-admin iff they are a superuser + user.is_staff = user.is_superuser + + if commit: + user.save() + self.save_m2m() + return user + + +# Largely the same as django.contrib.auth.forms.UserCreationForm, but with enough subtle changes +# (to make password non-required) that it isn't worth inheriting... +class UserEditForm(forms.ModelForm): + error_messages = { + 'duplicate_username': _("A user with that username already exists."), + 'password_mismatch': _("The two password fields didn't match."), + } + username = forms.RegexField(label=_("Username"), max_length=30, + regex=r'^[\w.@+-]+$', + help_text=_("Required. 30 characters or fewer. Letters, digits and " + "@/./+/-/_ only."), + error_messages={ + 'invalid': _("This value may contain only letters, numbers and " + "@/./+/-/_ characters.")}) + + email = forms.EmailField(required=True) + first_name = forms.CharField(required=True) + last_name = forms.CharField(required=True) + + password1 = forms.CharField(label=_("Password"), required=False, + widget=forms.PasswordInput, + help_text=_("Leave blank if not changing.")) + password2 = forms.CharField(label=_("Password confirmation"), required=False, + widget=forms.PasswordInput, + help_text=_("Enter the same password as above, for verification.")) + + is_superuser = forms.BooleanField(label=_("Administrator"), required=False, + help_text=_("Administrators have the ability to manage user accounts.") + ) + + class Meta: + model = User + fields = ("username", "email", "first_name", "last_name", "is_active", "is_superuser", "groups") + widgets = { + 'groups': forms.CheckboxSelectMultiple + } + + def clean_username(self): + # Since User.username is unique, this check is redundant, + # but it sets a nicer error message than the ORM. See #13147. + username = self.cleaned_data["username"] + try: + User._default_manager.exclude(id=self.instance.id).get(username=username) + except User.DoesNotExist: + return username + raise forms.ValidationError(self.error_messages['duplicate_username']) + + def clean_password2(self): + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 != password2: + raise forms.ValidationError( + self.error_messages['password_mismatch']) + return password2 + + def save(self, commit=True): + user = super(UserEditForm, self).save(commit=False) + + # users can access django-admin iff they are a superuser + user.is_staff = user.is_superuser + + if self.cleaned_data["password1"]: + user.set_password(self.cleaned_data["password1"]) + if commit: + user.save() + self.save_m2m() + return user diff --git a/wagtail/wagtailusers/templates/wagtailusers/create.html b/wagtail/wagtailusers/templates/wagtailusers/create.html new file mode 100644 index 000000000..a770e9c1b --- /dev/null +++ b/wagtail/wagtailusers/templates/wagtailusers/create.html @@ -0,0 +1,39 @@ +{% extends "wagtailadmin/base.html" %} +{% load image_tags %} +{% block titletag %}Add user{% endblock %} +{% block bodyclass %}menu-users{% endblock %} +{% block content %} +
+

Add user

+
+ + + +
+
+ {% csrf_token %} +
+
    + {% include "wagtailadmin/shared/field_as_li.html" with field=form.username %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.email %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %} + +
  • Roles
  • +
+
+
+
    + {% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %} +
  • +
+
+
+
+{% endblock %} diff --git a/wagtail/wagtailusers/templates/wagtailusers/edit.html b/wagtail/wagtailusers/templates/wagtailusers/edit.html new file mode 100644 index 000000000..38a76346c --- /dev/null +++ b/wagtail/wagtailusers/templates/wagtailusers/edit.html @@ -0,0 +1,41 @@ +{% extends "wagtailadmin/base.html" %} +{% load image_tags %} +{% block titletag %}Editing {{ user.username}}{% endblock %} +{% block bodyclass %}menu-users{% endblock %} +{% block content %} +
+

Editing {{ user.username }}

+
+ + + +
+
+ {% csrf_token %} + +
+
    + {% include "wagtailadmin/shared/field_as_li.html" with field=form.username %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.email %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.first_name %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.last_name %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.password1 %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.password2 %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.is_active %} + +
  • +
+
+
+
    + {% include "wagtailadmin/shared/field_as_li.html" with field=form.is_superuser %} + {% include "wagtailadmin/shared/field_as_li.html" with field=form.groups %} +
  • +
+
+
+
+{% endblock %} diff --git a/wagtail/wagtailusers/templates/wagtailusers/index.html b/wagtail/wagtailusers/templates/wagtailusers/index.html new file mode 100644 index 000000000..53e7274ca --- /dev/null +++ b/wagtail/wagtailusers/templates/wagtailusers/index.html @@ -0,0 +1,37 @@ +{% extends "wagtailadmin/base.html" %} +{% block titletag %}Users{% endblock %} +{% block bodyclass %}menu-users{% endblock %} +{% block content %} +
+
+
+

Users

+
+ +
+
+ + + + + + + + + + + {% for user in users %} + + + + + + + {% endfor %} + +
NameUsernameLevelStatus
+

{{ user.get_full_name|default:user.username }}

+
{{ user.username }}{% if user.is_superuser %}Admin{% endif %}
{% if user.is_active %}Active{% else %}Inactive{% endif %}
+{% endblock %} diff --git a/wagtail/wagtailusers/urls.py b/wagtail/wagtailusers/urls.py new file mode 100644 index 000000000..e8a26f951 --- /dev/null +++ b/wagtail/wagtailusers/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import patterns, url + +urlpatterns = patterns('wagtail.wagtailusers.views', + url(r'^$', 'users.index', name='wagtailusers_index'), + url(r'^new/$', 'users.create', name='wagtailusers_create'), + url(r'^(\d+)/$', 'users.edit', name='wagtailusers_edit'), +) diff --git a/wagtail/wagtailusers/views/__init__.py b/wagtail/wagtailusers/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/wagtail/wagtailusers/views/users.py b/wagtail/wagtailusers/views/users.py new file mode 100644 index 000000000..f973c180c --- /dev/null +++ b/wagtail/wagtailusers/views/users.py @@ -0,0 +1,50 @@ +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth.models import User +from django.contrib.auth.decorators import permission_required +from django.contrib import messages + +from wagtail.wagtailusers.forms import UserCreationForm, UserEditForm + +@permission_required('auth.change_user') +def index(request): + users = User.objects.order_by('last_name', 'first_name') + + return render(request, 'wagtailusers/index.html', { + 'users': users, + }) + +@permission_required('auth.change_user') +def create(request): + if request.POST: + form = UserCreationForm(request.POST) + if form.is_valid(): + user = form.save() + messages.success(request, "User '%s' created." % user) + return redirect('wagtailusers_index') + else: + messages.error(request, "The user could not be created due to errors.") + else: + form = UserCreationForm() + + return render(request, 'wagtailusers/create.html', { + 'form': form, + }) + +@permission_required('auth.change_user') +def edit(request, user_id): + user = get_object_or_404(User, id=user_id) + if request.POST: + form = UserEditForm(request.POST, instance=user) + if form.is_valid(): + user = form.save() + messages.success(request, "User '%s' updated." % user) + return redirect('wagtailusers_index') + else: + messages.error(request, "The user could not be saved due to errors.") + else: + form = UserEditForm(instance=user) + + return render(request, 'wagtailusers/edit.html', { + 'user': user, + 'form': form, + })