Registration refactored: email validation done first and registration process
finished on profile completion. django-registration removed
This commit is contained in:
parent
f133797268
commit
efa4305df0
|
@ -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',
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -180,7 +180,6 @@ INSTALLED_APPS = (
|
|||
'admin_tools.menu',
|
||||
'admin_tools.dashboard',
|
||||
'django.contrib.admin',
|
||||
'registration',
|
||||
'django_select2',
|
||||
'django_tables2',
|
||||
'authentic2.nonce',
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
|
@ -1,6 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% trans "Your account is now activated" %}
|
||||
{% endblock %}
|
|
@ -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>
|
|
@ -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 %}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{% load i18n %}{% trans "Account activation on" %} {{ site.name }}
|
||||
{% load i18n %}{% trans "Account activation on" %} {{ site }}
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<h2>{% trans "Registration" %}</h2>
|
||||
|
||||
<form method="post" action=".">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue