Registration refactored: email validation done first and registration process

finished on profile completion.

django-registration removed
This commit is contained in:
Serghei Mihai 2014-11-18 17:23:26 +01:00
parent f133797268
commit efa4305df0
25 changed files with 383 additions and 269 deletions

View File

@ -90,6 +90,8 @@ default_settings = dict(
definition='Root urlconf for the /accounts endpoints'),
A2_REGISTRATION_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.RegistrationForm',
definition='Default registration form'),
A2_REGISTRATION_COMPLETION_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.RegistrationCompletionForm',
definition='Default registration completion form'),
A2_REGISTRATION_SET_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.SetPasswordForm',
definition='Default set password form'),
A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.PasswordChangeForm',

View File

@ -19,7 +19,7 @@ from django.contrib.auth import authenticate, login
from django.contrib.auth import REDIRECT_FIELD_NAME
import registration.views
from authentic2.registration_backend.views import RegistrationView
from authentic2.constants import NONCE_FIELD_NAME
@ -188,7 +188,7 @@ error_ssl = SslErrorView.as_view()
def register(request):
'''Registration page for SSL auth without CA'''
next_url = request.GET.get(REDIRECT_FIELD_NAME, settings.LOGIN_REDIRECT_URL)
return registration.views.register(request, success_url=next_url,
form_class=functools.partial(forms.RegistrationForm,
request=request))
return RegistrationView.as_view(request, success_url=next_url,
form_class=functools.partial(forms.RegistrationForm,
request=request))

View File

@ -1,4 +1,13 @@
from django.conf.urls import patterns, url
from django.contrib.auth import views as auth_views
from authentic2.utils import get_form_class
from . import app_settings
SET_PASSWORD_FORM_CLASS = get_form_class(
app_settings.A2_REGISTRATION_SET_PASSWORD_FORM_CLASS)
CHANGE_PASSWORD_FORM_CLASS = get_form_class(
app_settings.A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS)
urlpatterns = patterns('authentic2.views',
url(r'^logged-in/$', 'logged_in', name='logged-in'),
@ -7,4 +16,24 @@ urlpatterns = patterns('authentic2.views',
url(r'^change-email/verify/$', 'email_change_verify',
name='email-change-verify'),
url(r'^$', 'profile', name='account_management'),
url(r'^password/change/$',
auth_views.password_change,
{'password_change_form': CHANGE_PASSWORD_FORM_CLASS},
name='auth_password_change'),
url(r'^password/change/done/$',
auth_views.password_change_done,
name='auth_password_change_done'),
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.password_reset_confirm,
{'set_password_form': SET_PASSWORD_FORM_CLASS},
name='auth_password_reset_confirm'),
url(r'^password/reset/$',
auth_views.password_reset,
name='auth_password_reset'),
url(r'^password/reset/complete/$',
auth_views.password_reset_complete,
name='auth_password_reset_complete'),
url(r'^password/reset/done/$',
auth_views.password_reset_done,
name='auth_password_reset_done'),
)

View File

@ -1,60 +0,0 @@
from django.conf import settings
from django.template.loader import render_to_string
from registration.models import RegistrationProfile
def send_activation_email(self, site):
"""
Send an activation email to the user associated with this
``RegistrationProfile``.
The activation email will make use of two templates:
``registration/activation_email_subject.txt``
This template will be used for the subject line of the
email. Because it is used as the subject line of an email,
this template's output **must** be only a single line of
text; output longer than one line will be forcibly joined
into only a single line.
``registration/activation_email.txt``
This template will be used for the body of the email.
These templates will each receive the following context
variables:
``user``
The new user account
``activation_key``
The activation key for the new account.
``expiration_days``
The number of days remaining during which the account may
be activated.
``site``
An object representing the site on which the user
registered; depending on whether ``django.contrib.sites``
is installed, this may be an instance of either
``django.contrib.sites.models.Site`` (if the sites
application is installed) or
``django.contrib.sites.models.RequestSite`` (if
not). Consult the documentation for the Django sites
framework for details regarding these objects' interfaces.
"""
ctx_dict = {'activation_key': self.activation_key,
'user': self.user,
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
'site': site}
subject = render_to_string('registration/activation_email_subject.txt',
ctx_dict)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
message = render_to_string('registration/activation_email.txt',
ctx_dict)
self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
RegistrationProfile.send_activation_email = send_activation_email

View File

@ -1,15 +1,72 @@
from uuid import uuid
import django
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.forms import Form, CharField, PasswordInput, EmailField
from django.utils.datastructures import SortedDict
from django.db.models import FieldDoesNotExist
from django.contrib.auth.models import BaseUserManager, Group
from django.contrib.auth import forms as auth_forms
from django.core.mail import send_mail
from django.core import signing
from django import get_version
from django.template.loader import render_to_string
from django.core.urlresolvers import reverse
from .. import app_settings, compat, forms, utils, validators, widgets, fields
from .. import app_settings, compat, forms, utils,\
validators, widgets, fields, models
User = compat.get_user_model()
class RegistrationForm(forms.UserAttributeFormMixin, Form):
class RegistrationForm(Form):
error_css_class = 'form-field-error'
required_css_class = 'form-field-required'
email = EmailField()
def clean_email(self):
"""
Verify if email is unique
"""
User = compat.get_user_model()
if app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE and \
User.objects.filter(email__iexact=self.cleaned_data['email']).exists():
raise ValidationError(_('This email address is already in '
'use. Please supply a different email address.'))
return self.cleaned_data['email']
def save(self, request):
data = self.cleaned_data
data.update({'next_url': request.GET.get('next_url')})
registration_token = signing.dumps(data)
ctx_dict = {'registration_url': request.build_absolute_uri(
reverse('registration_activate',
kwargs={'registration_token': registration_token})),
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
'email': data['email'],
'site': request.get_host()}
ctx_dict.update(self.cleaned_data)
subject = render_to_string('registration/activation_email_subject.txt',
ctx_dict)
subject = ''.join(subject.splitlines())
message = render_to_string('registration/activation_email.txt',
ctx_dict)
if django.VERSION >= (1, 7, 0):
html_message = render_to_string('registration/activation_email.html',
ctx_dict)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[data['email']], fail_silently=True,
html_message=message)
else:
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[data['email']], fail_silently=True)
class RegistrationCompletionForm(forms.UserAttributeFormMixin, Form):
error_css_class = 'form-field-error'
required_css_class = 'form-field-required'
@ -21,7 +78,7 @@ class RegistrationForm(forms.UserAttributeFormMixin, Form):
"""
Inject required fields in registration form
"""
super(RegistrationForm, self).__init__(*args, **kwargs)
super(RegistrationCompletionForm, self).__init__(*args, **kwargs)
User = compat.get_user_model()
insert_idx = 0
field_names = compat.get_registration_fields()
@ -38,7 +95,7 @@ class RegistrationForm(forms.UserAttributeFormMixin, Form):
kwargs['validators'] = model_field.validators
field = model_field.formfield(**kwargs)
if isinstance(field, EmailField):
field = fields.EmailFieldWithValidation(**kwargs)
continue
self.fields.insert(insert_idx, field_name, field)
insert_idx += 1
for field_name in self.fields:
@ -64,6 +121,7 @@ class RegistrationForm(forms.UserAttributeFormMixin, Form):
self.fields['username'].help_text = app_settings.A2_REGISTRATION_FORM_USERNAME_HELP_TEXT
self.fields['username'].label = app_settings.A2_REGISTRATION_FORM_USERNAME_LABEL
def clean_username(self):
"""
Validate that the username is alphanumeric and is not already
@ -82,17 +140,6 @@ class RegistrationForm(forms.UserAttributeFormMixin, Form):
else:
return self.cleaned_data['username']
def clean_email(self):
"""
Verify if email is unique
"""
User = compat.get_user_model()
if app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE:
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise ValidationError(_('This email address is already in '
'use. Please supply a different email address.'))
return self.cleaned_data['email']
def clean(self):
"""
Verifiy that the values entered into the two password fields
@ -105,6 +152,33 @@ class RegistrationForm(forms.UserAttributeFormMixin, Form):
raise ValidationError(_("The two password fields didn't match."))
return self.cleaned_data
def save(self, *args, **kwargs):
user_fields = {}
for field in compat.get_registration_fields():
# save User model fields
try:
User._meta.get_field(field)
except FieldDoesNotExist:
continue
if field.startswith('password'):
continue
user_fields[field] = kwargs[field]
if field == 'email':
user_fields[field] = BaseUserManager.normalize_email(kwargs[field])
new_user = User(is_active=True, **user_fields)
new_user.clean()
new_user.set_password(kwargs['password1'])
new_user.save()
if app_settings.A2_REGISTRATION_GROUPS:
groups = []
for name in app_settings.A2_REGISTRATION_GROUPS:
group, created = Group.objects.get_or_create(name=name)
groups.append(group)
new_user.groups = groups
return new_user, kwargs['next_url']
class SetPasswordForm(auth_forms.SetPasswordForm):
new_password1 = CharField(label=_("New password"),
widget=PasswordInput,

View File

@ -1,71 +1,38 @@
from django.conf.urls import patterns
from django.conf.urls import url
from django.utils.importlib import import_module
from django.contrib.auth import views as auth_views
from django.views.generic.base import TemplateView
from django.contrib.auth.decorators import login_required
from .views import RegistrationView, RegistrationCompletionView, DeleteView,\
LoginView, RegistrationCreateView
from .. import app_settings
from registration.backends.default.views import ActivationView
from .. import decorators
def get_form_class(form_class):
module, form_class = form_class.rsplit('.', 1)
module = import_module(module)
return getattr(module, form_class)
SET_PASSWORD_FORM_CLASS = get_form_class(
app_settings.A2_REGISTRATION_SET_PASSWORD_FORM_CLASS)
CHANGE_PASSWORD_FORM_CLASS = get_form_class(
app_settings.A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS)
password_change_view = decorators.setting_enabled(
'A2_REGISTRATION_CAN_CHANGE_PASSWORD')(auth_views.password_change)
urlpatterns = patterns('authentic2.registration_backend.views',
url(r'^activate/complete/$',
TemplateView.as_view(template_name='registration/activation_complete.html'),
name='registration_activation_complete'),
# Activation keys get matched by \w+ instead of the more specific
# [a-fA-F0-9]{40} because a bad activation key should still get to the view;
# that way it can return a sensible "invalid key" message instead of a
# confusing 404.
url(r'^activate/(?P<activation_key>\w+)/$',
ActivationView.as_view(),
name='registration_activate'),
url(r'^register/$',
'register',
name='registration_register'),
url(r'^register/complete/$',
TemplateView.as_view(template_name='registration/registration_complete.html'),
name='registration_complete'),
url(r'^register/closed/$',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'),
url(r'^password/change/$', password_change_view,
{'password_change_form': CHANGE_PASSWORD_FORM_CLASS},
name='auth_password_change'),
url(r'^password/change/done/$',
auth_views.password_change_done,
name='auth_password_change_done'),
url(r'^password/reset/$',
auth_views.password_reset,
name='auth_password_reset'),
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.password_reset_confirm,
{'set_password_form': SET_PASSWORD_FORM_CLASS},
name='auth_password_reset_confirm'),
url(r'^password/reset/complete/$',
auth_views.password_reset_complete,
name='auth_password_reset_complete'),
url(r'^password/reset/done/$',
auth_views.password_reset_done,
name='auth_password_reset_done'),
url(r'^delete/$',
'delete',
name='delete_account'),
)
urlpatterns = patterns('',
url(r'^activate/expired/$',
TemplateView.as_view(template_name='registration/activation_expired.html'),
name='registration_activation_expired'),
url(r'^activate/failed/$',
TemplateView.as_view(template_name='registration/activation_failed.html'),
name='registration_activation_failed'),
url(r'^activate/(?P<registration_token>[\w:-]+)/$',
RegistrationCompletionView.as_view(),
name='registration_activate'),
url(r'^create/(?P<registration_token>[\w:-]+)/$',
RegistrationCreateView.as_view(),
name='registration_create'),
url(r'^activate/(?P<registration_token>[\w:-]+)/(?P<username>\w+)$',
LoginView.as_view(),
name='registration_login'),
url(r'^register/$',
RegistrationView.as_view(),
name='registration_register'),
url(r'^register/complete/$',
TemplateView.as_view(template_name='registration/registration_complete.html'),
name='registration_complete'),
url(r'^register/closed/$',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'),
url(r'^delete/$',
login_required(DeleteView.as_view()),
name='delete_account'),
)

View File

@ -1,104 +1,117 @@
import logging
from datetime import datetime
from django.conf import settings
from django.shortcuts import redirect, render
from django.utils.translation import ugettext as _
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import RequestSite
from django.contrib.sites.models import Site
from django.contrib.auth.models import BaseUserManager, Group
from django.conf import settings
from django.contrib.auth import authenticate, login as django_login, logout
from django.db.models import FieldDoesNotExist
from django.db import IntegrityError
from django.template.loader import render_to_string
from django.core import signing
from django.views.generic.edit import FormView
from django.views.generic.base import TemplateView, View
from registration.views import RegistrationView as BaseRegistrationView
from registration.models import RegistrationProfile
from registration import signals
from authentic2.utils import get_form_class
from .. import models, app_settings, compat
from . import urls
logger = logging.getLogger(__name__)
User = compat.get_user_model()
class RegistrationView(BaseRegistrationView):
form_class = urls.get_form_class(app_settings.A2_REGISTRATION_FORM_CLASS)
def valid_token(method):
def f(obj, *args, **kwargs):
try:
registration_kwargs = signing.loads(kwargs['registration_token'],
max_age=settings.ACCOUNT_ACTIVATION_DAYS*3600*24)
params = kwargs.copy()
params.update(registration_kwargs)
except signing.SignatureExpired:
return redirect('registration_activation_expired')
except signing.BadSignature:
return redirect('registration_activation_failed')
return method(obj, *args, **params)
return f
def register(self, request, **cleaned_data):
User = compat.get_user_model()
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
user_fields = {}
for field in compat.get_registration_fields():
# save User model fields
def login(request, user, redirect_url='auth_homepage'):
user.backend = 'authentic2.backends.ModelBackend'
django_login(request, user)
return redirect(redirect_url)
class LoginView(View):
redirect_url = 'auth_homepage'
@valid_token
def get(self, request, *args, **kwargs):
try:
user = User.objects.get(email=kwargs['email'], username=kwargs['username'])
return login(request, user)
except User.DoesNotExist:
return redirect(self.redirect_url)
class RegistrationView(FormView):
form_class = get_form_class(app_settings.A2_REGISTRATION_FORM_CLASS)
template_name = 'registration/registration_form.html'
def form_valid(self, form):
form.save(self.request)
return redirect('registration_complete')
class RegistrationCompletionView(FormView):
form_class = get_form_class(app_settings.A2_REGISTRATION_COMPLETION_FORM_CLASS)
http_method_names = ['get', 'post']
template_name = 'registration/registration_completion_form.html'
@valid_token
def get(self, request, *args, **kwargs):
if app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE:
try:
User._meta.get_field(field)
except FieldDoesNotExist:
continue
if field.startswith('password'):
continue
user_fields[field] = cleaned_data[field]
if field == 'email':
user_fields[field] = BaseUserManager.normalize_email(user_fields[field])
new_user = User(is_active=False, **user_fields)
new_user.clean()
new_user.set_password(cleaned_data['password1'])
new_user.save()
attributes = models.Attribute.objects.filter(
asked_on_registration=True)
if attributes:
for attribute in attributes:
attribute.set_value(new_user, cleaned_data[attribute.name])
if app_settings.A2_REGISTRATION_GROUPS:
groups = []
for name in app_settings.A2_REGISTRATION_GROUPS:
group, created = Group.objects.get_or_create(name=name)
groups.append(group)
new_user.groups = groups
registration_profile = RegistrationProfile.objects.create_profile(new_user)
registration_profile.send_activation_email(site)
user = User.objects.get(email__iexact=kwargs['email'])
except User.DoesNotExist:
return super(RegistrationCompletionView, self).get(request, *args, **kwargs)
return login(request, user)
else:
user_accounts = User.objects.filter(email__iexact=kwargs['email'])
if user_accounts:
logout(request)
context = kwargs.copy()
context.update({'accounts': user_accounts})
self.template_name = 'registration/login_choices.html'
return self.render_to_response(context)
else:
return super(RegistrationCompletionView, self).get(request, *args, **kwargs)
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=request)
return new_user
@valid_token
def post(self, request, *args, **kwargs):
form = self.get_form(self.form_class)
if form.is_valid():
params = form.cleaned_data.copy()
params.update(kwargs)
user, next_url = form.save(**params)
if next_url:
return login(request, user, next_url)
return login(request, user)
else:
return self.form_invalid(form)
def registration_allowed(self, request):
"""
Indicate whether account registration is currently permitted,
based on the value of the setting ``REGISTRATION_OPEN``. This
is determined as follows:
class RegistrationCreateView(RegistrationCompletionView):
* If ``REGISTRATION_OPEN`` is not specified in settings, or is
set to ``True``, registration is permitted.
@valid_token
def get(self, request, *args, **kwargs):
return super(RegistrationCompletionView, self).get(request, *args, **kwargs)
* If ``REGISTRATION_OPEN`` is both specified and set to
``False``, registration is not permitted.
"""
return getattr(settings, 'REGISTRATION_OPEN', True)
class DeleteView(TemplateView):
def get(self, request, *args, **kwargs):
next_url = request.build_absolute_uri(request.META.get('HTTP_REFERER')\
or request.GET.get('next_url'))
if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT:
return redirect(next_url)
return render(request, 'registration/delete_account.html')
def get_success_url(self, request, user):
"""
Return the name of the URL to redirect to after successful
user registration.
"""
return ('registration_complete', (), {})
register = RegistrationView.as_view()
@login_required
def delete(request, next_url='/'):
next_url = request.build_absolute_uri(request.META.get('HTTP_REFERER') or next_url)
if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT:
return redirect(next_url)
if request.method == 'POST':
def post(self, request, *args, **kwargs):
next_url = request.build_absolute_uri(request.META.get('HTTP_REFERER')\
or request.GET.get('next_url'))
if 'submit' in request.POST:
models.DeletedUser.objects.delete_user(request.user)
logger.info(u'deletion of account %s requested' % request.user)
@ -106,4 +119,3 @@ def delete(request, next_url='/'):
return redirect('auth_logout')
else:
return redirect(next_url)
return render(request, 'registration/delete_account.html')

View File

@ -180,7 +180,6 @@ INSTALLED_APPS = (
'admin_tools.menu',
'admin_tools.dashboard',
'django.contrib.admin',
'registration',
'django_select2',
'django_tables2',
'authentic2.nonce',

View File

@ -15,6 +15,6 @@
<p>→ {% trans "Forgot password?" %} <a href="{% url 'auth_password_reset' %}">{% trans "Reset it!" %}</a></p>
{% endif %}
{% if registration_authorized %}
<p>→ {% trans "Not a member?" %} <a href="{% url 'registration_register' %}">{% trans "Register!" %}</a></p>
<p>→ {% trans "Not a member?" %} <a href="{% url 'registration_register' %}?{{ request.GET.urlencode }}">{% trans "Register!" %}</a></p>
{% endif %}
</div>

View File

@ -1,22 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}
{% trans "Account activation" %}
{% endblock %}
{% block content %}
{% if account %}
<p>{% trans "Account successfully activated" %}</p>
<p><a href="{% url 'auth_login' %}">{% trans "Log in" %}</a></p>
{% else %}
<p>{% trans "Account activation failed" %}</p>
{% endif %}
{% endblock %}

View File

@ -1,6 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
{% trans "Your account is now activated" %}
{% endblock %}

View File

@ -0,0 +1,8 @@
{% load i18n %}
<h3>{% trans "Account creation" %}</h3>
<p>
{% blocktrans %}
To continue your account creation on {{ site }} please <a href="{{ site }}{{ registration_token }}">click here</a>
{% endblocktrans %}
</p>
<p>{% blocktrans %}This link is valid for {{ expiration_days }} days.{% endblocktrans %}</p>

View File

@ -1,6 +1,6 @@
{% load i18n %}
{% trans "Activate account at" %} {{ site.name }}:
{% trans "Activate account" %}:
http://{{ site.domain }}{% url 'registration_activate' activation_key %}
{{ registration_url }}
{% blocktrans %}Link is valid for {{ expiration_days }} days.{% endblocktrans %}

View File

@ -1 +1 @@
{% load i18n %}{% trans "Account activation on" %} {{ site.name }}
{% load i18n %}{% trans "Account activation on" %} {{ site }}

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}
{% trans "Account activation expired" %}
{% endblock %}
{% block content %}
<h2>{% trans "Account activation" %}</h2>
<p>{% trans "Your activation key is expired" %}</p>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}
{% trans "Account activation failed" %}
{% endblock %}
{% block content %}
<h2>{% trans "Account activation" %}</h2>
<p>{% trans "Activation failed" %}</p>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends "base.html" %}
{% load breadcrumbs i18n %}
{% block title %}
{% trans "Login" %}
{% endblock %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb_url 'Register' %}
{% endblock %}
{% block content %}
<h2>{% trans "Login" %}</h2>
<p>{% trans "Multiple accounts are associated to this email." %}
{% trans "Please choose the account you want to log in with:" %}
</p>
<ul>
{% for account in accounts %}
<li><a href="{% url "registration_login" registration_token account.username %}">{{ account }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -6,6 +6,6 @@
{% endblock %}
{% block content %}
<p>{% trans "You are now registered. Activation email sent." %}</p>
<p>{% trans "Thank you for registering. Activation email sent." %}</p>
<p><a href="/">{% trans "Back" %}</a></p>
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}
{% trans "Registration" %}
{% endblock %}
{% load breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb_url 'Register' %}
{% endblock %}
{% block content %}
<h2>{% trans "Registration" %}</h2>
<p>{% trans "Please fill the formm to complete your registration" %}</p>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
{% endblock %}

View File

@ -15,7 +15,7 @@
<h2>{% trans "Registration" %}</h2>
<form method="post" action=".">
<form method="post">
{% csrf_token %}
{{ form.as_p }}

View File

@ -1,6 +1,12 @@
from django.test import TestCase
import re
from django.core import mail
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
from django.contrib.auth.hashers import check_password
from django.conf import settings
from . import hashers
@ -88,3 +94,36 @@ class SerializerTests(TestCase):
self.assertEqual(User.objects.count(), 1)
self.assertEqual(Attribute.objects.count(), 1)
self.assertEqual(AttributeValue.objects.count(), 1)
class RegistrationTests(TestCase):
def setUp(self):
self.client = Client()
def test_registration(self):
response = self.client.post(reverse('registration_register'),
{'email': 'testbot@entrouvert.com'})
self.assertRedirects(response, reverse('registration_complete'))
self.assertEqual(len(mail.outbox), 1)
links = re.findall('http[s]://.*/', mail.outbox[0].body)
self.assertIsInstance(links, list) and self.assertIsNot(links, [])
link = links[0]
completion = self.client.get(link)
self.assertEqual(completion.status_code, 200)
self.bad_password_test(link)
self.good_password_test(link)
mail.outbox = []
def bad_password_test(self, url):
"""
test short filled password
"""
completion = self.client.post(url, {'username': 'toto',
'password1': 'toto',
'password2': 'toto'})
self.assertEqual(completion.status_code, 200)
def good_password_test(self, url):
completion = self.client.post(url, {'username': 'toto',
'password1': 'T0toto',
'password2': 'T0toto'})
self.assertEqual(completion.status_code, 302)

View File

@ -206,3 +206,8 @@ def field_names(list_of_field_name_and_titles):
yield t
else:
yield t[0]
def get_form_class(form_class):
module, form_class = form_class.rsplit('.', 1)
module = import_module(module)
return getattr(module, form_class)

View File

@ -19,7 +19,3 @@ except ImportError:
raise
print 'django_authopenid is missing: easy_install django-authopenid'
try:
import registration
except ImportError:
print 'registration is missing: easy_install django-registration'

View File

@ -2,7 +2,6 @@ Django<1.6
south>=0.8.4
requests
django-model-utils
django-registration>=1
django-debug-toolbar>=1.2,<1.3
--allow-external django-admin-tools
--allow-unverified django-admin-tools

View File

@ -117,7 +117,6 @@ setup(name="authentic2",
'south>=0.8.4',
'requests',
'django-model-utils',
'django-registration>=1',
'django-admin-tools>=0.5.1',
'dnspython',
'django-select2',