damned-lies r1215 - in trunk: . common media/css people templates templates/people



Author: claudep
Date: Sat Dec 13 20:40:54 2008
New Revision: 1215
URL: http://svn.gnome.org/viewvc/damned-lies?rev=1215&view=rev

Log:
2008-12-13  Claude Paroz  <claude 2xlibre net>

	* common/views.py: Add site_register and activate_account views to support
	registration.
	* media/css/main.css: Add help and errorlist classes for forms display.
	* people/forms.py: New RegistrationForm class.
	* people/models.py: New activation_key field to support registration.
	* people/urls.py: More precise matches with 'begin of line' (^).
	* templates/error.html: Added general-purpose error template.
	* templates/login.html:
	* templates/logout_form.html: Externalize logout form.
	* templates/people/person_detail.html: Allow logout from 'profile'
	template.
	* templates/register.html:
	* templates/register_success.html: New templates for registration.
	* urls.py: Add registration urls.

Added:
   trunk/templates/error.html
   trunk/templates/logout_form.html
   trunk/templates/register.html
   trunk/templates/register_success.html
Modified:
   trunk/ChangeLog
   trunk/common/views.py
   trunk/media/css/main.css
   trunk/people/forms.py
   trunk/people/models.py
   trunk/people/urls.py
   trunk/templates/login.html
   trunk/templates/people/person_detail.html
   trunk/urls.py

Modified: trunk/common/views.py
==============================================================================
--- trunk/common/views.py	(original)
+++ trunk/common/views.py	Sat Dec 13 20:40:54 2008
@@ -25,6 +25,8 @@
 from django.utils.translation import ugettext as _
 from django.contrib.auth import login, authenticate, logout
 from django.conf import settings
+from people.models import Person
+from people.forms import RegistrationForm 
 
 
 def index(request):
@@ -41,9 +43,8 @@
     }
     return render_to_response('index.html', context, context_instance=RequestContext(request))
 
-def site_login(request):
+def site_login(request, messages=[]):
     """ Site-specific login page. Not named 'login' to not confuse with auth.login """
-    messages = []
     referer = None
     openid_path = ''
     if request.method == 'POST':
@@ -79,3 +80,32 @@
         'referer': referer,
     }
     return render_to_response('login.html', context, context_instance=RequestContext(request))
+
+def site_register(request):
+    openid_path = ''
+    if request.method == 'POST':
+        form = RegistrationForm(data = request.POST)
+        if form.is_valid():
+            new_user = form.save()
+            return HttpResponseRedirect(reverse('register_success'))
+    else:
+        form = RegistrationForm()
+    if 'django_openid' in settings.INSTALLED_APPS:
+        openid_path = '/openid/'
+    context = {
+        'pageSection': 'home',
+        'form': form,
+        'openid_path': openid_path,
+    }
+    return render_to_response('register.html', context, context_instance=RequestContext(request))
+
+def activate_account(request, key):
+    """ Activate an account through the link a requestor has received by email """
+    try:
+        person = Person.objects.get(activation_key=key)
+    except Person.DoesNotExist:
+        return render_to_response('error.html', {'error':"Sorry, the key you provided is not valid."})
+    person.activate()
+    Person.clean_unactivated_accounts()
+    return site_login(request, messages=[_("Your account has been activated.")])
+

Modified: trunk/media/css/main.css
==============================================================================
--- trunk/media/css/main.css	(original)
+++ trunk/media/css/main.css	Sat Dec 13 20:40:54 2008
@@ -144,6 +144,11 @@
   color: #666666;
 }
 
+.help {
+  font-size:10px;
+  color:#999;
+}
+
 .error {
   font-style: italic;
   color: #666666;
@@ -155,6 +160,8 @@
   background: #FAE28E;
 }
 
+.errorlist li { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:white; background:red url(../img/admin/icon_alert.gif) 5px .3em no-repeat; }
+
 .footnote {
   text-align: center;
   font-size: small;

Modified: trunk/people/forms.py
==============================================================================
--- trunk/people/forms.py	(original)
+++ trunk/people/forms.py	Sat Dec 13 20:40:54 2008
@@ -1,7 +1,79 @@
+import sha, random
+
 from django import forms
+from django.conf import settings
+from django.utils.translation import ugettext as _
+from django.core.urlresolvers import reverse
+from django.contrib.sites.models import Site
 from teams.models import Team
+from people.models import Person
 
 class JoinTeamForm(forms.Form):
     def __init__(self, *args, **kwargs):
         super(JoinTeamForm, self).__init__(*args, **kwargs)
         self.fields['teams'] = forms.ModelChoiceField(queryset=Team.objects.all())
+
+class RegistrationForm(forms.Form):
+    """ Form for user registration """
+    username = forms.CharField(max_length=30,
+                               label=_(u'Choose a username:'),
+                               help_text=_(u'May contain only letters, numbers, underscores or hyphens'))
+    email = forms.EmailField(label=_(u'Email:'))
+    openid_url = forms.URLField(label=_(u'OpenID:'),
+                                required=False)
+    password1 = forms.CharField(widget=forms.PasswordInput(render_value=False),
+                                label=_(u'Password:'), required=False, min_length=7,
+                                help_text=_(u'At least 7 characters'))
+    password2 = forms.CharField(widget=forms.PasswordInput(render_value=False),
+                                label=_(u'Confirm password:'), required=False)
+    
+    def clean_username(self):
+        """  Validate the username (correctness and uniqueness)"""
+        try:
+            user = Person.objects.get(username__iexact=self.cleaned_data['username'])
+        except Person.DoesNotExist:
+            return self.cleaned_data['username']
+        raise forms.ValidationError(_(u'This username is already taken. Please choose another.'))
+
+    def clean(self):
+        cleaned_data = self.cleaned_data
+        password1 = cleaned_data.get('password1')
+        password2 = cleaned_data.get('password2')
+        openid_url = cleaned_data.get('openid_url')
+        if not password1 and not openid_url:
+            raise forms.ValidationError(_(u'You must either provide an OpenId or a password'))
+        
+        if password1 and password1 != password2:
+            raise forms.ValidationError(_(u'The passwords do not match'))
+        return cleaned_data
+
+    def save(self):
+        """ Create the user """
+        username = self.cleaned_data['username']
+        email = self.cleaned_data['email']
+
+        password = self.cleaned_data['password1']
+        new_user = Person.objects.create_user(username=username,
+                           email=email,
+                           password=password or "!")
+        openid = self.cleaned_data['openid_url']
+        if openid:
+            new_user.openids.create(openid = openid)
+        salt = sha.new(str(random.random())).hexdigest()[:5]
+        activation_key = sha.new(salt+username).hexdigest()
+        new_user.activation_key = activation_key
+        new_user.is_active = False
+        new_user.save()
+        # Send activation email
+        from django.core.mail import send_mail
+        current_site = Site.objects.get_current()
+        subject = settings.EMAIL_SUBJECT_PREFIX + _(u'Account activation')
+        message = _(u"This is a confirmation that your registration on %s succeeded. To activate your account, please click on the link below or copy and paste it in a browser.") % current_site.name
+        message += "\n\nhttp://%s%s\n\n"; % (current_site.domain, str(reverse("register_activation", kwargs={'key': activation_key}))) 
+        message += _(u"Administrators of %s" % current_site.name)
+
+        send_mail(subject, message, settings.SERVER_EMAIL,
+                  (email,), fail_silently=False)
+
+        return new_user
+                           

Modified: trunk/people/models.py
==============================================================================
--- trunk/people/models.py	(original)
+++ trunk/people/models.py	Sat Dec 13 20:40:54 2008
@@ -1,3 +1,5 @@
+import datetime
+
 from django.db import models
 from django.contrib.auth.models import User, UserManager
 
@@ -14,19 +16,32 @@
     webpage_url = models.URLField(null=True, blank=True)
     irc_nick = models.SlugField(max_length=20, null=True, blank=True)
     bugzilla_account = models.EmailField(null=True, blank=True)
+    activation_key = models.CharField(max_length=40, null=True, blank=True)
 
     # Use UserManager to get the create_user method, etc.
     objects = UserManager()
-    
+       
     class Meta:
         db_table = 'person'
         ordering = ('username',)
 
+    @classmethod
+    def clean_unactivated_accounts(cls):
+        accounts = cls.objects.filter(activation_key__isnull=False)
+        for account in accounts:
+            if account.date_joined + datetime.timedelta(days=5) <= datetime.datetime.now():
+                account.delete()
+
     def save(self):
         if not self.password or self.password == "!":
             self.password = None
             self.set_unusable_password()
         super(User, self).save()
+    
+    def activate(self):
+        self.activation_key = None
+        self.is_active = True
+        self.save()
         
     def no_spam_email(self):
         return obfuscate_email(self.email)

Modified: trunk/people/urls.py
==============================================================================
--- trunk/people/urls.py	(original)
+++ trunk/people/urls.py	Sat Dec 13 20:40:54 2008
@@ -11,7 +11,7 @@
     
 urlpatterns = patterns('',
     url(r'^$', 'django.views.generic.list_detail.object_list', dict(info_dict_list), 'persons'),                    
-    url(r'(?P<object_id>\d+)/$', 'people.views.person_detail_from_id', name='person'),
+    url(r'^(?P<object_id>\d+)/$', 'people.views.person_detail_from_id', name='person'),
     # equivalent to the previous, but using username instead of user pk
-    url(r'(?P<slug>\w+)/$', 'people.views.person_detail_from_username', name='person'),
+    url(r'^(?P<slug>\w+)/$', 'people.views.person_detail_from_username', name='person'),
 )

Added: trunk/templates/error.html
==============================================================================
--- (empty file)
+++ trunk/templates/error.html	Sat Dec 13 20:40:54 2008
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block title %} {% trans "Damned Lies about GNOME" %} {% endblock %}
+
+{% block content %}
+<div class="mainpage">
+
+<h1>{% trans "Error:" %}</h1>
+
+<p class="errornote">{{ error }}</p>
+
+</div>
+{% endblock %}

Modified: trunk/templates/login.html
==============================================================================
--- trunk/templates/login.html	(original)
+++ trunk/templates/login.html	Sat Dec 13 20:40:54 2008
@@ -8,15 +8,13 @@
 
 {% if user.is_authenticated %}
   <p>{% blocktrans with user.username as username %}You are already logged in as {{ username }}.{% endblocktrans %}</p>
-  <form action="" method="post">
-    <input type="hidden" name="logout" value="1" />
-    <div class="submit-row">
-    <label>&nbsp;</label><input type="submit" value="{% trans 'Log out' %}" />
-    </div>
-  </form>
+  {% include "logout_form.html" %}
 {% else %}
+{% url register as link %}
+<p>{% blocktrans %}If you do not own an account on this site, you can <a href='{{ link }}'>register</a> for a new account.{% endblocktrans %}</p>
+
 <p>{% trans 'Log in with your username and password:' %}</p>
-<form action="{{ app_path }}" method="post" id="login-form" class="login">
+<form action="{% url login %}" method="post" id="login-form" class="login">
   <div class="form-row">
     <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
   </div>

Added: trunk/templates/logout_form.html
==============================================================================
--- (empty file)
+++ trunk/templates/logout_form.html	Sat Dec 13 20:40:54 2008
@@ -0,0 +1,8 @@
+{% load i18n %}
+<form action="{% url login %}" method="post">
+  <input type="hidden" name="logout" value="1" />
+  <div class="submit-row">
+  <label>&nbsp;</label><input type="submit" value="{% trans 'Log out' %}" />
+  </div>
+</form>
+

Modified: trunk/templates/people/person_detail.html
==============================================================================
--- trunk/templates/people/person_detail.html	(original)
+++ trunk/templates/people/person_detail.html	Sat Dec 13 20:40:54 2008
@@ -7,6 +7,12 @@
 {% block content %}
 <div class="mainpage">
   <h2>{{ person.name }}</h2>
+  {% if user.is_authenticated %}
+    {% ifequal user.username person.username %}
+      <div style="float: right">{% include "logout_form.html" %}</div>
+    {% endifequal %}
+  {% endif %}
+
   {% with 1 as printroles %}
   {% include "person_base.html" %}
   {% endwith %}

Added: trunk/templates/register.html
==============================================================================
--- (empty file)
+++ trunk/templates/register.html	Sat Dec 13 20:40:54 2008
@@ -0,0 +1,57 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block title %} {% trans "Damned Lies about GNOME" %} {% endblock %}
+{% block extrahead %} <link rel="stylesheet" href="/media/css/login.css"/> {% endblock %}
+{% block content %}
+<div class="mainpage">
+
+<h2>{% trans "Account Registration" %}</h2>
+{% if user.is_authenticated %}
+  <p>{% blocktrans with user.username as username %}You are already logged in as {{ username }}.{% endblocktrans %}</p>
+  {% include "logout_form.html" %}
+{% else %}
+<p>{% trans "You can register here for an account on this site. This is only useful if you plan to contribute to GNOME translations." %}</p>
+<p>{% trans "After registration and connection, you will be able to join an existing team from your profile page." %}</p>
+
+<form action="{{ app_path }}" method="post" id="login-form" class="login">
+  <div class="form-row">
+    {{ form.username.errors }}
+    <label for="id_username">{{ form.username.label }}</label> {{ form.username }} <span class="help">{{ form.username.help_text }}</span>
+  </div>
+  <div class="form-row">
+    {{ form.email.errors }}
+    <label for="id_email">{{ form.email.label }}</label> {{ form.email }}
+  </div>
+  <table style="clear:both"><tr><td colspan="2">
+    <div style="clear:both">{{ form.non_field_errors }}</div>
+{% if openid_path %}
+    <p>Authenticate via OpenID <strong>or</strong> password:</p></td></tr><tr><td valign="bottom">
+  <div>
+    {{ form.openid_url.errors }}
+    <label for="id_openid"><img src="{{ openid_path }}logo/" alt=""> {{ form.openid_url.label }}</label> {{ form.openid_url }}
+  </div>
+  <div style="text-align:center; padding-top:8px;">
+    <label>&nbsp;</label><input type="submit" value="{% trans 'Register with OpenId' %}" />
+  </div>
+  </td><td valign="bottom">
+{% endif %}
+  <div class="form-row">
+    {{ form.password1.errors }}
+    <label for="id_password">{{ form.password1.label }}</label> {{ form.password1 }} <span class="help">{{ form.password1.help_text }}</span>
+  </div>
+  <div class="form-row">
+    <label for="id_password">{{ form.password2.label }}</label> {{ form.password2 }}
+  </div>
+  <div style="text-align:center; padding-top:8px;">
+    <label>&nbsp;</label><input type="submit" value="{% trans 'Register with password' %}" />
+  </div>
+  </td></tr></table>
+</form>
+
+<script type="text/javascript">
+document.getElementById('id_username').focus()
+</script>
+{% endif %}
+</div>
+{% endblock %}

Added: trunk/templates/register_success.html
==============================================================================
--- (empty file)
+++ trunk/templates/register_success.html	Sat Dec 13 20:40:54 2008
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block title %} {% trans "Damned Lies about GNOME" %} {% endblock %}
+{% block content %}
+<div class="mainpage">
+
+<h2>{% trans "Registration Success" %}</h2>
+
+<p>{% trans "The registration succeeded. You will now receive an email containing a link to activate your account." %}</p>
+
+</div>
+{% endblock %}

Modified: trunk/urls.py
==============================================================================
--- trunk/urls.py	(original)
+++ trunk/urls.py	Sat Dec 13 20:40:54 2008
@@ -8,6 +8,9 @@
 urlpatterns = patterns('',
     url(r'^$', 'common.views.index', name='home'),
     url(r'^login/$', 'common.views.site_login', name='login'),
+    url(r'^register/$', 'common.views.site_register', name='register'),
+    url(r'^register/success$', 'django.views.generic.simple.direct_to_template', {'template': 'register_success.html'}, name='register_success'),
+    url(r'^register/activate/(?P<key>\w+)$', 'common.views.activate_account', name='register_activation'),
     (r'^teams/', include('teams.urls')),
     (r'^people/', include('people.urls')),
     # users is the hardcoded url in the contrib.auth User class, making it identical to /people



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]