├── .travis.yml ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── setup.py ├── test_project ├── __init__.py ├── manage.py ├── requirements.txt ├── settings.py ├── templates │ └── base.html ├── test_accounts │ ├── __init__.py │ ├── forms.py │ └── models.py └── urls.py └── userprofiles ├── __init__.py ├── admin.py ├── auth_backends.py ├── contrib ├── __init__.py ├── accountverification │ ├── __init__.py │ ├── admin.py │ ├── models.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_models.py │ │ └── test_views.py │ ├── urls.py │ └── views.py ├── emailverification │ ├── __init__.py │ ├── admin.py │ ├── forms.py │ ├── models.py │ ├── tests │ │ ├── __init__.py │ │ └── test_views.py │ ├── urls.py │ └── views.py └── profiles │ ├── __init__.py │ ├── forms.py │ ├── models.py │ ├── tests │ ├── __init__.py │ └── test_views.py │ ├── urls.py │ └── views.py ├── forms.py ├── locale └── de │ └── LC_MESSAGES │ ├── django.mo │ └── django.po ├── mixins.py ├── models.py ├── settings.py ├── templates └── userprofiles │ ├── email_change.html │ ├── email_change_requested.html │ ├── logged_out.html │ ├── login.html │ ├── mails │ ├── activation_email.html │ ├── activation_email_subject.html │ ├── emailverification.html │ ├── emailverification_subject.html │ └── password_reset_email.html │ ├── password_change.html │ ├── password_change_done.html │ ├── password_reset.html │ ├── password_reset_complete.html │ ├── password_reset_confirm.html │ ├── password_reset_done.html │ ├── profile.html │ ├── profile_change.html │ ├── registration.html │ ├── registration_activate.html │ └── registration_complete.html ├── tests ├── __init__.py ├── test_auth_backends.py ├── test_forms.py ├── test_settings.py ├── test_utils.py └── test_views.py ├── urls.py ├── utils.py └── views.py /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | env: 6 | - DJANGO=1.4.5 7 | - DJANGO=1.5 8 | install: 9 | - pip install -q Django==$DJANGO --use-mirrors 10 | - pip install -q -r test_project/requirements.txt --use-mirrors 11 | - pip install -q -e . --use-mirrors 12 | 13 | script: 14 | - make test 15 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * Stephan Jaekel 2 | * Frank Wiles 3 | * Peter Heise 4 | 5 | Translations: 6 | 7 | * Horst Gutmann 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Stephan Jaekel 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name django-userprofiles nor the names of its contributors may 13 | be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include AUTHORS 3 | include README.rst 4 | recursive-include userprofiles/templates *.html 5 | recursive-include userprofiles/locale *.po 6 | recursive-include userprofiles/locale *.mo 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | flake8 userprofiles --ignore=E501,E128 3 | coverage run --branch --source=userprofiles `which django-admin.py` test --settings=test_project.settings userprofiles 4 | coverage report --show-missing --omit=*test* 5 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | django-userprofiles 2 | =================== 3 | 4 | django-userprofiles is a simple registration app with some extra features. 5 | 6 | 7 | Registration settings 8 | --------------------- 9 | 10 | `USERPROFILES_CHECK_UNIQUE_EMAIL` 11 | If enabled, the form checks if the user provided email is already in use. 12 | (useful if you want to allow user to log in with their email address) 13 | 14 | `USERPROFILES_DOUBLE_CHECK_EMAIL` 15 | If enabled, the form shows two email fields. The user is required to enter 16 | the same email address twice. 17 | 18 | `USERPROFILES_DOUBLE_CHECK_PASSWORD` 19 | If enabled, the form shows two password fields. The user is required to 20 | enter the same password twice to proceed. 21 | 22 | `USERPROFILES_REGISTRATION_FULLNAME` 23 | If enabled, the registration form adds two fields for first and last name. 24 | 25 | `USERPROFILES_REGISTRATION_FORM` 26 | You can override the default registration form by changing this setting. 27 | Defaults to 'userprofiles.forms.RegistrationForm'. 28 | 29 | `USERPROFILES_USE_ACCOUNT_VERIFICATION` 30 | This app provides a mechanism to verify user accounts by sending an email 31 | with an activation link. To use the account verification you have to add 32 | `userprofiles.contrib.accountverification` to your `INSTALLED_APPS` in 33 | order to enable the verification. 34 | 35 | `USERPROFILES_ACCOUNT_VERIFICATION_DAYS` 36 | Defines the amount of days a user has to activate his account. Defaults to 37 | 7. 38 | 39 | `USERPROFILES_EMAIL_ONLY` 40 | Removes the username field and generates a UUID for the required username 41 | for sites that want to use email addresses as logins. 42 | 43 | `USERPROFILES_AUTO_LOGIN` 44 | Automatically log the user in upon registration. This setting cannot be 45 | used in conjunction with `USERPROFILES_USE_ACCOUNT_VERIFICATION`. 46 | 47 | `USERPROFILES_REDIRECT_ON_REGISTRATION` 48 | Define a named URL to redirect the user upon successful registration. 49 | Defaults to 'userprofiles_registration_complete'. 50 | 51 | Profile settings 52 | ---------------- 53 | 54 | django-userprofiles is prepared to work with profile models and provides some 55 | features to make it easy to manage these profiles. 56 | 57 | `USERPROFILES_USE_PROFILE` 58 | If enabled, userprofiles will look for the model set in 59 | `AUTH_PROFILE_MODULE`. it's likely that you need to overwrite 60 | `USERPROFILES_REGISTRATION_FORM` to add your additional profile fields and 61 | define a `save_profile` method which is called after the user was created. 62 | 63 | `USERPROFILES_INLINE_PROFILE_ADMIN` 64 | If enabled, userprofiles will add a profile inline to you user admin. 65 | 66 | 67 | userprofiles.contrib.profiles 68 | ------------------------------ 69 | 70 | django-userprofiles also comes with a contrib app to allow profile changes and 71 | a profile view. 72 | 73 | `USERPROFILES_PROFILE_FORM` 74 | You can overwrite the default profile form to add extra functionality. 75 | The default form is a ModelForm for you AUTH_PROFILE_MODULE. 76 | 77 | `USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE` 78 | If enabled, the user is allowed to simply change the email address in the 79 | profile change view. This setting can only be activated if 80 | `USERPROFILES_CHECK_UNIQUE_EMAIL` is disabled. 81 | 82 | If you want to check for unique emails and allow your users to change 83 | their email addresses, you have to use the emailverification app. 84 | 85 | `USERPROFILES_PROFILE_CHANGE_DONE_URL` 86 | Defines the redirect destination after the profile was saved. Defaults to 87 | the named URL `userprofiles_profile_change`. 88 | 89 | 90 | userprofiles.contrib.emailverification 91 | -------------------------------------- 92 | 93 | django-userprofiles provides a simple app to do confirmed email address changes. 94 | (Users have the re-verify their email address after a change) 95 | 96 | `USERPROFILES_USE_EMAIL_VERIFICATION` 97 | This app provides a mechanism to verify email changes by sending an email 98 | with an activation link. To use the email verification you have to add 99 | `userprofiles.contrib.emailverification` to your `INSTALLED_APPS` in 100 | order to enable the verification. 101 | 102 | `USERPROFILES_EMAIL_VERIFICATION_DAYS` 103 | Defines the number of days a user has time to verify her/his new email 104 | address. Defaults to 2. 105 | 106 | `USERPROFILES_EMAIL_VERIFICATION_DONE_URL` 107 | Defines the redirect destination after the email change was verified. 108 | Defaults to the named URL `userprofiles_email_change`. 109 | 110 | 111 | Tools 112 | ----- 113 | 114 | There is an auth backend which allows your users to log in using their email 115 | address. Add `userprofiles.auth_backends.EmailOrUsernameModelBackend` to your 116 | settings if you want to use this feature. 117 | 118 | 119 | Kudos to (the people who inspired me to write this code) 120 | -------------------------------------------------------- 121 | 122 | - django-registration by James Bennett 123 | (https://bitbucket.org/ubernostrum/django-registration/) 124 | 125 | - to be continued.. 126 | If I used your code, send me a message! I'll add you to this list. 127 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs, os 2 | from setuptools import setup, find_packages 3 | 4 | def read(fname): 5 | return codecs.open(os.path.join(os.path.dirname(__file__), fname)).read() 6 | 7 | setup( 8 | name='django-userprofiles', 9 | version='0.4', 10 | description='Registration, e-mail verifications and profiles.', 11 | long_description=read('README.rst'), 12 | author='Stephan Jaekel', 13 | author_email='steph@rdev.info', 14 | url='https://github.com/stephrdev/django-userprofiles/', 15 | packages=find_packages(exclude=['test_project', 'test_project.*']), 16 | package_data = { 17 | 'userprofiles': ['templates/userprofiles/*.html', 'templates/userprofiles/*/*.html', 18 | 'locale/de/LC_MESSAGES/*'], 19 | }, 20 | classifiers=[ 21 | 'Development Status :: 4 - Beta', 22 | 'Environment :: Web Environment', 23 | 'Intended Audience :: Developers', 24 | 'License :: OSI Approved :: BSD License', 25 | 'Operating System :: OS Independent', 26 | 'Programming Language :: Python', 27 | 'Framework :: Django', 28 | ], 29 | zip_safe=False, 30 | ) 31 | -------------------------------------------------------------------------------- /test_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/test_project/__init__.py -------------------------------------------------------------------------------- /test_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /test_project/requirements.txt: -------------------------------------------------------------------------------- 1 | django-discover-runner 2 | flake8 3 | coverage 4 | -------------------------------------------------------------------------------- /test_project/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | TEST_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 4 | '..', 'userprofiles', 'tests')) 5 | 6 | TEST_RUNNER = 'discover_runner.DiscoverRunner' 7 | 8 | DATABASES = { 9 | 'default': { 10 | 'ENGINE': 'django.db.backends.sqlite3', 11 | 'NAME': ':memory:', 12 | } 13 | } 14 | 15 | INSTALLED_APPS = [ 16 | 'django.contrib.auth', 17 | 'django.contrib.contenttypes', 18 | 'django.contrib.sessions', 19 | 'django.contrib.sites', 20 | 'userprofiles', 21 | 'userprofiles.contrib.accountverification', 22 | 'userprofiles.contrib.emailverification', 23 | 'userprofiles.contrib.profiles', 24 | 'test_project.test_accounts', 25 | ] 26 | 27 | TEMPLATE_DIRS = ( 28 | os.path.join(os.path.dirname(__file__), 'templates'), 29 | ) 30 | 31 | ROOT_URLCONF = 'test_project.urls' 32 | 33 | SITE_ID = 1 34 | 35 | SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 36 | -------------------------------------------------------------------------------- /test_project/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% block content %} 8 | {% endblock %} 9 | 10 | 11 | -------------------------------------------------------------------------------- /test_project/test_accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/test_project/test_accounts/__init__.py -------------------------------------------------------------------------------- /test_project/test_accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Profile 3 | 4 | from userprofiles.forms import RegistrationForm 5 | 6 | 7 | class ProfileRegistrationForm(RegistrationForm): 8 | short_info = forms.CharField(widget=forms.Textarea) 9 | 10 | def save_profile(self, new_user, *args, **kwargs): 11 | Profile.objects.create( 12 | user=new_user, 13 | short_info=self.cleaned_data['short_info'] 14 | ) 15 | -------------------------------------------------------------------------------- /test_project/test_accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class Profile(models.Model): 6 | user = models.OneToOneField(User) 7 | 8 | short_info = models.TextField(blank=True) 9 | -------------------------------------------------------------------------------- /test_project/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include 2 | 3 | 4 | urlpatterns = patterns('', 5 | (r'^userprofiles/', include('userprofiles.urls')), 6 | ) 7 | -------------------------------------------------------------------------------- /userprofiles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/__init__.py -------------------------------------------------------------------------------- /userprofiles/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib import admin 3 | from django.contrib.auth.admin import UserAdmin 4 | from django.contrib.auth.models import User 5 | 6 | from userprofiles.settings import up_settings 7 | 8 | 9 | if up_settings.USE_PROFILE and up_settings.INLINE_PROFILE_ADMIN: 10 | from userprofiles.utils import UserProfile 11 | 12 | admin.site.unregister(User) 13 | 14 | class UserProfileInline(admin.StackedInline): 15 | model = UserProfile 16 | extra = 1 17 | max_num = 1 18 | 19 | class UserProfileAdmin(UserAdmin): 20 | inlines = [UserProfileInline] 21 | 22 | admin.site.register(User, UserProfileAdmin) 23 | -------------------------------------------------------------------------------- /userprofiles/auth_backends.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib.auth.backends import ModelBackend 3 | from django.contrib.auth.models import User 4 | 5 | 6 | class EmailOrUsernameModelBackend(ModelBackend): 7 | def authenticate(self, username=None, password=None): 8 | if '@' in username: 9 | kwargs = {'email': username} 10 | else: 11 | kwargs = {'username': username} 12 | try: 13 | user = User.objects.get(**kwargs) 14 | if user.check_password(password): 15 | return user 16 | except User.DoesNotExist: 17 | return None 18 | -------------------------------------------------------------------------------- /userprofiles/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/accountverification/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib import admin 3 | 4 | from userprofiles.contrib.accountverification.models import AccountVerification 5 | 6 | 7 | class AccountVerificationAdmin(admin.ModelAdmin): 8 | list_display = ('__unicode__', 'activation_key_expired') 9 | search_fields = ('user__username', 'user__first_name', 'user__last_name') 10 | 11 | admin.site.register(AccountVerification, AccountVerificationAdmin) 12 | -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from datetime import timedelta 3 | import hashlib 4 | import random 5 | import re 6 | import uuid 7 | 8 | from django.conf import settings 9 | from django.contrib.sites.models import Site 10 | from django.contrib.auth.models import User 11 | from django.core.mail import send_mail 12 | from django.db import models 13 | from django.template.loader import render_to_string 14 | from django.utils.translation import gettext_lazy as _ 15 | from django.utils import timezone 16 | 17 | from userprofiles.settings import up_settings 18 | 19 | SHA1_RE = re.compile('^[a-f0-9]{40}$') 20 | 21 | 22 | class AccountVerificationManager(models.Manager): 23 | def activate_user(self, activation_key): 24 | if SHA1_RE.search(activation_key): 25 | try: 26 | verification = self.get(activation_key=activation_key) 27 | except self.model.DoesNotExist: 28 | return False 29 | 30 | if not verification.activation_key_expired(): 31 | user = verification.user 32 | user.is_active = True 33 | user.save() 34 | 35 | verification.activation_key = self.model.ACTIVATED 36 | verification.save() 37 | 38 | return user 39 | 40 | return False 41 | 42 | def create_inactive_user(self, username, password, email): 43 | new_user = User.objects.create_user(username, email, password) 44 | new_user.is_active = False 45 | new_user.save() 46 | 47 | account_verification = self.create_verification(new_user) 48 | current_site = Site.objects.get_current() 49 | 50 | subject = ''.join(render_to_string( 51 | 'userprofiles/mails/activation_email_subject.html', 52 | {'site': current_site}).splitlines()) 53 | 54 | message = render_to_string('userprofiles/mails/activation_email.html', { 55 | 'activation_key': account_verification.activation_key, 56 | 'expiration_days': up_settings.ACCOUNT_VERIFICATION_DAYS, 57 | 'site': current_site}) 58 | 59 | send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [new_user.email]) 60 | 61 | return new_user 62 | 63 | def create_verification(self, user): 64 | salt = hashlib.sha1(str(random.random())).hexdigest()[:5] 65 | activation_key = hashlib.sha1(salt + str(uuid.uuid4())).hexdigest() 66 | return self.create(user=user, activation_key=activation_key) 67 | 68 | def delete_expired_users(self): 69 | for verification in self.all(): 70 | if verification.activation_key_expired(): 71 | user = verification.user 72 | if not user.is_active: 73 | user.delete() 74 | 75 | 76 | class AccountVerification(models.Model): 77 | ACTIVATED = 'ALREADY_ACTIVATED' 78 | 79 | user = models.ForeignKey(User, unique=True, verbose_name=_('User')) 80 | activation_key = models.CharField(_('Activation key'), max_length=40) 81 | 82 | objects = AccountVerificationManager() 83 | 84 | def __unicode__(self): 85 | return u'Account verification: %s' % self.user 86 | 87 | def activation_key_expired(self): 88 | expiration_date = timedelta(days=up_settings.ACCOUNT_VERIFICATION_DAYS) 89 | return (self.activation_key == self.ACTIVATED 90 | or (self.user.date_joined + expiration_date <= timezone.now())) 91 | activation_key_expired.boolean = True 92 | 93 | class Meta: 94 | app_label = 'userprofiles' 95 | verbose_name = _('Account verification') 96 | verbose_name_plural = _('Account verifications') 97 | -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/accountverification/tests/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | 3 | from django.contrib.auth.models import User 4 | from django.test import TestCase 5 | 6 | from userprofiles.contrib.accountverification.models import AccountVerification 7 | from userprofiles.settings import up_settings 8 | 9 | 10 | class ModelsTests(TestCase): 11 | def setUp(self): 12 | self.data = { 13 | 'username': 'newuser', 14 | 'email': 'newuser@example.com', 15 | 'password': 'newuserpass', 16 | } 17 | 18 | def test_activate_user(self): 19 | user = AccountVerification.objects.create_inactive_user( 20 | self.data['username'], self.data['password'], self.data['email']) 21 | user.date_joined = user.date_joined - timedelta( 22 | days=up_settings.ACCOUNT_VERIFICATION_DAYS, seconds=1) 23 | user.save() 24 | 25 | verification = AccountVerification.objects.get(user=user) 26 | 27 | self.assertFalse( 28 | AccountVerification.objects.activate_user('wrong-pattern-format')) 29 | 30 | self.assertFalse( 31 | AccountVerification.objects.activate_user('f4a80274f851cb41ef9c20d00426d72fc4874471')) 32 | 33 | self.assertFalse( 34 | AccountVerification.objects.activate_user(verification.activation_key)) 35 | 36 | def test_delete_expired_users(self): 37 | user = AccountVerification.objects.create_inactive_user( 38 | self.data['username'], self.data['password'], self.data['email']) 39 | 40 | # Test with inactive user, but not expired 41 | AccountVerification.objects.delete_expired_users() 42 | self.assertTrue(User.objects.filter(pk=user.pk).exists()) 43 | 44 | # Test with active and not expired user 45 | user.is_active = True 46 | user.save() 47 | AccountVerification.objects.delete_expired_users() 48 | self.assertTrue(User.objects.filter(pk=user.pk).exists()) 49 | 50 | # Test with active but expired user 51 | user.date_joined = user.date_joined - timedelta( 52 | days=up_settings.ACCOUNT_VERIFICATION_DAYS + 1) 53 | user.save() 54 | AccountVerification.objects.delete_expired_users() 55 | self.assertTrue(User.objects.filter(pk=user.pk).exists()) 56 | 57 | # Test with expired and inactive user 58 | user.is_active = False 59 | user.save() 60 | AccountVerification.objects.delete_expired_users() 61 | self.assertFalse(User.objects.filter(pk=user.pk).exists()) 62 | -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/tests/test_views.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from django.core import mail 4 | from django.core.urlresolvers import reverse 5 | from django.test import TestCase 6 | from django.test.utils import override_settings 7 | 8 | from userprofiles.contrib.accountverification.models import AccountVerification 9 | 10 | 11 | @override_settings(USE_ACCOUNT_VERIFICATION=True) 12 | class ViewTests(TestCase): 13 | def setUp(self): 14 | self.data = { 15 | 'username': 'newuser', 16 | 'email': 'newuser@example.com', 17 | 'password': 'newuserpass', 18 | } 19 | 20 | def test_registration_activate(self): 21 | AccountVerification.objects.create_inactive_user( 22 | self.data['username'], self.data['password'], self.data['email']) 23 | 24 | self.assertEqual(len(mail.outbox), 1) 25 | 26 | activation_key_match = re.findall( 27 | r'http://example.com/userprofiles/activate/(\w+)', 28 | mail.outbox[0].body, re.MULTILINE) 29 | 30 | self.assertEqual(len(activation_key_match), 1) 31 | 32 | activation_key = activation_key_match[0] 33 | 34 | url = reverse('userprofiles_registration_activate', 35 | kwargs={'activation_key': activation_key}) 36 | 37 | response = self.client.get(url) 38 | self.assertTrue( 39 | 'We activated your account. You are now able to log in. Have fun!' in 40 | response.content) 41 | -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import patterns, url 3 | 4 | 5 | urlpatterns = patterns('userprofiles.contrib.accountverification.views', 6 | url(r'^(?P\w+)/$', 'registration_activate', 7 | name='userprofiles_registration_activate'), 8 | ) 9 | -------------------------------------------------------------------------------- /userprofiles/contrib/accountverification/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.views.generic import TemplateView 3 | 4 | from userprofiles.contrib.accountverification.models import AccountVerification 5 | from userprofiles.settings import up_settings 6 | 7 | 8 | class RegistrationActivateView(TemplateView): 9 | template_name = 'userprofiles/registration_activate.html' 10 | 11 | def get_context_data(self, **kwargs): 12 | activation_key = kwargs['activation_key'].lower() 13 | account = AccountVerification.objects.activate_user(activation_key) 14 | 15 | return { 16 | 'account': account, 17 | 'expiration_days': up_settings.ACCOUNT_VERIFICATION_DAYS 18 | } 19 | 20 | registration_activate = RegistrationActivateView.as_view() 21 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/emailverification/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib import admin 3 | 4 | from userprofiles.contrib.emailverification.models import EmailVerification 5 | 6 | 7 | class EmailVerificationAdmin(admin.ModelAdmin): 8 | list_display = ('user', 'old_email', 'new_email', 'expiration_date', 9 | 'is_approved', 'is_expired') 10 | list_filter = ('is_approved', 'is_expired') 11 | 12 | admin.site.register(EmailVerification, EmailVerificationAdmin) 13 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django import forms 3 | from django.conf import settings 4 | from django.contrib.auth.models import User 5 | from django.contrib.sites.models import Site 6 | from django.core.mail import send_mail 7 | from django.template.loader import render_to_string 8 | from django.utils.translation import ugettext_lazy as _ 9 | 10 | from userprofiles.contrib.emailverification.models import EmailVerification 11 | 12 | 13 | class ChangeEmailForm(forms.Form): 14 | new_email = forms.EmailField(label=_('New e-mail address'), required=True) 15 | 16 | def clean_new_email(self): 17 | new_email = self.cleaned_data['new_email'] 18 | 19 | user_emails = User.objects.filter(email__iexact=new_email).count() 20 | verification_emails = EmailVerification.objects.filter( 21 | new_email__iexact=new_email, is_expired=False).count() 22 | if user_emails + verification_emails > 0: 23 | raise forms.ValidationError(_( 24 | 'This email address is already in use. Please supply a different email address.')) 25 | 26 | return new_email 27 | 28 | def save(self, user): 29 | verification = EmailVerification.objects.create(user=user, 30 | old_email=user.email, new_email=self.cleaned_data['new_email']) 31 | 32 | context = { 33 | 'user': user, 34 | 'verification': verification, 35 | 'site': Site.objects.get_current(), 36 | } 37 | 38 | subject = ''.join(render_to_string( 39 | 'userprofiles/mails/emailverification_subject.html', context).splitlines()) 40 | body = render_to_string('userprofiles/mails/emailverification.html', context) 41 | 42 | send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, 43 | [self.cleaned_data['new_email']]) 44 | 45 | return verification 46 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from datetime import timedelta 3 | import uuid 4 | 5 | from django.contrib.auth.models import User 6 | from django.db import models 7 | from django.utils import timezone 8 | from django.utils.translation import ugettext_lazy as _ 9 | 10 | from userprofiles.settings import up_settings 11 | 12 | 13 | def generate_token(): 14 | return str(uuid.uuid4()) 15 | 16 | 17 | def generate_confirm_expire_date(): 18 | return timezone.now() + timedelta(days=up_settings.EMAIL_VERIFICATION_DAYS) 19 | 20 | 21 | class EmailVerification(models.Model): 22 | user = models.ForeignKey(User, verbose_name=_('User'), blank=False) 23 | old_email = models.EmailField(_('Old e-mail address')) 24 | new_email = models.EmailField(_('New e-mail address')) 25 | 26 | token = models.CharField(_('Token'), max_length=40, default=generate_token) 27 | code = models.CharField(_('Code'), max_length=40, default=generate_token) 28 | 29 | is_approved = models.BooleanField(_('Approved'), default=False) 30 | is_expired = models.BooleanField(_('Expired'), default=False) 31 | 32 | expiration_date = models.DateTimeField(_('Expiration date'), 33 | default=generate_confirm_expire_date) 34 | 35 | def __unicode__(self): 36 | return '%s - %s/%s' % (self.user, self.old_email, self.new_email) 37 | 38 | def save(self, *args, **kwargs): 39 | if self.is_approved: 40 | EmailVerification.objects.filter( 41 | user=self.user, is_approved=False).update(is_expired=True) 42 | 43 | self.is_expired = True 44 | 45 | if self.user.email == self.old_email: 46 | self.user.email = self.new_email 47 | self.user.save() 48 | return super(EmailVerification, self).save(*args, **kwargs) 49 | 50 | class Meta: 51 | app_label = 'userprofiles' 52 | verbose_name = _('E-mail verification') 53 | verbose_name_plural = _('E-mail verifications') 54 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/emailverification/tests/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.core.urlresolvers import reverse 3 | from django.test import TestCase 4 | from django.test.utils import override_settings 5 | 6 | from userprofiles.contrib.emailverification.models import EmailVerification 7 | from userprofiles.settings import up_settings 8 | 9 | 10 | @override_settings(USERPROFILES_USE_PROFILE=False, USERPROFILES_USE_EMAIL_VERIFICATION=True) 11 | class ViewTests(TestCase): 12 | 13 | def setUp(self): 14 | self.data = { 15 | 'username': 'newuser', 16 | 'email': 'newuser@example.com', 17 | 'email_repeat': 'newuser@example.com', 18 | 'password': 'newuserpass', 19 | 'password_repeat': 'newuserpass', 20 | 'first_name': 'New', 21 | 'last_name': 'User', 22 | } 23 | 24 | self.user = User.objects.create_user(self.data['username'], 25 | self.data['email'], self.data['password']) 26 | 27 | def tearDown(self): 28 | self.user.delete() 29 | 30 | def test_email_change(self): 31 | self.client.login(username=self.data['username'], password=self.data['password']) 32 | 33 | response = self.client.get(reverse('userprofiles_email_change')) 34 | 35 | response = self.client.post(reverse('userprofiles_email_change'), 36 | {'new_email': 'test@example.com'}, follow=True) 37 | 38 | self.assertTrue(EmailVerification.objects.filter(user=self.user).exists()) 39 | 40 | self.assertEqual(response.context['expiration_days'], up_settings.EMAIL_VERIFICATION_DAYS) 41 | 42 | def test_email_change_email_in_use(self): 43 | EmailVerification.objects.create( 44 | user=self.user, old_email=self.user.email, new_email='test@example.com') 45 | 46 | self.client.login(username=self.data['username'], password=self.data['password']) 47 | 48 | response = self.client.post(reverse('userprofiles_email_change'), 49 | {'new_email': 'test@example.com'}, follow=True) 50 | 51 | self.assertEqual(response.status_code, 200) 52 | self.assertFormError(response, 'form', 'new_email', 53 | [u'This email address is already in use. Please supply a different email address.']) 54 | 55 | def test_email_change_approve(self): 56 | verification = EmailVerification.objects.create( 57 | user=self.user, old_email=self.user.email, new_email='test@example.com') 58 | 59 | self.client.login(username=self.data['username'], password=self.data['password']) 60 | 61 | url = reverse('userprofiles_email_change_approve', 62 | kwargs={'token': verification.token, 'code': verification.code}) 63 | response = self.client.get(url) 64 | 65 | self.assertEqual(response.status_code, 302) 66 | self.assertEqual(User.objects.get(pk=self.user.pk).email, 'test@example.com') 67 | 68 | self.assertFalse(EmailVerification.objects.filter(user=self.user, 69 | is_approved=False).exists()) 70 | 71 | def test_email_change_approve_not_exists(self): 72 | verification = EmailVerification.objects.create( 73 | user=self.user, old_email=self.user.email, new_email='test@example.com') 74 | 75 | self.client.login(username=self.data['username'], password=self.data['password']) 76 | 77 | url = reverse('userprofiles_email_change_approve', 78 | kwargs={'token': verification.token, 'code': 'wrong-code'}) 79 | response = self.client.get(url) 80 | 81 | self.assertEqual(response.status_code, 302) 82 | self.assertEqual(User.objects.get(pk=self.user.pk).email, self.user.email) 83 | 84 | url = reverse('userprofiles_email_change_approve', 85 | kwargs={'token': 'wrong-token', 'code': verification.code}) 86 | response = self.client.get(url) 87 | 88 | self.assertEqual(response.status_code, 302) 89 | self.assertEqual(User.objects.get(pk=self.user.pk).email, self.user.email) 90 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import patterns, url 3 | 4 | 5 | urlpatterns = patterns('userprofiles.contrib.emailverification.views', 6 | url(r'^$', 'email_change', name='userprofiles_email_change'), 7 | url(r'^requested/$', 'email_change_requested', 8 | name='userprofiles_email_change_requested'), 9 | url(r'^verify/(?P[0-9A-Za-z-]+)/(?P[0-9A-Za-z-]+)/$', 10 | 'email_change_approve', name='userprofiles_email_change_approve'), 11 | ) 12 | -------------------------------------------------------------------------------- /userprofiles/contrib/emailverification/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib import messages 3 | from django.core.urlresolvers import reverse 4 | from django.shortcuts import redirect 5 | from django.utils.translation import ugettext_lazy as _ 6 | from django.views.generic import FormView, TemplateView, RedirectView 7 | 8 | from userprofiles.contrib.emailverification.forms import ChangeEmailForm 9 | from userprofiles.contrib.emailverification.models import EmailVerification 10 | from userprofiles.mixins import LoginRequiredMixin 11 | from userprofiles.settings import up_settings 12 | 13 | 14 | class EmailChangeView(LoginRequiredMixin, FormView): 15 | template_name = 'userprofiles/email_change.html' 16 | form_class = ChangeEmailForm 17 | 18 | def form_valid(self, form): 19 | form.save(self.request.user) 20 | return redirect('userprofiles_email_change_requested') 21 | 22 | email_change = EmailChangeView.as_view() 23 | 24 | 25 | class EmailChangeRequestedView(LoginRequiredMixin, TemplateView): 26 | template_name = 'userprofiles/email_change_requested.html' 27 | 28 | def get_context_data(self, **kwargs): 29 | return { 30 | 'expiration_days': up_settings.EMAIL_VERIFICATION_DAYS 31 | } 32 | 33 | email_change_requested = EmailChangeRequestedView.as_view() 34 | 35 | 36 | class EmailChangeApproveView(LoginRequiredMixin, RedirectView): 37 | permanent = False 38 | 39 | def get_redirect_url(self, token, code): 40 | try: 41 | verification = EmailVerification.objects.get(token=token, code=code, 42 | user=self.request.user, is_expired=False, is_approved=False) 43 | 44 | verification.is_approved = True 45 | verification.save() 46 | 47 | messages.success(self.request, _(u'E-mail address changed to %(email)s' % { 48 | 'email': verification.new_email})) 49 | 50 | except EmailVerification.DoesNotExist: 51 | messages.error(self.request, 52 | _(u'Unable to change e-mail address. Confirmation link is invalid.')) 53 | 54 | return reverse(up_settings.EMAIL_VERIFICATION_DONE_URL) 55 | 56 | email_change_approve = EmailChangeApproveView.as_view() 57 | -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/profiles/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django import forms 3 | from django.utils.translation import ugettext_lazy as _ 4 | 5 | from userprofiles.settings import up_settings 6 | from userprofiles.utils import UserProfile 7 | 8 | 9 | class ProfileForm(forms.ModelForm): 10 | first_name = forms.CharField(label=_('First name'), required=False) 11 | last_name = forms.CharField(label=_('Last name'), required=False) 12 | email = forms.EmailField(label=_('E-mail')) 13 | 14 | def __init__(self, *args, **kwargs): 15 | super(ProfileForm, self).__init__(*args, **kwargs) 16 | 17 | if not up_settings.PROFILE_ALLOW_EMAIL_CHANGE: 18 | del self.fields['email'] 19 | else: 20 | self.fields.keyOrder.remove('email') 21 | self.fields.keyOrder.insert(0, 'email') 22 | 23 | if not up_settings.REGISTRATION_FULLNAME: 24 | del self.fields['first_name'] 25 | del self.fields['last_name'] 26 | else: 27 | self.fields.keyOrder.remove('first_name') 28 | self.fields.keyOrder.remove('last_name') 29 | self.fields.keyOrder.insert(0, 'first_name') 30 | self.fields.keyOrder.insert(1, 'last_name') 31 | 32 | def save(self, *args, **kwargs): 33 | obj = super(ProfileForm, self).save(*args, **kwargs) 34 | if up_settings.REGISTRATION_FULLNAME: 35 | obj.user.first_name = self.cleaned_data['first_name'] 36 | obj.user.last_name = self.cleaned_data['last_name'] 37 | 38 | if up_settings.PROFILE_ALLOW_EMAIL_CHANGE: 39 | obj.user.email = self.cleaned_data['email'] 40 | 41 | if up_settings.REGISTRATION_FULLNAME or up_settings.PROFILE_ALLOW_EMAIL_CHANGE: 42 | obj.user.save() 43 | 44 | if hasattr(self, 'save_profile'): 45 | self.save_profile(obj, *args, **kwargs) 46 | 47 | return obj 48 | 49 | class Meta: 50 | model = UserProfile 51 | exclude = ('user',) 52 | -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/contrib/profiles/tests/__init__.py -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.core.urlresolvers import reverse 3 | from django.test import TestCase 4 | from django.test.utils import override_settings 5 | 6 | from test_project.test_accounts.models import Profile 7 | 8 | 9 | @override_settings(USERPROFILES_USE_PROFILE=True, AUTH_PROFILE_MODULE='test_accounts.Profile') 10 | class ViewTests(TestCase): 11 | def setUp(self): 12 | self.data = { 13 | 'username': 'newuser', 14 | 'email': 'newuser@example.com', 15 | 'new_email': 'anotheremail@example.com', 16 | 'password': 'newuserpass', 17 | 'first_name': 'John', 18 | 'last_name': 'Doe', 19 | 'short_info': 'Short Info Test!' 20 | } 21 | self.user = User.objects.create_user(self.data['username'], self.data['email'], 22 | self.data['password']) 23 | Profile(user=self.user).save() 24 | 25 | def tearDown(self): 26 | User.objects.get(username=self.data['username']).delete() 27 | 28 | def test_profile_view(self): 29 | self.client.login(username=self.data['username'], password=self.data['password']) 30 | 31 | url = reverse('userprofiles_profile') 32 | response = self.client.get(url) 33 | 34 | self.assertEqual(response.context['user'], self.user) 35 | 36 | @override_settings(USERPROFILES_REGISTRATION_FULLNAME=True) 37 | def test_profile_change_fullname_enabled(self): 38 | self.client.login(username=self.data['username'], password=self.data['password']) 39 | 40 | change_url = reverse('userprofiles_profile_change') 41 | 42 | response = self.client.get(change_url) 43 | self.assertTrue('first_name' in response.context['form'].fields and 44 | 'last_name' in response.context['form'].fields) 45 | 46 | self.client.post(change_url, {'first_name': self.data['first_name'], 47 | 'last_name': self.data['last_name']}) 48 | response = self.client.get(change_url) 49 | 50 | self.assertTrue(User.objects.filter(pk=self.user.pk, 51 | first_name=self.data['first_name'], last_name=self.data['last_name']).exists()) 52 | 53 | def test_profile_change_fullname_disabled(self): 54 | self.client.login(username=self.data['username'], password=self.data['password']) 55 | 56 | change_url = reverse('userprofiles_profile_change') 57 | 58 | response = self.client.get(change_url) 59 | self.assertFalse('first_name' in response.context['form'].fields and 60 | 'last_name' in response.context['form'].fields) 61 | 62 | @override_settings(USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE=True) 63 | def test_profile_change_email_enabled(self): 64 | self.client.login(username=self.data['username'], password=self.data['password']) 65 | 66 | change_url = reverse('userprofiles_profile_change') 67 | 68 | response = self.client.get(change_url) 69 | self.assertTrue('email' in response.context['form'].fields) 70 | 71 | self.client.post(change_url, {'email': self.data['new_email']}) 72 | response = self.client.get(change_url) 73 | 74 | self.assertTrue(User.objects.filter(pk=self.user.pk, 75 | email=self.data['new_email']).exists()) 76 | 77 | # def test_profile_change_test_extra_fields(self): 78 | # self.assertEqual(self.user.profile.short_info, '') 79 | # 80 | # self.client.login(username=self.data['username'], password=self.data['password']) 81 | # 82 | # change_url = reverse('userprofiles_profile_change') 83 | # 84 | # response = self.client.get(change_url) 85 | # 86 | # self.assertTrue('short_info' in response.context['form'].fields) 87 | # 88 | # self.client.post(change_url, {'short_info': self.data['short_info']}) 89 | # response = self.client.get(change_url) 90 | # 91 | # self.assertEqual(self.user.profile.short_info, self.data['short_info']) 92 | -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | 4 | urlpatterns = patterns('userprofiles.contrib.profiles.views', 5 | url(r'^$', 'profile', 6 | name='userprofiles_profile'), 7 | url(r'^change/$', 'profile_change', 8 | name='userprofiles_profile_change'), 9 | ) 10 | -------------------------------------------------------------------------------- /userprofiles/contrib/profiles/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib import messages 3 | from django.shortcuts import redirect 4 | from django.utils.translation import ugettext_lazy as _ 5 | from django.views.generic import TemplateView, FormView 6 | 7 | from userprofiles.mixins import LoginRequiredMixin 8 | from userprofiles.settings import up_settings 9 | from userprofiles.utils import get_form_class, get_profile_model 10 | 11 | 12 | class ProfileView(LoginRequiredMixin, TemplateView): 13 | template_name = 'userprofiles/profile.html' 14 | 15 | def get_context_data(self, **kwargs): 16 | return { 17 | 'user': self.request.user, 18 | } 19 | 20 | profile = ProfileView.as_view() 21 | 22 | 23 | class ProfileChangeView(LoginRequiredMixin, FormView): 24 | form_class = get_form_class(up_settings.PROFILE_FORM) 25 | template_name = 'userprofiles/profile_change.html' 26 | 27 | def get_form_kwargs(self): 28 | kwargs = super(ProfileChangeView, self).get_form_kwargs() 29 | kwargs['instance'] = get_profile_model().objects.get( 30 | user=self.request.user) 31 | 32 | if up_settings.REGISTRATION_FULLNAME: 33 | kwargs['initial'].update({ 34 | 'first_name': self.request.user.first_name, 35 | 'last_name': self.request.user.last_name, 36 | 'email': self.request.user.email 37 | }) 38 | return kwargs 39 | 40 | def form_valid(self, form): 41 | form.save() 42 | messages.success(self.request, _(u'Profile changed')) 43 | return redirect(up_settings.PROFILE_CHANGE_DONE_URL) 44 | 45 | profile_change = ProfileChangeView.as_view() 46 | -------------------------------------------------------------------------------- /userprofiles/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from django import forms 5 | from django.contrib.auth.models import User 6 | from django.utils.translation import ugettext_lazy as _ 7 | 8 | from userprofiles.settings import up_settings 9 | 10 | 11 | class RegistrationForm(forms.Form): 12 | username = forms.RegexField(label=_("Username"), max_length=30, 13 | regex=r'^[\w.-]+$', error_messages={'invalid': _( 14 | 'This value may contain only letters, numbers and ./-/_ characters.')}) 15 | 16 | email = forms.EmailField(label=_('E-mail')) 17 | email_repeat = forms.EmailField(label=_('E-mail (repeat)'), required=True) 18 | 19 | password = forms.CharField(label=_('Password'), 20 | widget=forms.PasswordInput(render_value=False)) 21 | password_repeat = forms.CharField(label=_('Password (repeat)'), 22 | widget=forms.PasswordInput(render_value=False)) 23 | 24 | first_name = forms.CharField(label=_('First name'), required=False) 25 | last_name = forms.CharField(label=_('Last name'), required=False) 26 | 27 | def __init__(self, *args, **kwargs): 28 | super(RegistrationForm, self).__init__(*args, **kwargs) 29 | 30 | if not up_settings.DOUBLE_CHECK_EMAIL: 31 | del self.fields['email_repeat'] 32 | 33 | if not up_settings.DOUBLE_CHECK_PASSWORD: 34 | del self.fields['password_repeat'] 35 | 36 | if not up_settings.REGISTRATION_FULLNAME: 37 | del self.fields['first_name'] 38 | del self.fields['last_name'] 39 | 40 | if up_settings.EMAIL_ONLY: 41 | self.fields['username'].widget = forms.widgets.HiddenInput() 42 | self.fields['username'].required = False 43 | 44 | def _generate_username(self): 45 | """ Generate a unique username """ 46 | while True: 47 | # Generate a UUID username, removing dashes and the last 2 chars 48 | # to make it fit into the 30 char User.username field. Gracefully 49 | # handle any unlikely, but possible duplicate usernames. 50 | username = str(uuid.uuid4()) 51 | username = username.replace('-', '') 52 | username = username[:-2] 53 | 54 | try: 55 | User.objects.get(username=username) 56 | except User.DoesNotExist: 57 | return username 58 | 59 | def clean_username(self): 60 | if up_settings.EMAIL_ONLY: 61 | username = self._generate_username() 62 | else: 63 | username = self.cleaned_data['username'] 64 | if User.objects.filter(username__iexact=username): 65 | raise forms.ValidationError( 66 | _(u'A user with that username already exists.')) 67 | 68 | return username 69 | 70 | def clean_email(self): 71 | if not up_settings.CHECK_UNIQUE_EMAIL: 72 | return self.cleaned_data['email'] 73 | 74 | new_email = self.cleaned_data['email'] 75 | 76 | emails = User.objects.filter(email__iexact=new_email).count() 77 | 78 | if up_settings.USE_EMAIL_VERIFICATION: 79 | from userprofiles.contrib.emailverification.models import EmailVerification 80 | 81 | emails += EmailVerification.objects.filter( 82 | new_email__iexact=new_email, is_expired=False).count() 83 | 84 | if emails > 0: 85 | raise forms.ValidationError( 86 | _(u'This email address is already in use. Please supply a different email address.')) 87 | 88 | return new_email 89 | 90 | def clean(self): 91 | if up_settings.DOUBLE_CHECK_EMAIL: 92 | if 'email' in self.cleaned_data and 'email_repeat' in self.cleaned_data: 93 | if self.cleaned_data['email'] != self.cleaned_data['email_repeat']: 94 | raise forms.ValidationError(_('The two email addresses do not match.')) 95 | 96 | if up_settings.DOUBLE_CHECK_PASSWORD: 97 | if 'password' in self.cleaned_data and 'password_repeat' in self.cleaned_data: 98 | if self.cleaned_data['password'] != self.cleaned_data['password_repeat']: 99 | raise forms.ValidationError(_('You must type the same password each time.')) 100 | 101 | return self.cleaned_data 102 | 103 | def save(self, *args, **kwargs): 104 | if up_settings.USE_ACCOUNT_VERIFICATION: 105 | from userprofiles.contrib.accountverification.models import AccountVerification 106 | 107 | new_user = AccountVerification.objects.create_inactive_user( 108 | username=self.cleaned_data['username'], 109 | password=self.cleaned_data['password'], 110 | email=self.cleaned_data['email'], 111 | ) 112 | else: 113 | new_user = User.objects.create_user( 114 | username=self.cleaned_data['username'], 115 | password=self.cleaned_data['password'], 116 | email=self.cleaned_data['email'] 117 | ) 118 | 119 | if up_settings.REGISTRATION_FULLNAME: 120 | new_user.first_name = self.cleaned_data['first_name'] 121 | new_user.last_name = self.cleaned_data['last_name'] 122 | 123 | new_user.save() 124 | 125 | if hasattr(self, 'save_profile'): 126 | self.save_profile(new_user, *args, **kwargs) 127 | 128 | return new_user 129 | -------------------------------------------------------------------------------- /userprofiles/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /userprofiles/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2011 3 | # This file is distributed under the same license as the django-userprofiles package. 4 | # Horst Gutmann , 2012. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: 0.1\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2013-03-11 17:26+0100\n" 11 | "PO-Revision-Date: 2012-02-11 12:02+0100\n" 12 | "Last-Translator: Stephan Jaekel \n" 13 | "Language-Team: LANGUAGE \n" 14 | "Language: \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 19 | 20 | #: forms.py:12 21 | msgid "Username" 22 | msgstr "Benutzername" 23 | 24 | #: forms.py:14 25 | msgid "This value may contain only letters, numbers and ./-/_ characters." 26 | msgstr "" 27 | "Dieses Feld darf nur Buchstaben, Ziffern sowie die Zeichen ./-/_ enthalten." 28 | 29 | #: forms.py:16 contrib/profiles/forms.py:12 30 | msgid "E-mail" 31 | msgstr "E-Mail" 32 | 33 | #: forms.py:17 34 | msgid "E-mail (repeat)" 35 | msgstr "E-Mail (Wiederholung)" 36 | 37 | #: forms.py:19 38 | msgid "Password" 39 | msgstr "Passwort" 40 | 41 | #: forms.py:21 42 | msgid "Password (repeat)" 43 | msgstr "Passwort (Wiederholung)" 44 | 45 | #: forms.py:24 contrib/profiles/forms.py:10 46 | msgid "First name" 47 | msgstr "Vorname" 48 | 49 | #: forms.py:25 contrib/profiles/forms.py:11 50 | msgid "Last name" 51 | msgstr "Nachname" 52 | 53 | #: forms.py:66 54 | msgid "A user with that username already exists." 55 | msgstr "Es existiert bereits ein Benutzer mit diesem Namen." 56 | 57 | #: forms.py:86 contrib/emailverification/forms.py:24 58 | msgid "" 59 | "This email address is already in use. Please supply a different email " 60 | "address." 61 | msgstr "" 62 | "Diese E-Mail-Adresse wird bereits verwendet. Bitte geben Sie eine andere E-" 63 | "Mail-Adresse ein." 64 | 65 | #: forms.py:94 66 | msgid "The two email addresses do not match." 67 | msgstr "Die beiden E-Mail-Adressen stimmen nicht überein." 68 | 69 | #: forms.py:99 70 | msgid "You must type the same password each time." 71 | msgstr "Die beiden Passwörter müssen übereinstimmen." 72 | 73 | #: contrib/accountverification/models.py:78 74 | #: contrib/emailverification/models.py:21 75 | msgid "User" 76 | msgstr "Benutzer" 77 | 78 | #: contrib/accountverification/models.py:79 79 | msgid "Activation key" 80 | msgstr "Aktivierungscode" 81 | 82 | #: contrib/accountverification/models.py:94 83 | msgid "Account verification" 84 | msgstr "Konto-Bestätigung" 85 | 86 | #: contrib/accountverification/models.py:95 87 | msgid "Account verifications" 88 | msgstr "Konto-Bestätigungen" 89 | 90 | #: contrib/emailverification/forms.py:14 91 | #: contrib/emailverification/models.py:23 92 | msgid "New e-mail address" 93 | msgstr "Neue E-Mail Adresse" 94 | 95 | #: contrib/emailverification/models.py:22 96 | msgid "Old e-mail address" 97 | msgstr "Alte E-Mail Adresse" 98 | 99 | #: contrib/emailverification/models.py:25 100 | msgid "Token" 101 | msgstr "Token" 102 | 103 | #: contrib/emailverification/models.py:26 104 | msgid "Code" 105 | msgstr "Code" 106 | 107 | #: contrib/emailverification/models.py:28 108 | msgid "Approved" 109 | msgstr "Bestätigt" 110 | 111 | #: contrib/emailverification/models.py:29 112 | msgid "Expired" 113 | msgstr "Abgelaufen" 114 | 115 | #: contrib/emailverification/models.py:31 116 | msgid "Expiration date" 117 | msgstr "Ablaufdatum" 118 | 119 | #: contrib/emailverification/models.py:51 120 | msgid "E-mail verification" 121 | msgstr "E-Mail Bestätigung" 122 | 123 | #: contrib/emailverification/models.py:52 124 | msgid "E-mail verifications" 125 | msgstr "E-Mail Bestätigungen" 126 | 127 | #: contrib/emailverification/views.py:47 128 | #, python-format 129 | msgid "E-mail address changed to %(email)s" 130 | msgstr "E-Mail Adresse geändert in %(email)s" 131 | 132 | #: contrib/emailverification/views.py:52 133 | msgid "Unable to change e-mail address. Confirmation link is invalid." 134 | msgstr "" 135 | "E-Mail Adresse kann nicht geändert werden. Bestätigungslink ist ungültig." 136 | 137 | #: contrib/profiles/views.py:42 138 | msgid "Profile changed" 139 | msgstr "Profil aktualisiert" 140 | 141 | #: templates/userprofiles/email_change.html:4 142 | #: templates/userprofiles/email_change.html:7 143 | #: templates/userprofiles/email_change.html:15 144 | #: templates/userprofiles/email_change_requested.html:4 145 | #: templates/userprofiles/email_change_requested.html:7 146 | msgid "Change e-mail address" 147 | msgstr "E-Mail Adresse ändern" 148 | 149 | #: templates/userprofiles/email_change_requested.html:10 150 | msgid "" 151 | "We send you a e-mail including a link. Please click the link to\n" 152 | " continue changing your e-mail address. Thank you!" 153 | msgstr "" 154 | "Wir haben Ihnen eine E-Mail mit einem Link zugesandt. Bitte folgen Sie " 155 | "diesem Link, um ihre E-Mail Adresse zu ändern. Danke!" 156 | 157 | #: templates/userprofiles/logged_out.html:4 158 | #: templates/userprofiles/logged_out.html:7 159 | msgid "Logged out" 160 | msgstr "Abgemeldet" 161 | 162 | #: templates/userprofiles/login.html:5 templates/userprofiles/login.html:8 163 | #: templates/userprofiles/login.html:16 164 | msgid "Login" 165 | msgstr "Anmelden" 166 | 167 | #: templates/userprofiles/login.html:18 168 | msgid "No account? Register here." 169 | msgstr "Noch kein Konto? Melden Sie sich hier an." 170 | 171 | #: templates/userprofiles/login.html:19 172 | msgid "No Password? Reset your password here." 173 | msgstr "Passwort vergessen? Setzen Sie Ihr Passwort hier zurück." 174 | 175 | #: templates/userprofiles/password_change.html:4 176 | #: templates/userprofiles/password_change.html:7 177 | #: templates/userprofiles/password_change.html:15 178 | #: templates/userprofiles/password_change_done.html:4 179 | #: templates/userprofiles/password_change_done.html:7 180 | #: templates/userprofiles/password_reset_confirm.html:16 181 | msgid "Change password" 182 | msgstr "Passwort ändern" 183 | 184 | #: templates/userprofiles/password_change_done.html:10 185 | msgid "We successfully changed your password." 186 | msgstr "Ihr Passwort wurde erfolgreich geändert." 187 | 188 | #: templates/userprofiles/password_reset.html:4 189 | #: templates/userprofiles/password_reset.html:7 190 | #: templates/userprofiles/password_reset.html:15 191 | #: templates/userprofiles/password_reset_complete.html:4 192 | #: templates/userprofiles/password_reset_complete.html:7 193 | #: templates/userprofiles/password_reset_confirm.html:4 194 | #: templates/userprofiles/password_reset_confirm.html:7 195 | #: templates/userprofiles/password_reset_done.html:4 196 | #: templates/userprofiles/password_reset_done.html:7 197 | msgid "Reset password" 198 | msgstr "Passwort zurücksetzen" 199 | 200 | #: templates/userprofiles/password_reset_complete.html:10 201 | msgid "We successfully resetted your password." 202 | msgstr "Ihr Passwort wurde erfolgreich zurückgesetzt." 203 | 204 | #: templates/userprofiles/password_reset_confirm.html:21 205 | msgid "The reset link is invalid. Please double check the link." 206 | msgstr "" 207 | "Der Passwort-Zurücksetzen-Link ist ungültig. Bitte überprüfen Sie den Link " 208 | "nochmals." 209 | 210 | #: templates/userprofiles/password_reset_done.html:10 211 | msgid "" 212 | "We send you a e-mail including a link. Please click the\n" 213 | " link to continue resetting your password. Thank you!" 214 | msgstr "" 215 | "Wir haben Ihnen eine E-Mail mit einem Link zugesandt. Bitte folgen Sie " 216 | "diesem Link, um ihr Passwort zurückzusetzen. Danke!" 217 | 218 | #: templates/userprofiles/profile.html:4 templates/userprofiles/profile.html:7 219 | msgid "Your profile" 220 | msgstr "Ihr Profil" 221 | 222 | #: templates/userprofiles/profile.html:10 223 | #, python-format 224 | msgid "Welcome back, %(user)s!" 225 | msgstr "Willkommen zurück, %(user)s!" 226 | 227 | #: templates/userprofiles/profile_change.html:3 228 | #: templates/userprofiles/profile_change.html:6 229 | #: templates/userprofiles/profile_change.html:14 230 | msgid "Change profile" 231 | msgstr "Profil ändern" 232 | 233 | #: templates/userprofiles/registration.html:4 234 | #: templates/userprofiles/registration.html:7 235 | #: templates/userprofiles/registration_activate.html:4 236 | #: templates/userprofiles/registration_activate.html:7 237 | #: templates/userprofiles/registration_complete.html:4 238 | #: templates/userprofiles/registration_complete.html:7 239 | msgid "Registration" 240 | msgstr "Registrierung" 241 | 242 | #: templates/userprofiles/registration.html:15 243 | msgid "Create account" 244 | msgstr "Konto anlegen" 245 | 246 | #: templates/userprofiles/registration_activate.html:11 247 | msgid "We activated your account. You are now able to log in. Have fun!" 248 | msgstr "Ihr Konto wurde aktiviert. Sie können sich jetzt anmelden. Viel Spass!" 249 | 250 | #: templates/userprofiles/registration_activate.html:15 251 | msgid "The submitted activation code is invalid. Activation is not possible." 252 | msgstr "Der Aktivierungscode ist ungültig. Die Aktivierung ist nicht möglich." 253 | 254 | #: templates/userprofiles/registration_complete.html:11 255 | #, python-format 256 | msgid "" 257 | "Your registration was successful. We send you a e-mail including a link.
\n" 259 | " Please click the link to activate your account. Thank you!
\n" 261 | "
\n" 262 | " The link is valid for %(expiration_days)s days." 263 | msgstr "" 264 | "Ihre Registrierung war erfolgreich. Wir haben Ihnen eine E-Mail mit einem " 265 | "Link zugesandt.
\n" 266 | "Bitte folgen Sie diesem Link, um das Konto zu aktivieren. Danke!
\n" 267 | "
\n" 268 | "Der Link ist %(expiration_days)s Tage gültig." 269 | 270 | #: templates/userprofiles/registration_complete.html:18 271 | msgid "Your registration was successful." 272 | msgstr "Ihre Registrierung war erfolgreich." 273 | 274 | #: templates/userprofiles/mails/activation_email.html:1 275 | #, python-format 276 | msgid "" 277 | "Thank you for creating an account.\n" 278 | "\n" 279 | "Please click on the following link to activate your account:\n" 280 | "\n" 281 | "http://%(domain)s%(url)s\n" 282 | "\n" 283 | "Cheers!" 284 | msgstr "" 285 | "Danke, dass Sie ein Konto angelegt haben.\n" 286 | "\n" 287 | "Bitte klicken Sie folgenden Link, um Ihr Konto zu aktivieren:\n" 288 | "\n" 289 | "http://%(domain)s%(url)s\n" 290 | "\n" 291 | "Danke!" 292 | 293 | #: templates/userprofiles/mails/activation_email_subject.html:1 294 | msgid "Account activation" 295 | msgstr "Konto-Aktivierung" 296 | 297 | #: templates/userprofiles/mails/emailverification.html:1 298 | #, python-format 299 | msgid "" 300 | "Please click on the following link to change your email address:\n" 301 | "\n" 302 | "http://%(domain)s%(url)s\n" 303 | "\n" 304 | "Cheers!" 305 | msgstr "" 306 | "Bitte klicken Sie folgenden Link, um Ihre E-Mail Adresse zu ändern:\n" 307 | "\n" 308 | "http://%(domain)s%(url)s\n" 309 | "\n" 310 | "Danke!" 311 | 312 | #: templates/userprofiles/mails/emailverification_subject.html:1 313 | msgid "E-mail confirmation" 314 | msgstr "E-Mail Bestätigung" 315 | 316 | #: templates/userprofiles/mails/password_reset_email.html:1 317 | #, python-format 318 | msgid "" 319 | "Please click on the following link to reset your password:\n" 320 | "\n" 321 | "%(protocol)s://%(domain)s%(url)s\n" 322 | "\n" 323 | "Cheers!" 324 | msgstr "" 325 | "Bitte klicken Sie folgenden Link, um Ihr Passwort zurückzusetzen:\n" 326 | "\n" 327 | "%(protocol)s://%(domain)s%(url)s\n" 328 | "\n" 329 | "Danke!" 330 | 331 | #~ msgid "" 332 | #~ "\n" 333 | #~ " Welcome back, %(user)s!\n" 334 | #~ " " 335 | #~ msgstr "Willkommen zurück, %(user)s!" 336 | 337 | #~ msgid "Change your password" 338 | #~ msgstr "Ändern Sie Ihr Passwort" 339 | 340 | #~ msgid "Reset your password" 341 | #~ msgstr "Setzen Sie Ihr Passwort zurück" 342 | 343 | #~ msgid "Profile: %(user)s" 344 | #~ msgstr "Profil: %(user)s" 345 | 346 | #~ msgid "" 347 | #~ "\n" 348 | #~ " The link is valid for %(expiration_days)s day.\n" 349 | #~ " " 350 | #~ msgid_plural "" 351 | #~ "\n" 352 | #~ " The link is valid for %(expiration_days)s days.\n" 353 | #~ " " 354 | #~ msgstr[0] "" 355 | #~ "\n" 356 | #~ "Der Link ist für einen Tag gültig." 357 | #~ msgstr[1] "" 358 | #~ "\n" 359 | #~ "Der Link ist für %(expiration_days)s Tage gültig." 360 | -------------------------------------------------------------------------------- /userprofiles/mixins.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.decorators import login_required 2 | from django.utils.decorators import method_decorator 3 | 4 | 5 | class LoginRequiredMixin(object): 6 | """Ensures that the user is authenticated in order to access the view. 7 | http://djangosnippets.org/snippets/2442/""" 8 | 9 | @method_decorator(login_required) 10 | def dispatch(self, *args, **kwargs): 11 | return super(LoginRequiredMixin, self).dispatch(*args, **kwargs) 12 | -------------------------------------------------------------------------------- /userprofiles/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /userprofiles/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | 4 | from django.conf import settings 5 | from django.core.exceptions import ImproperlyConfigured 6 | 7 | 8 | class Settings(object): 9 | def __init__(self, **kwargs): 10 | self.defaults = kwargs 11 | 12 | def __getattr__(self, key): 13 | return getattr(settings, 'USERPROFILES_%s' % key, self.defaults[key]) 14 | 15 | 16 | up_settings = Settings( 17 | REGISTRATION_FORM='userprofiles.forms.RegistrationForm', 18 | DOUBLE_CHECK_EMAIL=False, 19 | CHECK_UNIQUE_EMAIL=False, 20 | DOUBLE_CHECK_PASSWORD=False, 21 | REGISTRATION_FULLNAME=False, 22 | # Allows user to more easily control where registrations land 23 | REGISTRATION_REDIRECT='userprofiles_registration_complete', 24 | 25 | # Only use Email field on the form 26 | EMAIL_ONLY=False, 27 | 28 | # Automatically log in the user upon registration 29 | AUTO_LOGIN=False, 30 | 31 | USE_ACCOUNT_VERIFICATION=False, 32 | ACCOUNT_VERIFICATION_DAYS=7, 33 | 34 | USE_EMAIL_VERIFICATION=False, 35 | EMAIL_VERIFICATION_DAYS=2, 36 | EMAIL_VERIFICATION_DONE_URL='userprofiles_email_change', 37 | 38 | USE_PROFILE=False, 39 | PROFILE_FORM='userprofiles.contrib.profiles.forms.ProfileForm', 40 | PROFILE_ALLOW_EMAIL_CHANGE=False, 41 | PROFILE_CHANGE_DONE_URL='userprofiles_profile_change', 42 | 43 | INLINE_PROFILE_ADMIN=False, 44 | ) 45 | 46 | 47 | def validate_settings(): 48 | if (up_settings.USE_ACCOUNT_VERIFICATION and 49 | 'userprofiles.contrib.accountverification' not in settings.INSTALLED_APPS): 50 | raise ImproperlyConfigured('You need to add `userprofiles.contrib.accountverification` ' 51 | 'to INSTALLED_APPS to use account verification.') 52 | 53 | # These settings together make no sense 54 | if up_settings.USE_ACCOUNT_VERIFICATION and up_settings.AUTO_LOGIN: 55 | raise ImproperlyConfigured("You cannot use autologin with account verification") 56 | 57 | if up_settings.USE_PROFILE and 'userprofiles.contrib.profiles' not in settings.INSTALLED_APPS: 58 | raise ImproperlyConfigured('You need to add `userprofiles.contrib.profiles` ' 59 | 'to INSTALLED_APPS to use profiles.') 60 | 61 | if up_settings.PROFILE_ALLOW_EMAIL_CHANGE and up_settings.CHECK_UNIQUE_EMAIL: 62 | raise ImproperlyConfigured( 63 | 'USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE cannot be activated ' 64 | 'when USERPROFILES_CHECK_UNIQUE_EMAIL is active.') 65 | 66 | if (up_settings.USE_EMAIL_VERIFICATION and 67 | 'userprofiles.contrib.emailverification' not in settings.INSTALLED_APPS): 68 | raise ImproperlyConfigured('You need to add `userprofiles.contrib.emailverification` ' 69 | 'to INSTALLED_APPS to use emailverification.') 70 | 71 | if up_settings.PROFILE_ALLOW_EMAIL_CHANGE and up_settings.USE_EMAIL_VERIFICATION: 72 | raise ImproperlyConfigured( 73 | 'USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE cannot be activated ' 74 | 'when USERPROFILES_USE_EMAIL_VERIFICATION is activated.') 75 | 76 | if ('test' not in sys.argv and not up_settings.USE_EMAIL_VERIFICATION and 77 | 'userprofiles.contrib.emailverification' in settings.INSTALLED_APPS): 78 | raise ImproperlyConfigured('You need to set USERPROFILES_USE_EMAIL_VERIFICATION ' 79 | 'to use `userprofiles.contrib.emailverification`') 80 | 81 | validate_settings() 82 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/email_change.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Change e-mail address" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Change e-mail address" %}

8 | 9 |
10 | {% csrf_token %} 11 |
12 | {{ form.as_p }} 13 |
14 |
15 |

16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/email_change_requested.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Change e-mail address" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Change e-mail address" %}

8 | 9 |

10 | {% blocktrans %}We send you a e-mail including a link. Please click the link to 11 | continue changing your e-mail address. Thank you!{% endblocktrans %} 12 |

13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Logged out" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Logged out" %}

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load url from future %} 4 | 5 | {% block title %}{% trans "Login" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Login" %}

9 | 10 |
11 | {% csrf_token %} 12 |
13 | {{ form.as_p }} 14 |
15 |
16 |

17 | 21 |
22 |
23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/mails/activation_email.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% load url from future %}{% url 'userprofiles_registration_activate' activation_key as activation_url %}{% blocktrans with url=activation_url domain=site.domain %}Thank you for creating an account. 2 | 3 | Please click on the following link to activate your account: 4 | 5 | http://{{ domain }}{{ url }} 6 | 7 | Cheers!{% endblocktrans %} 8 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/mails/activation_email_subject.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% trans "Account activation" %} 2 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/mails/emailverification.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% load url from future %}{% url 'userprofiles_email_change_approve' verification.token verification.code as activation_url %}{% blocktrans with url=activation_url domain=site.domain %}Please click on the following link to change your email address: 2 | 3 | http://{{ domain }}{{ url }} 4 | 5 | Cheers!{% endblocktrans %} 6 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/mails/emailverification_subject.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% trans "E-mail confirmation" %} 2 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/mails/password_reset_email.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% load url from future %}{% url 'auth_password_reset_confirm' uid token as url%}{% blocktrans with protocol=protocol domain=domain url=url %}Please click on the following link to reset your password: 2 | 3 | {{ protocol }}://{{ domain }}{{ url }} 4 | 5 | Cheers!{% endblocktrans %} 6 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_change.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Change password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Change password" %}

8 | 9 |
10 | {% csrf_token %} 11 |
12 | {{ form.as_p }} 13 |
14 |
15 |

16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Change password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Change password" %}

8 | 9 |

10 | {% blocktrans %}We successfully changed your password.{% endblocktrans %} 11 |

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_reset.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Reset password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Reset password" %}

8 | 9 |
10 | {% csrf_token %} 11 |
12 | {{ form.as_p }} 13 |
14 |
15 |

16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Reset password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Reset password" %}

8 | 9 |

10 | {% blocktrans %}We successfully resetted your password.{% endblocktrans %} 11 |

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Reset password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Reset password" %}

8 | 9 | {% if validlink %} 10 |
11 | {% csrf_token %} 12 |
13 | {{ form.as_p }} 14 |
15 |
16 |

17 |
18 |
19 | {% else %} 20 |

21 | {% blocktrans %}The reset link is invalid. Please double check the link.{% endblocktrans %} 22 |

23 | {% endif %} 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Reset password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Reset password" %}

8 | 9 |

10 | {% blocktrans %}We send you a e-mail including a link. Please click the 11 | link to continue resetting your password. Thank you!{% endblocktrans %} 12 |

13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Your profile" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Your profile" %}

8 | 9 |

10 | {% blocktrans %}Welcome back, {{ user }}!{% endblocktrans %} 11 |

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/profile_change.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Change profile" %}{% endblock %} 4 | 5 | {% block content %} 6 |

{% trans "Change profile" %}

7 | 8 |
9 | {% csrf_token %} 10 |
11 | {{ form.as_p }} 12 |
13 |
14 |

15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/registration.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Registration" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Registration" %}

8 | 9 |
10 | {% csrf_token %} 11 |
12 | {{ form.as_p }} 13 |
14 |
15 |

16 |
17 |
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/registration_activate.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Registration" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Registration" %}

8 | 9 | {% if account %} 10 |

11 | {% blocktrans %}We activated your account. You are now able to log in. Have fun!{% endblocktrans %} 12 |

13 | {% else %} 14 |

15 | {% blocktrans %}The submitted activation code is invalid. Activation is not possible.{% endblocktrans %} 16 |

17 | {% endif %} 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /userprofiles/templates/userprofiles/registration_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Registration" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Registration" %}

8 | 9 | {% if account_verification_active %} 10 |

11 | {% blocktrans %}Your registration was successful. We send you a e-mail including a link.
12 | Please click the link to activate your account. Thank you!
13 |
14 | The link is valid for {{ expiration_days }} days.{% endblocktrans %} 15 |

16 | {% else %} 17 |

18 | {% blocktrans %}Your registration was successful.{% endblocktrans %} 19 |

20 | {% endif %} 21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /userprofiles/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephrdev/django-userprofiles/79227566abe53ee9b834709b35ae276b40114c0b/userprofiles/tests/__init__.py -------------------------------------------------------------------------------- /userprofiles/tests/test_auth_backends.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate 2 | from django.contrib.auth.models import User 3 | from django.test import TestCase 4 | from django.test.utils import override_settings 5 | 6 | 7 | class AuthBackendTests(TestCase): 8 | def setUp(self): 9 | self.existing_user = User.objects.create_user(username='test', 10 | email='test@example.com', password='password') 11 | 12 | def tearDown(self): 13 | self.existing_user.delete() 14 | 15 | def test_without_email_auth_backend(self): 16 | user = authenticate(username='test2', password='password2') 17 | self.assertEqual(user, None) 18 | 19 | user = authenticate(username='test', password='password') 20 | self.assertEqual(user, self.existing_user) 21 | 22 | user = authenticate(username='test@example.com', password='password') 23 | self.assertEqual(user, None) 24 | 25 | @override_settings(AUTHENTICATION_BACKENDS=[ 26 | 'userprofiles.auth_backends.EmailOrUsernameModelBackend']) 27 | def test_with_email_auth_backend(self): 28 | user = authenticate(username='test2', password='password2') 29 | self.assertEqual(user, None) 30 | 31 | user = authenticate(username='test', password='password') 32 | self.assertEqual(user, self.existing_user) 33 | 34 | user = authenticate(username='test@example.com', password='password') 35 | self.assertEqual(user, self.existing_user) 36 | -------------------------------------------------------------------------------- /userprofiles/tests/test_forms.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.test import TestCase 3 | from django.test.utils import override_settings 4 | 5 | from userprofiles.contrib.accountverification.models import AccountVerification 6 | from userprofiles.contrib.emailverification.models import EmailVerification 7 | from userprofiles.forms import RegistrationForm 8 | 9 | 10 | class RegistrationFormTests(TestCase): 11 | """ Test Registration Form against settings """ 12 | 13 | def setUp(self): 14 | self.existing_user = User.objects.create(username='existinguser', 15 | email='existingemail@example.com') 16 | 17 | def tearDown(self): 18 | self.existing_user.delete() 19 | 20 | def test_email_repeat_disabled(self): 21 | form = RegistrationForm() 22 | self.assertFalse('email_repeat' in form.fields.keys()) 23 | 24 | @override_settings(USERPROFILES_DOUBLE_CHECK_EMAIL=True) 25 | def test_email_repeat_enabled(self): 26 | form = RegistrationForm() 27 | self.assertTrue('email_repeat' in form.fields.keys()) 28 | 29 | def test_password_repeat_disabled(self): 30 | form = RegistrationForm() 31 | self.assertFalse('password_repeat' in form.fields.keys()) 32 | 33 | @override_settings(USERPROFILES_DOUBLE_CHECK_PASSWORD=True) 34 | def test_password_repeat_enabled(self): 35 | form = RegistrationForm() 36 | self.assertTrue('password_repeat' in form.fields.keys()) 37 | 38 | def test_fullname_disabled(self): 39 | form = RegistrationForm() 40 | self.assertFalse('first_name' in form.fields.keys()) 41 | self.assertFalse('last_name' in form.fields.keys()) 42 | 43 | @override_settings(USERPROFILES_REGISTRATION_FULLNAME=True) 44 | def test_fullname_enabled(self): 45 | form = RegistrationForm() 46 | self.assertTrue('first_name' in form.fields.keys()) 47 | self.assertTrue('last_name' in form.fields.keys()) 48 | 49 | def test_clean_username_email_only_disabled(self): 50 | form = RegistrationForm({ 51 | 'username': 'test', 52 | 'email': 'test@example.com', 53 | 'password': 'password' 54 | }) 55 | self.assertTrue(form.is_valid()) 56 | 57 | form = RegistrationForm({ 58 | 'username': 'existinguser', 59 | 'email': 'test@example.com', 60 | 'password': 'password' 61 | }) 62 | self.assertFalse(form.is_valid()) 63 | 64 | def test_clean_email_unique_disabled(self): 65 | form = RegistrationForm({ 66 | 'username': 'test', 67 | 'email': 'existingemail@example.com', 68 | 'password': 'password' 69 | }) 70 | self.assertTrue(form.is_valid()) 71 | 72 | @override_settings(USERPROFILES_CHECK_UNIQUE_EMAIL=True) 73 | def test_clean_email_unique_enabled(self): 74 | form = RegistrationForm({ 75 | 'username': 'test', 76 | 'email': 'test@example.com', 77 | 'password': 'password' 78 | }) 79 | self.assertTrue(form.is_valid()) 80 | 81 | form = RegistrationForm({ 82 | 'username': 'test', 83 | 'email': 'existingemail@example.com', 84 | 'password': 'password' 85 | }) 86 | self.assertFalse(form.is_valid()) 87 | 88 | @override_settings(USERPROFILES_CHECK_UNIQUE_EMAIL=True, 89 | USERPROFILES_USE_EMAIL_VERIFICATION=True) 90 | def test_clean_email_unique_enabled_with_emailverification(self): 91 | form = RegistrationForm({ 92 | 'username': 'test', 93 | 'email': 'existingemail2@example.com', 94 | 'password': 'password' 95 | }) 96 | self.assertTrue(form.is_valid()) 97 | 98 | EmailVerification.objects.create(user=self.existing_user, 99 | old_email=self.existing_user.email, new_email='existingemail2@example.com') 100 | 101 | form = RegistrationForm({ 102 | 'username': 'test', 103 | 'email': 'existingemail2@example.com', 104 | 'password': 'password' 105 | }) 106 | self.assertFalse(form.is_valid()) 107 | 108 | @override_settings(USERPROFILES_DOUBLE_CHECK_EMAIL=True) 109 | def test_double_check_email(self): 110 | form = RegistrationForm({ 111 | 'username': 'test', 112 | 'email': 'test@example.com', 113 | 'email_repeat': 'test@example.com', 114 | 'password': 'password' 115 | }) 116 | self.assertTrue(form.is_valid()) 117 | 118 | form = RegistrationForm({ 119 | 'username': 'test', 120 | 'email': 'test@example.com', 121 | 'email_repeat': 'test2@example.com', 122 | 'password': 'password' 123 | }) 124 | self.assertFalse(form.is_valid()) 125 | 126 | @override_settings(USERPROFILES_DOUBLE_CHECK_PASSWORD=True) 127 | def test_double_check_password(self): 128 | form = RegistrationForm({ 129 | 'username': 'test', 130 | 'email': 'test@example.com', 131 | 'password': 'password', 132 | 'password_repeat': 'password' 133 | }) 134 | self.assertTrue(form.is_valid()) 135 | 136 | form = RegistrationForm({ 137 | 'username': 'test', 138 | 'email': 'test@example.com', 139 | 'password': 'password', 140 | 'password_repeat': 'password2' 141 | }) 142 | self.assertFalse(form.is_valid()) 143 | 144 | def test_form_save(self): 145 | form = RegistrationForm({ 146 | 'username': 'test', 147 | 'email': 'test@example.com', 148 | 'password': 'password' 149 | }) 150 | self.assertTrue(form.is_valid()) 151 | new_user = form.save() 152 | 153 | self.assertEqual(new_user.username, 'test') 154 | self.assertTrue(new_user.is_active) 155 | 156 | @override_settings(USERPROFILES_USE_ACCOUNT_VERIFICATION=True) 157 | def test_form_save_with_account_verification(self): 158 | form = RegistrationForm({ 159 | 'username': 'test', 160 | 'email': 'test@example.com', 161 | 'password': 'password' 162 | }) 163 | self.assertTrue(form.is_valid()) 164 | new_user = form.save() 165 | 166 | self.assertEqual(new_user.username, 'test') 167 | self.assertFalse(new_user.is_active) 168 | 169 | self.assertEqual(AccountVerification.objects.count(), 1) 170 | 171 | @override_settings(USERPROFILES_REGISTRATION_FULLNAME=True) 172 | def test_form_save_with_fullname(self): 173 | form = RegistrationForm({ 174 | 'username': 'test', 175 | 'email': 'test@example.com', 176 | 'password': 'password', 177 | 'first_name': 'First', 178 | 'last_name': 'Last', 179 | }) 180 | self.assertTrue(form.is_valid()) 181 | new_user = form.save() 182 | 183 | self.assertEqual(new_user.username, 'test') 184 | self.assertTrue(new_user.is_active) 185 | 186 | self.assertEqual(new_user.first_name, 'First') 187 | self.assertEqual(new_user.last_name, 'Last') 188 | -------------------------------------------------------------------------------- /userprofiles/tests/test_settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.exceptions import ImproperlyConfigured 3 | from django.test import TestCase 4 | from django.test.utils import override_settings 5 | 6 | from userprofiles.settings import validate_settings 7 | 8 | 9 | class SettingsTests(TestCase): 10 | @override_settings(USERPROFILES_USE_ACCOUNT_VERIFICATION=True, 11 | INSTALLED_APPS=list(set(settings.INSTALLED_APPS) - set( 12 | ['userprofiles.contrib.accountverification']))) 13 | def test_account_verification(self): 14 | self.assertRaises(ImproperlyConfigured, validate_settings) 15 | 16 | @override_settings(USERPROFILES_USE_ACCOUNT_VERIFICATION=True, 17 | USERPROFILES_AUTO_LOGIN=True) 18 | def test_account_verification_auto_login(self): 19 | self.assertRaises(ImproperlyConfigured, validate_settings) 20 | 21 | @override_settings(USERPROFILES_USE_PROFILE=True, 22 | INSTALLED_APPS=list(set(settings.INSTALLED_APPS) - set( 23 | ['userprofiles.contrib.profiles']))) 24 | def test_profile(self): 25 | self.assertRaises(ImproperlyConfigured, validate_settings) 26 | 27 | @override_settings(USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE=True, 28 | USERPROFILES_CHECK_UNIQUE_EMAIL=True) 29 | def test_profile_email_check(self): 30 | self.assertRaises(ImproperlyConfigured, validate_settings) 31 | 32 | @override_settings(USERPROFILES_USE_EMAIL_VERIFICATION=True, 33 | INSTALLED_APPS=list(set(settings.INSTALLED_APPS) - set( 34 | ['userprofiles.contrib.emailverification']))) 35 | def test_email_verification(self): 36 | self.assertRaises(ImproperlyConfigured, validate_settings) 37 | 38 | @override_settings(USERPROFILES_USE_EMAIL_VERIFICATION=True, 39 | USERPROFILES_PROFILE_ALLOW_EMAIL_CHANGE=True) 40 | def test_email_verification_allow_email_change(self): 41 | self.assertRaises(ImproperlyConfigured, validate_settings) 42 | -------------------------------------------------------------------------------- /userprofiles/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.auth.models import SiteProfileNotAvailable 3 | from django.core.exceptions import ImproperlyConfigured 4 | from django.db.models import get_model 5 | from django.test import TestCase 6 | from django.test.utils import override_settings 7 | 8 | from userprofiles import forms 9 | from userprofiles import utils 10 | 11 | 12 | class UtilsTests(TestCase): 13 | def test_get_profile_module_disabled(self): 14 | self.assertEqual(utils.get_profile_model(), None) 15 | 16 | @override_settings(USERPROFILES_USE_PROFILE=True) 17 | def test_get_profile_module_enabled(self): 18 | settings.AUTH_PROFILE_MODULE = None 19 | self.assertRaises(SiteProfileNotAvailable, utils.get_profile_model) 20 | 21 | settings.AUTH_PROFILE_MODULE = 'test_project.test_accounts.Profile' 22 | self.assertRaises(SiteProfileNotAvailable, utils.get_profile_model) 23 | 24 | settings.AUTH_PROFILE_MODULE = 'test_accounts.InvalidProfile' 25 | self.assertRaises(SiteProfileNotAvailable, utils.get_profile_model) 26 | 27 | settings.AUTH_PROFILE_MODULE = 'test_accounts.Profile' 28 | self.assertEqual(utils.get_profile_model(), get_model('test_accounts', 'Profile')) 29 | 30 | def test_get_form_class(self): 31 | self.assertEqual(utils.get_form_class('userprofiles.forms.RegistrationForm'), 32 | forms.RegistrationForm) 33 | 34 | self.assertRaises(ImproperlyConfigured, 35 | utils.get_form_class, 'userprofiles.invalid_forms.RegistrationForm') 36 | 37 | self.assertRaises(ImproperlyConfigured, 38 | utils.get_form_class, 'userprofiles.forms.InvalidRegistrationForm') 39 | -------------------------------------------------------------------------------- /userprofiles/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.core.urlresolvers import reverse 3 | from django.test import TestCase 4 | from django.test.utils import override_settings 5 | 6 | from userprofiles.settings import up_settings 7 | 8 | 9 | class ViewTests(TestCase): 10 | def setUp(self): 11 | self.data = { 12 | 'username': 'newuser', 13 | 'email': 'newuser@example.com', 14 | 'email_repeat': 'newuser@example.com', 15 | 'password': 'newuserpass', 16 | 'password_repeat': 'newuserpass', 17 | 'first_name': 'New', 18 | 'last_name': 'User', 19 | } 20 | 21 | def test_registration(self): 22 | url = reverse('userprofiles_registration') 23 | response = self.client.get(url) 24 | self.assertEqual(response.status_code, 200) 25 | 26 | response = self.client.post(url, data=self.data) 27 | 28 | self.assertEqual(response.status_code, 302) 29 | self.assertRedirects(response, 30 | reverse(up_settings.REGISTRATION_REDIRECT)) 31 | self.assertTrue(User.objects.get(username='newuser')) 32 | 33 | @override_settings(USERPROFILES_EMAIL_ONLY=True) 34 | def test_email_only_registration(self): 35 | url = reverse('userprofiles_registration') 36 | response = self.client.get(url) 37 | 38 | self.assertTrue('' in response.content) 40 | 41 | data = self.data 42 | data['username'] = '' 43 | 44 | response = self.client.post(url, data=data) 45 | self.assertEqual(response.status_code, 302) 46 | self.assertRedirects(response, 47 | reverse(up_settings.REGISTRATION_REDIRECT)) 48 | user = User.objects.get(email=data['email']) 49 | self.assertNotEqual(user.username, self.data['username']) 50 | 51 | @override_settings(USERPROFILES_AUTO_LOGIN=True) 52 | def test_auto_login(self): 53 | url = reverse('userprofiles_registration') 54 | response = self.client.post(url, data=self.data) 55 | self.assertEqual(response.status_code, 302) 56 | self.assertRedirects(response, 57 | reverse(up_settings.REGISTRATION_REDIRECT)) 58 | 59 | user = User.objects.get(username=self.data['username']) 60 | self.assertTrue(user.is_authenticated()) 61 | 62 | @override_settings(USERPROFILES_AUTO_LOGIN=True, USERPROFILES_EMAIL_ONLY=True) 63 | def test_email_and_auto_login(self): 64 | url = reverse('userprofiles_registration') 65 | response = self.client.post(url, data=self.data) 66 | self.assertEqual(response.status_code, 302) 67 | self.assertRedirects(response, 68 | reverse(up_settings.REGISTRATION_REDIRECT)) 69 | 70 | user = User.objects.get(email=self.data['email']) 71 | self.assertTrue(user.is_authenticated()) 72 | 73 | def test_registration_complete(self): 74 | """ Simple test to make sure this renders """ 75 | response = self.client.get(reverse('userprofiles_registration_complete')) 76 | self.assertEqual(response.status_code, 200) 77 | -------------------------------------------------------------------------------- /userprofiles/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf import settings 3 | from django.conf.urls import patterns, url, include 4 | 5 | 6 | urlpatterns = patterns('userprofiles.views', 7 | url(r'^register/$', 'registration', name='userprofiles_registration'), 8 | url(r'^register/complete/$', 'registration_complete', 9 | name='userprofiles_registration_complete'), 10 | ) 11 | 12 | if 'userprofiles.contrib.accountverification' in settings.INSTALLED_APPS: 13 | urlpatterns += patterns('', 14 | (r'^activate/', include('userprofiles.contrib.accountverification.urls')), 15 | ) 16 | 17 | if 'userprofiles.contrib.emailverification' in settings.INSTALLED_APPS: 18 | urlpatterns += patterns('', 19 | (r'^email/', include('userprofiles.contrib.emailverification.urls')), 20 | ) 21 | 22 | if 'userprofiles.contrib.profiles' in settings.INSTALLED_APPS: 23 | urlpatterns += patterns('', 24 | (r'^profile/', include('userprofiles.contrib.profiles.urls')), 25 | ) 26 | 27 | urlpatterns += patterns('django.contrib.auth.views', 28 | url(r'^login/$', 'login', {'template_name': 'userprofiles/login.html'}, 29 | name='auth_login'), 30 | url(r'^logout/$', 'logout', {'template_name': 'userprofiles/logged_out.html'}, 31 | name='auth_logout'), 32 | url(r'^password/change/$', 'password_change', 33 | {'template_name': 'userprofiles/password_change.html'}, 34 | name='auth_password_change'), 35 | url(r'^password/change/done/$', 'password_change_done', 36 | {'template_name': 'userprofiles/password_change_done.html'}, 37 | name='auth_password_change_done'), 38 | url(r'^password/reset/$', 'password_reset', 39 | {'template_name': 'userprofiles/password_reset.html', 40 | 'email_template_name': 'userprofiles/mails/password_reset_email.html'}, 41 | name='auth_password_reset'), 42 | url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', 43 | 'password_reset_confirm', 44 | {'template_name': 'userprofiles/password_reset_confirm.html'}, 45 | name='auth_password_reset_confirm'), 46 | url(r'^password/reset/complete/$', 'password_reset_complete', 47 | {'template_name': 'userprofiles/password_reset_complete.html'}, 48 | name='auth_password_reset_complete'), 49 | url(r'^password/reset/done/$', 'password_reset_done', 50 | {'template_name': 'userprofiles/password_reset_done.html'}, 51 | name='auth_password_reset_done'), 52 | ) 53 | -------------------------------------------------------------------------------- /userprofiles/utils.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.auth.models import SiteProfileNotAvailable 3 | from django.core.exceptions import ImproperlyConfigured 4 | from django.db import models 5 | 6 | from userprofiles.settings import up_settings 7 | 8 | try: 9 | from importlib import import_module 10 | except ImportError: 11 | from django.utils.importlib import import_module 12 | 13 | 14 | def get_profile_model(): 15 | if up_settings.USE_PROFILE: 16 | if not getattr(settings, 'AUTH_PROFILE_MODULE', False): 17 | raise SiteProfileNotAvailable( 18 | 'You need to set AUTH_PROFILE_MODULE in your project settings') 19 | 20 | try: 21 | app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.') 22 | except ValueError: 23 | raise SiteProfileNotAvailable('app_label and model_name ' 24 | 'should be separated by a dot in the AUTH_PROFILE_MODULE ' 25 | 'setting') 26 | 27 | try: 28 | model = models.get_model(app_label, model_name) 29 | if model is None: 30 | raise SiteProfileNotAvailable('Unable to load the profile ' 31 | 'model, check AUTH_PROFILE_MODULE in your project sett' 32 | 'ings') 33 | return model 34 | except (ImportError, ImproperlyConfigured): 35 | raise SiteProfileNotAvailable 36 | else: 37 | return None 38 | 39 | UserProfile = get_profile_model() 40 | 41 | 42 | def get_form_class(path): 43 | i = path.rfind('.') 44 | module, attr = path[:i], path[i + 1:] 45 | try: 46 | mod = import_module(module) 47 | except ImportError, e: 48 | raise ImproperlyConfigured( 49 | 'Error loading module %s: "%s"' % (module, e)) 50 | try: 51 | form = getattr(mod, attr) 52 | except AttributeError: 53 | raise ImproperlyConfigured( 54 | 'Module "%s" does not define a form named "%s"' % (module, attr)) 55 | return form 56 | -------------------------------------------------------------------------------- /userprofiles/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib.auth import authenticate, login 3 | from django.shortcuts import redirect 4 | from django.views.generic import FormView, TemplateView 5 | 6 | from userprofiles.settings import up_settings 7 | from userprofiles.utils import get_form_class 8 | 9 | 10 | class RegistrationView(FormView): 11 | form_class = get_form_class(up_settings.REGISTRATION_FORM) 12 | template_name = 'userprofiles/registration.html' 13 | 14 | def form_valid(self, form): 15 | form.save() 16 | username = form.cleaned_data['username'] 17 | password = form.cleaned_data['password'] 18 | 19 | # Automatically log this user in 20 | if up_settings.AUTO_LOGIN: 21 | if up_settings.EMAIL_ONLY: 22 | username = form.cleaned_data['email'] 23 | 24 | user = authenticate(username=username, password=password) 25 | if user is not None: 26 | if user.is_active: 27 | login(self.request, user) 28 | 29 | return redirect(up_settings.REGISTRATION_REDIRECT) 30 | 31 | registration = RegistrationView.as_view() 32 | 33 | 34 | class RegistrationCompleteView(TemplateView): 35 | template_name = 'userprofiles/registration_complete.html' 36 | 37 | def get_context_data(self, **kwargs): 38 | return { 39 | 'account_verification_active': up_settings.USE_ACCOUNT_VERIFICATION, 40 | 'expiration_days': up_settings.ACCOUNT_VERIFICATION_DAYS, 41 | } 42 | 43 | registration_complete = RegistrationCompleteView.as_view() 44 | --------------------------------------------------------------------------------