[svn] Add user registration and user profiles.

Used modified versions of django-registration and django-profiles , both on bitbucket.

The Person model is now set up as the profile for auth.User s.

I set up a requestcontext so that settings is automatically passed to every template, no need to repeat ourselves in views. However, this needs to be refined: I will soon change it to only pass a subset of settings. E.G. we do not need to be passing the DB login and password!
Copied from http://cucc@cucc.survex.com/svn/trunk/expoweb/troggle/, rev. 8231 by aaron @ 1/29/2009 11:02 PM
This commit is contained in:
substantialnoninfringinguser 2009-05-13 05:48:10 +01:00
parent cdd4e685ee
commit ed345f2576
73 changed files with 3173 additions and 11 deletions

4
context.py Normal file
View File

@ -0,0 +1,4 @@
import troggle.settings as settings
def settingsContext(request):
return { 'settings':settings }

View File

@ -18,8 +18,13 @@ class SurveyAdmin(admin.ModelAdmin):
class LogbookEntryAdmin(admin.ModelAdmin):
search_fields = ('title','expedition__year')
class PersonExpeditionInline(admin.TabularInline):
model = PersonExpedition
extra = 1
class PersonAdmin(admin.ModelAdmin):
search_fields = ('first_name','last_name')
inlines = (PersonExpeditionInline,)
class PersonExpeditionAdmin(admin.ModelAdmin):
search_fields = ('person__first_name','expedition__year')

View File

@ -1,6 +1,10 @@
from django.forms import ModelForm
from models import Cave
from models import Cave, Person
class CaveForm(ModelForm):
class Meta:
model = Cave
model = Cave
class PersonForm(ModelForm):
class Meta:
model = Person

View File

@ -4,6 +4,7 @@ from django.forms import ModelForm
from django.db import models
from django.contrib import admin
from django.core.files.storage import FileSystemStorage
from django.contrib.auth.models import User
import os
import troggle.settings as settings
import datetime
@ -59,6 +60,7 @@ class Person(models.Model):
mug_shot = models.CharField(max_length=100, blank=True,null=True)
blurb = models.TextField(blank=True,null=True)
href = models.CharField(max_length=200)
user = models.ForeignKey(User, unique=True, null=True, blank=True)
class Meta:
verbose_name_plural = "People"
@ -482,4 +484,4 @@ class Survey(models.Model):
def elevations(self):
return self.scannedimage_set.filter(contents='elevation')

View File

@ -4,6 +4,7 @@ import troggle.settings as settings
from troggle.parsers.logbooks import LoadLogbookForExpedition
from troggle.parsers.people import GetPersonExpeditionNameLookup
from troggle.expo.forms import PersonForm
import search
import re
@ -58,3 +59,8 @@ def logbookSearch(request, extra):
return render_to_response('logbooksearch.html',
{ 'query_string': query_string, 'found_entries': found_entries, 'settings': settings})
#context_instance=RequestContext(request))
def personForm(request,pk):
person=Person.objects.get(pk=pk)
form=PersonForm(instance=person)
return render_to_response('personform.html', {'form':form,'settings':settings})

View File

@ -62,6 +62,8 @@ div#footer
margin-right:auto;
}
#frontPageBanner{ position:relative; width:inherit; height:inherit; }
div.logbookentry
{
text-align:left;

0
profiles/__init__.py Normal file
View File

43
profiles/urls.py Normal file
View File

@ -0,0 +1,43 @@
"""
URLConf for Django user profile management.
Recommended usage is to use a call to ``include()`` in your project's
root URLConf to include this URLConf for any URL beginning with
'/profiles/'.
If the default behavior of the profile views is acceptable to you,
simply use a line like this in your root URLConf to set up the default
URLs for profiles::
(r'^profiles/', include('profiles.urls')),
But if you'd like to customize the behavior (e.g., by passing extra
arguments to the various views) or split up the URLs, feel free to set
up your own URL patterns for these views instead. If you do, it's a
good idea to keep the name ``profiles_profile_detail`` for the pattern
which points to the ``profile_detail`` view, since several views use
``reverse()`` with that name to generate a default post-submission
redirect. If you don't use that name, remember to explicitly pass
``success_url`` to those views.
"""
from django.conf.urls.defaults import *
from profiles import views
urlpatterns = patterns('',
url(r'^create/$',
views.create_profile,
name='profiles_create_profile'),
url(r'^edit/$',
views.edit_profile,
name='profiles_edit_profile'),
url(r'^(?P<username>\w+)/$',
views.profile_detail,
name='profiles_profile_detail'),
url(r'^$',
views.profile_list,
name='profiles_profile_list'),
)

45
profiles/utils.py Normal file
View File

@ -0,0 +1,45 @@
"""
Utility functions for retrieving and generating forms for the
site-specific user profile model specified in the
``AUTH_PROFILE_MODULE`` setting.
"""
from django import forms
from django.conf import settings
from django.contrib.auth.models import SiteProfileNotAvailable
from django.db.models import get_model
def get_profile_model():
"""
Return the model class for the currently-active user profile
model, as defined by the ``AUTH_PROFILE_MODULE`` setting. If that
setting is missing, raise
``django.contrib.auth.models.SiteProfileNotAvailable``.
"""
if (not hasattr(settings, 'AUTH_PROFILE_MODULE')) or \
(not settings.AUTH_PROFILE_MODULE):
raise SiteProfileNotAvailable
profile_mod = get_model(*settings.AUTH_PROFILE_MODULE.split('.'))
if profile_mod is None:
raise SiteProfileNotAvailable
return profile_mod
def get_profile_form():
"""
Return a form class (a subclass of the default ``ModelForm``)
suitable for creating/editing instances of the site-specific user
profile model, as defined by the ``AUTH_PROFILE_MODULE``
setting. If that setting is missing, raise
``django.contrib.auth.models.SiteProfileNotAvailable``.
"""
profile_mod = get_profile_model()
class _ProfileForm(forms.ModelForm):
class Meta:
model = profile_mod
exclude = ('user',) # User will be filled in by the view.
return _ProfileForm

340
profiles/views.py Normal file
View File

@ -0,0 +1,340 @@
"""
Views for creating, editing and viewing site-specific user profiles.
"""
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic.list_detail import object_list
from profiles import utils
import troggle.settings as settings
def create_profile(request, form_class=None, success_url=None,
template_name='profiles/create_profile.html',
extra_context=None):
"""
Create a profile for the current user, if one doesn't already
exist.
If the user already has a profile, as determined by
``request.user.get_profile()``, a redirect will be issued to the
:view:`profiles.views.edit_profile` view. If no profile model has
been specified in the ``AUTH_PROFILE_MODULE`` setting,
``django.contrib.auth.models.SiteProfileNotAvailable`` will be
raised.
**Optional arguments:**
``extra_context``
A dictionary of variables to add to the template context. Any
callable object in this dictionary will be called to produce
the end result which appears in the context.
``form_class``
The form class to use for validating and creating the user
profile. This form class must define a method named
``save()``, implementing the same argument signature as the
``save()`` method of a standard Django ``ModelForm`` (this
view will call ``save(commit=False)`` to obtain the profile
object, and fill in the user before the final save). If the
profile object includes many-to-many relations, the convention
established by ``ModelForm`` of using a method named
``save_m2m()`` will be used, and so your form class should
also define this method.
If this argument is not supplied, this view will use a
``ModelForm`` automatically generated from the model specified
by ``AUTH_PROFILE_MODULE``.
``success_url``
The URL to redirect to after successful profile creation. If
this argument is not supplied, this will default to the URL of
:view:`profiles.views.profile_detail` for the newly-created
profile object.
``template_name``
The template to use when displaying the profile-creation
form. If not supplied, this will default to
:template:`profiles/create_profile.html`.
**Context:**
``form``
The profile-creation form.
**Template:**
``template_name`` keyword argument, or
:template:`profiles/create_profile.html`.
"""
try:
profile_obj = request.user.get_profile()
return HttpResponseRedirect(reverse('profiles_edit_profile'))
except ObjectDoesNotExist:
pass
#
# We set up success_url here, rather than as the default value for
# the argument. Trying to do it as the argument's default would
# mean evaluating the call to reverse() at the time this module is
# first imported, which introduces a circular dependency: to
# perform the reverse lookup we need access to profiles/urls.py,
# but profiles/urls.py in turn imports this module.
#
if success_url is None:
success_url = reverse('profiles_profile_detail',
kwargs={ 'username': request.user.username })
if form_class is None:
form_class = utils.get_profile_form()
if request.method == 'POST':
form = form_class(data=request.POST, files=request.FILES)
if form.is_valid():
profile_obj = form.save(commit=False)
profile_obj.user = request.user
profile_obj.save()
if hasattr(form, 'save_m2m'):
form.save_m2m()
return HttpResponseRedirect(success_url)
else:
form = form_class()
if extra_context is None:
extra_context = {}
context = RequestContext(request)
for key, value in extra_context.items():
context[key] = callable(value) and value() or value
return render_to_response(template_name,
{ 'form': form, 'settings':settings },
context_instance=context)
create_profile = login_required(create_profile)
def edit_profile(request, form_class=None, success_url=None,
template_name='profiles/edit_profile.html',
extra_context=None):
"""
Edit the current user's profile.
If the user does not already have a profile (as determined by
``User.get_profile()``), a redirect will be issued to the
:view:`profiles.views.create_profile` view; if no profile model
has been specified in the ``AUTH_PROFILE_MODULE`` setting,
``django.contrib.auth.models.SiteProfileNotAvailable`` will be
raised.
**Optional arguments:**
``extra_context``
A dictionary of variables to add to the template context. Any
callable object in this dictionary will be called to produce
the end result which appears in the context.
``form_class``
The form class to use for validating and editing the user
profile. This form class must operate similarly to a standard
Django ``ModelForm`` in that it must accept an instance of the
object to be edited as the keyword argument ``instance`` to
its constructor, and it must implement a method named
``save()`` which will save the updates to the object. If this
argument is not specified, this view will use a ``ModelForm``
generated from the model specified in the
``AUTH_PROFILE_MODULE`` setting.
``success_url``
The URL to redirect to following a successful edit. If not
specified, this will default to the URL of
:view:`profiles.views.profile_detail` for the profile object
being edited.
``template_name``
The template to use when displaying the profile-editing
form. If not specified, this will default to
:template:`profiles/edit_profile.html`.
**Context:**
``form``
The form for editing the profile.
``profile``
The user's current profile.
**Template:**
``template_name`` keyword argument or
:template:`profiles/edit_profile.html`.
"""
try:
profile_obj = request.user.get_profile()
except ObjectDoesNotExist:
return HttpResponseRedirect(reverse('profiles_create_profile'))
#
# See the comment in create_profile() for discussion of why
# success_url is set up here, rather than as a default value for
# the argument.
#
if success_url is None:
success_url = reverse('profiles_profile_detail',
kwargs={ 'username': request.user.username })
if form_class is None:
form_class = utils.get_profile_form()
if request.method == 'POST':
form = form_class(data=request.POST, files=request.FILES, instance=profile_obj)
if form.is_valid():
form.save()
return HttpResponseRedirect(success_url)
else:
form = form_class(instance=profile_obj)
if extra_context is None:
extra_context = {}
context = RequestContext(request)
for key, value in extra_context.items():
context[key] = callable(value) and value() or value
return render_to_response(template_name,
{ 'form': form,
'profile': profile_obj, },
context_instance=context)
edit_profile = login_required(edit_profile)
def profile_detail(request, username, public_profile_field=None,
template_name='profiles/profile_detail.html',
extra_context=None):
"""
Detail view of a user's profile.
If no profile model has been specified in the
``AUTH_PROFILE_MODULE`` setting,
``django.contrib.auth.models.SiteProfileNotAvailable`` will be
raised.
If the user has not yet created a profile, ``Http404`` will be
raised.
**Required arguments:**
``username``
The username of the user whose profile is being displayed.
**Optional arguments:**
``extra_context``
A dictionary of variables to add to the template context. Any
callable object in this dictionary will be called to produce
the end result which appears in the context.
``public_profile_field``
The name of a ``BooleanField`` on the profile model; if the
value of that field on the user's profile is ``False``, the
``profile`` variable in the template will be ``None``. Use
this feature to allow users to mark their profiles as not
being publicly viewable.
If this argument is not specified, it will be assumed that all
users' profiles are publicly viewable.
``template_name``
The name of the template to use for displaying the profile. If
not specified, this will default to
:template:`profiles/profile_detail.html`.
**Context:**
``profile``
The user's profile, or ``None`` if the user's profile is not
publicly viewable (see the description of
``public_profile_field`` above).
**Template:**
``template_name`` keyword argument or
:template:`profiles/profile_detail.html`.
"""
user = get_object_or_404(User, username=username)
try:
profile_obj = user.get_profile()
except ObjectDoesNotExist:
raise Http404
if public_profile_field is not None and \
not getattr(profile_obj, public_profile_field):
profile_obj = None
if extra_context is None:
extra_context = {}
context = RequestContext(request)
for key, value in extra_context.items():
context[key] = callable(value) and value() or value
return render_to_response(template_name,
{ 'profile': profile_obj },
context_instance=context)
def profile_list(request, public_profile_field=None,
template_name='profiles/profile_list.html', **kwargs):
"""
A list of user profiles.
If no profile model has been specified in the
``AUTH_PROFILE_MODULE`` setting,
``django.contrib.auth.models.SiteProfileNotAvailable`` will be
raised.
**Optional arguments:**
``public_profile_field``
The name of a ``BooleanField`` on the profile model; if the
value of that field on a user's profile is ``False``, that
profile will be excluded from the list. Use this feature to
allow users to mark their profiles as not being publicly
viewable.
If this argument is not specified, it will be assumed that all
users' profiles are publicly viewable.
``template_name``
The name of the template to use for displaying the profiles. If
not specified, this will default to
:template:`profiles/profile_list.html`.
Additionally, all arguments accepted by the
:view:`django.views.generic.list_detail.object_list` generic view
will be accepted here, and applied in the same fashion, with one
exception: ``queryset`` will always be the ``QuerySet`` of the
model specified by the ``AUTH_PROFILE_MODULE`` setting, optionally
filtered to remove non-publicly-viewable proiles.
**Context:**
Same as the :view:`django.views.generic.list_detail.object_list`
generic view.
**Template:**
``template_name`` keyword argument or
:template:`profiles/profile_list.html`.
"""
profile_model = utils.get_profile_model()
queryset = profile_model._default_manager.all()
if public_profile_field is not None:
queryset = queryset.filter(**{ public_profile_field: True })
kwargs['queryset'] = queryset
return object_list(request, template_name=template_name, **kwargs)

0
registration/__init__.py Normal file
View File

11
registration/admin.py Normal file
View File

@ -0,0 +1,11 @@
from django.contrib import admin
from registration.models import RegistrationProfile
class RegistrationAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'activation_key_expired')
search_fields = ('user__username', 'user__first_name')
admin.site.register(RegistrationProfile, RegistrationAdmin)

134
registration/forms.py Normal file
View File

@ -0,0 +1,134 @@
"""
Forms and validation code for user registration.
"""
from django.contrib.auth.models import User
from django import forms
from django.utils.translation import ugettext_lazy as _
from registration.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' }
class RegistrationForm(forms.Form):
"""
Form for registering a new user account.
Validates that the requested username is not already in use, and
requires the password to be entered twice to catch typos.
Subclasses should feel free to add any additional validation they
need, but should either preserve the base ``save()`` or implement
a ``save()`` method which returns a ``User``.
"""
username = forms.RegexField(regex=r'^\w+$',
max_length=30,
widget=forms.TextInput(attrs=attrs_dict),
label=_(u'username'))
email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
maxlength=75)),
label=_(u'email 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):
"""
Validate that the username is alphanumeric and is not already
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.'))
def clean(self):
"""
Verifiy that the values entered into the two password fields
match. Note that an error here will end up in
``non_field_errors()`` because it doesn't apply to a single
field.
"""
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_(u'You must type the same password each time'))
return self.cleaned_data
def save(self):
"""
Create the new ``User`` and ``RegistrationProfile``, and
returns the ``User`` (by calling
``RegistrationProfile.objects.create_inactive_user()``).
"""
new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'])
return new_user
class RegistrationFormTermsOfService(RegistrationForm):
"""
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 read and agree to the Terms of Service'),
error_messages={ 'required': u"You must agree to the terms to register" })
class RegistrationFormUniqueEmail(RegistrationForm):
"""
Subclass of ``RegistrationForm`` which enforces uniqueness of
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']
class RegistrationFormNoFreeEmail(RegistrationForm):
"""
Subclass of ``RegistrationForm`` which disallows registration with
email addresses from popular free webmail services; moderately
useful for preventing automated spam registrations.
To change the list of banned domains, subclass this form and
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']
def clean_email(self):
"""
Check the supplied email address against a list of known free
webmail domains.
"""
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']

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "اسم المستخدم"
#: forms.py:41
msgid "email address"
msgstr "عنوان البريد الالكتروني"
#: forms.py:43
msgid "password"
msgstr "كلمة المرور"
#: forms.py:45
msgid "password (again)"
msgstr "تأكيد كلمة المرور"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "يمكن أن يحتوي اسم المستخدم على احرف، ارقام وشرطات سطرية فقط"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "اسم المستخدم مسجل مسبقا. يرجى اختيار اسم اخر."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "يجب ادخال كلمة المرور مطابقة كل مرة"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "أقر بقراءة والموافقة على شروط الخدمة"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "يجب الموافقة على الشروط للتسجيل"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "عنوان البريد الالكتروني مسجل مسبقا. يرجى تزويد عنوان بريد الكتروني مختلف."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "يمنع التسجيل باستخدام عناوين بريد الكترونية مجانية. يرجى تزويد عنوان بريد الكتروني مختلف."
#: models.py:188
msgid "user"
msgstr "مستخدم"
#: models.py:189
msgid "activation key"
msgstr "رمز التفعيل"
#: models.py:194
msgid "registration profile"
msgstr "ملف التسجيل الشخصي"
#: models.py:195
msgid "registration profiles"
msgstr "ملفات التسجيل الشخصية"

Binary file not shown.

View File

@ -0,0 +1,78 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2008-03-05 12:37+0200\n"
"Last-Translator: Vladislav <vladislav.mitov@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Bookmarks: -1,-1,-1,-1,10,-1,-1,-1,-1,-1\n"
#: forms.py:38
msgid "username"
msgstr "Потребителско име "
#: forms.py:41
msgid "email address"
msgstr "Електронна поща"
#: forms.py:43
msgid "password"
msgstr "Парола"
#: forms.py:45
msgid "password (again)"
msgstr "Парола (проверка)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Потребителските имена могат да съдържат букви, цифри и подчертавки"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Потребителското име е заето. Моля изберето друго."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Грешка при проверка на паролата."
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Прочел съм и съм съгласен с условията за експлоатация"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Трябва да сте съгласни с условията за да се регистрирате."
#: forms.py:124
msgid "This email address is already in use. Please supply a different email address."
msgstr "Адреса на електронната поща е използван. Моля въведете друг адрес."
#: forms.py:149
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "Регистрациите с безплатни адреси е забранен. Моля въведете различен адрес за електронна поща"
#: models.py:188
msgid "user"
msgstr "Потребител"
#: models.py:189
msgid "activation key"
msgstr "Ключ за активация"
#: models.py:194
msgid "registration profile"
msgstr "регистрационен профил"
#: models.py:195
msgid "registration profiles"
msgstr "регистрационни профили"

Binary file not shown.

View File

@ -0,0 +1,85 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Jannis Leidel <jannis@leidel.info>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-registration 0.3 \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2007-09-29 16:50+0200\n"
"Last-Translator: Jannis Leidel <jannis@leidel.info>\n"
"Language-Team: Deutsch <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "Benutzername"
#: forms.py:41
msgid "email address"
msgstr "E-Mail-Adresse"
#: forms.py:43
msgid "password"
msgstr "Passwort"
#: forms.py:45
msgid "password (again)"
msgstr "Passwort (wiederholen)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Benutzernamen können nur Buchstaben, Zahlen und Unterstriche enthalten"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Dieser Benutzername ist schon vergeben. Bitte einen anderen wählen."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Bitte das gleiche Passwort zur Überprüfung nochmal eingeben"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Ich habe die Nutzungsvereinbarung gelesen und stimme ihr zu"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Sie müssen der Nutzungsvereinbarung zustimmen, um sich zu registrieren"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr ""
"Diese E-Mail-Adresse wird schon genutzt. Bitte geben Sie eine andere "
"E-Mail-Adresse an."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
"Die Registrierung mit einer kostenlosen E-Mail-Adresse ist untersagt. Bitte "
"geben Sie eine andere E-Mail-Adresse an."
#: models.py:188
msgid "user"
msgstr "Benutzer"
#: models.py:189
msgid "activation key"
msgstr "Aktivierungsschlüssel"
#: models.py:194
msgid "registration profile"
msgstr "Registrierungsprofil"
#: models.py:195
msgid "registration profiles"
msgstr "Registrierungsprofile"

Binary file not shown.

View File

@ -0,0 +1,84 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Panos Laganakos <panos.laganakos@gmail.com>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2007-11-14 21:50+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "όνομα χρήστη"
#: forms.py:41
msgid "email address"
msgstr "διεύθυνση ηλεκτρονικού ταχυδρομείου"
#: forms.py:43
msgid "password"
msgstr "συνθηματικό"
#: forms.py:45
msgid "password (again)"
msgstr "συνθηματικό (ξανά)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Τα ονόματα χρηστών μπορούν να περιλαμβάνουν μόνο γράμματα, αριθμούς και υπογραμμίσεις"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Αυτό το όνομα χρήστη χρησιμοποίειται ήδη. Παρακαλώ διαλέξτε ένα άλλο."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Πρέπει να εισάγετε το ίδιο συνθηματικό κάθε φορά"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Διάβασα και συμφωνώ με τους Όρους της Υπηρεσίας"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Πρέπει να συμφωνείται με τους όρους για να εγγραφείτε"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr ""
"Η συγκεκριμένη διεύθυνση ηλεκτρονικού ταχυδρομείου χρησιμοποιείται ήδη. "
"Παρακαλώ δώστε κάποια άλλη."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
"Η εγγραφή μέσω δωρεάν διευθύνσεων ηλεκτρονικού ταχυδρομείου απαγορεύεται. ""Παρακαλώ δώστε κάποια άλλη."
#: models.py:188
msgid "user"
msgstr "χρήστης"
#: models.py:189
msgid "activation key"
msgstr "κλειδί ενεργοποίησης"
#: models.py:194
msgid "registration profile"
msgstr "προφίλ εγγραφής"
#: models.py:195
msgid "registration profiles"
msgstr "προφίλ εγγραφών"

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr ""
#: forms.py:41
msgid "email address"
msgstr ""
#: forms.py:43
msgid "password"
msgstr ""
#: forms.py:45
msgid "password (again)"
msgstr ""
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr ""
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr ""
#: forms.py:68
msgid "You must type the same password each time"
msgstr ""
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr ""
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr ""
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr ""
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
#: models.py:188
msgid "user"
msgstr ""
#: models.py:189
msgid "activation key"
msgstr ""
#: models.py:194
msgid "registration profile"
msgstr ""
#: models.py:195
msgid "registration profiles"
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,85 @@
# Spanish translation for django-registration.
# Copyright (C) 2007, James Bennet
# This file is distributed under the same license as the registration package.
# Ernesto Rico Schmidt <e.rico.schmidt@gmail.com>, 2008.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-registration 0.3 \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-03-11 00:19-0400\n"
"PO-Revision-Date: 2008-03-11 00:19-0400\n"
"Last-Translator: Ernesto Rico Schmidt <e.rico.schmidt@gmail.com>\n"
"Language-Team: Español <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "nombre de usuario"
#: forms.py:41
msgid "email address"
msgstr "dirección de coreo electrónico"
#: forms.py:43
msgid "password"
msgstr "contraseña"
#: forms.py:45
msgid "password (again)"
msgstr "contraseña (otra vez)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Los nombres de usuarios sólo pueden contener letras, números y guiones bajos"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Este nombre de usuario ya está ocupado. Por favor escoge otro"
#: forms.py:71
msgid "You must type the same password each time"
msgstr "Tienes que introducir la misma contraseña cada vez"
#: forms.py:100
msgid "I have read and agree to the Terms of Service"
msgstr "He leído y acepto los términos de servicio"
#: forms.py:109
msgid "You must agree to the terms to register"
msgstr "Tienes que aceptar los términos para registrarte"
#: forms.py:128
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr ""
"La dirección de correo electrónico ya está siendo usada. Por favor"
"proporciona otra dirección."
#: forms.py:153
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
"El registro usando una dirección de correo electrónico gratis está prohibido."
"Por favor proporciona otra dirección."
#: models.py:188
msgid "user"
msgstr "usuario"
#: models.py:189
msgid "activation key"
msgstr "clave de activación"
#: models.py:194
msgid "registration profile"
msgstr "perfil de registro"
#: models.py:195
msgid "registration profiles"
msgstr "perfiles de registro"

Binary file not shown.

View File

@ -0,0 +1,83 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2008 Leonardo Manuel Rocha
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <l e o m a r o at g m a i l dot c o m>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "nombre de usuario"
#: forms.py:41
msgid "email address"
msgstr "dirección de e-mail"
#: forms.py:43
msgid "password"
msgstr "contraseña"
#: forms.py:45
msgid "password (again)"
msgstr "contraseña (nuevamente)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "El nombre de usuario solo puede contener letras, números y guiones bajos"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Ese nombre de usuario ya está asignado. Por favor elija otro."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Debe tipear la misma contraseña cada vez"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "He leído y estoy de acuerdo con las Condiciones de Servicio"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Debe estar de acuerdo con las Condiciones para poder registrarse"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Esa dirección de e-mail ya está en uso. Por favor provea otra "
"dirección."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "La registración con un e-mail gratuito está prohibida. Por favor "
"de una dirección de e-mail diferente."
#: models.py:188
msgid "user"
msgstr "usuario"
#: models.py:189
msgid "activation key"
msgstr "clave de activación"
#: models.py:194
msgid "registration profile"
msgstr "perfil de registro"
#: models.py:195
msgid "registration profiles"
msgstr "perfiles de registro"

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Samuel Adam <samuel.adam@gmail.com>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-registration 0.3 \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2007-09-20 10:30+0100\n"
"Last-Translator: Samuel Adam <samuel.adam@gmail.com>\n"
"Language-Team: Français <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "pseudo"
#: forms.py:41
msgid "email address"
msgstr "adresse email"
#: forms.py:43
msgid "password"
msgstr "mot de passe"
#: forms.py:45
msgid "password (again)"
msgstr "mot de passe (vérification)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Le pseudo ne peut contenir que des lettres, chiffres et le caractère souligné."
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Ce pseudo est déjà utilisé. Veuillez en choisir un autre."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Veuillez indiquer le même mot de passe dans les deux champs"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "J'ai lu et accepté les Conditions Générales d'Utilisation"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Vous devez accepter les conditions d'utilisation pour vous inscrire"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Cette adresse email est déjà utilisée. Veuillez en indiquer une autre."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "L'inscription avec une adresse email d'un compte gratuit est interdite. Veuillez en indiquer une autre."
#: models.py:188
msgid "user"
msgstr "utilisateur"
#: models.py:189
msgid "activation key"
msgstr "clé d'activation"
#: models.py:194
msgid "registration profile"
msgstr "profil d'inscription"
#: models.py:195
msgid "registration profiles"
msgstr "profils d'inscription"

Binary file not shown.

View File

@ -0,0 +1,86 @@
# translation of registration.
# Copyright (C) 2008 THE registration'S COPYRIGHT HOLDER
# This file is distributed under the same license as the registration package.
# <>, 2008.
# , fuzzy
# <>, 2008.
#
#
msgid ""
msgstr ""
"Project-Id-Version: registration\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-02-10 02:01+0200\n"
"PO-Revision-Date: 2008-02-10 02:05+0200\n"
"Last-Translator: Meir Kriheli <meir@mksoft.co.il>\n"
"Language-Team: Hebrew\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit"
#: forms.py:38
msgid "username"
msgstr "שם משתמש"
#: forms.py:41
msgid "email address"
msgstr "דואר אלקטרוני"
#: forms.py:43
msgid "password"
msgstr "סיסמה"
#: forms.py:45
msgid "password (again)"
msgstr "סיסמה (שוב)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "שמות משתמש יכולים להכיל רק אותיות, ספרות וקווים תחתונים"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "שם המשתמש תפוס כבר. נא לבחור אחר."
#: forms.py:64
msgid "You must type the same password each time"
msgstr "יש להקליד את אותה הסיסמה פעמיים"
#: forms.py:93
msgid "I have read and agree to the Terms of Service"
msgstr "קראתי והסכמתי לתנאי השימוש"
#: forms.py:102
msgid "You must agree to the terms to register"
msgstr "עליך להסכים לתנאי השימוש"
#: forms.py:121
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr ""
"כתובת הדואר האלקטרוני תפוסה כבר. נא לספק כתובת דואר אחרת."
#: forms.py:146
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
"הרישום בעזרת תיבת דואר אלקטרוני חינמית אסור. נא לספק כתובת אחרת."
#: models.py:188
msgid "user"
msgstr "משתמש"
#: models.py:189
msgid "activation key"
msgstr "מפתח הפעלה"
#: models.py:194
msgid "registration profile"
msgstr "פרופיל רישום"
#: models.py:195
msgid "registration profiles"
msgstr "פרופילי רישום"

Binary file not shown.

View File

@ -0,0 +1,82 @@
# translation of django.po to Italiano
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Nicola Larosa <nico@tekNico.net>, 2008.
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2008-05-27 15:05+0200\n"
"Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
"Language-Team: Italiano\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:38
msgid "username"
msgstr "nome utente"
#: forms.py:41
msgid "email address"
msgstr "indirizzo email"
#: forms.py:43
msgid "password"
msgstr "password"
#: forms.py:45
msgid "password (again)"
msgstr "password (di nuovo)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "I nomi utente possono contenere solo lettere, numeri e sottolineature"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Questo nome utente è già usato. Scegline un altro."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Bisogna inserire la stessa password ogni volta"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Dichiaro di aver letto e di approvare le Condizioni di Servizio"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Per registrarsi bisogna approvare le condizioni"
#: forms.py:124
msgid "This email address is already in use. Please supply a different email "
"address."
msgstr "Questo indirizzo email è già in uso. Inserisci un altro indirizzo email."
#: forms.py:149
msgid "Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "La registrazione con indirizzi email gratis non è permessa. "
"Inserisci un altro indirizzo email."
#: models.py:188
msgid "user"
msgstr "utente"
#: models.py:189
msgid "activation key"
msgstr "chiave di attivazione"
#: models.py:194
msgid "registration profile"
msgstr "profilo di registrazione"
#: models.py:195
msgid "registration profiles"
msgstr "profili di registrazione"

Binary file not shown.

View File

@ -0,0 +1,78 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Shinya Okano <xxshss@yahoo.co.jp>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-registration 0.4 \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2008-01-31 10:20+0900\n"
"Last-Translator: Shinya Okano <xxshss@yahoo.co.jp>\n"
"Language-Team: Japanese <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "ユーザ名"
#: forms.py:41
msgid "email address"
msgstr "メールアドレス"
#: forms.py:43
msgid "password"
msgstr "パスワード"
#: forms.py:45
msgid "password (again)"
msgstr "パスワード (確認)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "ユーザ名には半角英数とアンダースコアのみが使用できます。"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "このユーザ名は既に使用されています。他のユーザ名を指定してください。"
#: forms.py:68
msgid "You must type the same password each time"
msgstr "同じパスワードを入力する必要があります。"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "サービス利用規約を読み、同意します。"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "登録するためには規約に同意する必要があります。"
#: forms.py:124
msgid "This email address is already in use. Please supply a different email address."
msgstr "このメールアドレスは既に使用されています。他のメールアドレスを指定して下さい。"
#: forms.py:149
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "自由なメールアドレスを使用した登録は禁止されています。他のメールアドレスを指定してください。"
#: models.py:188
msgid "user"
msgstr "ユーザ"
#: models.py:189
msgid "activation key"
msgstr "アクティベーションキー"
#: models.py:194
msgid "registration profile"
msgstr "登録プロファイル"
#: models.py:195
msgid "registration profiles"
msgstr "登録プロファイル"

Binary file not shown.

View File

@ -0,0 +1,77 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: registration\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-08-14 13:25+0200\n"
"PO-Revision-Date: 2008-08-14 13:25+0200\n"
"Last-Translator: Joost Cassee <joost@cassee.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:38
msgid "username"
msgstr "gebruikersnaam"
#: forms.py:41
msgid "email address"
msgstr "e-mail adres"
#: forms.py:43
msgid "password"
msgstr "wachtwoord"
#: forms.py:45
msgid "password (again)"
msgstr "wachtwoord (opnieuw)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Gebruikersnamen kunnen alleen letters, nummer en liggende streepjes bevatten."
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Deze gebruikersnaam is reeds in gebruik. Kiest u alstublieft een andere gebruikersnaam."
#: forms.py:71
msgid "You must type the same password each time"
msgstr "U moet twee maal hetzelfde wachtwoord typen."
#: forms.py:100
msgid "I have read and agree to the Terms of Service"
msgstr "Ik heb de servicevoorwaarden gelezen en ga akkoord."
#: forms.py:109
msgid "You must agree to the terms to register"
msgstr "U moet akkoord gaan met de servicevoorwaarden om u te registreren."
#: forms.py:125
msgid "This email address is already in use. Please supply a different email address."
msgstr "Dit e-mail adres is reeds in gebruik. Kiest u alstublieft een ander e-mail adres."
#: forms.py:151
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "U kunt u niet registreren met een gratis e-mail adres. Kiest u alstublieft een ander e-mail adres."
#: models.py:191
msgid "user"
msgstr "gebruiker"
#: models.py:192
msgid "activation key"
msgstr "activatiecode"
#: models.py:197
msgid "registration profile"
msgstr "registratieprofiel"
#: models.py:198
msgid "registration profiles"
msgstr "registratieprofielen"

Binary file not shown.

View File

@ -0,0 +1,84 @@
# Polish translation for django-registration.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the django-registration package.
# Jarek Zgoda <jarek.zgoda@gmail.com>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2007-12-15 12:45+0100\n"
"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
"Language-Team: Polish <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "nazwa użytkownika"
#: forms.py:41
msgid "email address"
msgstr "adres email"
#: forms.py:43
msgid "password"
msgstr "hasło"
#: forms.py:45
msgid "password (again)"
msgstr "hasło (ponownie)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr ""
"Nazwa użytkownika może zawierać tylko litery, cyfry i znaki podkreślenia"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Ta nazwa użytkownika jest już zajęta. Wybierz inną."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Musisz wpisać to samo hasło w obu polach"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Przeczytałem regulamin i akceptuję go"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Musisz zaakceptować regulamin, aby się zarejestrować"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Ten adres email jest już używany. Użyj innego adresu email."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr ""
"Nie ma możliwości rejestracji przy użyciu darmowego adresu email. Użyj "
"innego adresu email."
#: models.py:188
msgid "user"
msgstr "użytkownik"
#: models.py:189
msgid "activation key"
msgstr "klucz aktywacyjny"
#: models.py:194
msgid "registration profile"
msgstr "profil rejestracji"
#: models.py:195
msgid "registration profiles"
msgstr "profile rejestracji"

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "usuário"
#: forms.py:41
msgid "email address"
msgstr "endereço de email"
#: forms.py:43
msgid "password"
msgstr ""
#: forms.py:45
msgid "password (again)"
msgstr "senha (novamente)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Nomes de usuário apenas podem conter letras, números, e underscore"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Este nome de usuário já existe. Por favor, escolha outro."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Você deve escrever a mesma senha nos dois campos"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Eu lí e concordo com os Termos de Uso do serviço"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Você deve concordar com os termos para registrar-se"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Este endereço de email já está em uso. Por favor, informe um endereço de email diferente."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "Registrar-se com contas de email gratuitos está proibido. Por favor, informe um endereço de email diferente."
#: models.py:188
msgid "user"
msgstr "usuário"
#: models.py:189
msgid "activation key"
msgstr "chave de ativação"
#: models.py:194
msgid "registration profile"
msgstr "profile de registro"
#: models.py:195
msgid "registration profiles"
msgstr "profiles de registro"

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "имя пользователя"
#: forms.py:41
msgid "email address"
msgstr "адрес электронной почты"
#: forms.py:43
msgid "password"
msgstr "пароль"
#: forms.py:45
msgid "password (again)"
msgstr "пароль (верификация)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Имя пользователя может содержать только буквы, цифры и подчеркивания"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Такое имя пользователя уже есть. Пожалуйста, выберите другое."
#: forms.py:68
msgid "You must type the same password each time"
msgstr "Вы должны вводить один и тот же пароль каждый раз"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "Я прочитал и согласен с Правилами Использования"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "Вы должны согласиться с Правилами для регистрации"
#: forms.py:124
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Этот адрес электронной почты уже используется. Пожалуйста, введите другой адрес."
#: forms.py:149
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "Регистрация с использованием свободных почтовых серверов запрещена. Пожалуйста, введите другой адрес электронной почты."
#: models.py:188
msgid "user"
msgstr "пользователь"
#: models.py:189
msgid "activation key"
msgstr "ключ активации"
#: models.py:194
msgid "registration profile"
msgstr "профиль регистрации"
#: models.py:195
msgid "registration profiles"
msgstr "профили регистрации"

Binary file not shown.

View File

@ -0,0 +1,80 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-registration trunk\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-04-05 13:51+0200\n"
"PO-Revision-Date: 2008-04-05 14:00+0100\n"
"Last-Translator: Nebojsa Djordjevic <djnesh@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Poedit-Language: Serbian\n"
"X-Poedit-Country: YUGOSLAVIA\n"
#: forms.py:38
msgid "username"
msgstr "korisničko ime"
#: forms.py:41
msgid "email address"
msgstr "email adresa"
#: forms.py:43
msgid "password"
msgstr "šifra"
#: forms.py:45
msgid "password (again)"
msgstr "šifra (ponovo)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Korisničko ime može da se sastoji samo od slova, brojeva i donje crte (\"_\")"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Korisničko ime je već zauzeto. Izaberite drugo."
#: forms.py:71
msgid "You must type the same password each time"
msgstr "Unete šifre se ne slažu"
#: forms.py:100
msgid "I have read and agree to the Terms of Service"
msgstr "Pročitao sam i slažem se sa uslovima korišćenja"
#: forms.py:109
msgid "You must agree to the terms to register"
msgstr "Morate se složiti sa uslovima korišćenja da bi ste se registrovali"
#: forms.py:128
msgid "This email address is already in use. Please supply a different email address."
msgstr "Ova e-mail adresa je već u upotrebi. Morate koristiti drugu e-mail adresu."
#: forms.py:153
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "Registracija korišćenjem besplatnig e-mail adresa je zabranjena. Morate uneti drugu e-mail adresu."
#: models.py:188
msgid "user"
msgstr "korisnik"
#: models.py:189
msgid "activation key"
msgstr "aktivacioni ključ"
#: models.py:194
msgid "registration profile"
msgstr "registracioni profil"
#: models.py:195
msgid "registration profiles"
msgstr "registracioni profili"

Binary file not shown.

View File

@ -0,0 +1,81 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-03-23 18:59+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emil Stenström <em@kth.se>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: .\forms.py:38
msgid "username"
msgstr "Användarnamn"
#: .\forms.py:41
msgid "email address"
msgstr "E-postadress"
#: .\forms.py:43
msgid "password"
msgstr "Lösenord"
#: .\forms.py:45
msgid "password (again)"
msgstr "Lösenord (igen)"
#: .\forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "Användarnamn får bara innehålla bokstäver, siffror och understreck"
#: .\forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "Det användarnamnet är upptaget. Prova ett annat."
#: .\forms.py:71
msgid "You must type the same password each time"
msgstr "Båda lösenord måste vara lika"
#: .\forms.py:100
msgid "I have read and agree to the Terms of Service"
msgstr "Jag har läst och accepterar avtalet"
#: .\forms.py:109
msgid "You must agree to the terms to register"
msgstr "Du måste acceptera avtalet för att registrera dig"
#: .\forms.py:128
msgid ""
"This email address is already in use. Please supply a different email "
"address."
msgstr "Den e-postadressen är upptagen, använd an annan adress."
#: .\forms.py:153
msgid ""
"Registration using free email addresses is prohibited. Please supply a "
"different email address."
msgstr "Gratis e-postadresser är inte tillåtna, använd en annan adress."
#: .\models.py:188
msgid "user"
msgstr "Användare"
#: .\models.py:189
msgid "activation key"
msgstr "Aktiveringsnyckel"
#: .\models.py:194
msgid "registration profile"
msgstr "Profil"
#: .\models.py:195
msgid "registration profiles"
msgstr "Profiler"

Binary file not shown.

View File

@ -0,0 +1,77 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2008-03-20 23:22+0800\n"
"Last-Translator: hutuworm <hutuworm@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "用户名"
#: forms.py:41
msgid "email address"
msgstr "Email 地址"
#: forms.py:43
msgid "password"
msgstr "密码"
#: forms.py:45
msgid "password (again)"
msgstr "密码(重复)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "用户名只能包含字母、数字和下划线"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "该用户名已被占用,请另选一个。"
#: forms.py:68
msgid "You must type the same password each time"
msgstr "您必须输入两遍同样的密码"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "我已阅读并同意该服务条款"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "您必须同意注册条款"
#: forms.py:124
msgid "This email address is already in use. Please supply a different email address."
msgstr "该 Email 地址已有人使用,请提供一个另外的 Email 地址。"
#: forms.py:149
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "禁止使用免费 Email 地址注册,请提供一个另外的 Email 地址。"
#: models.py:188
msgid "user"
msgstr "用户"
#: models.py:189
msgid "activation key"
msgstr "激活密钥"
#: models.py:194
msgid "registration profile"
msgstr "注册信息"
#: models.py:195
msgid "registration profiles"
msgstr "注册信息"

Binary file not shown.

View File

@ -0,0 +1,77 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-09-19 19:30-0500\n"
"PO-Revision-Date: 2008-03-20 23:22+0800\n"
"Last-Translator: hutuworm <hutuworm@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:38
msgid "username"
msgstr "用戶名"
#: forms.py:41
msgid "email address"
msgstr "Email 地址"
#: forms.py:43
msgid "password"
msgstr "密碼"
#: forms.py:45
msgid "password (again)"
msgstr "密碼(重復)"
#: forms.py:54
msgid "Usernames can only contain letters, numbers and underscores"
msgstr "用戶名只能包含字母、數字和下劃線"
#: forms.py:59
msgid "This username is already taken. Please choose another."
msgstr "該用戶名已被佔用,請另選一個。"
#: forms.py:68
msgid "You must type the same password each time"
msgstr "您必須輸入兩遍同樣的密碼"
#: forms.py:96
msgid "I have read and agree to the Terms of Service"
msgstr "我已閱讀並同意該服務條款"
#: forms.py:105
msgid "You must agree to the terms to register"
msgstr "您必須同意注冊條款"
#: forms.py:124
msgid "This email address is already in use. Please supply a different email address."
msgstr "該 Email 地址已有人使用,請提供一個另外的 Email 地址。"
#: forms.py:149
msgid "Registration using free email addresses is prohibited. Please supply a different email address."
msgstr "禁止使用免費 Email 地址注冊,請提供一個另外的 Email 地址。"
#: models.py:188
msgid "user"
msgstr "用戶"
#: models.py:189
msgid "activation key"
msgstr "激活密鑰"
#: models.py:194
msgid "registration profile"
msgstr "注冊信息"
#: models.py:195
msgid "registration profiles"
msgstr "注冊信息"

View File

View File

@ -0,0 +1,19 @@
"""
A management command which deletes expired accounts (e.g.,
accounts which signed up but never activated) from the database.
Calls ``RegistrationProfile.objects.delete_expired_users()``, which
contains the actual logic for determining which accounts are deleted.
"""
from django.core.management.base import NoArgsCommand
from registration.models import RegistrationProfile
class Command(NoArgsCommand):
help = "Delete expired user registrations from the database"
def handle_noargs(self, **options):
RegistrationProfile.objects.delete_expired_users()

255
registration/models.py Normal file
View File

@ -0,0 +1,255 @@
import datetime
import random
import re
import sha
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.db import models
from django.db import transaction
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
SHA1_RE = re.compile('^[a-f0-9]{40}$')
class RegistrationManager(models.Manager):
"""
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.
"""
def activate_user(self, 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``
after successful activation.
To execute customized logic when a ``User`` is activated,
connect a function to the signal
``registration.signals.user_activated``; this signal will be
sent (with the ``User`` as the value of the keyword argument
``user``) after a successful activation.
"""
from registration.signals import user_activated
# Make sure the key we're trying conforms to the pattern of a
# SHA1 hash; if it doesn't, no point trying to look it up in
# the database.
if SHA1_RE.search(activation_key):
try:
profile = self.get(activation_key=activation_key)
except self.model.DoesNotExist:
return False
if not profile.activation_key_expired():
user = profile.user
user.is_active = True
user.save()
profile.activation_key = self.model.ACTIVATED
profile.save()
user_activated.send(sender=self.model, user=user)
return user
return False
def create_inactive_user(self, username, password, email,
send_email=True):
"""
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:
``registration/activation_email_subject.txt``
This template will be used for the subject line of the
email. It receives one context variable, ``site``, which
is the currently-active
``django.contrib.sites.models.Site`` instance. Because it
is used as the subject line of an email, this template's
output **must** be only a single line of text; output
longer than one line will be forcibly joined into only a
single line.
``registration/activation_email.txt``
This template will be used for the body of the email. It
will receive three context variables: ``activation_key``
will be the user's activation key (for use in constructing
a URL to activate the account), ``expiration_days`` will
be the number of days for which the key will be valid and
``site`` will be the currently-active
``django.contrib.sites.models.Site`` instance.
To execute customized logic once the new ``User`` has been
created, connect a function to the signal
``registration.signals.user_registered``; this signal will be
sent (with the new ``User`` as the value of the keyword
argument ``user``) after the ``User`` and
``RegistrationProfile`` have been created, and the email (if
any) has been sent..
"""
from registration.signals import user_registered
new_user = User.objects.create_user(username, email, password)
new_user.is_active = False
new_user.save()
registration_profile = self.create_profile(new_user)
if send_email:
from django.core.mail import send_mail
current_site = Site.objects.get_current()
subject = render_to_string('registration/activation_email_subject.txt',
{ 'site': current_site })
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
message = render_to_string('registration/activation_email.txt',
{ 'activation_key': registration_profile.activation_key,
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
'site': current_site })
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [new_user.email])
user_registered.send(sender=self.model, user=new_user)
return new_user
create_inactive_user = transaction.commit_on_success(create_inactive_user)
def create_profile(self, user):
"""
Create a ``RegistrationProfile`` for a given
``User``, and return 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.
"""
salt = sha.new(str(random.random())).hexdigest()[:5]
activation_key = sha.new(salt+user.username).hexdigest()
return self.create(user=user,
activation_key=activation_key)
def delete_expired_users(self):
"""
Remove expired instances of ``RegistrationProfile`` and their
associated ``User``s.
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
does not have an associated ``RegistrationProfile`` will not
be deleted.
"""
for profile in self.all():
if profile.activation_key_expired():
user = profile.user
if not user.is_active:
user.delete()
class RegistrationProfile(models.Model):
"""
A simple profile which stores an activation key for use during
user account registration.
Generally, you will not want to interact directly with instances
of this model; the provided manager includes methods
for creating and activating new accounts, as well as for cleaning
out accounts which have never been activated.
While it is possible to use this model as the value of the
``AUTH_PROFILE_MODULE`` setting, it's not recommended that you do
so. This model's sole purpose is to store data temporarily during
account registration and activation.
"""
ACTIVATED = u"ALREADY_ACTIVATED"
user = models.ForeignKey(User, unique=True, verbose_name=_('user'))
activation_key = models.CharField(_('activation key'), max_length=40)
objects = RegistrationManager()
class Meta:
verbose_name = _('registration profile')
verbose_name_plural = _('registration profiles')
def __unicode__(self):
return u"Registration information for %s" % self.user
def activation_key_expired(self):
"""
Determine whether this ``RegistrationProfile``'s activation
key has expired, returning a boolean -- ``True`` if the key
has expired.
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 after signup during which a user is allowed to
activate their account); if the result is less than or
equal to the current date, the key has expired and this
method returns ``True``.
"""
expiration_date = datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS)
return self.activation_key == self.ACTIVATED or \
(self.user.date_joined + expiration_date <= datetime.datetime.now())
activation_key_expired.boolean = True

8
registration/signals.py Normal file
View File

@ -0,0 +1,8 @@
from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user"])
# A user has activated his or her account.
user_activated = Signal(providing_args=["user"])

355
registration/tests.py Normal file
View File

@ -0,0 +1,355 @@
"""
Unit tests for django-registration.
These tests assume that you've completed all the prerequisites for
getting django-registration running in the default setup, to wit:
1. You have ``registration`` in your ``INSTALLED_APPS`` setting.
2. You have created all of the templates mentioned in this
application's documentation.
3. You have added the setting ``ACCOUNT_ACTIVATION_DAYS`` to your
settings file.
4. You have URL patterns pointing to the registration and activation
views, with the names ``registration_register`` and
``registration_activate``, respectively, and a URL pattern named
'registration_complete'.
"""
import datetime
import sha
from django.conf import settings
from django.contrib.auth.models import User
from django.core import mail
from django.core import management
from django.core.urlresolvers import reverse
from django.test import TestCase
from registration import forms
from registration.models import RegistrationProfile
from registration import signals
class RegistrationTestCase(TestCase):
"""
Base class for the test cases; this sets up two users -- one
expired, one not -- which are used to exercise various parts of
the application.
"""
def setUp(self):
self.sample_user = RegistrationProfile.objects.create_inactive_user(username='alice',
password='secret',
email='alice@example.com')
self.expired_user = RegistrationProfile.objects.create_inactive_user(username='bob',
password='swordfish',
email='bob@example.com')
self.expired_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1)
self.expired_user.save()
class RegistrationModelTests(RegistrationTestCase):
"""
Tests for the model-oriented functionality of django-registration,
including ``RegistrationProfile`` and its custom manager.
"""
def test_new_user_is_inactive(self):
"""
Test that a newly-created user is inactive.
"""
self.failIf(self.sample_user.is_active)
def test_registration_profile_created(self):
"""
Test that a ``RegistrationProfile`` is created for a new user.
"""
self.assertEqual(RegistrationProfile.objects.count(), 2)
def test_activation_email(self):
"""
Test that user signup sends an activation email.
"""
self.assertEqual(len(mail.outbox), 2)
def test_activation_email_disable(self):
"""
Test that activation email can be disabled.
"""
RegistrationProfile.objects.create_inactive_user(username='noemail',
password='foo',
email='nobody@example.com',
send_email=False)
self.assertEqual(len(mail.outbox), 2)
def test_activation(self):
"""
Test that user activation actually activates the user and
properly resets the activation key, and fails for an
already-active or expired user, or an invalid key.
"""
# Activating a valid user returns the user.
self.failUnlessEqual(RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.sample_user).activation_key).pk,
self.sample_user.pk)
# The activated user must now be active.
self.failUnless(User.objects.get(pk=self.sample_user.pk).is_active)
# The activation key must now be reset to the "already activated" constant.
self.failUnlessEqual(RegistrationProfile.objects.get(user=self.sample_user).activation_key,
RegistrationProfile.ACTIVATED)
# Activating an expired user returns False.
self.failIf(RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.expired_user).activation_key))
# Activating from a key that isn't a SHA1 hash returns False.
self.failIf(RegistrationProfile.objects.activate_user('foo'))
# Activating from a key that doesn't exist returns False.
self.failIf(RegistrationProfile.objects.activate_user(sha.new('foo').hexdigest()))
def test_account_expiration_condition(self):
"""
Test that ``RegistrationProfile.activation_key_expired()``
returns ``True`` for expired users and for active users, and
``False`` otherwise.
"""
# Unexpired user returns False.
self.failIf(RegistrationProfile.objects.get(user=self.sample_user).activation_key_expired())
# Expired user returns True.
self.failUnless(RegistrationProfile.objects.get(user=self.expired_user).activation_key_expired())
# Activated user returns True.
RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user=self.sample_user).activation_key)
self.failUnless(RegistrationProfile.objects.get(user=self.sample_user).activation_key_expired())
def test_expired_user_deletion(self):
"""
Test that
``RegistrationProfile.objects.delete_expired_users()`` deletes
only inactive users whose activation window has expired.
"""
RegistrationProfile.objects.delete_expired_users()
self.assertEqual(RegistrationProfile.objects.count(), 1)
def test_management_command(self):
"""
Test that ``manage.py cleanupregistration`` functions
correctly.
"""
management.call_command('cleanupregistration')
self.assertEqual(RegistrationProfile.objects.count(), 1)
def test_signals(self):
"""
Test that the ``user_registered`` and ``user_activated``
signals are sent, and that they send the ``User`` as an
argument.
"""
def receiver(sender, **kwargs):
self.assert_('user' in kwargs)
self.assertEqual(kwargs['user'].username, u'signal_test')
received_signals.append(kwargs.get('signal'))
received_signals = []
expected_signals = [signals.user_registered, signals.user_activated]
for signal in expected_signals:
signal.connect(receiver)
RegistrationProfile.objects.create_inactive_user(username='signal_test',
password='foo',
email='nobody@example.com',
send_email=False)
RegistrationProfile.objects.activate_user(RegistrationProfile.objects.get(user__username='signal_test').activation_key)
self.assertEqual(received_signals, expected_signals)
class RegistrationFormTests(RegistrationTestCase):
"""
Tests for the forms and custom validation logic included in
django-registration.
"""
def test_registration_form(self):
"""
Test that ``RegistrationForm`` enforces username constraints
and matching passwords.
"""
invalid_data_dicts = [
# Non-alphanumeric username.
{
'data':
{ 'username': 'foo/bar',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' },
'error':
('username', [u"Enter a valid value."])
},
# Already-existing username.
{
'data':
{ 'username': 'alice',
'email': 'alice@example.com',
'password1': 'secret',
'password2': 'secret' },
'error':
('username', [u"This username is already taken. Please choose another."])
},
# Mismatched passwords.
{
'data':
{ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'bar' },
'error':
('__all__', [u"You must type the same password each time"])
},
]
for invalid_dict in invalid_data_dicts:
form = forms.RegistrationForm(data=invalid_dict['data'])
self.failIf(form.is_valid())
self.assertEqual(form.errors[invalid_dict['error'][0]], invalid_dict['error'][1])
form = forms.RegistrationForm(data={ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' })
self.failUnless(form.is_valid())
def test_registration_form_tos(self):
"""
Test that ``RegistrationFormTermsOfService`` requires
agreement to the terms of service.
"""
form = forms.RegistrationFormTermsOfService(data={ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' })
self.failIf(form.is_valid())
self.assertEqual(form.errors['tos'], [u"You must agree to the terms to register"])
form = forms.RegistrationFormTermsOfService(data={ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo',
'tos': 'on' })
self.failUnless(form.is_valid())
def test_registration_form_unique_email(self):
"""
Test that ``RegistrationFormUniqueEmail`` validates uniqueness
of email addresses.
"""
form = forms.RegistrationFormUniqueEmail(data={ 'username': 'foo',
'email': 'alice@example.com',
'password1': 'foo',
'password2': 'foo' })
self.failIf(form.is_valid())
self.assertEqual(form.errors['email'], [u"This email address is already in use. Please supply a different email address."])
form = forms.RegistrationFormUniqueEmail(data={ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' })
self.failUnless(form.is_valid())
def test_registration_form_no_free_email(self):
"""
Test that ``RegistrationFormNoFreeEmail`` disallows
registration with free email addresses.
"""
base_data = { 'username': 'foo',
'password1': 'foo',
'password2': 'foo' }
for domain in ('aim.com', 'aol.com', 'email.com', 'gmail.com',
'googlemail.com', 'hotmail.com', 'hushmail.com',
'msn.com', 'mail.ru', 'mailinator.com', 'live.com'):
invalid_data = base_data.copy()
invalid_data['email'] = u"foo@%s" % domain
form = forms.RegistrationFormNoFreeEmail(data=invalid_data)
self.failIf(form.is_valid())
self.assertEqual(form.errors['email'], [u"Registration using free email addresses is prohibited. Please supply a different email address."])
base_data['email'] = 'foo@example.com'
form = forms.RegistrationFormNoFreeEmail(data=base_data)
self.failUnless(form.is_valid())
class RegistrationViewTests(RegistrationTestCase):
"""
Tests for the views included in django-registration.
"""
def test_registration_view(self):
"""
Test that the registration view rejects invalid submissions,
and creates a new user and redirects after a valid submission.
"""
# Invalid data fails.
response = self.client.post(reverse('registration_register'),
data={ 'username': 'alice', # Will fail on username uniqueness.
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' })
self.assertEqual(response.status_code, 200)
self.failUnless(response.context['form'])
self.failUnless(response.context['form'].errors)
response = self.client.post(reverse('registration_register'),
data={ 'username': 'foo',
'email': 'foo@example.com',
'password1': 'foo',
'password2': 'foo' })
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], 'http://testserver%s' % reverse('registration_complete'))
self.assertEqual(RegistrationProfile.objects.count(), 3)
def test_activation_view(self):
"""
Test that the activation view activates the user from a valid
key and fails if the key is invalid or has expired.
"""
# Valid user puts the user account into the context.
response = self.client.get(reverse('registration_activate',
kwargs={ 'activation_key': RegistrationProfile.objects.get(user=self.sample_user).activation_key }))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['account'].pk, self.sample_user.pk)
# Expired user sets the account to False.
response = self.client.get(reverse('registration_activate',
kwargs={ 'activation_key': RegistrationProfile.objects.get(user=self.expired_user).activation_key }))
self.failIf(response.context['account'])
# Invalid key gets to the view, but sets account to False.
response = self.client.get(reverse('registration_activate',
kwargs={ 'activation_key': 'foo' }))
self.failIf(response.context['account'])
# Nonexistent key sets the account to False.
response = self.client.get(reverse('registration_activate',
kwargs={ 'activation_key': sha.new('foo').hexdigest() }))
self.failIf(response.context['account'])

72
registration/urls.py Normal file
View File

@ -0,0 +1,72 @@
"""
URLConf for Django user registration and authentication.
If the default behavior of the registration views is acceptable to
you, simply use a line like this in your root URLConf to set up the
default URLs for registration::
(r'^accounts/', include('registration.urls')),
This will also automatically set up the views in
``django.contrib.auth`` at sensible default locations.
But if you'd like to customize the behavior (e.g., by passing extra
arguments to the various views) or split up the URLs, feel free to set
up your own URL patterns for these views instead. If you do, it's a
good idea to use the names ``registration_activate``,
``registration_complete`` and ``registration_register`` for the
various steps of the user-signup process.
"""
from django.conf import settings
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.contrib.auth import views as auth_views
from registration.views import activate
from registration.views import register
urlpatterns = patterns('',
# Activation keys get matched by \w+ instead of the more specific
# [a-fA-F0-9]{40} because a bad activation key should still get to the view;
# that way it can return a sensible "invalid key" message instead of a
# confusing 404.
url(r'^activate/(?P<activation_key>\w+)/$',
activate,
name='registration_activate'),
url(r'^login/$',
auth_views.login,
{'template_name': 'registration/login.html'},
name='auth_login'),
url(r'^logout/$',
auth_views.logout,
{'template_name': 'registration/logout.html'},
name='auth_logout'),
url(r'^password/change/$',
auth_views.password_change,
name='auth_password_change'),
url(r'^password/change/done/$',
auth_views.password_change_done,
name='auth_password_change_done'),
url(r'^password/reset/$',
auth_views.password_reset,
name='auth_password_reset'),
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.password_reset_confirm,
name='auth_password_reset_confirm'),
url(r'^password/reset/complete/$',
auth_views.password_reset_complete,
name='auth_password_reset_complete'),
url(r'^password/reset/done/$',
auth_views.password_reset_done,
name='auth_password_reset_done'),
url(r'^register/$',
register,
name='registration_register'),
url(r'^register/complete/$',
direct_to_template,
{'template': 'registration/registration_complete.html','extra_context':{'settings':settings}},
name='registration_complete'),
)

153
registration/views.py Normal file
View File

@ -0,0 +1,153 @@
"""
Views which allow users to create and activate accounts.
"""
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from registration.forms import RegistrationForm
from registration.models import RegistrationProfile
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.
By default, use the template ``registration/activate.html``; to
change this, pass the name of a template as the keyword argument
``template_name``.
**Required arguments**
``activation_key``
The activation key to validate and use for activating the
``User``.
**Optional arguments**
``extra_context``
A dictionary of variables to add to the template context. Any
callable object in this dictionary will be called to produce
the end result which appears in the context.
``template_name``
A custom template to use.
**Context:**
``account``
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.
Any extra variables supplied in the ``extra_context`` argument
(see above).
**Template:**
registration/activate.html or ``template_name`` keyword argument.
"""
activation_key = activation_key.lower() # Normalize before trying anything with it.
account = RegistrationProfile.objects.activate_user(activation_key)
if extra_context is None:
extra_context = {}
context = RequestContext(request)
for key, value in extra_context.items():
context[key] = callable(value) and value() or value
return render_to_response(template_name,
{ 'account': account,
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, 'settings':settings},
context_instance=context)
def register(request, success_url=None,
form_class=RegistrationForm,
template_name='registration/registration_form.html',
extra_context=None):
"""
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 have a method ``save`` which will create and return
the new ``User``.
By default, use the template
``registration/registration_form.html``; to change this, pass the
name of a template as the keyword argument ``template_name``.
**Required arguments**
None.
**Optional arguments**
``form_class``
The form class to use for registration.
``extra_context``
A dictionary of variables to add to the template context. Any
callable object in this dictionary will be called to produce
the end result which appears in the context.
``success_url``
The URL to redirect to on successful registration.
``template_name``
A custom template to use.
**Context:**
``form``
The registration form.
Any extra variables supplied in the ``extra_context`` argument
(see above).
**Template:**
registration/registration_form.html or ``template_name`` keyword
argument.
"""
if request.method == 'POST':
form = form_class(data=request.POST, files=request.FILES)
if form.is_valid():
new_user = 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
# imports this file.
return HttpResponseRedirect(success_url or reverse('registration_complete'))
else:
form = form_class()
if extra_context is None:
extra_context = {}
context = RequestContext(request)
for key, value in extra_context.items():
context[key] = callable(value) and value() or value
return render_to_response(template_name,
{ 'form': form,'settings':settings },
context_instance=context)

View File

@ -46,6 +46,10 @@ TEMPLATE_LOADERS = (
# 'django.template.loaders.eggs.load_template_source',
)
TEMPLATE_CONTEXT_PROCESSORS = ( "django.core.context_processors.auth", "troggle.context.settingsContext")
LOGIN_REDIRECT_URL = '/'
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@ -56,6 +60,10 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = 'troggle.urls'
ACCOUNT_ACTIVATION_DAYS=3
AUTH_PROFILE_MODULE = 'expo.person'
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
@ -63,5 +71,7 @@ INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.redirects',
'troggle.registration',
'troggle.profiles',
'troggle.expo'
)

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="{{ settings.MEDIA_URL }}css/main2.css" />
<link rel="stylesheet" type="text/css" href="{{ settings.MEDIA_URL }}css/main3.css" />
<title>{% block title %}THE TITLE{% endblock %}</title>
@ -11,21 +11,34 @@
</head>
<body>
<a href="/">
<div style="float:none">
<div id="expoHeader" style="background:#222"> <img src="{{ settings.MEDIA_URL }}loserBanner.jpg" style="position:relative;width:inherit;height:inherit;"/>
<div>
<div id="expoHeader"> <img id="frontPageBanner" src="{{ settings.MEDIA_URL }}loserBanner.jpg"/>
<div id="expoHeaderText">
<h1>CUCC Expeditions to Austria: 1976 - 2008</h1>
<h1>CUCC Expeditions to Austria: 1976 - </h1>
<div id="expoFinalDate">
<h1>2009</h1>
</div>
</div>
</div>
<hr/>
<div id="editLink" style="right:0px; top:0px; text-align: right; position: absolute; top:0; right:0; z-index:1; background:#999">
<div id="editLink">
{% block loginInfo %}
{% if user %}
You are logged in as {{ user.username }}.
| <a href="{{ settings.URL_ROOT }}/accounts/logout">Log out</a>
{% else %}
<a href="{{ settings.URL_ROOT }}/accounts/register">Sign up</a>
| <a href="{{ settings.URL_ROOT }}/accounts/login">Log in</a>
{% endif %}
{% endblock%}
| <a href="{{ settings.URL_ROOT }}">Home </a>
{% block editLink %}
not editable
{% endblock %}
</div>
</div>
</a>
{% block nav %}

View File

@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block content %}
{{ form }}
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block content %}
<form method="post">
{{ form }}
<input type="submit" />
</form>
{% if form.errors %}
<p class="errornote">Please correct the errors below</p>
{% endif %}
{% endblock %}

View File

View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}
registration_form.html | {{ block.super }}
{% endblock %}
{% block header %}
<h1>activate.html</h1>
{% endblock %}
{% block content %}
You are now activated.
{% endblock %}

View File

@ -0,0 +1,3 @@
Activate your account in {{ expiration_days }} days...
{{ URL_ROOT }}{% url registration_activate activation_key %}

View File

@ -0,0 +1 @@
[CUCC Expo] Activation email

View File

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">
<table>
<tr><td>{{ form.username.label_tag }}</td><td>{{ form.username }}</td></tr>
<tr><td>{{ form.password.label_tag }}</td><td>{{ form.password }}</td></tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{% endblock %}

View File

@ -0,0 +1,4 @@
{% extends "base.html" %}
{% block content %}
You have been logged out.
{% endblock %}

View File

@ -0,0 +1,6 @@
{% extends “base.html” %}
{% block body %}
Hello {{ account }}!
Check your email to confirm the activation. There are {{ expiration_days }} days left to do it.
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}
registration_complete.html | {{ block.super }}
{% endblock %}
{% block header %}
<h1>registration_complete.html</h1>
{% endblock %}
{% block content %}
Thank you for signing up. An email with the activation code has been sent to your inbox.
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "base.html" %}
{% block title %}
registration_form.html | {{ block.super }}
{% endblock %}
{% block header %}
<h1>registration_form.html</h1>
{% endblock %}
{% block content %}
<form action="{% url registration_register %}" method="POST">
<table>
<tr>
<td align="right" valign="top">Username:</td>
<td>
{{ form.username }} <br/>
{% for error in form.username.errors %}
<span style="color:red">{{ error }}</span>
{% endfor %}
</td>
</tr>
<tr>
<td align="right" valign="top">Email:</td>
<td>
{{ form.email }} <br/>
{% for error in form.email.errors %}
<span style="color:red">{{ error }}</span>
{% endfor %}
</td>
</tr>
<tr>
<td align="right" valign="top">Password:</td>
<td>
{{ form.password1 }} <br/>
{% for error in form.password1.errors %}
<span style="color:red">{{ error }}</span>
{% endfor %}
</td>
</tr>
<tr>
<td align="right" valign="top">Password (again):</td>
<td>
{{ form.password2 }} <br/>
{% for error in form.password2.errors %}
<span style="color:red">{{ error }}</span>
{% endfor %}
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="Register" /></td>
</tr>
</table>
</form>
{% endblock %}

View File

@ -45,6 +45,11 @@ urlpatterns = patterns('',
(r'^admin/doc/?', include('django.contrib.admindocs.urls')),
(r'^admin/(.*)', admin.site.root),
(r'^accounts/', include('registration.urls')),
(r'^profiles/', include('profiles.urls')),
(r'^personform/(.*)$', personForm),
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),