[Users] fix username pattern and validation
[mygpo.git] / mygpo / users / views / registration.py
blob5a56763d145f67182e329ed12c226d4df3fb00e8
1 import uuid
2 import re
4 from django import forms
5 from django.core.validators import RegexValidator
6 from django.db import IntegrityError, transaction
7 from django.http import HttpResponseRedirect
8 from django.views.generic.edit import FormView
9 from django.utils.translation import ugettext as _
10 from django.template.loader import render_to_string
11 from django.core.urlresolvers import reverse, reverse_lazy
12 from django.views.generic import TemplateView
13 from django.views.generic.base import View
14 from django.contrib import messages
15 from django.contrib.auth import get_user_model
16 from django.contrib.sites.shortcuts import get_current_site
18 from mygpo.utils import random_token
19 from mygpo.users.models import UserProxy
22 USERNAME_MAXLEN = get_user_model()._meta.get_field('username').max_length
24 USERNAME_REGEX = re.compile(r'^\w[\w.+-]*$')
27 class UsernameValidator(RegexValidator):
28 """ Validates that a username uses only allowed characters """
29 regex = USERNAME_REGEX
30 message = 'Invalid Username'
31 code='invalid-username'
34 class RegistrationForm(forms.Form):
35 """ Form that is used to register a new user """
36 username = forms.CharField(max_length=USERNAME_MAXLEN,
37 validators=[UsernameValidator()],
39 email = forms.EmailField()
40 password1 = forms.CharField(widget=forms.PasswordInput())
41 password2 = forms.CharField(widget=forms.PasswordInput())
43 def clean(self):
44 cleaned_data = super(RegistrationForm, self).clean()
45 password1 = cleaned_data.get('password1')
46 password2 = cleaned_data.get('password2')
48 if not password1 or password1 != password2:
49 raise forms.ValidationError('Passwords do not match')
52 class RegistrationView(FormView):
53 """ View to register a new user """
54 template_name = 'registration/registration_form.html'
55 form_class = RegistrationForm
56 success_url = reverse_lazy('registration-complete')
58 def form_valid(self, form):
59 """ called whene the form was POSTed and its contents were valid """
61 try:
62 user = self.create_user(form)
64 except IntegrityError:
65 messages.error(self.request,
66 _('Username or email address already in use'))
67 return HttpResponseRedirect(reverse('register'))
69 send_activation_email(user, self.request)
70 return super(RegistrationView, self).form_valid(form)
72 @transaction.atomic
73 def create_user(self, form):
74 User = get_user_model()
75 user = User()
76 user.username = form.cleaned_data['username']
77 user.email = form.cleaned_data['email']
78 user.set_password(form.cleaned_data['password1'])
79 user.is_active = False
80 user.full_clean()
81 user.save()
83 user.profile.uuid == uuid.uuid1()
84 user.profile.activation_key = random_token()
85 user.profile.save()
87 return user
90 class ActivationView(TemplateView):
91 """ Activates an already registered user """
93 template_name = 'registration/activation_failed.html'
95 def get(self, request, activation_key):
96 User = get_user_model()
98 try:
99 user = UserProxy.objects.get(
100 profile__activation_key=activation_key,
101 is_active=False,
103 except UserProxy.DoesNotExist:
104 messages.error(request, _('The activation link is either not '
105 'valid or has already expired.'))
106 return super(ActivationView, self).get(request, activation_key)
108 user.activate()
109 messages.success(request, _('Your user has been activated. '
110 'You can log in now.'))
111 return HttpResponseRedirect(reverse('login'))
114 class ResendActivationForm(forms.Form):
115 """ Form for resending the activation email """
117 username = forms.CharField(max_length=USERNAME_MAXLEN, required=False)
118 email = forms.EmailField(required=False)
120 def clean(self):
121 cleaned_data = super(ResendActivationForm, self).clean()
122 username = cleaned_data.get('username')
123 email = cleaned_data.get('email')
125 if not username and not email:
126 raise forms.ValidationError(_('Either username or email address '
127 'are required.'))
130 class ResendActivationView(FormView):
131 """ View to resend the activation email """
132 template_name = 'registration/resend_activation.html'
133 form_class = ResendActivationForm
134 success_url = reverse_lazy('resent-activation')
136 def form_valid(self, form):
137 """ called whene the form was POSTed and its contents were valid """
139 try:
140 user = UserProxy.objects.all().by_username_or_email(
141 form.cleaned_data['username'],
142 form.cleaned_data['email'],
145 except UserProxy.DoesNotExist:
146 messages.error(self.request, _('User does not exist.'))
147 return HttpResponseRedirect(reverse('resend-activation'))
149 if user.profile.activation_key is None:
150 messages.success(self.request, _('Your account already has been '
151 'activated. Go ahead and log in.'))
153 send_activation_email(user, self.request)
154 return super(ResendActivationView, self).form_valid(form)
157 class ResentActivationView(TemplateView):
158 template_name = 'registration/resent_activation.html'
161 def send_activation_email(user, request):
162 """ Sends the activation email for the given user """
164 subj = render_to_string('registration/activation_email_subject.txt')
165 # remove trailing newline added by render_to_string
166 subj = subj.strip()
168 msg = render_to_string('registration/activation_email.txt', {
169 'site': get_current_site(request),
170 'activation_key': user.profile.activation_key,
172 user.email_user(subj, msg)