diff --git a/beat/web/ui/registration/admin.py b/beat/web/ui/registration/admin.py index 6768db83db1f8ebf4112b98a254f170c6b6f2ae5..0180c5f66629c9e2a8dd609689c29c56c614c340 100644 --- a/beat/web/ui/registration/admin.py +++ b/beat/web/ui/registration/admin.py @@ -27,8 +27,8 @@ from django.contrib import admin -from .models import RegistrationProfile from .models import PreregistrationProfile +from .models import RegistrationProfile class RegistrationAdmin(admin.ModelAdmin): diff --git a/beat/web/ui/registration/docs/models.txt b/beat/web/ui/registration/docs/models.txt index b0c6d845c6309183099069fb145fd45f0015a97c..a7a7a1580e55fad84f09290f9150fcb9317d8d16 100644 --- a/beat/web/ui/registration/docs/models.txt +++ b/beat/web/ui/registration/docs/models.txt @@ -32,7 +32,7 @@ so. This model's sole purpose is to store data temporarily during account registration and activation, and a mechanism for automatically creating an instance of a site-specific profile model is provided via the ``create_inactive_user`` on ``RegistrationManager``. - + ``RegistrationProfile`` objects have the following fields: ``activation_key`` @@ -47,15 +47,15 @@ the ``create_inactive_user`` on ``RegistrationManager``. ``activation_key_expired()`` Determines whether this ``RegistrationProfile``'s activation key has expired. - + Returns ``True`` if the key has expired, ``False`` otherwise. - + Key expiration is determined by a two-step process: - + 1. If the user has already activated, the key will have been reset to the string constant ``ACTIVATED``. Re-activating is not permitted, and so this method returns ``True`` in this case. - + 2. Otherwise, the date the user signed up is incremented by the number of days specified in the setting ``ACCOUNT_ACTIVATION_DAYS`` (which should be the number of days @@ -68,25 +68,25 @@ The ``RegistrationManager`` =========================== Custom manager for the ``RegistrationProfile`` model. - + The methods defined here provide shortcuts for account creation and activation (including generation and emailing of activation keys), and for cleaning out expired inactive accounts. - + Methods: ``activate_user(activation_key)`` Validate an activation key and activate the corresponding ``User`` if valid. - + If the key is valid and has not expired, return the ``User`` after activating. - + If the key is not valid or has expired, return ``False``. - + If the key is valid but the ``User`` is already active, return ``False``. - + To prevent reactivation of an account which has been deactivated by site administrators, the activation key is reset to the string constant ``RegistrationProfile.ACTIVATED`` @@ -102,7 +102,7 @@ Methods: Create a new, inactive ``User``, generate a ``RegistrationProfile`` and email its activation key to the ``User``, returning the new ``User``. - + To disable the email, call with ``send_email=False``. The activation email will make use of two templates: @@ -133,11 +133,11 @@ Methods: argument ``user``) after the ``User`` and ``RegistrationProfile`` have been created, and after the email (if any) has been sent. - + ``create_profile(user)`` Creates a ``RegistrationProfile`` for a given ``User``. Returns the ``RegistrationProfile``. - + The activation key for the ``RegistrationProfile`` will be a SHA1 hash, generated from a combination of the ``User``'s username and a random salt. @@ -145,34 +145,34 @@ Methods: ``deleted_expired_users()`` Removes expired instances of ``RegistrationProfile`` and their associated ``User`` objects. - + Accounts to be deleted are identified by searching for instances of ``RegistrationProfile`` with expired activation keys, and then checking to see if their associated ``User`` instances have the field ``is_active`` set to ``False``; any ``User`` who is both inactive and has an expired activation key will be deleted. - + It is recommended that this method be executed regularly as part of your routine site maintenance; this application provides a custom management command which will call this method, accessible as ``manage.py cleanupregistration``. - + Regularly clearing out accounts which have never been activated serves two useful purposes: - + 1. It alleviates the ocasional need to reset a ``RegistrationProfile`` and/or re-send an activation email when a user does not receive or does not act upon the initial activation email; since the account will be deleted, the user will be able to simply re-register and receive a new activation key. - + 2. It prevents the possibility of a malicious user registering one or more accounts and never activating them (thus denying the use of those usernames to anyone else); since those accounts will be deleted, the usernames will become available for use again. - + If you have a troublesome ``User`` and wish to disable their account while keeping it in the database, simply delete the associated ``RegistrationProfile``; an inactive ``User`` which diff --git a/beat/web/ui/registration/docs/overview.txt b/beat/web/ui/registration/docs/overview.txt index caed664b07bb53be141dcf62cbd8dd4bdbb8d87b..c1b173240b0aee8ea92f5e241bd7506005efdf3e 100644 --- a/beat/web/ui/registration/docs/overview.txt +++ b/beat/web/ui/registration/docs/overview.txt @@ -127,7 +127,7 @@ need to do the following: for details). 4. Add this line to your site's root URLConf:: - + (r'^accounts/', include('registration.urls')), 5. Link people to ``/accounts/register/`` so they can start signing diff --git a/beat/web/ui/registration/docs/views.txt b/beat/web/ui/registration/docs/views.txt index 86ca3d4ed5237d5b1c179e0f56705f3808777b07..b9ea14735ddd751a7fa4c6e8e423f65e084bdac6 100644 --- a/beat/web/ui/registration/docs/views.txt +++ b/beat/web/ui/registration/docs/views.txt @@ -23,7 +23,7 @@ change this, pass the name of a template as the keyword argument ``activation_key`` The activation key to validate and use for activating the ``User``. - + **Optional arguments** ``extra_context`` @@ -40,7 +40,7 @@ change this, pass the name of a template as the keyword argument The ``User`` object corresponding to the account, if the activation was successful. ``False`` if the activation was not successful. - + ``expiration_days`` The number of days for which activation keys stay valid after registration. @@ -49,7 +49,7 @@ Any extra variables supplied in the ``extra_context`` argument (see above). **Template:** - + registration/activate.html or ``template_name`` keyword argument. @@ -57,14 +57,14 @@ registration/activate.html or ``template_name`` keyword argument. ============ Allow a new user to register an account. - + Following successful registration, issue a redirect; by default, this will be whatever URL corresponds to the named URL pattern ``registration_complete``, which will be ``/accounts/register/complete/`` if using the included URLConf. To change this, point that named pattern at another URL, or pass your preferred URL as the keyword argument ``success_url``. - + By default, ``registration.forms.RegistrationForm`` will be used as the registration form; to change this, pass a different form class as the ``form_class`` keyword argument. The form class you specify must @@ -98,7 +98,7 @@ None. ``form`` The registration form. - + Any extra variables supplied in the ``extra_context`` argument (see above). diff --git a/beat/web/ui/registration/forms.py b/beat/web/ui/registration/forms.py index 6bcb3a39168c9d8f430ef9c79e682ec866e38004..99b3d33066b729a93fbb52a3aad37c2066adf852 100644 --- a/beat/web/ui/registration/forms.py +++ b/beat/web/ui/registration/forms.py @@ -29,25 +29,22 @@ Forms and validation code for user registration. """ - import datetime -from django.contrib.auth.models import User from django import forms -from django.conf import settings +from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ -from .models import RegistrationProfile -from .models import PreregistrationProfile - -from ...accounts.models import SupervisionTrack from ...accounts.models import Profile +from ...accounts.models import SupervisionTrack +from .models import PreregistrationProfile +from .models import RegistrationProfile # I put this on all required fields, because it's easier to pick up # on them with CSS or JavaScript if they have a class of "required" # in the HTML. Your mileage may vary. If/when Django ticket #3515 # lands in trunk, this will no longer be necessary. -attrs_dict = { 'class': 'required' } +attrs_dict = {"class": "required"} class RegistrationForm(forms.Form): @@ -63,30 +60,42 @@ class RegistrationForm(forms.Form): """ - username = forms.RegexField(regex=r'^\w+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Username')) - first_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'First name')) - last_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Last name')) - email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, - maxlength=75)), - label=_(u'Institutional E-mail address')) - password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), - label=_(u'Password')) - password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), - label=_(u'Password (again)')) - supervisor = forms.RegexField(regex=r'^\w+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Supervisor Username')) - + username = forms.RegexField( + regex=r"^\w+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Username"), + ) + first_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"First name"), + ) + last_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Last name"), + ) + email = forms.EmailField( + widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=75)), + label=_(u"Institutional E-mail address"), + ) + password1 = forms.CharField( + widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_(u"Password"), + ) + password2 = forms.CharField( + widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_(u"Password (again)"), + ) + supervisor = forms.RegexField( + regex=r"^\w+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Supervisor Username"), + ) def clean_username(self): """ @@ -94,11 +103,13 @@ class RegistrationForm(forms.Form): in use. """ - try: - user = User.objects.get(username__iexact=self.cleaned_data['username']) - except User.DoesNotExist: - return self.cleaned_data['username'] - raise forms.ValidationError(_(u'This username is already taken. Please choose another.')) + username = self.cleaned_data["username"] + if User.objects.filter(username__iexact=username).exists(): + raise forms.ValidationError( + _(u"This username is already taken. Please choose another.") + ) + + return username def clean_supervisor(self): """ @@ -106,17 +117,22 @@ class RegistrationForm(forms.Form): """ try: - user = User.objects.get(username__iexact=self.cleaned_data['supervisor']) + user = User.objects.get(username__iexact=self.cleaned_data["supervisor"]) if user.profile.status == Profile.BLOCKED: - raise forms.ValidationError(_(u'This user is not a valid supervisor. Please choose another.')) + raise forms.ValidationError( + _(u"This user is not a valid supervisor. Please choose another.") + ) except User.DoesNotExist: - raise forms.ValidationError(_(u'This supervisor username does not exist. Please choose another.')) + raise forms.ValidationError( + _(u"This supervisor username does not exist. Please choose another.") + ) if not user.profile.is_supervisor: - raise forms.ValidationError(_(u'This user is not a recognized supervisor. Please choose another.')) - - return self.cleaned_data['supervisor'] + raise forms.ValidationError( + _(u"This user is not a recognized supervisor. Please choose another.") + ) + return self.cleaned_data["supervisor"] def clean(self): """ @@ -126,9 +142,11 @@ class RegistrationForm(forms.Form): field. """ - if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data: - if self.cleaned_data['password1'] != self.cleaned_data['password2']: - self._errors["password2"] = self.error_class([_(u'You must type the same password each time')]) + if "password1" in self.cleaned_data and "password2" in self.cleaned_data: + if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + self._errors["password2"] = self.error_class( + [_(u"You must type the same password each time")] + ) del self.cleaned_data["password1"] del self.cleaned_data["password2"] @@ -143,23 +161,23 @@ class RegistrationForm(forms.Form): """ new_user = RegistrationProfile.objects.create_inactive_user( - username=self.cleaned_data['username'], - first_name=self.cleaned_data['first_name'], - last_name=self.cleaned_data['last_name'], - password=self.cleaned_data['password1'], - email=self.cleaned_data['email'], + username=self.cleaned_data["username"], + first_name=self.cleaned_data["first_name"], + last_name=self.cleaned_data["last_name"], + password=self.cleaned_data["password1"], + email=self.cleaned_data["email"], ) - #Create and assign key - new_user.profile.supervision_key = new_user.profile._generate_current_supervision_key() - supervisor = User.objects.get(username = self.cleaned_data['supervisor']) + # Create and assign key + new_user.profile.supervision_key = ( + new_user.profile._generate_current_supervision_key() + ) + supervisor = User.objects.get(username=self.cleaned_data["supervisor"]) supervisiontrack = SupervisionTrack.objects.create( - supervisee = new_user, - supervisor = supervisor, - is_valid = False, + supervisee=new_user, supervisor=supervisor, is_valid=False, ) - #Assign key to supervision track + # Assign key to supervision track supervisiontrack.supervision_key = new_user.profile.supervision_key supervisiontrack.save() new_user.profile.is_supervisor = False @@ -168,7 +186,6 @@ class RegistrationForm(forms.Form): new_user.profile.supervision.add(supervisiontrack) new_user.save() - return new_user @@ -176,23 +193,29 @@ class PreregistrationForm(forms.Form): """ Form for pre-registering a new user account. """ - first_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'First name')) - last_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Last name')) - email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, - maxlength=75)), - label=_(u'E-mail address')) + + first_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"First name"), + ) + last_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Last name"), + ) + email = forms.EmailField( + widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=75)), + label=_(u"E-mail address"), + ) def save(self): profile = PreregistrationProfile() - profile.first_name = self.cleaned_data['first_name'] - profile.last_name = self.cleaned_data['last_name'] - profile.email = self.cleaned_data['email'] + profile.first_name = self.cleaned_data["first_name"] + profile.last_name = self.cleaned_data["last_name"] + profile.email = self.cleaned_data["email"] profile.save() return profile @@ -204,10 +227,13 @@ class RegistrationFormTermsOfService(RegistrationForm): for agreeing to a site's Terms of Service. """ + tos = forms.BooleanField( widget=forms.CheckboxInput(attrs=attrs_dict), label=u'I have carefully read the <a href="">Terms of Service</a>, which include the Privacy and Data Protection Terms of Use, and fully agree and undertake to comply with all provisions therein by checking this box.', - error_messages=dict(required=u"You must agree to the Terms of Service in order to register"), + error_messages=dict( + required=u"You must agree to the Terms of Service in order to register" + ), ) @@ -217,15 +243,20 @@ class RegistrationFormUniqueEmail(RegistrationForm): email addresses. """ + def clean_email(self): """ Validate that the supplied email address is unique for the site. """ - if User.objects.filter(email__iexact=self.cleaned_data['email']): - raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.')) - return self.cleaned_data['email'] + if User.objects.filter(email__iexact=self.cleaned_data["email"]): + raise forms.ValidationError( + _( + u"This email address is already in use. Please supply a different email address." + ) + ) + return self.cleaned_data["email"] class RegistrationFormNoFreeEmail(RegistrationForm): @@ -238,9 +269,20 @@ class RegistrationFormNoFreeEmail(RegistrationForm): override the attribute ``bad_domains``. """ - bad_domains = ['aim.com', 'aol.com', 'email.com', 'gmail.com', - 'googlemail.com', 'hotmail.com', 'hushmail.com', - 'msn.com', 'mail.ru', 'mailinator.com', 'live.com'] + + bad_domains = [ + "aim.com", + "aol.com", + "email.com", + "gmail.com", + "googlemail.com", + "hotmail.com", + "hushmail.com", + "msn.com", + "mail.ru", + "mailinator.com", + "live.com", + ] def clean_email(self): """ @@ -248,10 +290,14 @@ class RegistrationFormNoFreeEmail(RegistrationForm): webmail domains. """ - email_domain = self.cleaned_data['email'].split('@')[1] + email_domain = self.cleaned_data["email"].split("@")[1] if email_domain in self.bad_domains: - raise forms.ValidationError(_(u'Registration using free email addresses is prohibited. Please supply a different email address.')) - return self.cleaned_data['email'] + raise forms.ValidationError( + _( + u"Registration using free email addresses is prohibited. Please supply a different email address." + ) + ) + return self.cleaned_data["email"] class BlockedUserRevalidationForm(forms.Form): @@ -267,28 +313,36 @@ class BlockedUserRevalidationForm(forms.Form): """ - username = forms.RegexField(regex=r'^\w+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Username')) - password = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), - label=_(u'Password')) - supervisor = forms.RegexField(regex=r'^\w+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Supervisor Username (Your account needs to be re-validated by a recognized person)')) - + username = forms.RegexField( + regex=r"^\w+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Username"), + ) + password = forms.CharField( + widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_(u"Password"), + ) + supervisor = forms.RegexField( + regex=r"^\w+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_( + u"Supervisor Username (Your account needs to be re-validated by a recognized person)" + ), + ) def clean_username(self): """ Validate that the username is alphanumeric and user exists """ - try: - user = User.objects.get(username__iexact=self.cleaned_data['username']) - return self.cleaned_data['username'] - except User.DoesNotExist: - raise forms.ValidationError(_(u'This username has not been recognized')) + username = self.cleaned_data["username"] + + if not User.objects.filter(username__iexact=username).exists(): + raise forms.ValidationError(_(u"This username has not been recognized")) + + return username def clean_supervisor(self): """ @@ -296,15 +350,18 @@ class BlockedUserRevalidationForm(forms.Form): """ try: - user = User.objects.get(username__iexact=self.cleaned_data['supervisor']) + user = User.objects.get(username__iexact=self.cleaned_data["supervisor"]) except User.DoesNotExist: - raise forms.ValidationError(_(u'This supervisor username does not exist. Please choose another.')) + raise forms.ValidationError( + _(u"This supervisor username does not exist. Please choose another.") + ) if not user.profile.is_supervisor: - raise forms.ValidationError(_(u'This user is not a recognized supervisor. Please choose another.')) - - return self.cleaned_data['supervisor'] + raise forms.ValidationError( + _(u"This user is not a recognized supervisor. Please choose another.") + ) + return self.cleaned_data["supervisor"] def clean(self): """ @@ -314,9 +371,11 @@ class BlockedUserRevalidationForm(forms.Form): field. """ - if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data: - if self.cleaned_data['password1'] != self.cleaned_data['password2']: - self._errors["password2"] = self.error_class([_(u'You must type the same password each time')]) + if "password1" in self.cleaned_data and "password2" in self.cleaned_data: + if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + self._errors["password2"] = self.error_class( + [_(u"You must type the same password each time")] + ) del self.cleaned_data["password1"] del self.cleaned_data["password2"] @@ -336,25 +395,36 @@ class RegistrationSupervisorForm(forms.Form): """ - username = forms.RegexField(regex=r'^\w+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Username')) - first_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'First name')) - last_name = forms.RegexField(regex=r'^[\w ]+$', - max_length=30, - widget=forms.TextInput(attrs=attrs_dict), - label=_(u'Last name')) - email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, - maxlength=75)), - label=_(u'Institutional E-mail address')) - password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), - label=_(u'Password')) - password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), - label=_(u'Password (again)')) + username = forms.RegexField( + regex=r"^\w+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Username"), + ) + first_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"First name"), + ) + last_name = forms.RegexField( + regex=r"^[\w ]+$", + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_(u"Last name"), + ) + email = forms.EmailField( + widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=75)), + label=_(u"Institutional E-mail address"), + ) + password1 = forms.CharField( + widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_(u"Password"), + ) + password2 = forms.CharField( + widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_(u"Password (again)"), + ) def clean_username(self): """ @@ -362,11 +432,12 @@ class RegistrationSupervisorForm(forms.Form): in use. """ - try: - user = User.objects.get(username__iexact=self.cleaned_data['username']) - except User.DoesNotExist: - return self.cleaned_data['username'] - raise forms.ValidationError(_(u'This username is already taken. Please choose another.')) + username = self.cleaned_data["username"] + if User.objects.get(username__iexact=username).exists(): + raise forms.ValidationError( + _(u"This username is already taken. Please choose another.") + ) + return username def clean(self): """ @@ -376,9 +447,11 @@ class RegistrationSupervisorForm(forms.Form): field. """ - if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data: - if self.cleaned_data['password1'] != self.cleaned_data['password2']: - self._errors["password2"] = self.error_class([_(u'You must type the same password each time')]) + if "password1" in self.cleaned_data and "password2" in self.cleaned_data: + if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + self._errors["password2"] = self.error_class( + [_(u"You must type the same password each time")] + ) del self.cleaned_data["password1"] del self.cleaned_data["password2"] @@ -393,31 +466,36 @@ class RegistrationSupervisorForm(forms.Form): """ new_user = RegistrationProfile.objects.create_inactive_user( - username=self.cleaned_data['username'], - first_name=self.cleaned_data['first_name'], - last_name=self.cleaned_data['last_name'], - password=self.cleaned_data['password1'], - email=self.cleaned_data['email'], - ) + username=self.cleaned_data["username"], + first_name=self.cleaned_data["first_name"], + last_name=self.cleaned_data["last_name"], + password=self.cleaned_data["password1"], + email=self.cleaned_data["email"], + ) - #Create and assign key - new_user.profile.supervision_key = new_user.profile._generate_current_supervision_key() + # Create and assign key + new_user.profile.supervision_key = ( + new_user.profile._generate_current_supervision_key() + ) new_user.profile.is_supervisor = True new_user.profile.status = Profile.NEWUSER new_user.profile.registration_date = datetime.datetime.now() new_user.save() - return new_user + class RegistrationFormTermsOfServiceSupervisor(RegistrationSupervisorForm): """ Subclass of ``RegistrationForm`` which adds a required checkbox for agreeing to a site's Terms of Service. """ + tos = forms.BooleanField( - widget=forms.CheckboxInput(attrs=attrs_dict), - label=u'I have carefully read the <a href="">Terms of Service</a>, which include the Privacy and Data Protection Terms of Use, and fully agree and undertake to comply with all provisions therein by checking this box.', - error_messages=dict(required=u"You must agree to the Terms of Service in order to register"), - ) + widget=forms.CheckboxInput(attrs=attrs_dict), + label=u'I have carefully read the <a href="">Terms of Service</a>, which include the Privacy and Data Protection Terms of Use, and fully agree and undertake to comply with all provisions therein by checking this box.', + error_messages=dict( + required=u"You must agree to the Terms of Service in order to register" + ), + ) diff --git a/beat/web/ui/registration/migrations/0001_initial.py b/beat/web/ui/registration/migrations/0001_initial.py index f418e34b7c5740530b34c4500a9ab41cfe2cfe8b..2f1231d3663edd50df999bb6840139fe79c94e32 100644 --- a/beat/web/ui/registration/migrations/0001_initial.py +++ b/beat/web/ui/registration/migrations/0001_initial.py @@ -27,8 +27,9 @@ from __future__ import unicode_literals -from django.db import migrations, models from django.conf import settings +from django.db import migrations +from django.db import models class Migration(migrations.Migration): @@ -39,28 +40,54 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='PreregistrationProfile', + name="PreregistrationProfile", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('first_name', models.CharField(max_length=30)), - ('last_name', models.CharField(max_length=30)), - ('email', models.CharField(max_length=75)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("first_name", models.CharField(max_length=30)), + ("last_name", models.CharField(max_length=30)), + ("email", models.CharField(max_length=75)), ], options={ - 'verbose_name': 'preregistration profile', - 'verbose_name_plural': 'preregistration profiles', + "verbose_name": "preregistration profile", + "verbose_name_plural": "preregistration profiles", }, ), migrations.CreateModel( - name='RegistrationProfile', + name="RegistrationProfile", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('activation_key', models.CharField(max_length=40, verbose_name='activation key')), - ('user', models.OneToOneField(verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "activation_key", + models.CharField(max_length=40, verbose_name="activation key"), + ), + ( + "user", + models.OneToOneField( + verbose_name="user", + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ), + ), ], options={ - 'verbose_name': 'registration profile', - 'verbose_name_plural': 'registration profiles', + "verbose_name": "registration profile", + "verbose_name_plural": "registration profiles", }, ), ] diff --git a/beat/web/ui/registration/signals.py b/beat/web/ui/registration/signals.py index 96209135f4a13afefb93958add16f98d817f142f..099307c21f5a30e9c0aab9cdc2a0db1a9c1f111c 100644 --- a/beat/web/ui/registration/signals.py +++ b/beat/web/ui/registration/signals.py @@ -27,7 +27,6 @@ from django.dispatch import Signal - # A new user has registered. user_registered = Signal(providing_args=["user"]) diff --git a/beat/web/ui/registration/templates/registration/blocked_user_reactivate.html b/beat/web/ui/registration/templates/registration/blocked_user_reactivate.html index c071fb713a14c967dc3a6ec5b99b73e078518e53..c96c48d7c0c2f33404fe7789a540a858cf27a5f3 100644 --- a/beat/web/ui/registration/templates/registration/blocked_user_reactivate.html +++ b/beat/web/ui/registration/templates/registration/blocked_user_reactivate.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/ui/registration/templates/registration/preregistration_complete.html b/beat/web/ui/registration/templates/registration/preregistration_complete.html index d776fef4cc7b20a7b65cc4337450d9d06781ad3c..ce4ca004497cc6dba5e353563877f1cbbf931cc8 100644 --- a/beat/web/ui/registration/templates/registration/preregistration_complete.html +++ b/beat/web/ui/registration/templates/registration/preregistration_complete.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/ui/registration/templates/registration/preregistration_form.html b/beat/web/ui/registration/templates/registration/preregistration_form.html index 962773654bc8eece3d42f0d97ab9e0ce0dc2f584..1d7264386c2ae2e50e5a92372d11dbb86e5b89a8 100644 --- a/beat/web/ui/registration/templates/registration/preregistration_form.html +++ b/beat/web/ui/registration/templates/registration/preregistration_form.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/ui/registration/templates/registration/registration_complete.html b/beat/web/ui/registration/templates/registration/registration_complete.html index ba9c1f5a09115403d848352bf4c3f8d0667ed3a0..a07c9ed055fe5afc169633cb98f4b1949b734b78 100644 --- a/beat/web/ui/registration/templates/registration/registration_complete.html +++ b/beat/web/ui/registration/templates/registration/registration_complete.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/ui/registration/templates/registration/registration_pending.html b/beat/web/ui/registration/templates/registration/registration_pending.html index c2962dae917e521ac27ded07516c763af5182088..06969d12127c3407d41ee08b365aeadc3bf8c42b 100644 --- a/beat/web/ui/registration/templates/registration/registration_pending.html +++ b/beat/web/ui/registration/templates/registration/registration_pending.html @@ -2,21 +2,21 @@ {% comment %} * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ * Contact: beat.support@idiap.ch - * + * * This file is part of the beat.web module of the BEAT platform. - * + * * Commercial License Usage * Licensees holding valid commercial BEAT licenses may use this file in * accordance with the terms contained in a written agreement between you * and Idiap. For further information contact tto@idiap.ch - * + * * Alternatively, this file may be used under the terms of the GNU Affero * Public License version 3 as published by the Free Software and appearing * in the file LICENSE.AGPL included in the packaging of this file. * The BEAT platform is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. - * + * * You should have received a copy of the GNU Affero Public License along * with the BEAT platform. If not, see http://www.gnu.org/licenses/. {% endcomment %} diff --git a/beat/web/ui/registration/templatetags/registration_tags.py b/beat/web/ui/registration/templatetags/registration_tags.py index e803648a15bfe19d7b4acd4e91ba94fa88f48e47..47ea8e1a03e43170cd1c9d722a3a39049c0e3188 100644 --- a/beat/web/ui/registration/templatetags/registration_tags.py +++ b/beat/web/ui/registration/templatetags/registration_tags.py @@ -27,15 +27,18 @@ from django import template + register = template.Library() + @register.filter def tabindex(value, index): """Add a tabindex attribute to the widget for a bound field.""" - value.field.widget.attrs['tabindex'] = index + value.field.widget.attrs["tabindex"] = index return value -@register.filter(name='addclass') + +@register.filter(name="addclass") def addclass(field, kls): - """Adds a class to the widget""" - return field.as_widget(attrs={"class":kls}) + """Adds a class to the widget""" + return field.as_widget(attrs={"class": kls}) diff --git a/beat/web/ui/registration/views.py b/beat/web/ui/registration/views.py index c706167c7b8f056e1bd16a8a622f57b73c7594d5..ace307d403d161df354d30482038824a81ae9174 100644 --- a/beat/web/ui/registration/views.py +++ b/beat/web/ui/registration/views.py @@ -29,12 +29,10 @@ Views which allow users to create and activate accounts. """ - - from django.conf import settings -from django.urls import reverse from django.http import HttpResponseRedirect from django.shortcuts import render +from django.urls import reverse from django.views.decorators.csrf import csrf_protect from .forms import RegistrationFormTermsOfService @@ -43,9 +41,12 @@ from .forms import RegistrationSupervisorForm from .models import RegistrationProfile -def activate(request, activation_key, - template_name='registration/activate.html', - extra_context=None): +def activate( + request, + activation_key, + template_name="registration/activate.html", + extra_context=None, +): """ Activate a ``User``'s account from an activation key, if their key is valid and hasn't expired. @@ -89,11 +90,10 @@ def activate(request, activation_key, registration/activate.html or ``template_name`` keyword argument. """ - activationKey = activation_key.lower() # Normalize before trying anything with it. + account = RegistrationProfile.objects.activate_user(activation_key) - context = { 'account': account, - 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS } + context = {"account": account, "expiration_days": settings.ACCOUNT_ACTIVATION_DAYS} if extra_context is not None: for key, value in extra_context.items(): @@ -103,10 +103,13 @@ def activate(request, activation_key, @csrf_protect -def register(request, success_url=None, - form_class=RegistrationFormTermsOfService, - template_name='registration/registration_form.html', - extra_context=None): +def register( + request, + success_url=None, + form_class=RegistrationFormTermsOfService, + template_name="registration/registration_form.html", + extra_context=None, +): """ Allow a new user to register an account. @@ -164,17 +167,19 @@ def register(request, success_url=None, supervisor_form_active = False - if request.GET.get('registration') == "supervisor": + if request.GET.get("registration") == "supervisor": supervisor_form_active = True - if request.method == 'POST': + if request.method == "POST": # Check the form - if 'supervisor' not in request.POST: + if "supervisor" not in request.POST: supervisor_form_active = True - form_supervisor = RegistrationSupervisorForm(data=request.POST, files=request.FILES) + form_supervisor = RegistrationSupervisorForm( + data=request.POST, files=request.FILES + ) form = form_class() if form_supervisor.is_valid(): - new_user = form_supervisor.save() + form_supervisor.save() # success_url needs to be dynamically generated here; setting a # a default value using reverse() will cause circular-import # problems with the default URLConf for this application, which @@ -185,7 +190,7 @@ def register(request, success_url=None, form = form_class(data=request.POST, files=request.FILES) form_supervisor = RegistrationSupervisorForm() if form.is_valid(): - new_user = form.save() + form.save() # success_url needs to be dynamically generated here; setting a # a default value using reverse() will cause circular-import # problems with the default URLConf for this application, which @@ -195,12 +200,13 @@ def register(request, success_url=None, form = form_class() form_supervisor = RegistrationFormTermsOfServiceSupervisor() - - context = { 'form': form, - 'form_supervisor': form_supervisor, - 'supervisor_form_active': supervisor_form_active, - 'documentation_link': settings.DOCUMENTATION_LINK, - 'url_prefix':settings.URL_PREFIX } + context = { + "form": form, + "form_supervisor": form_supervisor, + "supervisor_form_active": supervisor_form_active, + "documentation_link": settings.DOCUMENTATION_LINK, + "url_prefix": settings.URL_PREFIX, + } if extra_context is not None: for key, value in extra_context.items():