0001-django-registration-dependency-removed-with-however-.patch
authentic2/app_settings.py | ||
---|---|---|
88 | 88 |
'See http://www.openssl.org/docs/apps/verify.html#item__CApath'), |
89 | 89 |
A2_REGISTRATION_URLCONF = Setting(default='authentic2.registration_backend.urls', |
90 | 90 |
definition='Root urlconf for the /accounts endpoints'), |
91 |
A2_REGISTRATION_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.RegistrationForm', |
|
91 |
A2_REGISTRATION_BACKEND = Setting(default='default', |
|
92 |
definition='Backend for user\'s registration'), |
|
93 |
A2_REGISTRATION_FORM_CLASS = Setting(default='authentic2.registration_backend.default.forms.RegistrationForm', |
|
92 | 94 |
definition='Default registration form'), |
93 |
A2_REGISTRATION_SET_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.SetPasswordForm', |
|
95 |
A2_REGISTRATION_SET_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.default.forms.SetPasswordForm',
|
|
94 | 96 |
definition='Default set password form'), |
95 |
A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.forms.PasswordChangeForm', |
|
97 |
A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS = Setting(default='authentic2.registration_backend.default.forms.PasswordChangeForm',
|
|
96 | 98 |
definition='Default change password form'), |
97 | 99 |
A2_REGISTRATION_CAN_DELETE_ACCOUNT = Setting(default=True, |
98 | 100 |
definition='Can user self delete their account and all their data'), |
authentic2/registration_backend/__init__.py | ||
---|---|---|
1 |
from django.conf import settings |
|
2 |
from django.template.loader import render_to_string |
|
3 | 1 | |
4 |
from registration.models import RegistrationProfile |
|
5 | ||
6 |
def send_activation_email(self, site): |
|
7 |
""" |
|
8 |
Send an activation email to the user associated with this |
|
9 |
``RegistrationProfile``. |
|
10 |
|
|
11 |
The activation email will make use of two templates: |
|
12 | ||
13 |
``registration/activation_email_subject.txt`` |
|
14 |
This template will be used for the subject line of the |
|
15 |
email. Because it is used as the subject line of an email, |
|
16 |
this template's output **must** be only a single line of |
|
17 |
text; output longer than one line will be forcibly joined |
|
18 |
into only a single line. |
|
19 | ||
20 |
``registration/activation_email.txt`` |
|
21 |
This template will be used for the body of the email. |
|
22 | ||
23 |
These templates will each receive the following context |
|
24 |
variables: |
|
25 | ||
26 |
``user`` |
|
27 |
The new user account |
|
28 | ||
29 |
``activation_key`` |
|
30 |
The activation key for the new account. |
|
31 | ||
32 |
``expiration_days`` |
|
33 |
The number of days remaining during which the account may |
|
34 |
be activated. |
|
35 | ||
36 |
``site`` |
|
37 |
An object representing the site on which the user |
|
38 |
registered; depending on whether ``django.contrib.sites`` |
|
39 |
is installed, this may be an instance of either |
|
40 |
``django.contrib.sites.models.Site`` (if the sites |
|
41 |
application is installed) or |
|
42 |
``django.contrib.sites.models.RequestSite`` (if |
|
43 |
not). Consult the documentation for the Django sites |
|
44 |
framework for details regarding these objects' interfaces. |
|
45 | ||
46 |
""" |
|
47 |
ctx_dict = {'activation_key': self.activation_key, |
|
48 |
'user': self.user, |
|
49 |
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, |
|
50 |
'site': site} |
|
51 |
subject = render_to_string('registration/activation_email_subject.txt', |
|
52 |
ctx_dict) |
|
53 |
# Email subject *must not* contain newlines |
|
54 |
subject = ''.join(subject.splitlines()) |
|
55 |
|
|
56 |
message = render_to_string('registration/activation_email.txt', |
|
57 |
ctx_dict) |
|
58 |
|
|
59 |
self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) |
|
60 |
RegistrationProfile.send_activation_email = send_activation_email |
authentic2/registration_backend/default/forms.py | ||
---|---|---|
1 |
from django.core.exceptions import ValidationError |
|
2 |
from django.utils.translation import ugettext_lazy as _ |
|
3 |
from django.utils.datastructures import SortedDict |
|
4 |
from django.db.models import FieldDoesNotExist |
|
5 | ||
6 |
from authentic2 import app_settings, compat, forms, utils, validators |
|
7 |
from ..forms import RegistrationForm as BaseRegistrationForm, SetPasswordForm, PasswordChangeForm |
|
8 | ||
9 |
class RegistrationForm(forms.UserAttributeFormMixin, BaseRegistrationForm): |
|
10 | ||
11 |
def __init__(self, *args, **kwargs): |
|
12 |
""" |
|
13 |
Inject required fields in registration form |
|
14 |
""" |
|
15 |
super(RegistrationForm, self).__init__(*args, **kwargs) |
|
16 |
User = compat.get_user_model() |
|
17 |
insert_idx = 0 |
|
18 |
field_names = compat.get_registration_fields() |
|
19 |
required_fields = set(compat.get_required_fields()) |
|
20 |
for field_name in field_names: |
|
21 |
if field_name not in self.fields: |
|
22 |
try: |
|
23 |
model_field = User._meta.get_field(field_name) |
|
24 |
except FieldDoesNotExist: |
|
25 |
pass |
|
26 |
else: |
|
27 |
kwargs = {} |
|
28 |
if hasattr(model_field, 'validators'): |
|
29 |
kwargs['validators'] = model_field.validators |
|
30 |
field = model_field.formfield(**kwargs) |
|
31 |
self.fields.insert(insert_idx, field_name, field) |
|
32 |
insert_idx += 1 |
|
33 |
for field_name in self.fields: |
|
34 |
if field_name in required_fields: |
|
35 |
self.fields[field_name].required = True |
|
36 |
# reorder fields obeying A2_REGISTRATION_FIELDS |
|
37 |
new_fields = SortedDict() |
|
38 |
for field_name in utils.field_names(app_settings.A2_REGISTRATION_FIELDS): |
|
39 |
if field_name in self.fields: |
|
40 |
new_fields[field_name] = self.fields[field_name] |
|
41 |
for field_name in self.fields: |
|
42 |
if field_name not in new_fields: |
|
43 |
new_fields[field_name] = self.fields[field_name] |
|
44 |
# override titles |
|
45 |
for field in app_settings.A2_REGISTRATION_FIELDS: |
|
46 |
if isinstance(field, (list, tuple)): |
|
47 |
if len(field) > 1: |
|
48 |
self.fields[field[0]].label = field[1] |
|
49 | ||
50 |
self.fields = new_fields |
|
51 |
if 'username' in self.fields: |
|
52 |
self.fields['username'].regex = app_settings.A2_REGISTRATION_FORM_USERNAME_REGEX |
|
53 |
self.fields['username'].help_text = app_settings.A2_REGISTRATION_FORM_USERNAME_HELP_TEXT |
|
54 |
self.fields['username'].label = app_settings.A2_REGISTRATION_FORM_USERNAME_LABEL |
|
55 | ||
56 |
def clean_username(self): |
|
57 |
""" |
|
58 |
Validate that the username is alphanumeric and is not already |
|
59 |
in use. |
|
60 |
""" |
|
61 |
User = compat.get_user_model() |
|
62 |
username = self.cleaned_data['username'] |
|
63 |
if app_settings.A2_REGISTRATION_REALM: |
|
64 |
if '@' in username: |
|
65 |
raise ValidationError(_('The character @ is forbidden in usernames.')) |
|
66 |
username = u'{0}@{1}'.format(username, app_settings.A2_REGISTRATION_REALM) |
|
67 |
self.cleaned_data['username'] = username |
|
68 |
existing = User.objects.filter(username__iexact=self.cleaned_data['username']) |
|
69 |
if existing.exists(): |
|
70 |
raise ValidationError(_("A user with that username already exists.")) |
|
71 |
else: |
|
72 |
return self.cleaned_data['username'] |
|
73 | ||
74 |
def clean_email(self): |
|
75 |
""" |
|
76 |
Verify if email is unique |
|
77 |
""" |
|
78 |
User = compat.get_user_model() |
|
79 |
if app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE: |
|
80 |
if User.objects.filter(email__iexact=self.cleaned_data['email']): |
|
81 |
raise ValidationError(_('This email address is already in ' |
|
82 |
'use. Please supply a different email address.')) |
|
83 |
return self.cleaned_data['email'] |
authentic2/registration_backend/default/models.py | ||
---|---|---|
1 |
from django.utils.translation import ugettext_lazy as _ |
|
2 |
from django.contrib.sites.models import RequestSite |
|
3 |
from django.contrib.sites.models import Site |
|
4 |
from django.contrib.auth.models import BaseUserManager, Group |
|
5 |
from django.db import models |
|
6 | ||
7 |
from authentic2 import app_settings, compat, models as a2_models |
|
8 | ||
9 |
from ..models import RegistrationProfile as BaseRegistrationProfile |
|
10 |
from ..models import ACTIVATION_KEY_RE |
|
11 | ||
12 |
User = compat.get_user_model() |
|
13 | ||
14 |
class RegistrationProfile(BaseRegistrationProfile, models.Model): |
|
15 |
user = models.ForeignKey(User, unique=True, related_name='profile') |
|
16 |
activation_key = models.CharField(_(u'User\'s activation key'), |
|
17 |
max_length=64, db_index=True) |
|
18 | ||
19 |
def activate_user(self, activation_key): |
|
20 |
if ACTIVATION_KEY_RE.search(activation_key): |
|
21 |
try: |
|
22 |
self = RegistrationProfile.objects.get(activation_key=activation_key) |
|
23 |
if not self.activation_key_expired(): |
|
24 |
self.user.is_active = True |
|
25 |
self.user.save() |
|
26 |
self.activation_key = self.model.ACTIVATED |
|
27 |
self.save() |
|
28 |
return self.user |
|
29 |
except self.DoesNotExist: |
|
30 |
return False |
|
31 |
return False |
|
32 | ||
33 |
def create_profile(self, user, site): |
|
34 |
self.user = user |
|
35 |
self.activation_key = self.activation_token |
|
36 |
self.save() |
|
37 |
self.send_activation_email(site) |
|
38 | ||
39 |
def create_inactive_user(self, request, **cleaned_data): |
|
40 |
User = compat.get_user_model() |
|
41 |
if Site._meta.installed: |
|
42 |
site = Site.objects.get_current() |
|
43 |
else: |
|
44 |
site = RequestSite(request) |
|
45 |
user_fields = {} |
|
46 |
for field in compat.get_registration_fields(): |
|
47 |
# save User model fields |
|
48 |
try: |
|
49 |
User._meta.get_field(field) |
|
50 |
except models.FieldDoesNotExist: |
|
51 |
continue |
|
52 |
if field.startswith('password'): |
|
53 |
continue |
|
54 |
user_fields[field] = cleaned_data[field] |
|
55 |
if field == 'email': |
|
56 |
user_fields[field] = BaseUserManager.normalize_email(user_fields[field]) |
|
57 | ||
58 |
new_user = User(is_active=False, **user_fields) |
|
59 |
new_user.clean() |
|
60 |
new_user.set_password(cleaned_data['password1']) |
|
61 |
new_user.save() |
|
62 |
attributes = a2_models.Attribute.objects.filter( |
|
63 |
asked_on_registration=True) |
|
64 |
if attributes: |
|
65 |
for attribute in attributes: |
|
66 |
attribute.set_value(new_user, cleaned_data[attribute.name]) |
|
67 |
if app_settings.A2_REGISTRATION_GROUPS: |
|
68 |
groups = [] |
|
69 |
for name in app_settings.A2_REGISTRATION_GROUPS: |
|
70 |
group, created = Group.objects.get_or_create(name=name) |
|
71 |
groups.append(group) |
|
72 |
new_user.groups = groups |
|
73 |
return new_user, site |
authentic2/registration_backend/default/views.py | ||
---|---|---|
1 |
import logging |
|
2 | ||
3 |
from django.shortcuts import redirect, render |
|
4 |
from django.utils.translation import ugettext as _ |
|
5 |
from django.contrib import messages |
|
6 |
from django.contrib.auth.decorators import login_required |
|
7 |
from django.contrib.auth import views as auth_views |
|
8 |
from django.conf import settings |
|
9 | ||
10 |
from authentic2 import app_settings, models |
|
11 | ||
12 |
from ..views import RegistrationView as BaseRegistrationView |
|
13 |
from ..views import ActivationView as BaseActivationView |
|
14 |
from .models import RegistrationProfile |
|
15 |
from .forms import RegistrationForm |
|
16 | ||
17 |
logger = logging.getLogger(__name__) |
|
18 | ||
19 |
class RegistrationView(BaseRegistrationView): |
|
20 | ||
21 |
form_class = RegistrationForm |
|
22 | ||
23 |
def register(self, request, **cleaned_data): |
|
24 |
profile = RegistrationProfile() |
|
25 |
new_user = profile.create_user(request, **cleaned_data) |
|
26 |
return new_user |
|
27 | ||
28 |
register = RegistrationView.as_view() |
|
29 | ||
30 |
class ActivationView(BaseActivationView): |
|
31 |
def activate(self, request, activation_key): |
|
32 |
profile = RegistrationProfile() |
|
33 |
return profile.activate_user(activation_key) |
|
34 | ||
35 |
activate = ActivationView.as_view() |
|
36 | ||
37 | ||
38 |
@login_required |
|
39 |
def delete(request, next_url='/'): |
|
40 |
next_url = request.build_absolute_uri(request.META.get('HTTP_REFERER') or next_url) |
|
41 |
if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT: |
|
42 |
return redirect(next_url) |
|
43 |
if request.method == 'POST': |
|
44 |
if 'submit' in request.POST: |
|
45 |
models.DeletedUser.objects.delete_user(request.user) |
|
46 |
logger.info(u'deletion of account %s requested' % request.user) |
|
47 |
messages.info(request, _('Your account has been scheduled for deletion. You cannot use it anymore.')) |
|
48 |
return redirect('auth_logout') |
|
49 |
else: |
|
50 |
return redirect(next_url) |
|
51 |
return render(request, 'registration/delete_account.html') |
|
52 | ||
53 |
password_change = auth_views.password_change |
|
54 |
password_change_done = auth_views.password_change_done |
|
55 |
password_reset = auth_views.password_reset |
|
56 |
password_reset_confirm = auth_views.password_reset_confirm |
|
57 |
password_reset_complete = auth_views.password_reset_complete |
|
58 |
password_reset_done = auth_views.password_reset_done |
authentic2/registration_backend/forms.py | ||
---|---|---|
1 |
from django.core.exceptions import ValidationError |
|
2 |
from django.utils.translation import ugettext_lazy as _ |
|
3 | 1 |
from django.forms import Form, CharField, PasswordInput |
4 |
from django.utils.datastructures import SortedDict |
|
5 |
from django.db.models import FieldDoesNotExist |
|
6 | ||
7 |
from django.contrib.auth import forms as auth_forms |
|
2 |
from django.utils.translation import ugettext_lazy as _ |
|
8 | 3 | |
9 |
from .. import app_settings, compat, forms, utils, validators
|
|
4 |
from django.contrib.auth import forms
|
|
10 | 5 | |
6 |
from authentic2 import validators |
|
11 | 7 | |
12 |
class RegistrationForm(forms.UserAttributeFormMixin, Form):
|
|
8 |
class RegistrationForm(Form): |
|
13 | 9 |
error_css_class = 'form-field-error' |
14 | 10 |
required_css_class = 'form-field-required' |
15 | 11 | |
... | ... | |
17 | 13 |
validators=[validators.validate_password]) |
18 | 14 |
password2 = CharField(widget=PasswordInput, label=_("Password (again)")) |
19 | 15 | |
20 |
def __init__(self, *args, **kwargs): |
|
21 |
""" |
|
22 |
Inject required fields in registration form |
|
23 |
""" |
|
24 |
super(RegistrationForm, self).__init__(*args, **kwargs) |
|
25 |
User = compat.get_user_model() |
|
26 |
insert_idx = 0 |
|
27 |
field_names = compat.get_registration_fields() |
|
28 |
required_fields = set(compat.get_required_fields()) |
|
29 |
for field_name in field_names: |
|
30 |
if field_name not in self.fields: |
|
31 |
try: |
|
32 |
model_field = User._meta.get_field(field_name) |
|
33 |
except FieldDoesNotExist: |
|
34 |
pass |
|
35 |
else: |
|
36 |
kwargs = {} |
|
37 |
if hasattr(model_field, 'validators'): |
|
38 |
kwargs['validators'] = model_field.validators |
|
39 |
field = model_field.formfield(**kwargs) |
|
40 |
self.fields.insert(insert_idx, field_name, field) |
|
41 |
insert_idx += 1 |
|
42 |
for field_name in self.fields: |
|
43 |
if field_name in required_fields: |
|
44 |
self.fields[field_name].required = True |
|
45 |
# reorder fields obeying A2_REGISTRATION_FIELDS |
|
46 |
new_fields = SortedDict() |
|
47 |
for field_name in utils.field_names(app_settings.A2_REGISTRATION_FIELDS): |
|
48 |
if field_name in self.fields: |
|
49 |
new_fields[field_name] = self.fields[field_name] |
|
50 |
for field_name in self.fields: |
|
51 |
if field_name not in new_fields: |
|
52 |
new_fields[field_name] = self.fields[field_name] |
|
53 |
# override titles |
|
54 |
for field in app_settings.A2_REGISTRATION_FIELDS: |
|
55 |
if isinstance(field, (list, tuple)): |
|
56 |
if len(field) > 1: |
|
57 |
self.fields[field[0]].label = field[1] |
|
58 | ||
59 |
self.fields = new_fields |
|
60 |
if 'username' in self.fields: |
|
61 |
self.fields['username'].regex = app_settings.A2_REGISTRATION_FORM_USERNAME_REGEX |
|
62 |
self.fields['username'].help_text = app_settings.A2_REGISTRATION_FORM_USERNAME_HELP_TEXT |
|
63 |
self.fields['username'].label = app_settings.A2_REGISTRATION_FORM_USERNAME_LABEL |
|
64 | ||
65 | 16 |
def clean_username(self): |
66 |
""" |
|
67 |
Validate that the username is alphanumeric and is not already |
|
68 |
in use. |
|
69 |
""" |
|
70 |
User = compat.get_user_model() |
|
71 |
username = self.cleaned_data['username'] |
|
72 |
if app_settings.A2_REGISTRATION_REALM: |
|
73 |
if '@' in username: |
|
74 |
raise ValidationError(_('The character @ is forbidden in usernames.')) |
|
75 |
username = u'{0}@{1}'.format(username, app_settings.A2_REGISTRATION_REALM) |
|
76 |
self.cleaned_data['username'] = username |
|
77 |
existing = User.objects.filter(username__iexact=self.cleaned_data['username']) |
|
78 |
if existing.exists(): |
|
79 |
raise ValidationError(_("A user with that username already exists.")) |
|
80 |
else: |
|
81 |
return self.cleaned_data['username'] |
|
17 |
raise NotImplementedError |
|
82 | 18 | |
83 | 19 |
def clean_email(self): |
84 |
""" |
|
85 |
Verify if email is unique |
|
86 |
""" |
|
87 |
User = compat.get_user_model() |
|
88 |
if app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE: |
|
89 |
if User.objects.filter(email__iexact=self.cleaned_data['email']): |
|
90 |
raise ValidationError(_('This email address is already in ' |
|
91 |
'use. Please supply a different email address.')) |
|
92 |
return self.cleaned_data['email'] |
|
20 |
raise NotImplementedError |
|
93 | 21 | |
94 | 22 |
def clean(self): |
95 | 23 |
""" |
... | ... | |
103 | 31 |
raise ValidationError(_("The two password fields didn't match.")) |
104 | 32 |
return self.cleaned_data |
105 | 33 | |
106 |
class SetPasswordForm(auth_forms.SetPasswordForm):
|
|
34 |
class SetPasswordForm(forms.SetPasswordForm): |
|
107 | 35 |
new_password1 = CharField(label=_("New password"), |
108 | 36 |
widget=PasswordInput, |
109 | 37 |
validators=[validators.validate_password]) |
110 | 38 | |
111 |
class PasswordChangeForm(auth_forms.PasswordChangeForm):
|
|
39 |
class PasswordChangeForm(forms.PasswordChangeForm): |
|
112 | 40 |
new_password1 = CharField(label=_("New password"), |
113 | 41 |
widget=PasswordInput, |
114 | 42 |
validators=[validators.validate_password]) |
115 | ||
116 |
authentic2/registration_backend/models.py | ||
---|---|---|
1 |
import hashlib |
|
2 |
import random |
|
3 |
import re |
|
4 |
from datetime import datetime, timedelta |
|
5 | ||
6 |
from django.conf import settings |
|
7 |
from django.template.loader import render_to_string |
|
8 |
from django.core.mail import send_mail |
|
9 | ||
10 |
ACTIVATION_KEY_RE = re.compile('^[a-f0-9]{40}$') |
|
11 | ||
12 |
class RegistrationProfile(object): |
|
13 |
ACTIVATED = 'ACTIVATED' |
|
14 | ||
15 |
def __unicode__(self): |
|
16 |
return u"Registration information for %s" % self.user |
|
17 | ||
18 |
@property |
|
19 |
def activation_token(self): |
|
20 |
salt = hashlib.sha1(str(random.random())).hexdigest()[:5] |
|
21 |
now = datetime.now().isoformat() |
|
22 |
activation_key = hashlib.sha1(salt+now).hexdigest() |
|
23 |
return activation_key |
|
24 | ||
25 |
def create_profile(self, user, site): |
|
26 |
raise NotImplementedError |
|
27 | ||
28 |
def create_inactive_user(self, request, **cleaned_data): |
|
29 |
raise NotImplementedError |
|
30 | ||
31 |
def create_user(self, *args, **kwargs): |
|
32 |
user, site = self.create_inactive_user(*args, **kwargs) |
|
33 |
self.create_profile(user, site) |
|
34 |
return user |
|
35 | ||
36 |
def activate_user(self, activation_key): |
|
37 |
raise NotImplementedError |
|
38 | ||
39 |
def activation_key_expired(self): |
|
40 |
expiration_date = timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS) |
|
41 |
return self.activation_key == self.ACTIVATED or \ |
|
42 |
(self.user.date_joined + expiration_date <= datetime.now()) |
|
43 |
activation_key_expired.boolean = True |
|
44 | ||
45 |
def send_activation_email(self, site): |
|
46 |
ctx_dict = {'activation_key': self.activation_key, |
|
47 |
'user': self.user, |
|
48 |
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, |
|
49 |
'site': site} |
|
50 |
subject = render_to_string('registration/activation_email_subject.txt', |
|
51 |
ctx_dict) |
|
52 |
subject = ''.join(subject.splitlines()) |
|
53 |
message = render_to_string('registration/activation_email.txt', |
|
54 |
ctx_dict) |
|
55 |
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, |
|
56 |
[self.user.email], fail_silently=True) |
authentic2/registration_backend/urls.py | ||
---|---|---|
1 | 1 |
from django.conf.urls import patterns |
2 | 2 |
from django.conf.urls import url |
3 |
from django.utils.importlib import import_module |
|
4 |
from django.contrib.auth import views as auth_views |
|
5 | 3 |
from django.views.generic.base import TemplateView |
6 | 4 | |
7 | ||
8 | 5 |
from .. import app_settings |
9 | ||
10 |
from registration.backends.default.views import ActivationView |
|
11 | ||
12 | ||
13 |
def get_form_class(form_class): |
|
14 |
module, form_class = form_class.rsplit('.', 1) |
|
15 |
module = import_module(module) |
|
16 |
return getattr(module, form_class) |
|
17 | ||
6 |
from ..utils import get_form_class |
|
18 | 7 | |
19 | 8 |
SET_PASSWORD_FORM_CLASS = get_form_class( |
20 | 9 |
app_settings.A2_REGISTRATION_SET_PASSWORD_FORM_CLASS) |
21 | 10 |
CHANGE_PASSWORD_FORM_CLASS = get_form_class( |
22 | 11 |
app_settings.A2_REGISTRATION_CHANGE_PASSWORD_FORM_CLASS) |
23 | 12 | |
13 |
REGISTRATION_BACKEND = app_settings.A2_REGISTRATION_BACKEND |
|
24 | 14 | |
25 |
urlpatterns = patterns('authentic2.registration_backend.views',
|
|
15 |
urlpatterns = patterns('authentic2.registration_backend.%s.views' % REGISTRATION_BACKEND,
|
|
26 | 16 |
url(r'^activate/complete/$', |
27 | 17 |
TemplateView.as_view(template_name='registration/activation_complete.html'), |
28 | 18 |
name='registration_activation_complete'), |
... | ... | |
31 | 21 |
# that way it can return a sensible "invalid key" message instead of a |
32 | 22 |
# confusing 404. |
33 | 23 |
url(r'^activate/(?P<activation_key>\w+)/$', |
34 |
ActivationView.as_view(),
|
|
24 |
'activate',
|
|
35 | 25 |
name='registration_activate'), |
36 | 26 |
url(r'^register/$', |
37 | 27 |
'register', |
... | ... | |
43 | 33 |
TemplateView.as_view(template_name='registration/registration_closed.html'), |
44 | 34 |
name='registration_disallowed'), |
45 | 35 |
url(r'^password/change/$', |
46 |
auth_views.password_change, |
|
47 |
{'password_change_form': CHANGE_PASSWORD_FORM_CLASS}, |
|
36 |
'password_change', |
|
37 |
{'password_change_form': CHANGE_PASSWORD_FORM_CLASS, |
|
38 |
'post_change_redirect': 'done'}, |
|
48 | 39 |
name='auth_password_change'), |
49 | 40 |
url(r'^password/change/done/$', |
50 |
auth_views.password_change_done,
|
|
41 |
'password_change_done',
|
|
51 | 42 |
name='auth_password_change_done'), |
52 | 43 |
url(r'^password/reset/$', |
53 |
auth_views.password_reset, |
|
44 |
'password_reset', |
|
45 |
{'post_reset_redirect': 'done'}, |
|
54 | 46 |
name='auth_password_reset'), |
55 | 47 |
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', |
56 |
auth_views.password_reset_confirm,
|
|
48 |
'password_reset_confirm',
|
|
57 | 49 |
{'set_password_form': SET_PASSWORD_FORM_CLASS}, |
58 | 50 |
name='auth_password_reset_confirm'), |
59 | 51 |
url(r'^password/reset/complete/$', |
60 |
auth_views.password_reset_complete,
|
|
52 |
'password_reset_complete',
|
|
61 | 53 |
name='auth_password_reset_complete'), |
62 | 54 |
url(r'^password/reset/done/$', |
63 |
auth_views.password_reset_done,
|
|
55 |
'password_reset_done',
|
|
64 | 56 |
name='auth_password_reset_done'), |
65 | 57 |
url(r'^delete/$', |
66 | 58 |
'delete', |
authentic2/registration_backend/views.py | ||
---|---|---|
1 | 1 |
import logging |
2 | 2 | |
3 | ||
4 | 3 |
from django.shortcuts import redirect, render |
5 | 4 |
from django.utils.translation import ugettext as _ |
6 | 5 |
from django.contrib import messages |
7 | 6 |
from django.contrib.auth.decorators import login_required |
8 |
from django.contrib.sites.models import RequestSite |
|
9 |
from django.contrib.sites.models import Site |
|
10 |
from django.contrib.auth.models import BaseUserManager, Group |
|
11 | 7 |
from django.conf import settings |
12 |
from django.db.models import FieldDoesNotExist |
|
8 |
from django.views.generic.edit import FormView |
|
9 |
from django.views.generic.base import TemplateView |
|
10 |
from django.shortcuts import redirect |
|
13 | 11 | |
12 |
from .. import models, app_settings, compat |
|
14 | 13 | |
15 |
from registration.views import RegistrationView as BaseRegistrationView |
|
16 |
from registration.models import RegistrationProfile |
|
17 |
from registration import signals |
|
14 |
logger = logging.getLogger(__name__) |
|
18 | 15 | |
19 |
from .. import models, app_settings, compat |
|
20 |
from . import urls |
|
21 | 16 | |
17 |
class RegistrationView(FormView): |
|
22 | 18 | |
23 |
logger = logging.getLogger(__name__) |
|
19 |
disallowed_url = 'registration_disallowed' |
|
20 |
template_name = 'registration/registration_form.html' |
|
24 | 21 | |
22 |
def dispatch(self, request, *args, **kwargs): |
|
23 |
if not self.registration_allowed(request): |
|
24 |
return redirect(self.disallowed_url) |
|
25 |
return super(RegistrationView, self).dispatch(request, *args, **kwargs) |
|
25 | 26 | |
26 |
class RegistrationView(BaseRegistrationView): |
|
27 |
form_class = urls.get_form_class(app_settings.A2_REGISTRATION_FORM_CLASS) |
|
27 |
def post(self, request, *args, **kwargs): |
|
28 |
form_class = self.get_form_class() |
|
29 |
form = self.get_form(form_class) |
|
30 |
if form.is_valid(): |
|
31 |
return self.form_valid(request, form) |
|
32 |
else: |
|
33 |
return self.form_invalid(form) |
|
28 | 34 | |
29 | 35 |
def register(self, request, **cleaned_data): |
30 |
User = compat.get_user_model() |
|
31 |
if Site._meta.installed: |
|
32 |
site = Site.objects.get_current() |
|
33 |
else: |
|
34 |
site = RequestSite(request) |
|
35 |
user_fields = {} |
|
36 |
for field in compat.get_registration_fields(): |
|
37 |
# save User model fields |
|
38 |
try: |
|
39 |
User._meta.get_field(field) |
|
40 |
except FieldDoesNotExist: |
|
41 |
continue |
|
42 |
if field.startswith('password'): |
|
43 |
continue |
|
44 |
user_fields[field] = cleaned_data[field] |
|
45 |
if field == 'email': |
|
46 |
user_fields[field] = BaseUserManager.normalize_email(user_fields[field]) |
|
47 |
new_user = User(is_active=False, **user_fields) |
|
48 |
new_user.clean() |
|
49 |
new_user.set_password(cleaned_data['password1']) |
|
50 |
new_user.save() |
|
51 |
attributes = models.Attribute.objects.filter( |
|
52 |
asked_on_registration=True) |
|
53 |
if attributes: |
|
54 |
for attribute in attributes: |
|
55 |
attribute.set_value(new_user, cleaned_data[attribute.name]) |
|
56 |
if app_settings.A2_REGISTRATION_GROUPS: |
|
57 |
groups = [] |
|
58 |
for name in app_settings.A2_REGISTRATION_GROUPS: |
|
59 |
group, created = Group.objects.get_or_create(name=name) |
|
60 |
groups.append(group) |
|
61 |
new_user.groups = groups |
|
62 |
registration_profile = RegistrationProfile.objects.create_profile(new_user) |
|
63 |
registration_profile.send_activation_email(site) |
|
64 | ||
65 |
signals.user_registered.send(sender=self.__class__, |
|
66 |
user=new_user, |
|
67 |
request=request) |
|
68 |
return new_user |
|
36 |
raise NotImplementedError |
|
69 | 37 | |
70 | 38 |
def registration_allowed(self, request): |
71 |
""" |
|
72 |
Indicate whether account registration is currently permitted, |
|
73 |
based on the value of the setting ``REGISTRATION_OPEN``. This |
|
74 |
is determined as follows: |
|
75 | ||
76 |
* If ``REGISTRATION_OPEN`` is not specified in settings, or is |
|
77 |
set to ``True``, registration is permitted. |
|
78 | ||
79 |
* If ``REGISTRATION_OPEN`` is both specified and set to |
|
80 |
``False``, registration is not permitted. |
|
81 |
|
|
82 |
""" |
|
83 | 39 |
return getattr(settings, 'REGISTRATION_OPEN', True) |
84 | 40 | |
85 |
def get_success_url(self, request, user): |
|
86 |
""" |
|
87 |
Return the name of the URL to redirect to after successful |
|
88 |
user registration. |
|
89 |
|
|
90 |
""" |
|
91 |
return ('registration_complete', (), {}) |
|
41 |
def get_success_url(self): |
|
42 |
return ('registration_complete') |
|
43 | ||
44 |
def form_valid(self, request, form): |
|
45 |
self.register(request, **form.cleaned_data) |
|
46 |
return redirect(self.get_success_url()) |
|
92 | 47 | |
93 | 48 |
register = RegistrationView.as_view() |
94 | 49 | |
50 |
class ActivationView(TemplateView): |
|
51 |
http_method_names = ['get'] |
|
52 |
template_name = 'registration/activate.html' |
|
53 | ||
54 |
def get(self, request, *args, **kwargs): |
|
55 |
activated_user = self.activate(request, *args, **kwargs) |
|
56 |
if activated_user: |
|
57 |
return redirect(self.get_success_url()) |
|
58 | ||
59 |
def activate(self, request, *args, **kwargs): |
|
60 |
raise NotImplementedError |
|
61 | ||
62 |
def get_success_url(self): |
|
63 |
return ('registration_activation_complete') |
|
64 | ||
95 | 65 | |
96 | 66 |
@login_required |
97 | 67 |
def delete(request, next_url='/'): |
authentic2/utils.py | ||
---|---|---|
206 | 206 |
yield t |
207 | 207 |
else: |
208 | 208 |
yield t[0] |
209 | ||
210 |
def get_form_class(form_class): |
|
211 |
module, form_class = form_class.rsplit('.', 1) |
|
212 |
module = import_module(module) |
|
213 |
return getattr(module, form_class) |
requirements.txt | ||
---|---|---|
2 | 2 |
south>=0.8.4,<0.9 |
3 | 3 |
requests |
4 | 4 |
django-model-utils |
5 |
django-registration>=1 |
|
6 | 5 |
django-debug-toolbar>=1.2,<1.3 |
7 | 6 |
--allow-external django-admin-tools |
8 | 7 |
--allow-unverified django-admin-tools |
setup.py | ||
---|---|---|
117 | 117 |
'south>=0.8.4,<0.9', |
118 | 118 |
'requests', |
119 | 119 |
'django-model-utils', |
120 |
'django-registration>=1', |
|
121 | 120 |
'django-admin-tools>=0.5.1', |
122 | 121 |
'django-debug-toolbar>=1.2,<1.3', |
123 | 122 |
'dnspython', |
124 |
- |