Merge branch 'develop' into feature/user-account-settings

Conflicts:
	django-verdant/verdantadmin/templates/verdantadmin/home.html
	django-verdant/verdantadmin/urls.py
	django-wagtail/wagtail/wagtailadmin/templates/wagtailadmin/shared/main_nav.html
pull/3/head
Karl Hobley 2014-01-28 16:03:49 +00:00
rodzic 7f248bdf63
commit 67a069dbd3
17 zmienionych plików z 391 dodań i 135 usunięć

Wyświetl plik

@ -1,5 +1,6 @@
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm
class SearchForm(forms.Form):
q = forms.CharField(label="Search term")
@ -28,3 +29,30 @@ class LoginForm(AuthenticationForm):
password = forms.CharField(
widget=forms.PasswordInput(attrs={'placeholder': "Enter password"}),
)
class PasswordResetForm(PasswordResetForm):
def clean(self):
cleaned_data = super(PasswordResetForm, self).clean()
# Find users of this email address
UserModel = get_user_model()
email = cleaned_data['email']
active_users = UserModel._default_manager.filter(email__iexact=email, is_active=True)
if active_users.exists():
# Check if all users of the email address are LDAP users (and give an error if they are)
found_non_ldap_user = False
for user in active_users:
if user.has_usable_password():
found_non_ldap_user = True
break
if not found_non_ldap_user:
# All found users are LDAP users, give error message
raise forms.ValidationError("Sorry, you cannot reset your password here as your user account is managed by another server.")
else:
# No user accounts exist
raise forms.ValidationError("This email address is not recognised.")
return cleaned_data

Wyświetl plik

@ -7,11 +7,12 @@ html{
height:100%;
}
body{
margin-left: 0px;
padding:0 5%;
height:100%;
color:white;
margin:0;
}
h1{
.nice-padding();
font-weight:300;
font-size:2em;
line-height:1em;
@ -30,24 +31,68 @@ h1{
vertical-align: -15%;
}
}
form{
.content-wrapper{
width:100%;
ul{
.unlist();
float:none;
background:none;
border:0;
}
.fields{
.unlist();
li.full{
overflow:hidden;
position:relative;
padding:0;
margin-bottom:1px;
label{
display:none;
}
input{
border:0;
}
label{
.border-radius(2px);
text-transform:uppercase;
padding:2px 5px;
position:absolute;
top:0;
left:0;
margin-top:-1px;
font-size:0.7em;
z-index:1;
margin:0.2em 0;
line-height:1.5em;
font-weight:normal;
}
input{
.border-radius(0px);
font-weight:300;
border:0;
padding-top:1.5em;
padding-bottom:1.5em;
font-size:1.6em;
line-height:1.6em;
}
}
.fields li{
.nice-padding();
padding-top:1em;
padding-bottom:1em;
li:first-child input{
border-top:0;
}
.fields .checkbox{
.checkbox{
padding-top:2em;
padding-bottom:2em;
}
.field{
padding:0;
}
.field.icon:before{
display:none;
}
}
label{
color:white;
}
input[type=submit]{
font-size:1.5em;
padding:1.1em 2.4em;
@ -57,55 +102,7 @@ input[type=checkbox]:before{
color:#555;
border:1px solid #555;
}
.fields li.full{
position:relative;
padding:0;
label{
display:none;
}
input{
border-top: 1px dashed @color-input-border;
}
}
.fields li:first-child input{
border-top:0;
}
.field{
padding:0;
}
.field.icon:before{
display:none;
}
.full label{
.border-radius(2px);
text-transform:uppercase;
padding:2px 5px;
position:absolute;
top:0;
left:0;
margin-top:-1px;
font-size:0.7em;
z-index:1;
margin:0.2em 0;
line-height:1.5em;
font-weight:normal;
}
/* Special full-width, one-off fields i.e a single text or textarea input */
.full input{
.nice-padding;
.border-radius(0px);
font-weight:300;
border:0;
padding-top:1.5em;
padding-bottom:1.5em;
font-size:1.6em;
line-height:1.6em;
}
.help{
opacity:1;
position:absolute;
@ -118,6 +115,7 @@ input[type=checkbox]:before{
@media screen and (min-width: @breakpoint-mobile){
body{
font-size:85%;
padding:0 10%;
}
/* centres login form vertically */
@ -132,44 +130,43 @@ input[type=checkbox]:before{
margin-left:-4px;
}
}
form{
.content-wrapper{
width:100%;
display:inline-block;
vertical-align: middle;
.fields li{
padding-left:10%;
}
}
h1{
padding-left:10%;
font-weight:300;
font-size:4em;
line-height:1em;
}
.full input{
padding-left:10%;
}
.field.icon:before{
display:inline-block;
position: absolute;
color:@color-grey-4;
border: 2px solid @color-grey-4;
border-radius: 100%;
width: 1em;
padding: 0.3em;
left: 12%;
margin-left: 80px;
margin-left: -25px;
top: 50%;
margin-top: -25px;
}
.full input{
padding-left:15%;
.fields{
.field.icon:before{
display:inline-block;
position: absolute;
color:@color-grey-4;
border: 2px solid @color-grey-4;
border-radius: 100%;
width: 1em;
padding: 0.3em;
left: 12%;
margin-left: -25px;
margin-top: -25px;
top: 50%;
}
.full{
margin:0 -13%;
}
.full input{
padding-left:15%;
}
.submit{
margin-top:2em;
}
}
.messages li{
padding-left:11%;
.messages{
margin:0 -13%
}
}

Wyświetl plik

@ -0,0 +1,31 @@
{% extends "wagtailadmin/base.html" %}
{% block content %}
<header>
<h1>Account</h1>
</header>
<div class="nice-padding">
<ul class="listing">
<li class="row row-flush">
<div class="col6">
<a href="http://gravatar.com" class="button button-primary">Set gravatar</a>
</div>
<small class="col6">
Your avatar image is provided by Gravatar and is connected to your email address. With a Gravatar account you can set an avatar for any number of other email addresses you use.
</small>
</li>
<li class="row row-flush">
<div class="col6">
<a href="{% url 'wagtailadmin_account_change_password' %}" class="button button-primary">Change password</a>
</div>
<small class="col6">
Change the password you use to log in.
</small>
</li>
</ul>
</div>
{% endblock %}

Wyświetl plik

@ -0,0 +1,23 @@
{% extends "wagtailadmin/base.html" %}
{% block content %}
<header>
<h1>Change password</h1>
</header>
<div class="nice-padding">
{% if can_change_password %}
<form action="{% url 'wagtailadmin_account_change_password' %}" method="POST">
{% csrf_token %}
<ul class="fields">
{% for field in form %}
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
{% endfor %}
</ul>
<input type="submit" value="Change" />
</form>
{% else %}
<p>Your password can't be changed here. Please contact a site administrator.</p>
{% endif %}
</div>
{% endblock %}

Wyświetl plik

@ -0,0 +1,17 @@
{% extends "wagtailadmin/skeleton.html" %}
{% load compress %}
{% block titletag %}Reset password{% endblock %}
{% block bodyclass %}login{% endblock %}
{% block extra_css %}
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/css/layouts/login.less" type="text/less" />
{% endcompress %}
{% endblock %}
{% block furniture %}
<div class="content-wrapper">
<h1>Password change successful</h1>
<p><a href="{% url 'django.contrib.auth.views.login' %}" class="button button-primary">Login</a></p>
</div>
{% endblock %}

Wyświetl plik

@ -0,0 +1,45 @@
{% extends "wagtailadmin/skeleton.html" %}
{% load compress %}
{% block titletag %}Set your new password{% endblock %}
{% block bodyclass %}login{% endblock %}
{% block extra_css %}
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/css/layouts/login.less" type="text/less" />
{% endcompress %}
{% endblock %}
{% block furniture %}
<div class="content-wrapper">
<form method="post">
{% csrf_token %}
<h1>Set your new password</h1>
{% if form.errors %}
<div class="messages">
<ul>
<li class="error">The passwords do not match. Please try again.</li>
</ul>
</div>
{% endif %}
<ul class="fields">
<li>
<div class="field">
{{ form.new_password1.label_tag }}
{{ form.new_password1 }}
</div>
</li>
<li>
<div class="field">
{{ form.new_password2.label_tag }}
{{ form.new_password2 }}
</div>
</li>
<li class="submit">
<input type="submit" value="Reset password"/>
</li>
</ul>
</form>
</div>
{% endblock %}

Wyświetl plik

@ -0,0 +1,17 @@
{% extends "wagtailadmin/skeleton.html" %}
{% load compress %}
{% block titletag %}Reset password{% endblock %}
{% block bodyclass %}login{% endblock %}
{% block extra_css %}
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/css/layouts/login.less" type="text/less" />
{% endcompress %}
{% endblock %}
{% block furniture %}
<div class="content-wrapper">
<h1>Check your email</h1>
<p>A link to reset your password has been emailed to you.</p>
</div>
{% endblock %}

Wyświetl plik

@ -0,0 +1,2 @@
Please follow the link below to reset your password
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

Wyświetl plik

@ -0,0 +1,43 @@
{% extends "wagtailadmin/skeleton.html" %}
{% load compress %}
{% block titletag %}Reset password{% endblock %}
{% block bodyclass %}login{% endblock %}
{% block extra_css %}
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/css/layouts/login.less" type="text/less" />
{% endcompress %}
{% endblock %}
{% block furniture %}
<div class="content-wrapper">
<form method="post">
{% csrf_token %}
<h1>Reset your password</h1>
<p>Enter your email address in the box below</p>
{% if form.non_field_errors %}
<div class="messages">
<ul>
{% for error in form.non_field_errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<ul class="fields">
<li>
<div class="field">
{{ form.email.label_tag }}
{{ form.email }}
</div>
</li>
<li class="submit">
<input type="submit" value="Reset password"/>
</li>
</ul>
</form>
</div>
{% endblock %}

Wyświetl plik

@ -10,47 +10,46 @@
{% endblock %}
{% block furniture %}
<form action="{% url 'django.contrib.auth.views.login' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<h1>Sign in to <span>V</span>erdant</h1>
<div class="content-wrapper">
<form action="{% url 'django.contrib.auth.views.login' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<h1>Sign in to <span>V</span>erdant</h1>
{% if form.errors %}
<div class="messages">
<ul>
<li class="error">Your username and password didn't match. Please try again.</li>
</ul>
</div>
{% endif %}
<ul class="fields">
<li class="full">
<div class="field icon icon-user">
{{ form.username.label_tag }}
{{ form.username }}
</div>
</li>
<li class="full">
<div class="field icon icon-password">
{{ form.password.label_tag }}
{{ form.password }}
</div>
{% comment %}
Removed until functionality exists
<p class="help"><a href="#">Forgotten it?</a></p>
{% endcomment %}
</li>
{% comment %}
Removed until functionality exists
<li class="checkbox">
<div class="field">
<label><input type="checkbox" /> Remember me</label>
{% if form.errors %}
<div class="messages">
<ul>
<li class="error">Your username and password didn't match. Please try again.</li>
</ul>
</div>
</li>
{% endcomment %}
<li>
<input type="submit" value="Sign in"/>
</li>
</ul>
</form>
{% endif %}
<ul class="fields">
<li class="full">
<div class="field icon icon-user">
{{ form.username.label_tag }}
{{ form.username }}
</div>
</li>
<li class="full">
<div class="field icon icon-password">
{{ form.password.label_tag }}
{{ form.password }}
</div>
<p class="help"><a href="{% url 'django.contrib.auth.views.password_reset' %}">Forgotten it?</a></p>
</li>
{% comment %}
Removed until functionality exists
<li class="checkbox">
<div class="field">
<label><input type="checkbox" /> Remember me</label>
</div>
</li>
{% endcomment %}
<li class="submit">
<input type="submit" value="Sign in"/>
</li>
</ul>
</form>
</div>
{% endblock %}

Wyświetl plik

@ -1,5 +1,5 @@
{% load fieldtype %}
<li class="{{ field|fieldtype }} {% if field.errors %}error{% endif %}">
<li class="{{ field.css_classes }} {{ field|fieldtype }} {% if field.errors %}error{% endif %}">
<div class="field">
{% if field|fieldtype != "boolean_field" %}{{ field.label_tag }}{% endif %}
{% block form_field %}

Wyświetl plik

@ -1,4 +1,5 @@
{% load gravatar wagtailadmin_nav %}
<nav class="nav-main">
<ul>
{% for menu_item in menu_items %}
@ -10,9 +11,7 @@
<li><a href="{% url 'wagtailadmin_pages_select_type' %}" class="icon teal icon-plus-inverse">New page</a></li>
{% endcomment %}
<li class="footer">
{% if request.user.email %}
<div class="avatar icon icon-user"><a href="http://gravatar.com" title="Change or set your Gravatar"><img src="{% gravatar_url request.user.email %}" /></a></div>
{% endif %}
<div class="avatar icon icon-user"><a href="{% url 'verdantadmin_account' %}" title="Account settings">{% if request.user.email %}<img src="{% gravatar_url request.user.email %}" />{% else %}Account{% endif %}</a></div>
<a href="{% url 'django.contrib.auth.views.logout' %}">Log out</a>
</li>
{% if request.user.is_superuser %} {# for now, 'More' links will be superuser-only #}

Wyświetl plik

@ -1,9 +1,24 @@
from django.conf.urls import patterns, url
from wagtail.wagtailadmin.forms import LoginForm
from wagtail.wagtailadmin.forms import LoginForm, PasswordResetForm
urlpatterns = patterns('django.contrib.auth.views',
url(r'^login/$', 'login', {'template_name': 'wagtailadmin/login.html', 'authentication_form': LoginForm}),
url(r'^logout/$', 'logout', {'next_page': '/admin/login/'}),
# Password reset
url(r'^password_reset/$', 'password_reset', {
'template_name': 'verdantadmin/account/password_reset/form.html',
'email_template_name': 'verdantadmin/account/password_reset/email.txt',
'subject_template_name': 'verdantadmin/account/password_reset/email_subject.txt',
'password_reset_form': PasswordResetForm,
}, name='password_reset'),
url(r'^password_reset/done/$', 'password_reset_done', {'template_name': 'verdantadmin/account/password_reset/done.html'}, name='password_reset_done'),
url(r'^password_reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'password_reset_confirm',
{'template_name': 'verdantadmin/account/password_reset/confirm.html'},
name='password_reset_confirm',
),
url(r'^password_reset/complete/$', 'password_reset_complete', {'template_name': 'verdantadmin/account/password_reset/complete.html'}, name='password_reset_complete'),
)
urlpatterns += patterns('wagtail.wagtailadmin.views',
@ -47,4 +62,7 @@ urlpatterns += patterns('wagtail.wagtailadmin.views',
url(r'^choose-email-link/$', 'chooser.email_link', name='wagtailadmin_choose_page_email_link'),
url(r'^tag-autocomplete/$', 'tags.autocomplete', name='wagtailadmin_tag_autocomplete'),
url(r'^account/$', 'account.account', name='verdantadmin_account'),
url(r'^account/change_password/$', 'account.change_password', name='verdantadmin_account_change_password'),
)

Wyświetl plik

@ -0,0 +1,30 @@
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.forms import SetPasswordForm
def account(request):
return render(request, 'wagtailadmin/account/account.html')
def change_password(request):
can_change_password = request.user.has_usable_password()
if can_change_password:
if request.POST:
form = SetPasswordForm(request.user, request.POST)
if form.is_valid():
form.save()
messages.success(request, "Your password has been changed successfully!")
return redirect('wagtailadmin_account')
else:
form = SetPasswordForm(request.user)
else:
form = None
return render(request, 'wagtailadmin/account/change_password.html', {
'form': form,
'can_change_password': can_change_password,
})

Wyświetl plik

@ -4,6 +4,8 @@ from wagtail.wagtaildocs.models import Document
class DocumentForm(forms.ModelForm):
required_css_class = "required"
class Meta:
model = Document
widgets = {

Wyświetl plik

@ -6,6 +6,8 @@ from django.utils.translation import ugettext_lazy as _
# extend Django's UserCreationForm with an 'is_superuser' field
class UserCreationForm(BaseUserCreationForm):
required_css_class = "required"
is_superuser = forms.BooleanField(label=_("Administrator"), required=False,
help_text=_("If ticked, this user has the ability to manage user accounts.")
)
@ -35,6 +37,8 @@ class UserCreationForm(BaseUserCreationForm):
# 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):
required_css_class = "required"
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'password_mismatch': _("The two password fields didn't match."),