Commit 3e13bc798b277823e4bb3ab0992fbb6fa5eb99ec
1 parent
dab8f064
Exists in
master
and in
39 other branches
Refactorign signup process
Showing
8 changed files
with
87 additions
and
177 deletions
Show diff stats
src/accounts/forms.py
| 1 | 1 | # -*- coding: utf-8 -*- |
| 2 | 2 | |
| 3 | 3 | from django import forms |
| 4 | -from django.contrib.auth.models import User | |
| 4 | +from django.contrib.auth import get_user_model | |
| 5 | 5 | from django.contrib.auth.forms import UserCreationForm as UserCreationForm_ |
| 6 | 6 | from django.utils.translation import ugettext_lazy as _ |
| 7 | 7 | |
| 8 | 8 | from super_archives.models import MailingList |
| 9 | -from super_archives.validators import UniqueValidator | |
| 10 | 9 | |
| 11 | 10 | |
| 12 | -LISTS_NAMES = [] | |
| 13 | -for list_ in MailingList.objects.iterator(): | |
| 14 | - choice = (list_.name, list_.name) | |
| 15 | - LISTS_NAMES.append(choice) | |
| 11 | +User = get_user_model() | |
| 16 | 12 | |
| 17 | 13 | |
| 18 | -class UserCreationForm(UserCreationForm_): | |
| 19 | - first_name = forms.CharField(max_length=30, label=_(u'Name'), | |
| 20 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 21 | - last_name = forms.CharField(max_length=30, label=_(u'Last name'), | |
| 22 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 23 | - email = forms.EmailField(validators=[UniqueValidator(User, 'email')], | |
| 24 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 25 | - lists = forms.MultipleChoiceField(label=u'Listas', | |
| 26 | - required=False, | |
| 27 | - widget=forms.CheckboxSelectMultiple, | |
| 28 | - choices=LISTS_NAMES) | |
| 29 | - | |
| 14 | +class NewUserForm(forms.ModelForm): | |
| 15 | + class Meta: | |
| 16 | + model = User | |
| 17 | + fields = ('first_name', 'last_name', 'email', 'username') | |
| 30 | 18 | |
| 31 | 19 | def __init__(self, *args, **kwargs): |
| 32 | - super(UserCreationForm, self).__init__(*args, **kwargs) | |
| 33 | - self.fields.pop('password1') | |
| 34 | - self.fields.pop('password2') | |
| 35 | - | |
| 36 | - | |
| 37 | -class UserUpdateForm(UserCreationForm): | |
| 38 | - institution= forms.CharField(max_length=120, label=_(u'Institution'), required=False, | |
| 39 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 40 | - role = forms.CharField(max_length=60, label=_(u'Role'), required=False, | |
| 41 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 42 | - twitter = forms.URLField(label=_(u'Twitter'), required=False, | |
| 43 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 44 | - facebook = forms.URLField(label=_(u'Facebook'), required=False, | |
| 45 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 46 | - google_talk = forms.EmailField(label=_(u'Google Talk'), required=False, | |
| 47 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 48 | - webpage = forms.URLField(label=_(u'Personal Website/Blog'), required=False, | |
| 49 | - widget=forms.TextInput(attrs={'class':'form-control'})) | |
| 20 | + super(NewUserForm, self).__init__(*args, **kwargs) | |
| 21 | + for field in self.fields.values(): | |
| 22 | + field.widget.attrs.update({'class': 'form-control'}) | |
| 23 | + field.required = True | |
| 50 | 24 | |
| 51 | - def __init__(self, *args, **kwargs): | |
| 52 | - super(UserUpdateForm, self).__init__(*args, **kwargs) | |
| 53 | - self.fields.pop('username') | |
| 54 | - self.fields.pop('first_name') | |
| 55 | - self.fields.pop('last_name') | |
| 56 | - self.fields.pop('email') | |
| 57 | - self.fields.pop('lists') | |
| 25 | + | |
| 26 | +class ListsForm(forms.Form): | |
| 27 | + LISTS_NAMES = ((list.name, list.name) for list in MailingList.objects.all()) | |
| 28 | + lists = forms.MultipleChoiceField(label=_(u'Mailing lists'), | |
| 29 | + required=False, | |
| 30 | + widget=forms.CheckboxSelectMultiple, | |
| 31 | + choices=LISTS_NAMES) | ... | ... |
src/accounts/models.py
| ... | ... | @@ -4,13 +4,13 @@ from django.contrib.auth.models import AbstractUser |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | class User(AbstractUser): |
| 7 | - institution = models.CharField(max_length=128, null=True) | |
| 8 | - role = models.CharField(max_length=128, null=True) | |
| 9 | - twitter = models.CharField(max_length=128, null=True) | |
| 10 | - facebook = models.CharField(max_length=128, null=True) | |
| 11 | - google_talk = models.EmailField(null=True) | |
| 12 | - webpage = models.CharField(max_length=256, null=True) | |
| 13 | - verification_hash = models.CharField(max_length=32, null=True) | |
| 7 | + institution = models.CharField(max_length=128, null=True, blank=True) | |
| 8 | + role = models.CharField(max_length=128, null=True, blank=True) | |
| 9 | + twitter = models.CharField(max_length=128, null=True, blank=True) | |
| 10 | + facebook = models.CharField(max_length=128, null=True, blank=True) | |
| 11 | + google_talk = models.EmailField(null=True, blank=True) | |
| 12 | + webpage = models.CharField(max_length=256, null=True, blank=True) | |
| 13 | + verification_hash = models.CharField(max_length=32, null=True, blank=True) | |
| 14 | 14 | |
| 15 | 15 | # We need to have `email` field set as unique but Django does not |
| 16 | 16 | # support field overriding (at least not until 1.6). | ... | ... |
src/accounts/templates/accounts/account_message.html
src/accounts/templates/accounts/email_signup-email-confirmation.html
| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | -{% load i18n %} | |
| 2 | - | |
| 3 | -{% trans "Welcome to the Colab!" %} | |
| 4 | - | |
| 5 | -{% trans "To activate your account, please confirm your mail's activation by accessing the following link:" %} | |
| 6 | - | |
| 7 | -<a href="http://{{ server_name }}{% url 'email_verification' hash %}"> | |
| 8 | - http://{{ server_name }}{% url 'email_verification' hash %} | |
| 9 | -</a> |
src/accounts/urls.py
| ... | ... | @@ -5,10 +5,9 @@ from .views import UserProfileDetailView |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | urlpatterns = patterns('', |
| 8 | - url(r'^$', 'accounts.views.signup', name='signup'), | |
| 8 | + #url(r'^$', 'accounts.views.signup', name='signup'), | |
| 9 | 9 | |
| 10 | - url(r'^verify/(?P<hash>[\w]{32})/$', | |
| 11 | - 'accounts.views.verify_email', name='email_verification'), | |
| 10 | + url(r'^register/$', 'accounts.views.signup', name='signup'), | |
| 12 | 11 | |
| 13 | 12 | url(r'^(?P<username>[\w@+.-]+)/?$', |
| 14 | 13 | UserProfileDetailView.as_view(), name='user_profile'), | ... | ... |
src/accounts/views.py
| 1 | 1 | #!/usr/bin/env python |
| 2 | 2 | # encoding: utf-8 |
| 3 | 3 | |
| 4 | -import uuid | |
| 5 | -from colab.deprecated import signup as signup_ | |
| 4 | +from django.contrib import messages | |
| 6 | 5 | |
| 7 | -from django.template import RequestContext | |
| 8 | 6 | from django.contrib.auth import get_user_model |
| 9 | 7 | from django.views.generic import DetailView |
| 10 | 8 | from django.utils.translation import ugettext as _ |
| 11 | -from django.shortcuts import render, get_object_or_404 | |
| 9 | +from django.shortcuts import render, redirect | |
| 12 | 10 | |
| 13 | 11 | from colab.deprecated import solrutils |
| 12 | +from colab.deprecated import signup as signup_ | |
| 14 | 13 | |
| 15 | -from .forms import UserCreationForm | |
| 16 | 14 | from super_archives.models import EmailAddress, Message |
| 17 | - | |
| 18 | - | |
| 19 | -# helper | |
| 20 | -def get_field_set(form): | |
| 21 | - fieldsets = ( | |
| 22 | - (_('Personal Information'), ( | |
| 23 | - form['first_name'], | |
| 24 | - form['last_name'], | |
| 25 | - form['email'], | |
| 26 | - form['username'], | |
| 27 | - ) | |
| 28 | - ), | |
| 29 | - (_('Subscribe to mail lists'), ( | |
| 30 | - form['lists'], | |
| 31 | - ) | |
| 32 | - ), | |
| 33 | - ) | |
| 34 | - return fieldsets | |
| 35 | - | |
| 36 | - | |
| 37 | -def signup(request): | |
| 38 | - | |
| 39 | - # If the request method is GET just return the form | |
| 40 | - if request.method == 'GET': | |
| 41 | - form = UserCreationForm() | |
| 42 | - return render(request, 'accounts/signup-form.html', | |
| 43 | - {'form': form, 'fieldsets': get_field_set(form)}) | |
| 44 | - | |
| 45 | - # If the request method is POST try to store data | |
| 46 | - form = UserCreationForm(request.POST) | |
| 47 | - | |
| 48 | - # If there is validation errors give the form back to the user | |
| 49 | - if not form.is_valid(): | |
| 50 | - return render(request, 'accounts/signup-form.html', | |
| 51 | - {'form': form, 'fieldsets': get_field_set(form)}) | |
| 52 | - | |
| 53 | - user = User( | |
| 54 | - username=form.cleaned_data.get('username'), | |
| 55 | - email=form.cleaned_data.get('email'), | |
| 56 | - first_name=form.cleaned_data.get('first_name'), | |
| 57 | - last_name=form.cleaned_data.get('last_name'), | |
| 58 | - is_active=False, | |
| 59 | - ) | |
| 60 | - user.set_password(form.cleaned_data.get('password1')) | |
| 61 | - user.save() | |
| 62 | - | |
| 63 | - profile = UserProfile( | |
| 64 | - user=user, | |
| 65 | - institution=form.cleaned_data.get('institution'), | |
| 66 | - role=form.cleaned_data.get('role'), | |
| 67 | - twitter=form.cleaned_data.get('twitter'), | |
| 68 | - facebook=form.cleaned_data.get('facebook'), | |
| 69 | - google_talk=form.cleaned_data.get('google_talk'), | |
| 70 | - webpage=form.cleaned_data.get('webpage'), | |
| 71 | - verification_hash=uuid.uuid4().get_hex(), | |
| 72 | - ) | |
| 73 | - profile.save() | |
| 74 | - | |
| 75 | - signup_.send_verification_email(request, user) | |
| 76 | - | |
| 77 | - mailing_lists = form.cleaned_data.get('lists') | |
| 78 | - if mailing_lists: | |
| 79 | - signup_.send_email_lists(user, mailing_lists) | |
| 80 | - | |
| 81 | - | |
| 82 | - # Check if the user's email have been used previously | |
| 83 | - # in the mainling lists to link the user to old messages | |
| 84 | - email_addr, created = EmailAddress.objects.get_or_create(address=user.email) | |
| 85 | - if created: | |
| 86 | - email_addr.real_name = user.get_full_name() | |
| 87 | - | |
| 88 | - email_addr.user = user | |
| 89 | - email_addr.save() | |
| 90 | - | |
| 91 | - template_data = { | |
| 92 | - 'msg': _(u'Registration completed successfully. Please visit your email address to validate it.'), | |
| 93 | - 'msg_css_class': 'alert-success', | |
| 94 | - } | |
| 95 | - | |
| 96 | - return render(request, 'accounts/account_message.html', template_data) | |
| 97 | - | |
| 98 | - | |
| 99 | -def verify_email(request, hash): | |
| 100 | - """Verify hash and activate user's account""" | |
| 101 | - | |
| 102 | - profile = get_object_or_404(UserProfile, verification_hash=hash) | |
| 103 | - | |
| 104 | - profile.verification_hash = 'verified' | |
| 105 | - profile.save() | |
| 106 | - | |
| 107 | - profile.user.is_active = True | |
| 108 | - profile.user.save() | |
| 109 | - | |
| 110 | - template_data = { | |
| 111 | - 'msg': _(u'E-mail validated correctly.'), | |
| 112 | - 'msg_css_class': 'alert-success', | |
| 113 | - } | |
| 114 | - | |
| 115 | - return render(request, 'accounts/account_message.html', template_data) | |
| 15 | +from .forms import NewUserForm, ListsForm | |
| 116 | 16 | |
| 117 | 17 | |
| 118 | 18 | class UserProfileDetailView(DetailView): |
| ... | ... | @@ -141,5 +41,43 @@ class UserProfileDetailView(DetailView): |
| 141 | 41 | query = query.order_by('-received_time') |
| 142 | 42 | context['emails'] = query[:10] |
| 143 | 43 | |
| 44 | + context.update(kwargs) | |
| 144 | 45 | return super(UserProfileDetailView, self).get_context_data(**context) |
| 145 | 46 | |
| 47 | + | |
| 48 | +def signup(request): | |
| 49 | + # If the request method is GET just return the form | |
| 50 | + if request.method == 'GET': | |
| 51 | + user_form = NewUserForm() | |
| 52 | + lists_form = ListsForm() | |
| 53 | + return render(request, 'registration/registration_form.html', | |
| 54 | + {'user_form': user_form, 'lists_form': lists_form}) | |
| 55 | + | |
| 56 | + user_form = NewUserForm(request.POST) | |
| 57 | + lists_form = ListsForm(request.POST) | |
| 58 | + | |
| 59 | + if not user_form.is_valid() or not lists_form.is_valid(): | |
| 60 | + return render(request, 'registration/registration_form.html', | |
| 61 | + {'user_form': user_form, 'lists_form': lists_form}) | |
| 62 | + | |
| 63 | + user = user_form.save() | |
| 64 | + | |
| 65 | + mailing_lists = lists_form.cleaned_data.get('lists') | |
| 66 | + if mailing_lists: | |
| 67 | + signup_.send_email_lists(user, mailing_lists) | |
| 68 | + | |
| 69 | + # Check if the user's email have been used previously | |
| 70 | + # in the mainling lists to link the user to old messages | |
| 71 | + email_addr, created = EmailAddress.objects.get_or_create(address=user.email) | |
| 72 | + if created: | |
| 73 | + email_addr.real_name = user.get_full_name() | |
| 74 | + | |
| 75 | + email_addr.user = user | |
| 76 | + email_addr.save() | |
| 77 | + | |
| 78 | + messages.success(request, _('Your profile has been created!')) | |
| 79 | + messages.warning(request, _('You must login to validated your profile. ' | |
| 80 | + 'Profiles not validated are deleted in 24h.')) | |
| 81 | + | |
| 82 | + return redirect('user_profile', username=user.username) | |
| 83 | + | ... | ... |
src/colab/custom_settings.py
| ... | ... | @@ -23,7 +23,6 @@ INSTALLED_APPS = INSTALLED_APPS + ( |
| 23 | 23 | 'cliauth', |
| 24 | 24 | 'django_browserid', |
| 25 | 25 | 'conversejs', |
| 26 | - 'registration', | |
| 27 | 26 | |
| 28 | 27 | # Own apps |
| 29 | 28 | 'super_archives', |
| ... | ... | @@ -145,6 +144,14 @@ STATIC_ROOT = os.path.join(BASE_DIR, '..', 'www', 'static') |
| 145 | 144 | |
| 146 | 145 | AUTH_USER_MODEL = 'accounts.User' |
| 147 | 146 | |
| 147 | +from django.contrib.messages import constants as messages | |
| 148 | +MESSAGE_TAGS = { | |
| 149 | + messages.INFO: 'alert-info', | |
| 150 | + messages.SUCCESS: 'alert-success', | |
| 151 | + messages.WARNING: 'alert-warning', | |
| 152 | + messages.ERROR: 'alert-danger', | |
| 153 | +} | |
| 154 | + | |
| 148 | 155 | |
| 149 | 156 | ### Proxy configuration |
| 150 | 157 | SOCKS_SERVER = None | ... | ... |
src/colab/deprecated/templates/base.html
| ... | ... | @@ -47,8 +47,6 @@ |
| 47 | 47 | <div class="row"> |
| 48 | 48 | </div> |
| 49 | 49 | |
| 50 | - {% block header %}{% endblock %} | |
| 51 | - | |
| 52 | 50 | <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> |
| 53 | 51 | <div class="navbar-header"> |
| 54 | 52 | <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main"> |
| ... | ... | @@ -119,6 +117,17 @@ |
| 119 | 117 | </div> |
| 120 | 118 | </nav> |
| 121 | 119 | |
| 120 | + {% block messages %} | |
| 121 | + {% for message in messages %} | |
| 122 | + <div class="alert alert-dismissable {{ message.tags }}"> | |
| 123 | + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> | |
| 124 | + {{ message }} | |
| 125 | + </div> | |
| 126 | + {% endfor %} | |
| 127 | + {% endblock %} | |
| 128 | + | |
| 129 | + {% block header %}{% endblock %} | |
| 130 | + | |
| 122 | 131 | <div> |
| 123 | 132 | {% block main-content %} {% endblock %} |
| 124 | 133 | </div> | ... | ... |