diff --git a/context.py b/context.py new file mode 100644 index 0000000..f0fd208 --- /dev/null +++ b/context.py @@ -0,0 +1,4 @@ +import troggle.settings as settings + +def settingsContext(request): + return { 'settings':settings } \ No newline at end of file diff --git a/expo/admin.py b/expo/admin.py index 52138af..d5a7ddd 100644 --- a/expo/admin.py +++ b/expo/admin.py @@ -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') diff --git a/expo/forms.py b/expo/forms.py index c8e2842..91f39f0 100644 --- a/expo/forms.py +++ b/expo/forms.py @@ -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 \ No newline at end of file + model = Cave + +class PersonForm(ModelForm): + class Meta: + model = Person \ No newline at end of file diff --git a/expo/models.py b/expo/models.py index 2b3919c..98b5d2b 100644 --- a/expo/models.py +++ b/expo/models.py @@ -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') - \ No newline at end of file + diff --git a/expo/views_logbooks.py b/expo/views_logbooks.py index 72c44e8..513701b 100644 --- a/expo/views_logbooks.py +++ b/expo/views_logbooks.py @@ -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}) \ No newline at end of file diff --git a/media/css/main2.css b/media/css/main2.css index c7c7276..fee993c 100644 --- a/media/css/main2.css +++ b/media/css/main2.css @@ -62,6 +62,8 @@ div#footer margin-right:auto; } +#frontPageBanner{ position:relative; width:inherit; height:inherit; } + div.logbookentry { text-align:left; diff --git a/profiles/__init__.py b/profiles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/profiles/urls.py b/profiles/urls.py new file mode 100644 index 0000000..05ff9e4 --- /dev/null +++ b/profiles/urls.py @@ -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\w+)/$', + views.profile_detail, + name='profiles_profile_detail'), + url(r'^$', + views.profile_list, + name='profiles_profile_list'), + ) diff --git a/profiles/utils.py b/profiles/utils.py new file mode 100644 index 0000000..faacfcb --- /dev/null +++ b/profiles/utils.py @@ -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 diff --git a/profiles/views.py b/profiles/views.py new file mode 100644 index 0000000..c119165 --- /dev/null +++ b/profiles/views.py @@ -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) diff --git a/registration/__init__.py b/registration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/registration/admin.py b/registration/admin.py new file mode 100644 index 0000000..3f36c18 --- /dev/null +++ b/registration/admin.py @@ -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) diff --git a/registration/forms.py b/registration/forms.py new file mode 100644 index 0000000..f2298ac --- /dev/null +++ b/registration/forms.py @@ -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'] diff --git a/registration/locale/ar/LC_MESSAGES/django.mo b/registration/locale/ar/LC_MESSAGES/django.mo new file mode 100644 index 0000000..07bc79f Binary files /dev/null and b/registration/locale/ar/LC_MESSAGES/django.mo differ diff --git a/registration/locale/ar/LC_MESSAGES/django.po b/registration/locale/ar/LC_MESSAGES/django.po new file mode 100644 index 0000000..dd61869 --- /dev/null +++ b/registration/locale/ar/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "ملفات التسجيل الشخصية" diff --git a/registration/locale/bg/LC_MESSAGES/django.mo b/registration/locale/bg/LC_MESSAGES/django.mo new file mode 100644 index 0000000..be9adf4 Binary files /dev/null and b/registration/locale/bg/LC_MESSAGES/django.mo differ diff --git a/registration/locale/bg/LC_MESSAGES/django.po b/registration/locale/bg/LC_MESSAGES/django.po new file mode 100644 index 0000000..5089ec1 --- /dev/null +++ b/registration/locale/bg/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "регистрационни профили" + diff --git a/registration/locale/de/LC_MESSAGES/django.mo b/registration/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000..b9bc1fa Binary files /dev/null and b/registration/locale/de/LC_MESSAGES/django.mo differ diff --git a/registration/locale/de/LC_MESSAGES/django.po b/registration/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..96e00ee --- /dev/null +++ b/registration/locale/de/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: Deutsch \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" diff --git a/registration/locale/el/LC_MESSAGES/django.mo b/registration/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000..acc9726 Binary files /dev/null and b/registration/locale/el/LC_MESSAGES/django.mo differ diff --git a/registration/locale/el/LC_MESSAGES/django.po b/registration/locale/el/LC_MESSAGES/django.po new file mode 100644 index 0000000..cd38eb1 --- /dev/null +++ b/registration/locale/el/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "προφίλ εγγραφών" diff --git a/registration/locale/en/LC_MESSAGES/django.mo b/registration/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000..4728fe0 Binary files /dev/null and b/registration/locale/en/LC_MESSAGES/django.mo differ diff --git a/registration/locale/en/LC_MESSAGES/django.po b/registration/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..37bc9e2 --- /dev/null +++ b/registration/locale/en/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "" diff --git a/registration/locale/es/LC_MESSAGES/django.mo b/registration/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000..3872adf Binary files /dev/null and b/registration/locale/es/LC_MESSAGES/django.mo differ diff --git a/registration/locale/es/LC_MESSAGES/django.po b/registration/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..ba0384f --- /dev/null +++ b/registration/locale/es/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: Español \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" diff --git a/registration/locale/es_AR/LC_MESSAGES/django.mo b/registration/locale/es_AR/LC_MESSAGES/django.mo new file mode 100644 index 0000000..ce8b4e5 Binary files /dev/null and b/registration/locale/es_AR/LC_MESSAGES/django.mo differ diff --git a/registration/locale/es_AR/LC_MESSAGES/django.po b/registration/locale/es_AR/LC_MESSAGES/django.po new file mode 100644 index 0000000..fb746b5 --- /dev/null +++ b/registration/locale/es_AR/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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" diff --git a/registration/locale/fr/LC_MESSAGES/django.mo b/registration/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000..f8911c7 Binary files /dev/null and b/registration/locale/fr/LC_MESSAGES/django.mo differ diff --git a/registration/locale/fr/LC_MESSAGES/django.po b/registration/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..34b520b --- /dev/null +++ b/registration/locale/fr/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: Français \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" diff --git a/registration/locale/he/LC_MESSAGES/django.mo b/registration/locale/he/LC_MESSAGES/django.mo new file mode 100644 index 0000000..be93650 Binary files /dev/null and b/registration/locale/he/LC_MESSAGES/django.mo differ diff --git a/registration/locale/he/LC_MESSAGES/django.po b/registration/locale/he/LC_MESSAGES/django.po new file mode 100644 index 0000000..5567e08 --- /dev/null +++ b/registration/locale/he/LC_MESSAGES/django.po @@ -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 \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 "פרופילי רישום" + diff --git a/registration/locale/it/LC_MESSAGES/django.mo b/registration/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000..83ec9dd Binary files /dev/null and b/registration/locale/it/LC_MESSAGES/django.mo differ diff --git a/registration/locale/it/LC_MESSAGES/django.po b/registration/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000..00129b0 --- /dev/null +++ b/registration/locale/it/LC_MESSAGES/django.po @@ -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 , 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 \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" + diff --git a/registration/locale/ja/LC_MESSAGES/django.mo b/registration/locale/ja/LC_MESSAGES/django.mo new file mode 100644 index 0000000..e0332b0 Binary files /dev/null and b/registration/locale/ja/LC_MESSAGES/django.mo differ diff --git a/registration/locale/ja/LC_MESSAGES/django.po b/registration/locale/ja/LC_MESSAGES/django.po new file mode 100644 index 0000000..afaaf94 --- /dev/null +++ b/registration/locale/ja/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: Japanese \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 "登録プロファイル" + diff --git a/registration/locale/nl/LC_MESSAGES/django.mo b/registration/locale/nl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..9e84eb3 Binary files /dev/null and b/registration/locale/nl/LC_MESSAGES/django.mo differ diff --git a/registration/locale/nl/LC_MESSAGES/django.po b/registration/locale/nl/LC_MESSAGES/django.po new file mode 100644 index 0000000..03cb2e5 --- /dev/null +++ b/registration/locale/nl/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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" diff --git a/registration/locale/pl/LC_MESSAGES/django.mo b/registration/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..1f2a228 Binary files /dev/null and b/registration/locale/pl/LC_MESSAGES/django.mo differ diff --git a/registration/locale/pl/LC_MESSAGES/django.po b/registration/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..498fd5b --- /dev/null +++ b/registration/locale/pl/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: Polish \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" diff --git a/registration/locale/pt_BR/LC_MESSAGES/django.mo b/registration/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000..e81b620 Binary files /dev/null and b/registration/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/registration/locale/pt_BR/LC_MESSAGES/django.po b/registration/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..9e8addb --- /dev/null +++ b/registration/locale/pt_BR/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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" diff --git a/registration/locale/ru/LC_MESSAGES/django.mo b/registration/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000..b6eb3f1 Binary files /dev/null and b/registration/locale/ru/LC_MESSAGES/django.mo differ diff --git a/registration/locale/ru/LC_MESSAGES/django.po b/registration/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..8b0c309 --- /dev/null +++ b/registration/locale/ru/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "профили регистрации" diff --git a/registration/locale/sr/LC_MESSAGES/django.mo b/registration/locale/sr/LC_MESSAGES/django.mo new file mode 100644 index 0000000..1699326 Binary files /dev/null and b/registration/locale/sr/LC_MESSAGES/django.mo differ diff --git a/registration/locale/sr/LC_MESSAGES/django.po b/registration/locale/sr/LC_MESSAGES/django.po new file mode 100644 index 0000000..4fa699c --- /dev/null +++ b/registration/locale/sr/LC_MESSAGES/django.po @@ -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 , 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 \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" + diff --git a/registration/locale/sv/LC_MESSAGES/django.mo b/registration/locale/sv/LC_MESSAGES/django.mo new file mode 100644 index 0000000..50eca67 Binary files /dev/null and b/registration/locale/sv/LC_MESSAGES/django.mo differ diff --git a/registration/locale/sv/LC_MESSAGES/django.po b/registration/locale/sv/LC_MESSAGES/django.po new file mode 100644 index 0000000..dec76e2 --- /dev/null +++ b/registration/locale/sv/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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" diff --git a/registration/locale/zh_CN/LC_MESSAGES/django.mo b/registration/locale/zh_CN/LC_MESSAGES/django.mo new file mode 100644 index 0000000..ece5cc9 Binary files /dev/null and b/registration/locale/zh_CN/LC_MESSAGES/django.mo differ diff --git a/registration/locale/zh_CN/LC_MESSAGES/django.po b/registration/locale/zh_CN/LC_MESSAGES/django.po new file mode 100644 index 0000000..7c609c3 --- /dev/null +++ b/registration/locale/zh_CN/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "注册信息" + diff --git a/registration/locale/zh_TW/LC_MESSAGES/django.mo b/registration/locale/zh_TW/LC_MESSAGES/django.mo new file mode 100644 index 0000000..24a3534 Binary files /dev/null and b/registration/locale/zh_TW/LC_MESSAGES/django.mo differ diff --git a/registration/locale/zh_TW/LC_MESSAGES/django.po b/registration/locale/zh_TW/LC_MESSAGES/django.po new file mode 100644 index 0000000..7cc090d --- /dev/null +++ b/registration/locale/zh_TW/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "注冊信息" + diff --git a/registration/management/__init__.py b/registration/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/registration/management/commands/__init__.py b/registration/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/registration/management/commands/cleanupregistration.py b/registration/management/commands/cleanupregistration.py new file mode 100644 index 0000000..abec5ae --- /dev/null +++ b/registration/management/commands/cleanupregistration.py @@ -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() diff --git a/registration/models.py b/registration/models.py new file mode 100644 index 0000000..4a211c1 --- /dev/null +++ b/registration/models.py @@ -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 diff --git a/registration/signals.py b/registration/signals.py new file mode 100644 index 0000000..2a6eed9 --- /dev/null +++ b/registration/signals.py @@ -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"]) diff --git a/registration/tests.py b/registration/tests.py new file mode 100644 index 0000000..0f26553 --- /dev/null +++ b/registration/tests.py @@ -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']) diff --git a/registration/urls.py b/registration/urls.py new file mode 100644 index 0000000..25cf2b0 --- /dev/null +++ b/registration/urls.py @@ -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\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[0-9A-Za-z]+)-(?P.+)/$', + 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'), + ) diff --git a/registration/views.py b/registration/views.py new file mode 100644 index 0000000..aac17c5 --- /dev/null +++ b/registration/views.py @@ -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) diff --git a/settings.py b/settings.py index 353809d..9ad299d 100644 --- a/settings.py +++ b/settings.py @@ -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' ) diff --git a/templates/base.html b/templates/base.html index b1fc47f..c88ac19 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,7 +2,7 @@ - + {% block title %}THE TITLE{% endblock %} @@ -11,21 +11,34 @@ - -
-
+ +
+
-

CUCC Expeditions to Austria: 1976 - 2008

+

CUCC Expeditions to Austria: 1976 -

+
+

2009

+

-
- + {% block nav %} diff --git a/templates/personForm.html b/templates/personForm.html new file mode 100644 index 0000000..84ee7b7 --- /dev/null +++ b/templates/personForm.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% block content %} + +{{ form }} + +{% endblock %} \ No newline at end of file diff --git a/templates/profiles/create_profile.html b/templates/profiles/create_profile.html new file mode 100644 index 0000000..2eed3e4 --- /dev/null +++ b/templates/profiles/create_profile.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block content %} + +
+{{ form }} + +
+ +{% if form.errors %} +

Please correct the errors below

+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/templates/profiles/profile_list.html b/templates/profiles/profile_list.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/registration/activate.html b/templates/registration/activate.html new file mode 100644 index 0000000..f87d519 --- /dev/null +++ b/templates/registration/activate.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +registration_form.html | {{ block.super }} +{% endblock %} + +{% block header %} +

activate.html

+{% endblock %} + +{% block content %} +You are now activated. +{% endblock %} \ No newline at end of file diff --git a/templates/registration/activation_email.txt b/templates/registration/activation_email.txt new file mode 100644 index 0000000..3047d8f --- /dev/null +++ b/templates/registration/activation_email.txt @@ -0,0 +1,3 @@ +Activate your account in {{ expiration_days }} days... +{{ URL_ROOT }}{% url registration_activate activation_key %} + diff --git a/templates/registration/activation_email_subject.txt b/templates/registration/activation_email_subject.txt new file mode 100644 index 0000000..78ae905 --- /dev/null +++ b/templates/registration/activation_email_subject.txt @@ -0,0 +1 @@ +[CUCC Expo] Activation email \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html new file mode 100644 index 0000000..04b5074 --- /dev/null +++ b/templates/registration/login.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} + +{% block content %} + +{% if form.errors %} +

Your username and password didn't match. Please try again.

+{% endif %} + +
+ + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+ +{% endblock %} diff --git a/templates/registration/logout.html b/templates/registration/logout.html new file mode 100644 index 0000000..9e40c20 --- /dev/null +++ b/templates/registration/logout.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} +{% block content %} + You have been logged out. +{% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_activate.html b/templates/registration/registration_activate.html new file mode 100644 index 0000000..cbd540e --- /dev/null +++ b/templates/registration/registration_activate.html @@ -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 %} \ No newline at end of file diff --git a/templates/registration/registration_complete.html b/templates/registration/registration_complete.html new file mode 100644 index 0000000..552fa04 --- /dev/null +++ b/templates/registration/registration_complete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +registration_complete.html | {{ block.super }} +{% endblock %} + +{% block header %} +

registration_complete.html

+{% endblock %} + +{% block content %} +Thank you for signing up. An email with the activation code has been sent to your inbox. +{% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html new file mode 100644 index 0000000..17bebf2 --- /dev/null +++ b/templates/registration/registration_form.html @@ -0,0 +1,56 @@ +{% extends "base.html" %} + +{% block title %} +registration_form.html | {{ block.super }} +{% endblock %} + +{% block header %} +

registration_form.html

+{% endblock %} + +{% block content %} +
+ + + + + + + + + + + + + + + + + + + + + +
Username: + {{ form.username }}
+ {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
Email: + {{ form.email }}
+ {% for error in form.email.errors %} + {{ error }} + {% endfor %} +
Password: + {{ form.password1 }}
+ {% for error in form.password1.errors %} + {{ error }} + {% endfor %} +
Password (again): + {{ form.password2 }}
+ {% for error in form.password2.errors %} + {{ error }} + {% endfor %} +
 
+
+{% endblock %} \ No newline at end of file diff --git a/urls.py b/urls.py index 36c502e..8c2810c 100644 --- a/urls.py +++ b/urls.py @@ -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.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),