create assisted password input in registration (#24439)
This commit is contained in:
parent
6235bc1782
commit
71785a47e3
|
@ -143,6 +143,7 @@ default_settings = dict(
|
|||
A2_PASSWORD_POLICY_MIN_LENGTH=Setting(default=8, definition='Minimum number of characters in a password'),
|
||||
A2_PASSWORD_POLICY_REGEX=Setting(default=None, definition='Regular expression for validating passwords'),
|
||||
A2_PASSWORD_POLICY_REGEX_ERROR_MSG=Setting(default=None, definition='Error message to show when the password do not validate the regular expression'),
|
||||
A2_PASSWORD_WIDGET_SHOW_ALL_BUTTON=Setting(default=False, definition='Show a button on BasePasswordInput for the user to see password input text'),
|
||||
A2_PASSWORD_POLICY_CLASS=Setting(
|
||||
default='authentic2.passwords.DefaultPasswordChecker',
|
||||
definition='path of a class to validate passwords'),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import re
|
||||
import copy
|
||||
from collections import OrderedDict
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -15,10 +16,10 @@ from django.contrib.auth import forms as auth_forms, get_user_model, REDIRECT_FI
|
|||
from django.core.mail import send_mail
|
||||
from django.core import signing
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import RegexValidator
|
||||
|
||||
from .widgets import CheckPasswordInput, NewPasswordInput
|
||||
from .. import app_settings, compat, forms, utils, validators, models, middleware, hooks
|
||||
from authentic2.a2_rbac.models import OrganizationalUnit
|
||||
|
||||
|
@ -115,10 +116,11 @@ class RegistrationCompletionFormNoPassword(forms.BaseUserForm):
|
|||
|
||||
|
||||
class RegistrationCompletionForm(RegistrationCompletionFormNoPassword):
|
||||
password1 = CharField(widget=PasswordInput, label=_("Password"),
|
||||
validators=[validators.validate_password],
|
||||
help_text=validators.password_help_text())
|
||||
password2 = CharField(widget=PasswordInput, label=_("Password (again)"))
|
||||
|
||||
password1 = CharField(widget=NewPasswordInput(), label=_("Password"),
|
||||
validators=[validators.validate_password],
|
||||
help_text=validators.password_help_text())
|
||||
password2 = CharField(widget=CheckPasswordInput(), label=_("Password (again)"))
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
from django.forms import PasswordInput
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from .. import app_settings
|
||||
|
||||
|
||||
class BasePasswordInput(PasswordInput):
|
||||
"""
|
||||
a password Input with some features to help the user choosing a new password
|
||||
Inspired by Django >= 1.11 new-style rendering
|
||||
(cf. https://docs.djangoproject.com/fr/1.11/ref/forms/renderers)
|
||||
"""
|
||||
template_name = 'authentic2/widgets/assisted_password.html'
|
||||
features = {}
|
||||
|
||||
class Media:
|
||||
js = ('authentic2/js/password.js',)
|
||||
css = {
|
||||
'all': ('authentic2/css/password.css',)
|
||||
}
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
"""
|
||||
Base get_context
|
||||
"""
|
||||
context = {
|
||||
'app_settings': {
|
||||
'A2_PASSWORD_POLICY_MIN_LENGTH': app_settings.A2_PASSWORD_POLICY_MIN_LENGTH,
|
||||
'A2_PASSWORD_POLICY_MIN_CLASSES': app_settings.A2_PASSWORD_POLICY_MIN_CLASSES,
|
||||
'A2_PASSWORD_POLICY_REGEX': app_settings.A2_PASSWORD_POLICY_REGEX,
|
||||
},
|
||||
'features': self.features
|
||||
}
|
||||
# attach data-* attributes for password.js to activate events
|
||||
attrs.update(dict([('data-%s' % feat.replace('_', '-'), is_active) for feat, is_active in self.features.items()]))
|
||||
|
||||
context['widget'] = {
|
||||
'name': name,
|
||||
'is_hidden': self.is_hidden,
|
||||
'required': self.is_required,
|
||||
'template_name': self.template_name,
|
||||
'attrs': self.build_attrs(extra_attrs=attrs, name=name, type=self.input_type)
|
||||
}
|
||||
# Only add the 'value' attribute if a value is non-empty.
|
||||
if value is None:
|
||||
value = ''
|
||||
if value != '':
|
||||
context['widget']['value'] = force_text(self._format_value(value))
|
||||
|
||||
return context
|
||||
|
||||
def render(self, name, value, attrs=None, **kwargs):
|
||||
"""
|
||||
Override render with a template-based system
|
||||
Remove this line when dropping Django 1.8, 1.9, 1.10 compatibility
|
||||
"""
|
||||
return mark_safe(render_to_string(self.template_name,
|
||||
self.get_context(name, value, attrs)))
|
||||
|
||||
|
||||
class CheckPasswordInput(BasePasswordInput):
|
||||
"""
|
||||
Password typing assistance widget (eg. password2)
|
||||
"""
|
||||
features = {
|
||||
'check_equality': True,
|
||||
'show_all': app_settings.A2_PASSWORD_WIDGET_SHOW_ALL_BUTTON,
|
||||
'show_last': True,
|
||||
}
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super(CheckPasswordInput, self).get_context(
|
||||
name, value, attrs)
|
||||
return context
|
||||
|
||||
|
||||
class NewPasswordInput(CheckPasswordInput):
|
||||
"""
|
||||
Password creation assistance widget with policy (eg. password1)
|
||||
"""
|
||||
features = {
|
||||
'check_equality': False,
|
||||
'show_all': app_settings.A2_PASSWORD_WIDGET_SHOW_ALL_BUTTON,
|
||||
'show_last': True,
|
||||
'check_policy': True,
|
||||
}
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
context = super(NewPasswordInput, self).get_context(name, value, attrs)
|
||||
return context
|
|
@ -0,0 +1,140 @@
|
|||
/* required in order to position a2-password-show-all and a2-password-show-last */
|
||||
input[type=password].a2-password-assisted {
|
||||
padding-right: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.a2-password-icon {
|
||||
display: inline-block;
|
||||
width: calc(18em / 14);
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
/* default circle icon */
|
||||
.a2-password-icon:before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f111"; /* right hand icon */
|
||||
font-size: 50%;
|
||||
}
|
||||
|
||||
.a2-password-policy-helper {
|
||||
display: flex;
|
||||
height: auto;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
padding: 0.5rem 1rem;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
/* we don't want helptext when a2-password-policy-helper is here */
|
||||
.a2-password-policy-helper ~ .helptext {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.a2-password-policy-rule {
|
||||
flex: 1 1 50%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.password-error {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.password-ok {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.password-error .a2-password-icon:before {
|
||||
content: "\f00d"; /* cross icon */
|
||||
color: red;
|
||||
}
|
||||
|
||||
.password-ok .a2-password-icon::before {
|
||||
content: "\f00c"; /* ok icon */
|
||||
color: green;
|
||||
}
|
||||
|
||||
.a2-password-show-last {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
opacity: 0;
|
||||
text-align: center;
|
||||
right: 10px;
|
||||
top: -4.5ex;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.a2-password-show-button {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
padding: 0;
|
||||
right: 10px;
|
||||
top: -4.4ex;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.a2-password-show-button:after {
|
||||
content: "\f06e"; /* eye */
|
||||
font-family: FontAwesome;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.hide-password-button:after {
|
||||
content: "\f070"; /* crossed eye */
|
||||
font-family: FontAwesome;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.a2-passwords-messages {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.a2-passwords-default {
|
||||
list-style: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.password-error .a2-passwords-default,
|
||||
.password-ok .a2-passwords-default {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.a2-passwords-matched,
|
||||
.a2-passwords-unmatched {
|
||||
display: none;
|
||||
list-style: none;
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.password-error.a2-passwords-messages:before,
|
||||
.password-ok.a2-passwords-messages:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.password-error .a2-passwords-unmatched,
|
||||
.password-ok .a2-passwords-matched {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.password-error .a2-passwords-unmatched .a2-password-icon:before {
|
||||
content: "\f00d"; /* cross icon */
|
||||
color: red;
|
||||
}
|
||||
|
||||
.password-ok .a2-passwords-matched .a2-password-icon:before {
|
||||
content: "\f00c"; /* ok icon */
|
||||
color: green;
|
||||
}
|
||||
|
||||
.a2-password-policy-intro {
|
||||
margin: 0;
|
||||
}
|
|
@ -76,3 +76,22 @@
|
|||
.a2-log-message {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.a2-registration-completion {
|
||||
padding: 1rem;
|
||||
min-width: 320px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.a2-registration-completion {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.a2-registration-completion input,
|
||||
.a2-registration-completion select,
|
||||
.a2-registration-completion textarea
|
||||
{
|
||||
width: 100%;
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
"use strict";
|
||||
/* globals $, window, console */
|
||||
|
||||
$(function () {
|
||||
var debounce = function (func, milliseconds) {
|
||||
var timer;
|
||||
return function() {
|
||||
window.clearTimeout(timer);
|
||||
timer = window.setTimeout(function() {
|
||||
func();
|
||||
}, milliseconds);
|
||||
};
|
||||
}
|
||||
var toggleError = function($elt) {
|
||||
$elt.removeClass('password-ok');
|
||||
$elt.addClass('password-error');
|
||||
}
|
||||
var toggleOk = function($elt) {
|
||||
$elt.removeClass('password-error');
|
||||
$elt.addClass('password-ok');
|
||||
}
|
||||
/*
|
||||
* toggle error/ok on element with class names same as the validation code names
|
||||
* (cf. error_codes in authentic2.validators.validate_password)
|
||||
*/
|
||||
var validatePassword = function(event) {
|
||||
var $this = $(event.target);
|
||||
if (event.type == 'paste') {
|
||||
window.setTimeout(function() {
|
||||
$this.trigger('keyup');
|
||||
});
|
||||
return;
|
||||
}
|
||||
var password = $this.val();
|
||||
var inputName = $this.attr('name');
|
||||
getValidation(password, inputName);
|
||||
}
|
||||
var getValidation = function(password, inputName) {
|
||||
var policyContainer = $('#a2-password-policy-helper-' + inputName);
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '/api/validate-password/',
|
||||
data: JSON.stringify({'password': password}),
|
||||
dataType: 'json',
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
success: function(data) {
|
||||
if (data.result) {
|
||||
policyContainer
|
||||
.empty()
|
||||
.removeClass('password-error password-ok');
|
||||
data.checks.forEach(function (error) {
|
||||
var $li = $('<li class="a2-password-policy-rule"></li>')
|
||||
.html('<i class="a2-password-icon"></i>' + error.label)
|
||||
.appendTo(policyContainer);
|
||||
if (!error.result) {
|
||||
toggleError($li);
|
||||
} else {
|
||||
toggleOk($li);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
if (!password.length) {
|
||||
$('.a2-password-policy-rule').each(function() {
|
||||
$(this).removeClass('password-ok password-error');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
* Check password equality
|
||||
*/
|
||||
var displayPasswordEquality = function($input, $inputTarget) {
|
||||
var messages = $('#a2-password-equality-helper-' + $input.attr('name'));
|
||||
var form = $input.parents('form');
|
||||
if ($inputTarget === undefined) {
|
||||
$inputTarget = form.find('input[type=password]:not(input[name='+$input.attr('name')+'])');
|
||||
}
|
||||
if (!$input.val() || !$inputTarget.val()) {
|
||||
messages.removeClass('password-ok password-error');
|
||||
return;
|
||||
}
|
||||
if ($inputTarget.val() !== $input.val()) {
|
||||
toggleError(messages);
|
||||
} else {
|
||||
toggleOk(messages);
|
||||
}
|
||||
}
|
||||
var passwordEquality = function () {
|
||||
var $this = $(this);
|
||||
displayPasswordEquality($this);
|
||||
}
|
||||
/*
|
||||
* Hide and show password handlers
|
||||
*/
|
||||
var showPassword = function (event) {
|
||||
var $this = $(event.target);
|
||||
$this.addClass('hide-password-button');
|
||||
var name = $this.attr('id').split('a2-password-show-button-')[1];
|
||||
$('[name='+name+']').attr('type', 'text');
|
||||
event.preventDefault();
|
||||
}
|
||||
var hidePassword = function (event) {
|
||||
var $this = $(event.target);
|
||||
window.setTimeout(function () {
|
||||
$this.removeClass('hide-password-button');
|
||||
var name = $this.attr('id').split('a2-password-show-button-')[1];
|
||||
$('[name='+name+']').attr('type', 'password');
|
||||
}, 3000);
|
||||
}
|
||||
/*
|
||||
* Show the last character
|
||||
*/
|
||||
var showLastChar = function(event) {
|
||||
if (event.keyCode == 32 || event.key === undefined || event.key == ""
|
||||
|| event.key == "Unidentified" || event.key.length > 1) {
|
||||
return;
|
||||
}
|
||||
var duration = 1000;
|
||||
$('#a2-password-show-last-'+$(event.target).attr('name'))
|
||||
.text(event.key)
|
||||
.animate({'opacity': 1}, {
|
||||
duration: 50,
|
||||
queue: false,
|
||||
complete: function () {
|
||||
var $this = $(this);
|
||||
window.setTimeout(
|
||||
debounce(function () {
|
||||
$this.animate({'opacity': 0}, {
|
||||
duration: 50
|
||||
});
|
||||
}, duration), duration);
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
* Init events
|
||||
*/
|
||||
/* add password validation and equality check event handlers */
|
||||
$('form input[type=password]:not(input[data-check-policy])').each(function () {
|
||||
$('#a2-password-policy-helper-' + $(this).attr('name')).hide();
|
||||
});
|
||||
$('body').on('keyup paste', 'form input[data-check-policy]', validatePassword);
|
||||
$('body').on('keyup paste', 'form input[data-check-equality]', passwordEquality);
|
||||
/*
|
||||
* Add event to handle displaying error/OK
|
||||
* while editing the first password
|
||||
* only if the second one is not empty
|
||||
*/
|
||||
$('input[data-check-equality]')
|
||||
.each(function () {
|
||||
var $input2 = $(this);
|
||||
$('body')
|
||||
.on('keyup', 'form input[type=password]:not([name=' + $input2.attr('name') + '])',
|
||||
function (event) {
|
||||
var $input1 = $(event.target);
|
||||
if ($input2.val().length) {
|
||||
displayPasswordEquality($input2, $input1);
|
||||
}
|
||||
});
|
||||
});
|
||||
/* add the a2-password-show-button after the first input */
|
||||
$('input[data-show-all]')
|
||||
.each(function () {
|
||||
var $this = $(this);
|
||||
if (!$('#a2-password-show-button-' + $this.attr('name')).length) {
|
||||
$(this).after($('<i class="a2-password-show-button" id="a2-password-show-button-'
|
||||
+ $this.attr('name') + '"></i>')
|
||||
.on('mousedown', showPassword)
|
||||
.on('mouseup mouseleave', hidePassword)
|
||||
);
|
||||
}
|
||||
});
|
||||
/* show the last character on keypress */
|
||||
$('input[data-show-last]')
|
||||
.each(function () {
|
||||
var $this = $(this);
|
||||
if (!$('#a2-password-show-last-' + $this.attr('name')).length) {
|
||||
// on crée un div placé dans le padding-right de l'input
|
||||
var $span = $('<span class="a2-password-show-last" id="a2-password-show-last-'
|
||||
+ $this.attr('name') + '"></span>)')
|
||||
$span.css({
|
||||
'font-size': $this.css('font-size'),
|
||||
'font-family': $this.css('font-family'),
|
||||
'line-height': parseInt($this.css('line-height').replace('px', '')) - parseInt($this.css('padding-bottom').replace('px', '')) + 'px',
|
||||
'vertical-align': $this.css('vertical-align'),
|
||||
'padding-top': $this.css('padding-top'),
|
||||
'padding-bottom': $this.css('padding-bottom')
|
||||
});
|
||||
$this.after($span);
|
||||
}
|
||||
});
|
||||
$('body').on('keyup', 'form input[data-show-last]', showLastChar);
|
||||
});
|
|
@ -9,10 +9,12 @@
|
|||
{{ block.super }}
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}authentic2/css/style.css" />
|
||||
{% renderblock "css" %}
|
||||
{{ form.media.css }}
|
||||
{% endblock %}
|
||||
|
||||
{% block extrascripts %}
|
||||
{{ block.super }}
|
||||
{{ form.media.js }}
|
||||
{% comment %}block extra_scripts is kept for compatibility with old themes{% endcomment %}
|
||||
{% block extra_scripts %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
{% load i18n %}
|
||||
<input class="a2-password-assisted" {% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "authentic2/widgets/attrs.html" %}>
|
||||
{% if features.check_policy %}
|
||||
<p class="a2-password-policy-intro">{% blocktrans %}In order to create a secure password, please use <i>at least</i> : {% endblocktrans %}</p>
|
||||
<ul class="a2-password-policy-helper" id="a2-password-policy-helper-{{ widget.attrs.name }}">
|
||||
{% comment %}Required to display the initial rules on page load{% endcomment %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_MIN_LENGTH %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% blocktrans with A2_PASSWORD_POLICY_MIN_LENGTH=app_settings.A2_PASSWORD_POLICY_MIN_LENGTH %}{{ A2_PASSWORD_POLICY_MIN_LENGTH }} characters{% endblocktrans %}</li>
|
||||
{% endif %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_MIN_CLASSES > 0 %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% trans "1 lowercase letter" %}</li>
|
||||
{% endif %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_MIN_CLASSES > 1 %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% trans "1 digit" %}</li>
|
||||
{% endif %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_MIN_CLASSES > 2 %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% trans "1 uppercase letter" %}</li>
|
||||
{% endif %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_REGEX %}
|
||||
{% if app_settings.A2_PASSWORD_POLICY_REGEX_ERROR_MSG %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% blocktrans with A2_PASSWORD_POLICY_REGEX_ERROR_MSG=app_settings.A2_PASSWORD_POLICY_REGEX_ERROR_MSG %}{{ A2_PASSWORD_POLICY_REGEX_ERROR_MSG }}{% endblocktrans %}</li>
|
||||
{% else %}
|
||||
<li class="a2-password-policy-rule"><i class="a2-password-icon"></i>{% blocktrans with A2_PASSWORD_POLICY_REGEX=app_settings.A2_PASSWORD_POLICY_REGEX %}Match the regular expression: {{ A2_PASSWORD_POLICY_REGEX }}, please change this message using the A2_PASSWORD_POLICY_REGEX_ERROR_MSG setting.'{% endblocktrans %}</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if features.check_equality %}
|
||||
<ul class="a2-passwords-messages" id="a2-password-equality-helper-{{ widget.attrs.name }}">
|
||||
<li class="a2-passwords-default"><i class="a2-password-icon"></i>{% trans 'Both passwords must match.' %}</li>
|
||||
<li class="a2-passwords-matched"><i class="a2-password-icon"></i>{% trans 'Passwords match.' %}</li>
|
||||
<li class="a2-passwords-unmatched"><i class="a2-password-icon"></i>{% trans 'Passwords do not match.' %}</li>
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -0,0 +1,2 @@
|
|||
{% comment %}Will be deprecated in Django 1.11 : replace with django/forms/widgets/attrs.html{% endcomment %}
|
||||
{% for name, value in widget.attrs.items %}{% if value != False %} {{ name }}{% if value != True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}
|
|
@ -4,12 +4,10 @@
|
|||
|
||||
{% block css %}
|
||||
{{ block.super }}
|
||||
{{ form.media.css }}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
{{ block.super }}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -25,7 +23,7 @@
|
|||
{% block content %}
|
||||
<h2>{% trans "Registration" %}</h2>
|
||||
<p>{% trans "Please fill the form to complete your registration" %}</p>
|
||||
<form method="post">
|
||||
<form method="post" class="a2-registration-completion">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button class="submit-button">{% trans 'Submit' %}</button>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from urlparse import urlparse
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
@ -585,3 +586,49 @@ def test_registration_redirect_tuple(app, db, settings, mailoutbox, external_red
|
|||
response = response.form.submit()
|
||||
assert new_next_url in response.content
|
||||
|
||||
|
||||
def test_registration_activate_passwords_not_equal(app, db, settings, mailoutbox):
|
||||
settings.LANGUAGE_CODE = 'en-us'
|
||||
settings.A2_VALIDATE_EMAIL_DOMAIN = can_resolve_dns()
|
||||
settings.A2_EMAIL_IS_UNIQUE = True
|
||||
|
||||
response = app.get(reverse('registration_register'))
|
||||
response.form.set('email', 'testbot@entrouvert.com')
|
||||
response = response.form.submit()
|
||||
response = response.follow()
|
||||
link = get_link_from_mail(mailoutbox[0])
|
||||
response = app.get(link)
|
||||
response.form.set('password1', 'azerty12AZ')
|
||||
response.form.set('password2', 'AAAazerty12AZ')
|
||||
response = response.form.submit()
|
||||
assert "The two password fields didn't match." in response.content
|
||||
|
||||
|
||||
def test_registration_activate_assisted_password(app, db, settings, mailoutbox):
|
||||
response = app.get(reverse('registration_register'))
|
||||
response.form.set('email', 'testbot@entrouvert.com')
|
||||
response = response.form.submit()
|
||||
response = response.follow()
|
||||
link = get_link_from_mail(mailoutbox[0])
|
||||
response = app.get(link)
|
||||
# check presence of the script and css for RegistrationCompletionForm to work
|
||||
assert "password.js" in response.content
|
||||
assert "password.css" in response.content
|
||||
# check default attributes for password.js and css to work
|
||||
assert re.search('<input class="a2-password-assisted".*data-show-last.*>', response.content, re.I | re.M | re.S)
|
||||
assert re.search('<input class="a2-password-assisted".*data-check-equality.*>', response.content, re.I | re.M | re.S)
|
||||
assert re.search('<input class="a2-password-assisted".*data-check-policy.*>', response.content, re.I | re.M | re.S)
|
||||
# check template containers for password.js to display its results
|
||||
assert re.search('class="a2-passwords-messages" id="a2-password-equality-helper-', response.content, re.I | re.M | re.S)
|
||||
assert re.search('class="a2-password-policy-helper" id="a2-password-policy-helper-', response.content, re.I | re.M | re.S)
|
||||
assert re.search('class="a2-password-policy-rule"', response.content, re.I | re.M | re.S)
|
||||
|
||||
|
||||
def test_registration_activate_password_no_show_all_button(app, db, settings, mailoutbox):
|
||||
response = app.get(reverse('registration_register'))
|
||||
response.form.set('email', 'testbot@entrouvert.com')
|
||||
response = response.form.submit()
|
||||
response = response.follow()
|
||||
link = get_link_from_mail(mailoutbox[0])
|
||||
response = app.get(link)
|
||||
assert not re.search('<input class="a2-password-assisted".*data-show-all.*>', response.content, re.I | re.M | re.S)
|
Loading…
Reference in New Issue