[Registration] handle already used email address
[mygpo.git] / mygpo / users / views / registration.py
blob4d4b86a656228c65d77d8c1a5b486b2c70f08eb0
1 import uuid
2 import re
4 from django import forms
5 from django.core.validators import RegexValidator
6 from django.core.exceptions import ValidationError
7 from django.db import IntegrityError, transaction
8 from django.http import HttpResponseRedirect
9 from django.views.generic.edit import FormView
10 from django.utils.translation import ugettext as _
11 from django.template.loader import render_to_string
12 from django.core.urlresolvers import reverse, reverse_lazy
13 from django.views.generic import TemplateView
14 from django.views.generic.base import View
15 from django.contrib import messages
16 from django.contrib.auth import get_user_model
17 from django.contrib.sites.shortcuts import get_current_site
19 from mygpo.utils import random_token
20 from mygpo.users.models import UserProxy
23 USERNAME_MAXLEN = get_user_model()._meta.get_field('username').max_length
25 USERNAME_REGEX = re.compile(r'^\w[\w.+-]*$')
28 class UsernameValidator(RegexValidator):
29 """ Validates that a username uses only allowed characters """
30 regex = USERNAME_REGEX
31 message = 'Invalid Username'
32 code='invalid-username'
35 class RegistrationForm(forms.Form):
36 """ Form that is used to register a new user """
37 username = forms.CharField(max_length=USERNAME_MAXLEN,
38 validators=[UsernameValidator()],
40 email = forms.EmailField()
41 password1 = forms.CharField(widget=forms.PasswordInput())
42 password2 = forms.CharField(widget=forms.PasswordInput())
44 def clean(self):
45 cleaned_data = super(RegistrationForm, self).clean()
46 password1 = cleaned_data.get('password1')
47 password2 = cleaned_data.get('password2')
49 if not password1 or password1 != password2:
50 raise forms.ValidationError('Passwords do not match')
53 class RegistrationView(FormView):
54 """ View to register a new user """
55 template_name = 'registration/registration_form.html'
56 form_class = RegistrationForm
57 success_url = reverse_lazy('registration-complete')
59 def form_valid(self, form):
60 """ called whene the form was POSTed and its contents were valid """
62 try:
63 user = self.create_user(form)
65 except ValidationError as e:
66 messages.error(self.request, '; '.join(e.messages))
67 return HttpResponseRedirect(reverse('register'))
69 except IntegrityError:
70 messages.error(self.request,
71 _('Username or email address already in use'))
72 return HttpResponseRedirect(reverse('register'))
74 send_activation_email(user, self.request)
75 return super(RegistrationView, self).form_valid(form)
77 @transaction.atomic
78 def create_user(self, form):
79 User = get_user_model()
80 user = User()
81 user.username = form.cleaned_data['username']
83 email_addr = form.cleaned_data['email']
84 user.email = email_addr
86 user.set_password(form.cleaned_data['password1'])
87 user.is_active = False
88 user.full_clean()
90 try:
91 user.save()
93 except IntegrityError as e:
94 if 'django_auth_unique_email' in str(e):
95 # this was not caught by the form validation, but now validates
96 # the DB's unique constraint
97 raise ValidationError('The email address {0} is '
98 'already in use.'.format(email_addr))
99 else:
100 raise
102 user.profile.uuid == uuid.uuid1()
103 user.profile.activation_key = random_token()
104 user.profile.save()
106 return user
109 class ActivationView(TemplateView):
110 """ Activates an already registered user """
112 template_name = 'registration/activation_failed.html'
114 def get(self, request, activation_key):
115 User = get_user_model()
117 try:
118 user = UserProxy.objects.get(
119 profile__activation_key=activation_key,
120 is_active=False,
122 except UserProxy.DoesNotExist:
123 messages.error(request, _('The activation link is either not '
124 'valid or has already expired.'))
125 return super(ActivationView, self).get(request, activation_key)
127 user.activate()
128 messages.success(request, _('Your user has been activated. '
129 'You can log in now.'))
130 return HttpResponseRedirect(reverse('login'))
133 class ResendActivationForm(forms.Form):
134 """ Form for resending the activation email """
136 username = forms.CharField(max_length=USERNAME_MAXLEN, required=False)
137 email = forms.EmailField(required=False)
139 def clean(self):
140 cleaned_data = super(ResendActivationForm, self).clean()
141 username = cleaned_data.get('username')
142 email = cleaned_data.get('email')
144 if not username and not email:
145 raise forms.ValidationError(_('Either username or email address '
146 'are required.'))
149 class ResendActivationView(FormView):
150 """ View to resend the activation email """
151 template_name = 'registration/resend_activation.html'
152 form_class = ResendActivationForm
153 success_url = reverse_lazy('resent-activation')
155 def form_valid(self, form):
156 """ called whene the form was POSTed and its contents were valid """
158 try:
159 user = UserProxy.objects.all().by_username_or_email(
160 form.cleaned_data['username'],
161 form.cleaned_data['email'],
164 except UserProxy.DoesNotExist:
165 messages.error(self.request, _('User does not exist.'))
166 return HttpResponseRedirect(reverse('resend-activation'))
168 if user.profile.activation_key is None:
169 messages.success(self.request, _('Your account already has been '
170 'activated. Go ahead and log in.'))
172 send_activation_email(user, self.request)
173 return super(ResendActivationView, self).form_valid(form)
176 class ResentActivationView(TemplateView):
177 template_name = 'registration/resent_activation.html'
180 def send_activation_email(user, request):
181 """ Sends the activation email for the given user """
183 subj = render_to_string('registration/activation_email_subject.txt')
184 # remove trailing newline added by render_to_string
185 subj = subj.strip()
187 msg = render_to_string('registration/activation_email.txt', {
188 'site': get_current_site(request),
189 'activation_key': user.profile.activation_key,
191 user.email_user(subj, msg)