From 551482faa947d5f94e4bec7d831d5d50eb46f942 Mon Sep 17 00:00:00 2001 From: Serghei MIHAI Date: Thu, 11 Sep 2014 01:29:47 +0200 Subject: [PATCH 1/3] Registration process refactored, django-registration removed. --- authentic2/registration_backend/urls.py | 98 ++++++++++----------- authentic2/registration_backend/views.py | 109 +++++++++++++----------- authentic2/templates/registration/activate.html | 6 ++ authentic2/urls.py | 2 + authentic2/utils.py | 5 ++ requirements.txt | 1 - setup.py | 1 - 7 files changed, 118 insertions(+), 104 deletions(-) diff --git a/authentic2/registration_backend/urls.py b/authentic2/registration_backend/urls.py index f5754e1..135143e 100644 --- a/authentic2/registration_backend/urls.py +++ b/authentic2/registration_backend/urls.py @@ -4,17 +4,9 @@ from django.utils.importlib import import_module from django.contrib.auth import views as auth_views from django.views.generic.base import TemplateView - +from authentic2.utils import get_form_class from .. import app_settings - -from registration.backends.default.views import ActivationView - - -def get_form_class(form_class): - module, form_class = form_class.rsplit('.', 1) - module = import_module(module) - return getattr(module, form_class) - +from .views import RegistrationView, ActivationView SET_PASSWORD_FORM_CLASS = get_form_class( app_settings.A2_REGISTRATION_SET_PASSWORD_FORM_CLASS) @@ -23,46 +15,46 @@ CHANGE_PASSWORD_FORM_CLASS = get_form_class( 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\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/$', - 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/$', - auth_views.password_reset, - name='auth_password_reset'), - url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', - 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'), - ) + 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[\w:-]+)/$', + ActivationView.as_view(), + name='registration_activate'), + 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'^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[0-9A-Za-z]+)-(?P.+)/$', + auth_views.password_reset_confirm, + {'set_password_form': SET_PASSWORD_FORM_CLASS}, + name='auth_password_reset_confirm'), + url(r'^delete/$', + 'delete', + name='delete_account'), + 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'), +) diff --git a/authentic2/registration_backend/views.py b/authentic2/registration_backend/views.py index 3602e9a..4b4ca8f 100644 --- a/authentic2/registration_backend/views.py +++ b/authentic2/registration_backend/views.py @@ -1,37 +1,78 @@ import logging - +from datetime import datetime 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.sites.models import Site, RequestSite from django.contrib.auth.models import BaseUserManager, Group from django.conf import settings from django.db.models import FieldDoesNotExist +from django.db import IntegrityError +from django.core import signing +from django.core.mail import send_mail +from django.template.loader import render_to_string -from registration.views import RegistrationView as BaseRegistrationView -from registration.models import RegistrationProfile -from registration import signals +from django.views.generic.edit import FormView +from django.views.generic.base import TemplateView +from authentic2.utils import get_form_class from .. import models, app_settings, compat -from . import urls +EXPIRATION = settings.ACCOUNT_ACTIVATION_DAYS logger = logging.getLogger(__name__) +class RegistrationView(FormView): + form_class = get_form_class(app_settings.A2_REGISTRATION_FORM_CLASS) + template_name = 'registration/registration_form.html' -class RegistrationView(BaseRegistrationView): - form_class = urls.get_form_class(app_settings.A2_REGISTRATION_FORM_CLASS) - - def register(self, request, **cleaned_data): - User = compat.get_user_model() + def form_valid(self, form): if Site._meta.installed: site = Site.objects.get_current() else: - site = RequestSite(request) + site = RequestSite(self.request) + + activation_key = signing.dumps(form.cleaned_data) + ctx_dict = {'activation_key': activation_key, + 'user': form.cleaned_data, + 'expiration_days': EXPIRATION, + 'site': site} + + 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) + + send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, + [form.cleaned_data['email']], fail_silently=True) + return redirect('registration_complete') + +register = RegistrationView.as_view() + +class ActivationView(TemplateView): + http_method_names = ['get'] + template_name = 'registration/activate.html' + + def get(self, request, *args, **kwargs): + context = {} + try: + self.register(kwargs['activation_key']) + return redirect('registration_activation_complete') + except signing.SignatureExpired: + context['expired'] = True + except IntegrityError: + context['existing_user'] = True + return self.render_to_response(context) + + def register(self, registration_token): + User = compat.get_user_model() + registration_fields = signing.loads(registration_token, + max_age=EXPIRATION * 3600 * 24) user_fields = {} for field in compat.get_registration_fields(): # save User model fields @@ -41,58 +82,28 @@ class RegistrationView(BaseRegistrationView): continue if field.startswith('password'): continue - user_fields[field] = cleaned_data[field] + user_fields[field] = registration_fields[field] if field == 'email': user_fields[field] = BaseUserManager.normalize_email(user_fields[field]) - new_user = User(is_active=False, **user_fields) + + new_user = User(is_active=True, **user_fields) new_user.clean() - new_user.set_password(cleaned_data['password1']) + new_user.set_password(registration_fields['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]) + attribute.set_value(new_user, registration_fields[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) - - signals.user_registered.send(sender=self.__class__, - user=new_user, - request=request) return new_user - 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: - - * If ``REGISTRATION_OPEN`` is not specified in settings, or is - set to ``True``, registration is permitted. - - * If ``REGISTRATION_OPEN`` is both specified and set to - ``False``, registration is not permitted. - - """ - return getattr(settings, 'REGISTRATION_OPEN', True) - - 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) diff --git a/authentic2/templates/registration/activate.html b/authentic2/templates/registration/activate.html index 640352e..f147cc5 100644 --- a/authentic2/templates/registration/activate.html +++ b/authentic2/templates/registration/activate.html @@ -16,6 +16,12 @@ {% else %}

{% trans "Account activation failed" %}

+{% if expired %} +

{% trans "Your activation key is expired" %}

+{% endif %} +{% if existing_user %} +

{% trans "A user with that username already exists." %}

+{% endif %} {% endif %} diff --git a/authentic2/urls.py b/authentic2/urls.py index 9516766..8fbd7e8 100644 --- a/authentic2/urls.py +++ b/authentic2/urls.py @@ -18,6 +18,8 @@ not_homepage_patterns = patterns('authentic2.views', url(r'^accounts/', include('authentic2.profile_urls')), ) + + not_homepage_patterns += patterns('', url(r'^accounts/', include(app_settings.A2_REGISTRATION_URLCONF)), url(r'^admin/', include(admin.site.urls)), diff --git a/authentic2/utils.py b/authentic2/utils.py index 6678ab2..115ca3b 100644 --- a/authentic2/utils.py +++ b/authentic2/utils.py @@ -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) diff --git a/requirements.txt b/requirements.txt index 466ed1c..8720c59 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ Django<1.6 south>=0.8.4,<0.9 requests django-model-utils -django-registration>=1 django-debug-toolbar>=1.2,<1.3 --allow-external django-admin-tools --allow-unverified django-admin-tools diff --git a/setup.py b/setup.py index 23d3202..c446349 100755 --- a/setup.py +++ b/setup.py @@ -117,7 +117,6 @@ setup(name="authentic2", 'south>=0.8.4,<0.9', 'requests', 'django-model-utils', - 'django-registration>=1', 'django-admin-tools>=0.5.1', 'django-debug-toolbar>=1.2,<1.3', 'dnspython', -- 2.1.0