Skip to content

Commit

Permalink
Merge beadbf5 into 623baa7
Browse files Browse the repository at this point in the history
  • Loading branch information
laginha committed Nov 11, 2014
2 parents 623baa7 + beadbf5 commit 636bcdf
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 73 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ django-registration-redux changelog
===================================


Version 1.2, 23 October, 2014
-------------------------------

* Feature: Added settings' options that allows to exlude the default auth urls (`INCLUDE_AUTH_URLS`) and register url (`INCLUDE_REGISTER_URL`).

* Feature: Added support to dynamically import any chosen registration form using the settings option `REGISTRATION_FORM`.

* Enhancement: Make `RegistrationForm` a subclass of Django's `UserCreationForm`

* Enhancement: Use registration form `save` method to create user instance, whenever form is a subclass of Django's `ModelForm`.



Version 1.1, 19 September, 2014
-------------------------------

Expand Down
25 changes: 18 additions & 7 deletions docs/default-backend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ This backend makes use of the following settings:
is optional, and a default of ``True`` will be assumed if it is
not supplied.

``INCLUDE_AUTH_URLS``
A boolean (either ``True`` or ``False``) indicating whether auth urls
(mapped to ``django.contrib.auth.views``) should be included in the
``urlpatterns`` of the application backend.

``INCLUDE_REGISTER_URL``
A boolean (either ``True`` or ``False``) indicating whether the view
for registering accounts should be included in the ``urlpatterns``
of the application backend.

``REGISTRATION_FORM``
A string dotted path to the desired registration form.

By default, this backend uses
:class:`registration.forms.RegistrationForm` as its form class for
user registration; this can be overridden by passing the keyword
Expand Down Expand Up @@ -226,18 +239,16 @@ Additionally, :class:`RegistrationProfile` has a custom manager

:rtype: ``None``

.. method:: create_inactive_user(username, email, password, site[, send_email, request])
.. method:: create_inactive_user(site, [new_user=None, send_email=True, request=None, **user_info])

Creates a new, inactive user account and an associated instance
of :class:`RegistrationProfile`, sends the activation email and
returns the new ``User`` object representing the account.

:param username: The username to use for the new account.
:type username: string
:param email: The email address to use for the new account.
:type email: string
:param password: The password to use for the new account.
:type password: string
:param new_user: The user instance.
:type new_user: ``django.contrib.auth.models.AbstractBaseUser```
:param user_info: The fields to use for the new account.
:type user_info: dict
:param site: An object representing the site on which the
account is being registered.
:type site: ``django.contrib.sites.models.Site`` or
Expand Down
2 changes: 1 addition & 1 deletion registration/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (1, 1, 0, 'final', 0)
VERSION = (1, 2, 0, 'final', 0)


def get_version():
Expand Down
18 changes: 14 additions & 4 deletions registration/backends/default/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from django.conf.urls import patterns
from django.conf.urls import include
from django.conf.urls import url
from django.conf import settings
from django.views.generic.base import TemplateView

from registration.backends.default.views import ActivationView
Expand All @@ -37,14 +38,23 @@
url(r'^activate/(?P<activation_key>\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'),
(r'', include('registration.auth_urls')),
)

if getattr(settings, 'INCLUDE_REGISTER_URL', True):
urlpatterns += patterns('',
url(r'^register/$',
RegistrationView.as_view(),
name='registration_register'),
)

if getattr(settings, 'INCLUDE_AUTH_URLS', True):
urlpatterns += patterns('',
(r'', include('registration.auth_urls')),
)

13 changes: 10 additions & 3 deletions registration/backends/default/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from registration.models import RegistrationProfile
from registration.views import ActivationView as BaseActivationView
from registration.views import RegistrationView as BaseRegistrationView
from registration.users import UserModel


class RegistrationView(BaseRegistrationView):
Expand Down Expand Up @@ -56,7 +57,7 @@ class variable to False to skip sending the new user a confirmation
"""
SEND_ACTIVATION_EMAIL = getattr(settings, 'SEND_ACTIVATION_EMAIL', True)

def register(self, request, **cleaned_data):
def register(self, request, form):
"""
Given a username, email address and password, register a new
user account, which will initially be inactive.
Expand All @@ -80,13 +81,19 @@ def register(self, request, **cleaned_data):
class of this backend as the sender.
"""
username, email, password = cleaned_data['username'], cleaned_data['email'], cleaned_data['password1']
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)

if hasattr(form, 'save'):
new_user_instance = form.save()
else:
new_user_instance = UserModel().objects.create_user(**form.cleaned_data)

new_user = RegistrationProfile.objects.create_inactive_user(
username, email, password, site,
new_user=new_user_instance,
site=site,
send_email=self.SEND_ACTIVATION_EMAIL,
request=request,
)
Expand Down
17 changes: 13 additions & 4 deletions registration/backends/simple/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,29 @@
from django.conf.urls import include
from django.conf.urls import patterns
from django.conf.urls import url
from django.conf import settings
from django.views.generic.base import TemplateView

from registration.backends.simple.views import RegistrationView


urlpatterns = patterns('',
url(r'^register/$',
RegistrationView.as_view(),
name='registration_register'),
url(r'^register/closed/$',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'),
url(r'^register/complete/$',
TemplateView.as_view(template_name='registration/registration_complete.html'),
name='registration_complete'),
(r'', include('registration.auth_urls')),
)

if getattr(settings, 'INCLUDE_REGISTER_URL', True):
urlpatterns += patterns('',
url(r'^register/$',
RegistrationView.as_view(),
name='registration_register'),
)

if getattr(settings, 'INCLUDE_AUTH_URLS', True):
urlpatterns += patterns('',
(r'', include('registration.auth_urls')),
)
13 changes: 8 additions & 5 deletions registration/backends/simple/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ class RegistrationView(BaseRegistrationView):
up and logged in).
"""
def register(self, request, **cleaned_data):
username, email, password = cleaned_data['username'], cleaned_data['email'], cleaned_data['password1']
UserModel().objects.create_user(username, email, password)

new_user = authenticate(username=username, password=password)
def register(self, request, form):
new_user = form.save()
username_field = getattr(new_user, 'USERNAME_FIELD', 'username')
new_user = authenticate(
username=getattr(new_user, username_field),
password=form.cleaned_data['password1']
)

login(request, new_user)
signals.user_registered.send(sender=self.__class__,
user=new_user,
Expand Down
43 changes: 7 additions & 36 deletions registration/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@


from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.forms import UserCreationForm

from registration.users import UserModel


class RegistrationForm(forms.Form):
class RegistrationForm(UserCreationForm):
"""
Form for registering a new user account.
Expand All @@ -30,41 +31,11 @@ class RegistrationForm(forms.Form):
"""
required_css_class = 'required'

username = forms.RegexField(regex=r'^[\w.@+-]+$',
max_length=30,
label=_("Username"),
error_messages={'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})
email = forms.EmailField(label=_("E-mail"))
password1 = forms.CharField(widget=forms.PasswordInput,
label=_("Password"))
password2 = forms.CharField(widget=forms.PasswordInput,
label=_("Password (again)"))

def clean_username(self):
"""
Validate that the username is alphanumeric and is not already
in use.
"""
existing = UserModel().objects.filter(username__iexact=self.cleaned_data['username'])
if existing.exists():
raise forms.ValidationError(_("A user with that username already exists."))
else:
return self.cleaned_data['username']

def clean(self):
"""
Verifiy that the values entered into the two password fields
match. Note that an error here will end up in
``non_field_errors()`` because it doesn't apply to a single
field.
"""
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields didn't match."))
return self.cleaned_data

class Meta:
model = UserModel()
fields = ("username", "email")


class RegistrationFormTermsOfService(RegistrationForm):
Expand Down
16 changes: 9 additions & 7 deletions registration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ def activate_user(self, activation_key):
return user
return False

def create_inactive_user(self, username, email, password,
site, send_email=True, request=None):
def create_inactive_user(self, site, new_user=None, send_email=True, request=None, **user_info):
"""
Create a new, inactive ``User``, generate a
``RegistrationProfile`` and email its activation key to the
Expand All @@ -84,7 +83,10 @@ def create_inactive_user(self, username, email, password,
it will be passed to the email template.
"""
new_user = UserModel().objects.create_user(username, email, password)
if new_user == None:
password = user_info.pop('password')
new_user = UserModel()(**user_info)
new_user.set_password( password )
new_user.is_active = False
new_user.save()

Expand All @@ -107,10 +109,10 @@ def create_profile(self, user):
"""
salt = hashlib.sha1(six.text_type(random.random()).encode('ascii')).hexdigest()[:5]
salt = salt.encode('ascii')
username = user.username
if isinstance(username, six.text_type):
username = username.encode('utf-8')
activation_key = hashlib.sha1(salt+username).hexdigest()
user_pk = str(user.pk)
if isinstance(user_pk, six.text_type):
user_pk = user_pk.encode('utf-8')
activation_key = hashlib.sha1(salt+user_pk).hexdigest()
return self.create(user=user,
activation_key=activation_key)

Expand Down
6 changes: 5 additions & 1 deletion registration/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@

from .default_backend import *
from .forms import *
from .models import *
from .simple_backend import *
from .urls import *
2 changes: 1 addition & 1 deletion registration/tests/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def test_registration_form(self):
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'bar'},
'error': ('__all__', ["The two password fields didn't match."])},
'error': ('password2', ["The two password fields didn't match."])},
]

for invalid_dict in invalid_data_dicts:
Expand Down
28 changes: 28 additions & 0 deletions registration/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import sys
try:
from importlib import import_module
except ImportError:
from django.utils.importlib import import_module
from django.utils import six


def import_string(dotted_path):
"""
COPIED FROM DJANGO 1.7 (django.utils.module_loading.import_string)
Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.
"""
try:
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError:
msg = "%s doesn't look like a module path" % dotted_path
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

module = import_module(module_path)

try:
return getattr(module, class_name)
except AttributeError:
msg = 'Module "%s" does not define a "%s" attribute/class' % (
dotted_path, class_name)
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
17 changes: 13 additions & 4 deletions registration/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@
from django.shortcuts import redirect
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from django.conf import settings
try:
from django.utils.module_loading import import_string
except ImportError:
from registration.utils import import_string


from registration import signals
from registration.forms import RegistrationForm
# from registration.forms import RegistrationForm

REGISTRATION_FORM_PATH = getattr(settings, 'REGISTRATION_FORM', 'registration.forms.RegistrationForm')
REGISTRATION_FORM = import_string( REGISTRATION_FORM_PATH )


class _RequestPassingFormView(FormView):
Expand Down Expand Up @@ -63,7 +72,7 @@ class RegistrationView(_RequestPassingFormView):
"""
disallowed_url = 'registration_disallowed'
form_class = RegistrationForm
form_class = REGISTRATION_FORM
http_method_names = ['get', 'post', 'head', 'options', 'trace']
success_url = None
template_name = 'registration/registration_form.html'
Expand All @@ -79,7 +88,7 @@ def dispatch(self, request, *args, **kwargs):
return super(RegistrationView, self).dispatch(request, *args, **kwargs)

def form_valid(self, request, form):
new_user = self.register(request, **form.cleaned_data)
new_user = self.register(request, form)
success_url = self.get_success_url(request, new_user)

# success_url may be a simple string, or a tuple providing the
Expand All @@ -99,7 +108,7 @@ def registration_allowed(self, request):
"""
return True

def register(self, request, **cleaned_data):
def register(self, request, form):
"""
Implement user-registration logic here. Access to both the
request and the full cleaned_data of the registration form is
Expand Down

0 comments on commit 636bcdf

Please sign in to comment.