From 66fea3caebd87223d19e8cf5aecd06effd140f86 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 13 Feb 2011 00:02:05 -0500 Subject: [PATCH] django reg --- lib/registration | 1 + src/django-registration/.hg_archival.txt | 5 + src/django-registration/.hgignore | 6 + src/django-registration/.hgtags | 27 + src/django-registration/AUTHORS | 29 ++ src/django-registration/CHANGELOG | 232 +++++++++ src/django-registration/INSTALL | 28 ++ src/django-registration/LICENSE | 28 ++ src/django-registration/MANIFEST.in | 8 + src/django-registration/README | 13 + src/django-registration/docs/Makefile | 88 ++++ src/django-registration/docs/backend-api.rst | 230 +++++++++ src/django-registration/docs/conf.py | 194 +++++++ .../docs/default-backend.rst | 239 +++++++++ src/django-registration/docs/faq.rst | 195 +++++++ src/django-registration/docs/forms.rst | 100 ++++ src/django-registration/docs/index.rst | 55 ++ src/django-registration/docs/make.bat | 112 +++++ src/django-registration/docs/quickstart.rst | 294 +++++++++++ .../docs/release-notes.rst | 69 +++ src/django-registration/docs/signals.rst | 56 +++ .../docs/simple-backend.rst | 61 +++ src/django-registration/docs/upgrade.rst | 120 +++++ src/django-registration/docs/views.rst | 122 +++++ .../registration/__init__.py | 14 + src/django-registration/registration/admin.py | 46 ++ .../registration/auth_urls.py | 58 +++ .../registration/backends/__init__.py | 32 ++ .../registration/backends/default/__init__.py | 139 +++++ .../registration/backends/default/urls.py | 54 ++ .../registration/backends/simple/__init__.py | 64 +++ .../registration/backends/simple/urls.py | 38 ++ src/django-registration/registration/forms.py | 123 +++++ .../locale/ar/LC_MESSAGES/django.mo | Bin 0 -> 2135 bytes .../locale/ar/LC_MESSAGES/django.po | 81 +++ .../locale/bg/LC_MESSAGES/django.mo | Bin 0 -> 2302 bytes .../locale/bg/LC_MESSAGES/django.po | 78 +++ .../locale/da/LC_MESSAGES/django.mo | Bin 0 -> 1803 bytes .../locale/da/LC_MESSAGES/django.po | 92 ++++ .../locale/de/LC_MESSAGES/django.mo | Bin 0 -> 1999 bytes .../locale/de/LC_MESSAGES/django.po | 93 ++++ .../locale/el/LC_MESSAGES/django.mo | Bin 0 -> 2424 bytes .../locale/el/LC_MESSAGES/django.po | 84 ++++ .../locale/en/LC_MESSAGES/django.mo | Bin 0 -> 367 bytes .../locale/en/LC_MESSAGES/django.po | 89 ++++ .../locale/es/LC_MESSAGES/django.mo | Bin 0 -> 1909 bytes .../locale/es/LC_MESSAGES/django.po | 85 ++++ .../locale/es_AR/LC_MESSAGES/django.mo | Bin 0 -> 1849 bytes .../locale/es_AR/LC_MESSAGES/django.po | 83 +++ .../locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 1883 bytes .../locale/fr/LC_MESSAGES/django.po | 81 +++ .../locale/he/LC_MESSAGES/django.mo | Bin 0 -> 1896 bytes .../locale/he/LC_MESSAGES/django.po | 86 ++++ .../locale/is/LC_MESSAGES/django.mo | Bin 0 -> 1476 bytes .../locale/is/LC_MESSAGES/django.po | 74 +++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 1864 bytes .../locale/it/LC_MESSAGES/django.po | 82 +++ .../locale/ja/LC_MESSAGES/django.mo | Bin 0 -> 2035 bytes .../locale/ja/LC_MESSAGES/django.po | 78 +++ .../locale/ko/LC_MESSAGES/django.mo | Bin 0 -> 1947 bytes .../locale/ko/LC_MESSAGES/django.po | 89 ++++ .../locale/nl/LC_MESSAGES/django.mo | Bin 0 -> 1898 bytes .../locale/nl/LC_MESSAGES/django.po | 77 +++ .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1769 bytes .../locale/pl/LC_MESSAGES/django.po | 84 ++++ .../locale/pt_BR/LC_MESSAGES/django.mo | Bin 0 -> 1796 bytes .../locale/pt_BR/LC_MESSAGES/django.po | 81 +++ .../locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 2470 bytes .../locale/ru/LC_MESSAGES/django.po | 92 ++++ .../locale/sl/LC_MESSAGES/django.mo | Bin 0 -> 1903 bytes .../locale/sl/LC_MESSAGES/django.po | 87 ++++ .../locale/sr/LC_MESSAGES/django.mo | Bin 0 -> 1966 bytes .../locale/sr/LC_MESSAGES/django.po | 80 +++ .../locale/sv/LC_MESSAGES/django.mo | Bin 0 -> 1687 bytes .../locale/sv/LC_MESSAGES/django.po | 81 +++ .../locale/zh_CN/LC_MESSAGES/django.mo | Bin 0 -> 1669 bytes .../locale/zh_CN/LC_MESSAGES/django.po | 77 +++ .../locale/zh_TW/LC_MESSAGES/django.mo | Bin 0 -> 1669 bytes .../locale/zh_TW/LC_MESSAGES/django.po | 77 +++ .../registration/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../commands/cleanupregistration.py | 19 + .../registration/models.py | 257 ++++++++++ .../registration/signals.py | 8 + .../registration/tests/__init__.py | 45 ++ .../registration/tests/backends.py | 476 ++++++++++++++++++ .../registration/tests/forms.py | 119 +++++ .../registration/tests/models.py | 225 +++++++++ .../registration/tests/urls.py | 82 +++ .../registration/tests/views.py | 246 +++++++++ src/django-registration/registration/urls.py | 15 + src/django-registration/registration/views.py | 204 ++++++++ src/django-registration/setup.py | 48 ++ 93 files changed, 6535 insertions(+) create mode 120000 lib/registration create mode 100644 src/django-registration/.hg_archival.txt create mode 100644 src/django-registration/.hgignore create mode 100644 src/django-registration/.hgtags create mode 100644 src/django-registration/AUTHORS create mode 100644 src/django-registration/CHANGELOG create mode 100644 src/django-registration/INSTALL create mode 100644 src/django-registration/LICENSE create mode 100644 src/django-registration/MANIFEST.in create mode 100644 src/django-registration/README create mode 100644 src/django-registration/docs/Makefile create mode 100644 src/django-registration/docs/backend-api.rst create mode 100644 src/django-registration/docs/conf.py create mode 100644 src/django-registration/docs/default-backend.rst create mode 100644 src/django-registration/docs/faq.rst create mode 100644 src/django-registration/docs/forms.rst create mode 100644 src/django-registration/docs/index.rst create mode 100644 src/django-registration/docs/make.bat create mode 100644 src/django-registration/docs/quickstart.rst create mode 100644 src/django-registration/docs/release-notes.rst create mode 100644 src/django-registration/docs/signals.rst create mode 100644 src/django-registration/docs/simple-backend.rst create mode 100644 src/django-registration/docs/upgrade.rst create mode 100644 src/django-registration/docs/views.rst create mode 100644 src/django-registration/registration/__init__.py create mode 100644 src/django-registration/registration/admin.py create mode 100644 src/django-registration/registration/auth_urls.py create mode 100644 src/django-registration/registration/backends/__init__.py create mode 100644 src/django-registration/registration/backends/default/__init__.py create mode 100644 src/django-registration/registration/backends/default/urls.py create mode 100644 src/django-registration/registration/backends/simple/__init__.py create mode 100644 src/django-registration/registration/backends/simple/urls.py create mode 100644 src/django-registration/registration/forms.py create mode 100644 src/django-registration/registration/locale/ar/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/ar/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/bg/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/bg/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/da/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/da/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/de/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/de/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/el/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/el/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/en/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/en/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/es/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/es/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/fr/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/fr/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/he/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/he/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/is/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/is/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/it/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/it/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/ja/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/ja/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/ko/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/ko/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/nl/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/nl/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/pl/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/pl/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/ru/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/ru/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/sl/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/sl/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/sr/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/sr/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/sv/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/sv/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/zh_CN/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/zh_CN/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.mo create mode 100644 src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.po create mode 100644 src/django-registration/registration/management/__init__.py create mode 100644 src/django-registration/registration/management/commands/__init__.py create mode 100644 src/django-registration/registration/management/commands/cleanupregistration.py create mode 100644 src/django-registration/registration/models.py create mode 100644 src/django-registration/registration/signals.py create mode 100644 src/django-registration/registration/tests/__init__.py create mode 100644 src/django-registration/registration/tests/backends.py create mode 100644 src/django-registration/registration/tests/forms.py create mode 100644 src/django-registration/registration/tests/models.py create mode 100644 src/django-registration/registration/tests/urls.py create mode 100644 src/django-registration/registration/tests/views.py create mode 100644 src/django-registration/registration/urls.py create mode 100644 src/django-registration/registration/views.py create mode 100644 src/django-registration/setup.py diff --git a/lib/registration b/lib/registration new file mode 120000 index 0000000..5556139 --- /dev/null +++ b/lib/registration @@ -0,0 +1 @@ +../src/django-registration/registration/ \ No newline at end of file diff --git a/src/django-registration/.hg_archival.txt b/src/django-registration/.hg_archival.txt new file mode 100644 index 0000000..78d36fb --- /dev/null +++ b/src/django-registration/.hg_archival.txt @@ -0,0 +1,5 @@ +repo: 54211b4bb6c6c1c4698b76a63a366f05d7636e78 +node: d36a38202ee3d09d342b000f4ff634296f90df49 +branch: default +latesttag: v0.7 +latesttagdistance: 186 diff --git a/src/django-registration/.hgignore b/src/django-registration/.hgignore new file mode 100644 index 0000000..b792257 --- /dev/null +++ b/src/django-registration/.hgignore @@ -0,0 +1,6 @@ +syntax: glob +*.pyc +dist +MANIFEST +_build +_static \ No newline at end of file diff --git a/src/django-registration/.hgtags b/src/django-registration/.hgtags new file mode 100644 index 0000000..7236b23 --- /dev/null +++ b/src/django-registration/.hgtags @@ -0,0 +1,27 @@ +195dbb4707d01307bea99ca51fd439f37cec098b v0.1 +de1e97d7b5cb2b67b29f0e139bbda9bb1c47b31f v0.2 +673c8f0b5faf95aa0bc8fd00ddd1f36dae05669e v0.3 +a8aaa47fbf44f33e555c46d7bf55e216dc247f96 v0.3p1 +01c5ad085a0a8b834a8ba4ca3813536f8d480848 v0.3p2 +1987d9bf18ffa702c31c9d769afa1eeb36626e7f v0.3p4 +fc2020d59b3ab1ac3c9d3a59cadd71e61bafc8f7 v0.3p5 +63229f323b2e5b5eac198c5e717926250452e32f v0.4 +9f0ea4d78035539137a91ca81368c63fba51b1ca v0.4p1 +0000000000000000000000000000000000000000 v0.1 +0000000000000000000000000000000000000000 v0.2 +0000000000000000000000000000000000000000 v0.3 +0000000000000000000000000000000000000000 v0.3p1 +0000000000000000000000000000000000000000 v0.3p2 +0000000000000000000000000000000000000000 v0.3p4 +0000000000000000000000000000000000000000 v0.3p5 +0000000000000000000000000000000000000000 v0.4 +0000000000000000000000000000000000000000 v0.4p1 +3fcf78590fc7a013dec8e112ea586ab22701cb9c v0.1 +0000000000000000000000000000000000000000 v0.1 +d28e5a770ff890587181024a62f4ed125f26fb1a v0.1 +e5110bb8d48a07b4cfa6ec77cf76ca8ab2fd99e9 v0.2 +f41e8a239016661f7489e2e9929eb006b8a33d51 v0.3 +4d2a725d8c188edc18705462167f5fbf3bfc02ea v0.4 +dc2bf754aa9462c1d9a1dd70503e14ff4e0e0b9c v0.5 +e263c551ef7be3d99813effdc7a4f22041539f83 v0.6 +d073602dc103edfae55419b043af1f4b6a58e1e5 v0.7 diff --git a/src/django-registration/AUTHORS b/src/django-registration/AUTHORS new file mode 100644 index 0000000..3770765 --- /dev/null +++ b/src/django-registration/AUTHORS @@ -0,0 +1,29 @@ +The primary author of django-registration is James Bennett +, who may be found online at +. + + +Others who have contributed to the application: + +* Samuel Adam (French translation) +* Jannis Leidel (German translation) +* Rapahel Hertzog (helpful suggestions on packaging and distribution) +* Panos Laganakos (Greek translation) +* Ilya Filippov and Andy Mikhailenko (Russian translation) +* Jarek Zgoda (Polish translation) +* Meir Kriheli (Hebrew translation) +* Italo Maia (Brazilian Portuguese translation) +* Shinya Okano (Japanese translation) +* A. Al-Ibrahim (Arabic translation) +* Ernesto Rico Schmidt (Spanish translation) +* Vladislav Mitov (Bulgarian translation) +* Leonardo Manuel Rocha (Argentinean Spanish translation) +* Emil Stenström (Swedish translation) +* Liang Feng (Chinese translations) +* Nebojsa Djordjevic (Serbian translation) +* Nicola Larosa (Italian translation) +* Joost Cassee (Dutch translation) +* Björn Kristinsson (Icelandic translation) +* Rune Bromer (Danish translation) +* Domen Kožar (Slovenian translation) +* Young Gyu Park (Korean translation) diff --git a/src/django-registration/CHANGELOG b/src/django-registration/CHANGELOG new file mode 100644 index 0000000..ced4cad --- /dev/null +++ b/src/django-registration/CHANGELOG @@ -0,0 +1,232 @@ +============================= +django-registration changelog +============================= + + +Version 0.7, 6 November 2008: +----------------------------- + +* Project hosting moved from Google Code to Bitbucket, and from a + Subversion repository to Mercurial. + +* Added test suite. + +* Full Django 1.0 compatibility. + +* Registration and activation views now accept an ``extra_context`` + argument, identical to the way that argument works in Django's + generic views. + +* Added a custom management command for cleaning up expired + registrations; you can now run ``manage.py cleanupregistration`` to + handle this. + +* BACKWARDS-INCOMPATIBLE CHANGE: The "username" field in + ``RegistrationForm`` is now a ``RegexField``. + +* BACKWARDS-INCOMPATIBLE CHANGE: Removed the standalone script for + deleting expired user registrations; use the new management command + instead. + + +Version 0.6, 29 July 2008: +-------------------------- + +* Packaged from revision 166 in Subversion. + +* Fixed a multiple-objects exception in + ``RegistrationFormUniqueEmail`` when multiple users already have the + same email address. + +* Changed the ``success_url`` of the ``register()`` view to use + reverse URL resolution. + +* Added an ``extra_context`` argument to the ``register`` and + ``activate`` views, mimicking its functionality in Django's generic + views. + +* BACKWARDS-INCOMPATIBLE CHANGE: Switched the admin declaration to be + compliant with the newforms-admin refactor; the admin declaration + now lives in ``registration/admin.py``. + +* BACKWARDS-INCOMPATIBLE CHANGE: Switched form imports from using + ``django.newforms`` to using ``django.forms``; the old style now + raises a deprecation warning on Django trunk and on Django 1.0 + alpha. + + +Version 0.5, 4 June 2008: +------------------------- + +* Packaged from revision 155 in Subversion. + +* Added Serbian translation. + +* Added Italian translation. + +* Username/email uniqueness checks are now case-insensitive. This is + potentially backwards-incompatible if you relied on them being + case-sensitive, but I don't know of any reason why you'd be doing + that. + +* Included forms now use lazy translations. + +* The ``register`` view can now handle files submitted for use in form + processing. + +* Reactivation of a manually-deactivated account is now prevented by + changing the activation key, on successful activation, to a dummy + string which will fail on subsequent activation attempts. + + +Version 0.4p2, 10 Feburary 2008: +-------------------------------- + +* Added Brazilian Portuguese translation. + +* Added Japanese translation. + +* Added Hebrew translation. + +* Minor documentation fixes. + + +Version 0.4p1, 16 December 2007: +-------------------------------- + +* Packaged from revision 129 in Subversion. + +* Added Polish translation. + + +Version 0.4, 8 December 2007: +----------------------------- + +* Packaged from revision 122 in Subversion. + +* Added Greek translation. + +* Added Russian translation. + +* Changed ``maxlength`` to ``max_length`` now that Django issues a + deprecation warning for it. + +* BACKWARDS-INCOMPATIBLE CHANGE: Changed the password validation to be + on ``clean()`` instead of ``clean_password2()``. This means that + errors from this must be accessed via ``non_field_errors()``. + + +Version 0.3p5, 6 October 2007: +------------------------------ + +* Packaged from revision 112 in Subversion. + +* Added German translation. + +* Fixed a mismatch between the default ``RegistrationForm``'s maximum + length on email addresses and the actual maximum length on Django's + ``User`` model. + +* Fixed a situation where bad input for the ``password1`` field on + ``RegistrationForm`` could cause validation of ``password2`` to fail + with an exception. + + +Version 0.3p4, 4 October 2007: +------------------------------ + +* Packaged from revision 101 in Subversion. + +* BACKWARDS-INCOMPATIBLE CHANGE: In response to larger numbers of + complaints from people trying to use the example templates as-is, + the example templates have been removed. + + +Version 0.3p2, 23 September 2007: +--------------------------------- + +* Packaged from revision 100 in Subversion. + +* Fixed ``activate`` view to actually take the ``template_name`` + argument. + + +Version 0.3p1, 22 September 2007: +--------------------------------- + +* Packaged from revision 99 in Subversion. + +* Fixed a typo in docs/overview.txt. + +* Fixed a typo in bin/delete_expired_users.py. + +* Added French translation. + + +Version 0.3, 19 September 2007: +------------------------------- + +Packaged from revision 89 in Subversion; download at +http://django-registration.googlecode.com/files/registration-0.3.tar.gz + +* Changed ``register`` and ``activate`` views to accept + ``template_name`` keyword argument for selecting a custom template. + +* Changed ``register`` view to accept ``form_class`` keyword + argument specifying the form to use. + +* BACKWARDS-INCOMPATIBLE CHANGE: Changed + ``RegistrationManager.create_inactive_user`` to use a template for + the subject of the activation email. + +* BACKWARDS-INCOMPATIBLE CHANGE: Removed the ``tos`` field from + ``RegistrationForm``; if you were relying on it, switch to using + ``RegistrationFormTermsOfService`` instead. + +* BACKWARDS-INCOMPATIBLE CHANGE: The activation email template now + receives the current ``Site`` object as the context variable + ``site``, and the ``current_site`` variable, which only held the + domain, is no longer available. + +* Added script ``bin/delete_expired_users.py`` with instructions on + how to use it as a cron job to clean up expired/inactive accounts. + +* Marked strings for translation and added ``locale`` directory so + that translations can be added. + +* Updated to deal with merge of Django's Unicode branch into trunk; + now using Unicode-aware functions everywhere. + + +Version 0.2, 29 May 2007: +------------------------- + +Packaged from revision 76 in Subversion; download at +http://django-registration.googlecode.com/files/registration-0.2.tar.gz + +* Added ability to specify a callback in + ``RegistrationManager.create_inactive_user`` or in the ``register`` + view to enable creation of site-specific user profile. + +* Separated out the logic of creating the profile into a new method on + ``RegistrationManager``: ``create_profile``. + +* Added URLConf support for various useful views in + ``django.contrib.auth``. + +* BACKWARDS-INCOMPATIBLE CHANGE: removed the ``key_generated`` field + from ``RegistrationProfile``; activation key expiration is now + calculated based on the ``date_joined`` field in the ``User`` model. + Drop the ``key_generated`` column from your database when upgrading + from 0.1. + + +Version 0.1, 23 May 2007: +------------------------- + +Packaged from revision 56 in Subversion; download at +http://django-registration.googlecode.com/files/registration-0.1.tar.gz + +* First packaged version using distutils. + +* Added docs/ directory and overview. diff --git a/src/django-registration/INSTALL b/src/django-registration/INSTALL new file mode 100644 index 0000000..a63c1b9 --- /dev/null +++ b/src/django-registration/INSTALL @@ -0,0 +1,28 @@ +Thanks for downloading django-registration. + +To install it, run the following command inside this directory: + + python setup.py install + +If you have the Python ``easy_install`` utility available, you can +also type the following to download and install in one step:: + + easy_install -Z django-registration + +(the ``-Z`` flag is required to force ``easy_install`` to do a normal +source install rather than a zipped egg; django-registration cannot be +used from a zipped egg install) + +Or if you're using ``pip``:: + + pip install django-registration + +Or if you'd prefer you can simply place the included ``registration`` +directory somewhere on your Python path, or symlink to it from +somewhere on your Python path; this is useful if you're working from a +Mercurial checkout. + +Note that this application requires Python 2.3 or later, and a +functional installation of Django 1.` or newer. You can obtain Python +from http://www.python.org/ and Django from +http://www.djangoproject.com/. diff --git a/src/django-registration/LICENSE b/src/django-registration/LICENSE new file mode 100644 index 0000000..caa9073 --- /dev/null +++ b/src/django-registration/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2007-2010, James Bennett +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the author nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/django-registration/MANIFEST.in b/src/django-registration/MANIFEST.in new file mode 100644 index 0000000..2ee0377 --- /dev/null +++ b/src/django-registration/MANIFEST.in @@ -0,0 +1,8 @@ +include CHANGELOG +include INSTALL +include LICENSE +include MANIFEST.in +include README +include AUTHORS +recursive-include docs * +recursive-include registration/locale * diff --git a/src/django-registration/README b/src/django-registration/README new file mode 100644 index 0000000..bae160a --- /dev/null +++ b/src/django-registration/README @@ -0,0 +1,13 @@ +======================== +Django user registration +======================== + +This is a fairly simple user-registration application for Django_, +designed to make allowing user signups as painless as possible. It +requires a functional installation of Django 1.1 or newer, but has no +other dependencies. + +For installation instructions, see the file "INSTALL" in this +directory; for instructions on how to use this application, and on +what it provides, see the file "quickstart.rst" in the "docs/" +directory. \ No newline at end of file diff --git a/src/django-registration/docs/Makefile b/src/django-registration/docs/Makefile new file mode 100644 index 0000000..c84c16a --- /dev/null +++ b/src/django-registration/docs/Makefile @@ -0,0 +1,88 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf _build/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html + @echo + @echo "Build finished. The HTML pages are in _build/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml + @echo + @echo "Build finished. The HTML pages are in _build/dirhtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in _build/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in _build/qthelp, like this:" + @echo "# qcollectiongenerator _build/qthelp/django-registration.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile _build/qthelp/django-registration.qhc" + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex + @echo + @echo "Build finished; the LaTeX files are in _build/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes + @echo + @echo "The overview file is in _build/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in _build/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in _build/doctest/output.txt." diff --git a/src/django-registration/docs/backend-api.rst b/src/django-registration/docs/backend-api.rst new file mode 100644 index 0000000..79270b3 --- /dev/null +++ b/src/django-registration/docs/backend-api.rst @@ -0,0 +1,230 @@ +.. _backend-api: + +User registration backends +========================== + +At its core, django-registration is built around the idea of pluggable +backends which can implement different workflows for user +registration. Although :ref:`the default backend ` +uses a common two-phase system (registration followed by activation), +backends are generally free to implement any workflow desired by their +authors. + +This is deliberately meant to be complementary to Django's own +`pluggable authentication backends +`_; +a site which uses an OpenID authentication backend, for example, can +and should make use of a registration backend which handles signups +via OpenID. And, like a Django authentication backend, a registration +backend is simply a class which implements a particular standard API +(described below). + +This allows for a great deal of flexibility in the actual workflow of +registration; backends can, for example, implement any of the +following (not an exhaustive list): + +* One-step (register, and done) or multi-step (register and activate) + signup. + +* Invitation-based registration. + +* Selectively allowing or disallowing registration (e.g., by requiring + particular credentials to register). + +* Enabling/disabling registration entirely. + +* Registering via sources other than a standard username/password, + such as OpenID. + +* Selective customization of the registration process (e.g., using + different forms or imposing different requirements for different + types of users). + + +Specifying the backend to use +----------------------------- + +To determine which backend to use, the :ref:`views in +django-registration ` accept a keyword argument ``backend``; in +all cases, this should be a string containing the full dotted Python +import path to the backend class to be used. So, for example, to use +the default backend, you'd pass the string +``'registration.backends.default.DefaultBackend'`` as the value of the +``backend`` argument (and the default URLconf included with that +backend does so). The specified backend class will then be imported +and instantiated (by calling its constructor with no arguments), and +the resulting instance will be used for all backend-specific +functionality. + +If the specified backend class cannot be imported, django-registration +will raise ``django.core.exceptions.ImproperlyConfigured``. + + +Backend API +----------- + +To be used as a registration backend, a class must implement the +following methods. For many cases, subclassing the default backend and +selectively overriding behavior will be suitable, but for other +situations (e.g., workflows significantly different from the default) +a full implementation is needed. + + +register(request, \*\*kwargs) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This method implements the logic of actually creating the new user +account. Often, but not necessarily always, this will involve creating +an instance of ``django.contrib.auth.models.User`` from the supplied +data. + +This method will only be called after a signup form has been +displayed, and the data collected by the form has been properly +validated. + +Arguments to this method are: + +``request`` + The Django `HttpRequest + `_ + object in which a new user is attempting to register. + +``**kwargs`` + A dictionary of the ``cleaned_data`` from the signup form. + +After creating the new user account, this method should create or +obtain an instance of ``django.contrib.auth.models.User`` representing +that account. It should then send the signal +:data:`registration.signals.user_registered`, with three arguments: + +``sender`` + The backend class (e.g., ``self.__class__``). + +``user`` + The ``User`` instance representing the new account. + +``request`` + The ``HttpRequest`` in which the user registered. + +Finally, this method should return the ``User`` instance. + + +activate(request, \*\*kwargs) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For workflows which require a separate activation step, this method +should implement the necessary logic for account activation. + +Arguments to this method are: + +``request`` + The Django ``HttpRequest`` object in which the account is being + activated. + +``**kwargs`` + A dictionary of any additional arguments (e.g., information + captured from the URL, such as an activation key) received by the + :func:`~registration.views.activate` view. The combination of the + ``HttpRequest`` and this additional information must be sufficient + to identify the account which will be activated. + +If the account cannot be successfully activated (for example, in the +default backend if the activation period has expired), this method +should return ``False``. + +If the account is successfully activated, this method should create or +obtain an instance of ``django.contrib.auth.models.User`` representing +the activated account. It should then send the signal +:data:`registration.signals.user_activated`, with three arguments: + +``sender`` + The backend class. + +``user`` + The ``User`` instance representing the activated account. + +``request`` + The ``HttpRequest`` in which the user activated. + +This method should then return the ``User`` instance. + +For workflows which do not require a separate activation step, this +method can and should raise ``NotImplementedError``. + + +registration_allowed(request) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This method returns a boolean value indicating whether the given +``HttpRequest`` is permitted to register a new account (``True`` if +registration is permitted, ``False`` otherwise). It may determine this +based on some aspect of the ``HttpRequest`` (e.g., the presence or +absence of an invitation code in the URL), based on a setting (in the +default backend, a setting can be used to disable registration), +information in the database or any other information it can access. + +Arguments to this method are: + +``request`` + The Django ``HttpRequest`` object in which a new user is + attempting to register. + +If this method returns ``False``, the +:func:`~registration.views.register` view will not display a form for +account creation; instead, it will issue a redirect to a URL +explaining that registration is not permitted. + + +get_form_class(request) +~~~~~~~~~~~~~~~~~~~~~~~ + +This method should return a form class -- a subclass of +``django.forms.Form`` -- suitable for use in registering users with +this backend. As such, it should collect and validate any information +required by the backend's ``register`` method. + +Arguments to this method are: + +``request`` + The Django ``HttpRequest`` object in which a new user is + attempting to register. + + +post_registration_redirect(request, user) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This method should return a location to which the user will be +redirected after successful registration. This should be a tuple of +``(to, args, kwargs)``, suitable for use as the arguments to `Django's +"redirect" shortcut +`_. + +Arguments to this method are: + +``request`` + The Django ``HttpRequest`` object in which the user registered. + +``user`` + The ``User`` instance representing the new user account. + + +post_activation_redirect(request, user) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For workflows which require a separate activation step, this method +should return a location to which the user will be redirected after +successful activation. This should be a tuple of ``(to, args, +kwargs)``, suitable for use as the arguments to `Django's "redirect" +shortcut +`_. + +Arguments to this method are: + +``request`` + The Django ``HttpRequest`` object in which the user activated. + +``user`` + The ``User`` instance representing the activated user account. + +For workflows which do not require a separate activation step, this +method can and should raise ``NotImplementedError``. diff --git a/src/django-registration/docs/conf.py b/src/django-registration/docs/conf.py new file mode 100644 index 0000000..b20aaa9 --- /dev/null +++ b/src/django-registration/docs/conf.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- +# +# django-registration documentation build configuration file, created by +# sphinx-quickstart on Mon Jun 22 02:57:42 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'django-registration' +copyright = u'2009, James Bennett' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.8' +# The full version, including alpha/beta/rc tags. +release = '0.8' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'django-registrationdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'django-registration.tex', u'django-registration Documentation', + u'James Bennett', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/src/django-registration/docs/default-backend.rst b/src/django-registration/docs/default-backend.rst new file mode 100644 index 0000000..a557a64 --- /dev/null +++ b/src/django-registration/docs/default-backend.rst @@ -0,0 +1,239 @@ +.. _default-backend: +.. module:: registration.backends.default + +The default backend +=================== + +A default :ref:`registration backend ` is bundled with +django-registration, as the class +``registration.backends.default.DefaultBackend``, and implements a +simple two-step workflow in which a new user first registers, then +confirms and activates the new account by following a link sent to the +email address supplied during registration. + + +Default behavior and configuration +---------------------------------- + +This backend makes use of the following settings: + +``ACCOUNT_ACTIVATION_DAYS`` + This is the number of days users will have to activate their + accounts after registering. Failing to activate during that period + will leave the account inactive (and possibly subject to + deletion). This setting is required, and must be an integer. + +``REGISTRATION_OPEN`` + A boolean (either ``True`` or ``False``) indicating whether + registration of new accounts is currently permitted. This setting + is optional, and a default of ``True`` will be assumed if it is + not supplied. + +By default, this backend uses +:class:`registration.forms.RegistrationForm` as its form class for +user registration; this can be overridden by passing the keyword +argument ``form_class`` to the :func:`~registration.views.register` +view. + +Upon successful registration -- not activation -- the default redirect +is to the URL pattern named ``registration_complete``; this can be +overridden by passing the keyword argument ``success_url`` to the +:func:`~registration.views.register` view. + +Upon successful activation, the default redirect is to the URL pattern +named ``registration_activation_complete``; this can be overridden by +passing the keyword argument ``success_url`` to the +:func:`~registration.views.activate` view. + + +How account data is stored for activation +----------------------------------------- + +During registration, a new instance of +``django.contrib.auth.models.User`` is created to represent the new +account, with the ``is_active`` field set to ``False``. An email is +then sent to the email address of the account, containing a link the +user must click to activate the account; at that point the +``is_active`` field is set to ``True``, and the user may log in +normally. + +Activation is handled by generating and storing an activation key in +the database, using the following model: + + +.. currentmodule:: registration.models + +.. class:: RegistrationProfile + + A simple representation of the information needed to activate a new + user account. This is **not** a user profile; it simply provides a + place to temporarily store the activation key and determine whether + a given account has been activated. + + Has the following fields: + + .. attribute:: user + + A ``ForeignKey`` to ``django.contrib.auth.models.User``, + representing the user account for which activation information + is being stored. + + .. attribute:: activation_key + + A 40-character ``CharField``, storing the activation key for the + account. Initially, the activation key is the hexdigest of a + SHA1 hash; after activation, this is reset to :attr:`ACTIVATED`. + + Additionally, one class attribute exists: + + .. attribute:: ACTIVATED + + A constant string used as the value of :attr:`activation_key` + for accounts which have been activated. + + And the following methods: + + .. method:: activation_key_expired() + + Determines whether this account's activation key has expired, + and returns a boolean (``True`` if expired, ``False`` + otherwise). Uses the following algorithm: + + 1. If :attr:`activation_key` is :attr:`ACTIVATED`, the account + has already been activated and so the key is considered to + have expired. + + 2. Otherwise, the date of registration (obtained from the + ``date_joined`` field of :attr:`user`) is compared to the + current date; if the span between them is greater than the + value of the setting ``ACCOUNT_ACTIVATION_DAYS``, the key is + considered to have expired. + + :rtype: bool + + .. method:: send_activation_email(site) + + Sends an activation email to the address of the account. + + The activation email will make use of two templates: + ``registration/activation_email_subject.txt`` and + ``registration/activation_email.txt``, which are used for the + subject of the email and the body of the email, + respectively. Each will receive the following context: + + ``activation_key`` + The value of :attr:`activation_key`. + + ``expiration_days`` + The number of days the user has to activate, taken from the + setting ``ACCOUNT_ACTIVATION_DAYS``. + + ``site`` + An object representing the site on which the account was + registered; depending on whether ``django.contrib.sites`` is + installed, this may be an instance of either + ``django.contrib.sites.models.Site`` (if the sites + application is installed) or + ``django.contrib.sites.models.RequestSite`` (if + not). Consult `the documentation for the Django sites + framework + `_ + for details regarding these objects' interfaces. + + Because email subjects must be a single line of text, the + rendered output of ``registration/activation_email_subject.txt`` + will be forcibly condensed to a single line. + + :param site: An object representing the site on which account + was registered. + :type site: ``django.contrib.sites.models.Site`` or + ``django.contrib.sites.models.RequestSite`` + :rtype: ``None`` + + +Additionally, :class:`RegistrationProfile` has a custom manager +(accessed as ``RegistrationProfile.objects``): + + +.. class:: RegistrationManager + + This manager provides several convenience methods for creating and + working with instances of :class:`RegistrationProfile`: + + .. method:: activate_user(activation_key) + + Validates ``activation_key`` and, if valid, activates the + associated account by setting its ``is_active`` field to + ``True``. To prevent re-activation of accounts, the + :attr:`~RegistrationProfile.activation_key` of the + :class:`RegistrationProfile` for the account will be set to + :attr:`RegistrationProfile.ACTIVATED` after successful + activation. + + Returns the ``User`` instance representing the account if + activation is successful, ``False`` otherwise. + + :param activation_key: The activation key to use for the + activation. + :type activation_key: string, a 40-character SHA1 hexdigest + :rtype: ``User`` or bool + + .. method:: delete_expired_users + + Removes expired instances of :class:`RegistrationProfile`, and + their associated user accounts, from the database. This is + useful as a periodic maintenance task to clean out accounts + which registered but never activated. + + Accounts to be deleted are identified by searching for instances + of :class:`RegistrationProfile` with expired activation keys and + with associated user accounts which are inactive (have their + ``is_active`` field set to ``False``). To disable a user account + without having it deleted, simply delete its associated + :class:`RegistrationProfile`; any ``User`` which does not have + an associated :class:`RegistrationProfile` will not be deleted. + + A custom management command is provided which will execute this + method, suitable for use in cron jobs or other scheduled + maintenance tasks: ``manage.py cleanupregistration``. + + :rtype: ``None`` + + .. method:: create_inactive_user(username, email, password, site[, send_email]) + + Creates a new, inactive user account and an associated instance + of :class:`RegistrationProfile`, sends the activation email and + returns the new ``User`` object representing the account. + + :param username: The username to use for the new account. + :type username: string + :param email: The email address to use for the new account. + :type email: string + :param password: The password to use for the new account. + :type password: string + :param site: An object representing the site on which the + account is being registered. + :type site: ``django.contrib.sites.models.Site`` or + ``django.contrib.sites.models.RequestSite`` + :param send_email: If ``True``, the activation email will be + sent to the account (by calling + :meth:`RegistrationProfile.send_activation_email`). If + ``False``, no email will be sent (but the account will still + be inactive) + :type send_email: bool + :rtype: ``User`` + + .. method:: create_profile(user) + + Creates and returns a :class:`RegistrationProfile` instance for + the account represented by ``user``. + + The ``RegistrationProfile`` created by this method will have its + :attr:`~RegistrationProfile.activation_key` set to a SHA1 hash + generated from a combination of the account's username and a + random salt. + + :param user: The user account; an instance of + ``django.contrib.auth.models.User``. + :type user: ``User`` + :rtype: ``RegistrationProfile`` diff --git a/src/django-registration/docs/faq.rst b/src/django-registration/docs/faq.rst new file mode 100644 index 0000000..cd03cd5 --- /dev/null +++ b/src/django-registration/docs/faq.rst @@ -0,0 +1,195 @@ +.. _faq: + +Frequently-asked questions +========================== + +The following are miscellaneous common questions and answers related +to installing/using django-registration, culled from bug reports, +emails and other sources. + + +General +------- + +**What license is django-registration under?** + django-registration is offered under a three-clause BSD-style + license; this is `an OSI-approved open-source license + `_, and allows + you a large degree of freedom in modifiying and redistributing the + code. For the full terms, see the file ``LICENSE`` which came with + your copy of django-registration; if you did not receive a copy of + this file, you can view it online at + . + +**Why are the forms and models for the default backend not in the default backend?** + The model and manager used by :ref:`the default backend + ` are in ``registration.models``, and the default + form class (and various subclasses) are in ``registration.forms``; + logically, they might be expected to exist in + ``registration.backends.default``, but there are several reasons + why that's not such a good idea: + + 1. Older versions of django-registration made use of the model and + form classes, and moving them would create an unnecessary + backwards incompatibility: ``import`` statements would need to + be changed, and some database updates would be needed to + reflect the new location of the + :class:`~registration.models.RegistrationProfile` model. + + 2. Due to the design of Django's ORM, the ``RegistrationProfile`` + model would end up with an ``app_label`` of ``default``, which + isn't particularly descriptive and may conflict with other + applications. By keeping it in ``registration.models``, it + retains an ``app_label`` of ``registration``, which more + accurately reflects what it does and is less likely to cause + problems. + + 3. Although the ``RegistrationProfile`` model and the various + :ref:`form classes ` are used by the default backend, + they can and are meant to be reused as needed by other + backends. Any backend which uses an activation step should feel + free to reuse the ``RegistrationProfile`` model, for example, + and the registration form classes are in no way tied to a + specific backend (and cover a number of common use cases which + will crop up regardless of the specific backend logic in use). + + +Installation and setup +---------------------- + +**How do I install django-registration?** + Full instructions are available in :ref:`the quick start guide `. + +**Do I need to put a copy of django-registration in every project I use it in?** + No; putting applications in your project directory is a very bad + habit, and you should stop doing it. If you followed the + instructions mentioned above, django-registration was installed + into a location that's on your Python import path, so you'll only + ever need to add ``registration`` to your ``INSTALLED_APPS`` + setting (in any project, or in any number of projects), and it + will work. + +**Does django-registration come with any sample templates I can use right away?** + No, for two reasons: + + 1. Providing default templates with an application is generally + hard to impossible, because different sites can have such + wildly different design and template structure. Any attempt to + provide templates which would work with all the possibilities + would probably end up working with none of them. + + 2. A number of things in django-registration depend on the + specific :ref:`registration backend ` you use, + including the variables which end up in template + contexts. Since django-registration has no way of knowing in + advance what backend you're going to be using, it also has no + way of knowing what your templates will need to look like. + + Fortunately, however, django-registration has good documentation + which explains what context variables will be available to + templates, and so it should be easy for anyone who knows Django's + template system to create templates which integrate with their own + site. + + +Configuration +------------- + +**Do I need to rewrite the views to change the way they behave?** + No. There are several ways you can customize behavior without + making any changes whatsoever: + + * Pass custom arguments -- e.g., to specify forms, template names, + etc. -- to :ref:`the registration views `. + + * Use the :ref:`signals ` sent by the views to add custom + behavior. + + * Write a custom :ref:`registration backend ` which + implements the behavior you need, and have the views use your + backend. + + If none of these are sufficient, your best option is likely to + simply write your own views; however, it is hoped that the level + of customization exposed by these options will be sufficient for + nearly all user-registration workflows. + +**How do I pass custom arguments to the views?** + Part 3 of the official Django tutorial, when it `introduces + generic views + `_, + covers the necessary mechanism: simply provide a dictionary of + keyword arguments in your URLconf. + +**Does that mean I should rewrite django-registration's default URLconf?** + No; if you'd like to pass custom arguments to the registration + views, simply write and include your own URLconf instead of + including the default one provided with django-registration. + +**I don't want to write my own URLconf because I don't want to write patterns for all the auth views!** + You're in luck, then; django-registration provides a URLconf which + *only* contains the patterns for the auth views, and which you can + include in your own URLconf anywhere you'd like; it lives at + ``registration.auth_urls``. + +**I don't like the names you've given to the URL patterns!** + In that case, you should feel free to set up your own URLconf + which uses the names you want. + + +Troubleshooting +--------------- + +**I've got functions listening for the registration/activation signals, but they're not getting called!** + + The most common cause of this is placing django-registration in a + sub-directory that's on your Python import path, rather than + installing it directly onto the import path as normal. Importing + from django-registration in that case can cause various issues, + including incorrectly connecting signal handlers. For example, if + you were to place django-registration inside a directory named + ``django_apps``, and refer to it in that manner, you would end up + with a situation where your code does this:: + + from django_apps.registration.signals import user_registered + + But django-registration will be doing:: + + from registration.signals import user_registered + + From Python's point of view, these import statements refer to two + different objects in two different modules, and so signal handlers + connected to the signal from the first import will not be called + when the signal is sent using the second import. + + To avoid this problem, follow the standard practice of installing + django-registration directly on your import path and always + referring to it by its own module name: ``registration`` (and in + general, it is always a good idea to follow normal Python + practices for installing and using Django applications). + + +Tips and tricks +--------------- + +**How do I log a user in immediately after registration or activation?** + You can most likely do this simply by writing a function which + listens for the appropriate :ref:`signal `; your function + should set the ``backend`` attribute of the user to the correct + authentication backend, and then call + ``django.contrib.auth.login()`` to log the user in. + +**How do I re-send an activation email?** + Assuming you're using :ref:`the default backend + `, a `custom admin action + `_ + is provided for this; in the admin for the + :class:`~registration.models.RegistrationProfile` model, simply + click the checkbox for the user(s) you'd like to re-send the email + for, then select the "Re-send activation emails" action. + +**How do I manually activate a user?** + In the default backend, a custom admin action is provided for + this. In the admin for the ``RegistrationProfile`` model, click + the checkbox for the user(s) you'd like to activate, then select + the "Activate users" action. \ No newline at end of file diff --git a/src/django-registration/docs/forms.rst b/src/django-registration/docs/forms.rst new file mode 100644 index 0000000..ce5ca41 --- /dev/null +++ b/src/django-registration/docs/forms.rst @@ -0,0 +1,100 @@ +.. _forms: +.. module:: registration.forms + +Forms for user registration +=========================== + +Several form classes are provided with django-registration, covering +common cases for gathering account information and implementing common +constraints for user registration. These forms were designed with +django-registration's :ref:`default backend ` in +mind, but may also be useful in other situations. + + +.. class:: RegistrationForm + + A simple form for registering an account. Has the following fields, + all of which are required: + + ``username`` + The username to use for the new account. This is represented as + a text input which validates that the username is unique, + consists entirely of alphanumeric characters and underscores + and is at most 30 characters in length. + + ``email`` + The email address to use for the new account. This is + represented as a text input which accepts email addresses up to + 75 characters in length. + + ``password1`` + The password to use for the new account. This represented as a + password input (``input type="password"`` in the rendered HTML). + + ``password2`` + The password to use for the new account. This represented as a + password input (``input type="password"`` in the rendered HTML). + + The constraints on usernames and email addresses match those + enforced by Django's default authentication backend for instances + of ``django.contrib.auth.models.User``. The repeated entry of the + password serves to catch typos. + + Because it does not apply to any single field of the form, the + validation error for mismatched passwords is attached to the form + itself, and so must be accessed via the form's + ``non_field_errors()`` method. + + +.. class:: RegistrationFormTermsOfService + + A subclass of :class:`RegistrationForm` which adds one additional, + required field: + + ``tos`` + A checkbox indicating agreement to the site's terms of + service/user agreement. + + +.. class:: RegistrationFormUniqueEmail + + A subclass of :class:`RegistrationForm` which enforces uniqueness + of email addresses in addition to uniqueness of usernames. + + +.. class:: RegistrationFormNoFreeEmail + + A subclass of :class:`RegistrationForm` which disallows + registration using addresses from some common free email + providers. This can, in some cases, cut down on automated + registration by spambots. + + By default, the following domains are disallowed for email + addresses: + + * ``aim.com`` + + * ``aol.com`` + + * ``email.com`` + + * ``gmail.com`` + + * ``googlemail.com`` + + * ``hotmail.com`` + + * ``hushmail.com`` + + * ``msn.com`` + + * ``mail.ru`` + + * ``mailinator.com`` + + * ``live.com`` + + * ``yahoo.com`` + + To change this, subclass this form and set the class attribute + ``bad_domains`` to a list of domains you wish to disallow. diff --git a/src/django-registration/docs/index.rst b/src/django-registration/docs/index.rst new file mode 100644 index 0000000..35c6b36 --- /dev/null +++ b/src/django-registration/docs/index.rst @@ -0,0 +1,55 @@ +.. django-registration documentation master file, created by + sphinx-quickstart on Mon Jun 22 02:57:42 2009. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +django-registration 0.8 documentation +===================================== + +This documentation covers the 0.8 release of django-registration, a +simple but extensible application providing user registration +functionality for `Django `_-powered +websites. + +Although nearly all aspects of the registration process are +customizable, the default setup of django-registration attempts to +cover the most common use case: two-phase registration, consisting of +initial signup followed by a confirmation email which contains +instructions for activating the new account. + +To get up and running quickly, consult the :ref:`quick-start guide +`, which describes all the necessary steps to install +django-registration and configure it for the default workflow. For +more detailed information, including how to customize the registration +process (and support for alternate registration systems), read through +the documentation listed below. + +If you are upgrading from a previous release, please read the +:ref:`upgrade guide ` for information on what's changed. + +Contents: + +.. toctree:: + :maxdepth: 1 + + quickstart + release-notes + upgrade + backend-api + default-backend + simple-backend + forms + views + signals + faq + +.. seealso:: + + * `Django's authentication documentation + `_; Django's + authentication system is used by django-registration's default + configuration. + + * `django-profiles + `_, an + application which provides simple user-profile management. diff --git a/src/django-registration/docs/make.bat b/src/django-registration/docs/make.bat new file mode 100644 index 0000000..b80dbdd --- /dev/null +++ b/src/django-registration/docs/make.bat @@ -0,0 +1,112 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +set SPHINXBUILD=sphinx-build +set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (_build\*) do rmdir /q /s %%i + del /q /s _build\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html + echo. + echo.Build finished. The HTML pages are in _build/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml + echo. + echo.Build finished. The HTML pages are in _build/dirhtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in _build/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in _build/qthelp, like this: + echo.^> qcollectiongenerator _build\qthelp\django-registration.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile _build\qthelp\django-registration.ghc + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex + echo. + echo.Build finished; the LaTeX files are in _build/latex. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes + echo. + echo.The overview file is in _build/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck + echo. + echo.Link check complete; look for any errors in the above output ^ +or in _build/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in _build/doctest/output.txt. + goto end +) + +:end diff --git a/src/django-registration/docs/quickstart.rst b/src/django-registration/docs/quickstart.rst new file mode 100644 index 0000000..b04ba49 --- /dev/null +++ b/src/django-registration/docs/quickstart.rst @@ -0,0 +1,294 @@ +.. _quickstart: + +Quick start guide +================= + +Before installing django-registration, you'll need to have a copy of +`Django `_ already installed. For the +|version| release, Django 1.1 or newer is required. + +For further information, consult the `Django download page +`_, which offers convenient +packaged downloads and installation instructions. + + +Installing django-registration +------------------------------ + +There are several ways to install django-registration: + +* Automatically, via a package manager. + +* Manually, by downloading a copy of the release package and + installing it yourself. + +* Manually, by performing a Mercurial checkout of the latest code. + +It is also highly recommended that you learn to use `virtualenv +`_ for development and +deployment of Python software; ``virtualenv`` provides isolated Python +environments into which collections of software (e.g., a copy of +Django, and the necessary settings and applications for deploying a +site) can be installed, without conflicting with other installed +software. This makes installation, testing, management and deployment +far simpler than traditional site-wide installation of Python +packages. + + +Automatic installation via a package manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Several automatic package-installation tools are available for Python; +the most popular are `easy_install +`_ and `pip +`_. Either can be used to install +django-registration. + +Using ``easy_install``, type:: + + easy_install -Z django-registration + +Note that the ``-Z`` flag is required, to tell ``easy_install`` not to +create a zipped package; zipped packages prevent certain features of +Django from working properly. + +Using ``pip``, type:: + + pip install django-registration + +It is also possible that your operating system distributor provides a +packaged version of django-registration (for example, `Debian +GNU/Linux `_ provides a package, installable via +``apt-get-install python-django-registration``). Consult your +operating system's package list for details, but be aware that +third-party distributions may be providing older versions of +django-registration, and so you should consult the documentation which +comes with your operating system's package. + + +Manual installation from a downloaded package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you prefer not to use an automated package installer, you can +download a copy of django-registration and install it manually. The +latest release package can be downloaded from `django-registration's +listing on the Python Package Index +`_. + +Once you've downloaded the package, unpack it (on most operating +systems, simply double-click; alternately, type ``tar zxvf +django-registration-0.8.tar.gz`` at a command line on Linux, Mac OS X +or other Unix-like systems). This will create the directory +``django-registration-0.8``, which contains the ``setup.py`` +installation script. From a command line in that directory, type:: + + python setup.py install + +Note that on some systems you may need to execute this with +administrative privileges (e.g., ``sudo python setup.py install``). + + +Manual installation from a Mercurial checkout +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you'd like to try out the latest in-development code, you can +obtain it from the django-registration repository, which is hosted at +`Bitbucket `_ and uses `Mercurial +`_ for version control. To +obtain the latest code and documentation, you'll need to have +Mercurial installed, at which point you can type:: + + hg clone http://bitbucket.org/ubernostrum/django-registration/ + +You can also obtain a copy of a particular release of +django-registration by specifying the ``-r`` argument to ``hg clone``; +each release is given a tag of the form ``vX.Y``, where "X.Y" is the +release number. So, for example, to check out a copy of the 0.8 +release, type:: + + hg clone -r v0.8 http://bitbucket.org/ubernostrum/django-registration/ + +In either case, this will create a copy of the django-registration +Mercurial repository on your computer; you can then add the +``django-registration`` directory inside the checkout your Python +import path, or use the ``setup.py`` script to install as a package. + + +Basic configuration and use +--------------------------- + +Once installed, you can add django-registration to any Django-based +project you're developing. The default setup will enable user +registration with the following workflow: + +1. A user signs up for an account by supplying a username, email + address and password. + +2. From this information, a new ``User`` object is created, with its + ``is_active`` field set to ``False``. Additionally, an activation + key is generated and stored, and an email is sent to the user + containing a link to click to activate the account. + +3. Upon clicking the activation link, the new account is made active + (the ``is_active`` field is set to ``True``); after this, the user + can log in. + +Note that the default workflow requires ``django.contrib.auth`` to be +installed, and it is recommended that ``django.contrib.sites`` be +installed as well. You will also need to have a working mail server +(for sending activation emails), and provide Django with the necessary +settings to make use of this mail server (consult `Django's +email-sending documentation +`_ for details). + + +Required settings +~~~~~~~~~~~~~~~~~ + +Begin by adding ``registration`` to the ``INSTALLED_APPS`` setting of +your project, and specifying one additional setting: + +``ACCOUNT_ACTIVATION_DAYS`` + This is the number of days users will have to activate their + accounts after registering. If a user does not activate within + that period, the account will remain permanently inactive and may + be deleted by maintenance scripts provided in django-registration. + +For example, you might have something like the following in your +Django settings file:: + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.sites', + 'registration', + # ...other installed applications... + ) + + ACCOUNT_ACTIVATION_DAYS = 7 # One-week activation window; you may, of course, use a different value. + +Once you've done this, run ``manage.py syncdb`` to install the model +used by the default setup. + + +Setting up URLs +~~~~~~~~~~~~~~~ + +The :ref:`default backend ` includes a Django +``URLconf`` which sets up URL patterns for :ref:`the views in +django-registration `, as well as several useful views in +``django.contrib.auth`` (e.g., login, logout, password +change/reset). This ``URLconf`` can be found at +``registration.backends.default.urls``, and so can simply be included +in your project's root URL configuration. For example, to place the +URLs under the prefix ``/accounts/``, you could add the following to +your project's root ``URLconf``:: + + (r'^accounts/', include('registration.backends.default.urls')), + +Users would then be able to register by visiting the URL +``/accounts/register/``, login (once activated) at +``/accounts/login/``, etc. + + +Required templates +~~~~~~~~~~~~~~~~~~ + +In the default setup, you will need to create several templates +required by django-registration, and possibly additional templates +required by views in ``django.contrib.auth``. The templates requires +by django-registration are as follows; note that, with the exception +of the templates used for account activation emails, all of these are +rendered using a ``RequestContext`` and so will also receive any +additional variables provided by `context processors +`_. + +**registration/registration_form.html** + +Used to show the form users will fill out to register. By default, has +the following context: + +``form`` + The registration form. This will be an instance of some subclass + of ``django.forms.Form``; consult `Django's forms documentation + `_ for + information on how to display this in a template. + +**registration/registration_complete.html** + +Used after successful completion of the registration form. This +template has no context variables of its own, and should simply inform +the user that an email containing account-activation information has +been sent. + +**registration/activate.html** + +Used if account activation fails. With the default setup, has the following context: + +``activation_key`` + The activation key used during the activation attempt. + +**registration/activation_complete.html** + +Used after successful account activation. This template has no context +variables of its own, and should simply inform the user that their +account is now active. + +**registration/activation_email_subject.txt** + +Used to generate the subject line of the activation email. Because the +subject line of an email must be a single line of text, any output +from this template will be forcibly condensed to a single line before +being used. This template has the following context: + +``activation_key`` + The activation key for the new account. + +``expiration_days`` + The number of days remaining during which the account may be + activated. + +``site`` + An object representing the site on which the user registered; + depending on whether ``django.contrib.sites`` is installed, this + may be an instance of either ``django.contrib.sites.models.Site`` + (if the sites application is installed) or + ``django.contrib.sites.models.RequestSite`` (if not). Consult `the + documentation for the Django sites framework + `_ for + details regarding these objects' interfaces. + +**registration/activation_email.txt** + +Used to generate the body of the activation email. Should display a +link the user can click to activate the account. This template has the +following context: + +``activation_key`` + The activation key for the new account. + +``expiration_days`` + The number of days remaining during which the account may be + activated. + +``site`` + An object representing the site on which the user registered; + depending on whether ``django.contrib.sites`` is installed, this + may be an instance of either ``django.contrib.sites.models.Site`` + (if the sites application is installed) or + ``django.contrib.sites.models.RequestSite`` (if not). Consult `the + documentation for the Django sites framework + `_ for + details regarding these objects' interfaces. + +Note that the templates used to generate the account activation email +use the extension ``.txt``, not ``.html``. Due to widespread antipathy +toward and interoperability problems with HTML email, +django-registration defaults to plain-text email, and so these +templates should simply output plain text rather than HTML. + +To make use of the views from ``django.contrib.auth`` (which are set +up for you by the default URLconf mentioned above), you will also need +to create the templates required by those views. Consult `the +documentation for Django's authentication system +`_ +for details regarding these templates. diff --git a/src/django-registration/docs/release-notes.rst b/src/django-registration/docs/release-notes.rst new file mode 100644 index 0000000..261725d --- /dev/null +++ b/src/django-registration/docs/release-notes.rst @@ -0,0 +1,69 @@ +.. _release-notes: + +Release notes +============= + +The |version| release of django-registration represents a complete +rewrite of the previous codebase, and as such introduces a number of +new features and greatly enhances the flexibility and customizability +of django-registration. This document summarizes those features; for a +list of changes which impact existing installations, consult :ref:`the +upgrade guide `. + + +The backend system +------------------ + +The largest overall change consists of factoring out the logic of user +registration into pluggable/swappable backend classes. The +:ref:`registration views ` now accept a (required) argument, +``backend``, which indicates the backend class to use, and that class +has full control over the registration (and, if needed, activation) +process, including: + +* Determining whether registration will be allowed at all, on a + per-request basis. + +* Specifying a form class to use for account registration. + +* Implementing the actual process of account creation. + +* Determining whether a separate activation step is needed, and if so + what it will entail. + +* Specifying actions to take (e.g., redirects, automatic login, etc.) + following successful registration or activation. + +For full details, see the documentation for :ref:`the backend API +`. + +The workflow used by previous releases of django-registration +(two-step registration/activation) has been implemented using this +system, and is shipped as :ref:`the default backend ` +in django-registration |version|. + + +Other new features +------------------ + +An alternate :ref:`one-step registration system ` is +provided, for use by sites which do not require a two-step +registration/activation system. + +During the registration and (optional) activation process, +:ref:`custom signals ` are now sent, allowing easy injection +of custom processing into the registration workflow without needing to +write a full backend. + +The default backend now supplies several `custom admin actions +`_ to +make the process of administering a site with django-registration +simpler. + +The :func:`~registration.views.activate` view now supplies any +captured keyword arguments from the URL (in the case of the default +backend, this is the activation key) to its template in case of +unsuccessful activation; this greatly simplifies the process of +determining why activation failed and displaying appropriate error +messages. + diff --git a/src/django-registration/docs/signals.rst b/src/django-registration/docs/signals.rst new file mode 100644 index 0000000..a66fd56 --- /dev/null +++ b/src/django-registration/docs/signals.rst @@ -0,0 +1,56 @@ +.. _signals: +.. module:: registration.signals + + +Custom signals used by django-registration +========================================== + +Much of django-registration's customizability comes through the +ability to write and use :ref:`registration backends ` +implementing different workflows for user registration. However, there +are many cases where only a small bit of additional logic needs to be +injected into the registration process, and writing a custom backend +to support this represents an unnecessary amount of work. A more +lightweight customization option is provided through two custom +signals which backends are required to send at specific points during +the registration process; functions listening for these signals can +then add whatever logic is needed. + +For general documentation on signals and the Django dispatcher, +consult `Django's signals documentation +`_. This +documentation assumes that you are familiar with how signals work and +the process of writing and connecting functions which will listen for +signals. + + +.. data:: user_activated + + Sent when a user account is activated (not applicable to all + backends). Provides the following arguments: + + ``sender`` + The backend class used to activate the user. + + ``user`` + An instance of ``django.contrib.auth.models.User`` + representing the activated account. + + ``request`` + The ``HttpRequest`` in which the account was activated. + + +.. data:: user_registered + + Sent when a new user account is registered. Provides the following + arguments: + + ``sender`` + The backend class used to register the account. + + ``user`` + An instance of ``django.contrib.auth.models.User`` + representing the new account. + + ``request`` + The ``HttpRequest`` in which the new account was registered. diff --git a/src/django-registration/docs/simple-backend.rst b/src/django-registration/docs/simple-backend.rst new file mode 100644 index 0000000..03efa87 --- /dev/null +++ b/src/django-registration/docs/simple-backend.rst @@ -0,0 +1,61 @@ +.. _simple-backend: +.. module:: registration.backends.simple + +The "simple" (one-step) backend +=============================== + +As an alternative to :ref:`the default backend `, and +an example of writing :ref:`registration backends `, +django-registration bundles a one-step registration system in +``registration.backend.simple``. This backend's workflow is +deliberately as simple as possible: + +1. A user signs up by filling out a registration form. + +2. The user's account is created and is active immediately, with no + intermediate confirmation or activation step. + +3. The new user is logged in immediately. + + +Configuration +------------- + +To use this backend, simply include the URLconf +``registration.backends.simple.urls`` somewhere in your site's own URL +configuration. For example:: + + (r'^accounts/', include('registration.backends.simple.urls')), + +No additional settings are required, but one optional setting is +supported: + +``REGISTRATION_OPEN`` + A boolean (either ``True`` or ``False``) indicating whether + registration of new accounts is currently permitted. A default of + ``True`` will be assumed if this setting is not supplied. + +Upon successful registration, the default redirect is to the URL +specified by the ``get_absolute_url()`` method of the newly-created +``User`` object; by default, this will be ``/users//``, +although it can be overridden in either of two ways: + +1. Specify a custom URL pattern for the + :func:`~registration.views.register` view, passing the keyword + argument ``success_url``. + +2. Override the default ``get_absolute_url()`` of the ``User`` model + in your Django configuration, as covered in `Django's settings + documentation + `_. + +The default form class used for account registration will be +:class:`registration.forms.RegistrationForm`, although this can be +overridden by supplying a custom URL pattern for the ``register()`` +view and passing the keyword argument ``form_class``. + +Note that because this backend does not use an activation step, +attempting to use the :func:`~registration.views.activate` view with +this backend or calling the backend's ``activate()`` or +``post_activation_redirect()`` methods will raise +``NotImplementedError``. diff --git a/src/django-registration/docs/upgrade.rst b/src/django-registration/docs/upgrade.rst new file mode 100644 index 0000000..29f4edd --- /dev/null +++ b/src/django-registration/docs/upgrade.rst @@ -0,0 +1,120 @@ +.. _upgrade: + +Upgrade guide +============= + +The |version| release of django-registration represents a complete +rewrite of the previous codebase, and introduces several new features +which greatly enhance the customizability and extensibility of +django-registration. Whenever possible, changes were made in ways +which preserve backwards compatibility with previous releases, but +some changes to existing installations will still be required in order +to upgrade to |version|. This document provides a summary of those +changes, and of the new features available in the |version| release. + + +Django version requirement +-------------------------- + +As of |version|, django-registration requires Django 1.1 or newer; +older Django releases will not work, as django-registration |version| +takes advantage of several Django features which are only present as +of 1.1. + + +Backwards-incompatible changes +------------------------------ + +If you're upgrading from an older release of django-registration, and +if you were using the default setup (i.e., the included default +URLconf and no custom URL patterns or custom arguments to views), most +things will continue to work as normal (although you will need to +create one new template; see the section on views below). However, the +old default URLconf has been deprecated and will be removed in version +1.0 of django-registration, so it is recommended that you begin +migrating now. To do so, change any use of ``registration.urls`` to +``registration.backends.default.urls``. For example, if you had the +following in your root URLconf:: + + (r'^accounts/', include('registration.urls')), + +you should change it to:: + + (r'^accounts/', include('registration.backends.default.urls')), + +The older include will continue to work until django-registration 1.0; +in |version| it raises a ``PendingDeprecationWarning`` (which is +ignored by default in Python), in 0.9 it will raise +``DeprecationWarning`` (which will begin printing warning messages on +import) and in 1.0 it will be removed entirely. + + +Changes to registration views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`The views used to handle user registration ` have changed +significantly as of django-registration |version|. Both views now +require the keyword argument ``backend``, which specifies the +:ref:`registration backend ` to use, and so any URL +pattern for these views must supply that argument. The URLconf +provided with :ref:`the default backend ` properly +passes this argument. + +The ``profile_callback`` argument of the +:func:`~registration.views.register` view has been removed; the +functionality it provided can now be implemented easily via a custom +backend, or by connecting listeners to :ref:`the signals sent during +the registration process `. + +The :func:`~registration.views.activate` view now issues a redirect +upon successful activation; in the default backend this is to the URL +pattern named ``registration_activation_complete``; in the default +setup, this will redirect to a view which renders the template +``registration/activation_complete.html``, and so this template should +be present when using the default backend and default +configuration. Other backends can specify the location to redirect to +through their ``post_activation_redirect()`` method, and this can be +overridden on a case-by-case basis by passing the (new) keyword +argument ``success_url`` to the ``activate()`` view. On unsuccessful +activation, the ``activate()`` view still displays the same template, +but its context has changed: the context will simply consist of any +keyword arguments captured in the URL and passed to the view. + + +Changes to registration forms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, the form used to collect data during registration was +expected to implement a ``save()`` method which would create the new +user account. This is no longer the case; creating the account is +handled by the backend, and so any custom logic should be moved into a +custom backend, or by connecting listeners to :ref:`the signals sent +during the registration process `. + + +Changes to the :class:`~registration.models.RegistrationProfile` model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The +:meth:`~registration.models.RegistrationManager.create_inactive_user` +method of :class:`~registration.models.RegistrationManager` now has an +additional required argument: ``site``. This allows +django-registration to easily be used regardless of whether +``django.contrib.sites`` is installed, since a ``RequestSite`` object +can be passed in place of a regular ``Site`` object. + +The :data:`~registration.signals.user_registered` signal is no longer +sent by ``create_inactive_user()``, and the +:data:`~registration.signals.user_activated` signal is no longer sent +by :meth:`~registration.models.RegistrationManager.activate_user`; +these signals are now sent by the backend after these methods have +been called. Note that :ref:`these signals ` were added after +the django-registration 0.7 release but before the refactoring which +introduced :ref:`the backend API `, so only installations +which were tracking the in-development codebase will have made use of +them. + +The sending of activation emails has been factored out of +``create_inactive_user()``, and now exists as the method +:meth:`~registration.models.RegistrationProfile.send_activation_email` +on instances of ``RegistrationProfile``. diff --git a/src/django-registration/docs/views.rst b/src/django-registration/docs/views.rst new file mode 100644 index 0000000..faca644 --- /dev/null +++ b/src/django-registration/docs/views.rst @@ -0,0 +1,122 @@ +.. _views: +.. module:: registration.views + +Registration views +================== + +In order to allow users to register using whatever workflow is +implemented by the :ref:`registration backend ` in use, +django-registration provides two views. Both are designed to allow +easy configurability without writing or rewriting view code. + +.. function:: activate(request, backend[, template_name[, success_url[, extra_context[, **kwargs]]]]) + + Activate a user's account, for workflows which require a separate + activation step. + + The actual activation of the account will be delegated to the + backend specified by the ``backend`` keyword argument; the + backend's ``activate()`` method will be called, passing the + ``HttpRequest`` and any keyword arguments captured from the URL, + and will be assumed to return a ``User`` if activation was + successful, or a value which evaluates to ``False`` in boolean + context if not. + + Upon successful activation, the backend's + ``post_activation_redirect()`` method will be called, passing the + ``HttpRequest`` and the activated ``User`` to determine the URL to + redirect the user to. To override this, pass the argument + ``success_url`` (see below). + + On unsuccessful activation, will render the template + ``registration/activate.html`` to display an error message; to + override thise, pass the argument ``template_name`` (see below). + + **Context** + + The context will be populated from the keyword arguments captured + in the URL. This view uses ``RequestContext``, so variables + populated by context processors will also be present in the + context. + + :param backend: The dotted Python path to the backend class to use. + :type backend: string + :param extra_context: Optionally, variables to add to the template + context. Any callable object in this dictionary will be called + to produce the final result which appears in the context. + :type extra_context: dict + :param template_name: Optional. A custom template name to use. If + not specified, this will default to + ``registration/activate.html``. + :type template_name: string + :param **kwargs: Any keyword arguments captured from the URL, such + as an activation key, which will be passed to the backend's + ``activate()`` method. + + +.. function:: register(request, backend[, success_url[, form_class[, disallowed_url[, template_name[, extra_context]]]]]) + + Allow a new user to register an account. + + The actual registration of the account will be delegated to the + backend specified by the ``backend`` keyword argument. The backend + is used as follows: + + 1. The backend's ``registration_allowed()`` method will be called, + passing the ``HttpRequest``, to determine whether registration + of an account is to be allowed; if not, a redirect is issued to + a page indicating that registration is not permitted. + + 2. The form to use for account registration will be obtained by + calling the backend's ``get_form_class()`` method, passing the + ``HttpRequest``. To override this, pass the keyword argument + ``form_class``. + + 3. If valid, the form's ``cleaned_data`` will be passed (as keyword + arguments, and along with the ``HttpRequest``) to the backend's + ``register()`` method, which should return a ``User`` object + representing the new account. + + 4. Upon successful registration, the backend's + ``post_registration_redirect()`` method will be called, passing + the ``HttpRequest`` and the new ``User``, to determine the URL + to redirect to. To override this, pass the keyword argument + ``success_url``. + + **Context** + + ``form`` + The form instance being used to collect registration data. + + This view uses ``RequestContext``, so variables populated by + context processors will also be present in the context. + + :param backend: The dotted Python path to the backend class to use. + :type backend: string + :param disallowed_url: The URL to redirect to if registration is + not permitted (e.g., if registration is closed). This should be + a string suitable for passing as the ``to`` argument to + `Django's "redirect" shortcut + `_. If + not specified, this will default to ``registration_disallowed``. + :type disallowed_url: string + :param extra_context: Optionally, variables to add to the template + context. Any callable object in this dictionary will be called + to produce the final result which appears in the context. + :type extra_context: dict + :param form_class: The form class to use for registration; this + should be some subclass of ``django.forms.Form``. If not + specified, the backend's ``get_form_class()`` method will be + called to obtain the form class. + :type form_class: subclass of ``django.forms.Form`` + :param success_url: The URL to redirect to after successful + registration. This should be a string suitable for passing as + the ``to`` argument to `Django's "redirect" shortcut + `_. If + not specified, the backend's ``post_registration_redirect()`` + method will be called to obtain the URL. + :type success_url: string + :param template_name: Optional. A custom template name to use. If + not specified, this will default to + ``registration/registration_form.html``. + :type template_name: string diff --git a/src/django-registration/registration/__init__.py b/src/django-registration/registration/__init__.py new file mode 100644 index 0000000..bdb490c --- /dev/null +++ b/src/django-registration/registration/__init__.py @@ -0,0 +1,14 @@ +VERSION = (0, 8, 0, 'alpha', 1) + +def get_version(): + version = '%s.%s' % (VERSION[0], VERSION[1]) + if VERSION[2]: + version = '%s.%s' % (version, VERSION[2]) + if VERSION[3:] == ('alpha', 0): + version = '%s pre-alpha' % version + else: + if VERSION[3] != 'final': + version = "%s %s" % (version, VERSION[3]) + if VERSION[4] != 0: + version = '%s %s' % (version, VERSION[4]) + return version diff --git a/src/django-registration/registration/admin.py b/src/django-registration/registration/admin.py new file mode 100644 index 0000000..d7626d7 --- /dev/null +++ b/src/django-registration/registration/admin.py @@ -0,0 +1,46 @@ +from django.contrib import admin +from django.contrib.sites.models import RequestSite +from django.contrib.sites.models import Site +from django.utils.translation import ugettext_lazy as _ + +from registration.models import RegistrationProfile + + +class RegistrationAdmin(admin.ModelAdmin): + actions = ['activate_users', 'resend_activation_email'] + list_display = ('user', 'activation_key_expired') + raw_id_fields = ['user'] + search_fields = ('user__username', 'user__first_name') + + def activate_users(self, request, queryset): + """ + Activates the selected users, if they are not alrady + activated. + + """ + for profile in queryset: + RegistrationProfile.objects.activate_user(profile.activation_key) + activate_users.short_description = _("Activate users") + + def resend_activation_email(self, request, queryset): + """ + Re-sends activation emails for the selected users. + + Note that this will *only* send activation emails for users + who are eligible to activate; emails will not be sent to users + whose activation keys have expired or who have already + activated. + + """ + if Site._meta.installed: + site = Site.objects.get_current() + else: + site = RequestSite(request) + + for profile in queryset: + if not profile.activation_key_expired(): + profile.send_activation_email(site) + resend_activation_email.short_description = _("Re-send activation emails") + + +admin.site.register(RegistrationProfile, RegistrationAdmin) diff --git a/src/django-registration/registration/auth_urls.py b/src/django-registration/registration/auth_urls.py new file mode 100644 index 0000000..9bb1bc3 --- /dev/null +++ b/src/django-registration/registration/auth_urls.py @@ -0,0 +1,58 @@ +""" +URL patterns for the views included in ``django.contrib.auth``. + +Including these URLs (via the ``include()`` directive) will set up the +following patterns based at whatever URL prefix they are included +under: + +* User login at ``login/``. + +* User logout at ``logout/``. + +* The two-step password change at ``password/change/`` and + ``password/change/done/``. + +* The four-step password reset at ``password/reset/``, + ``password/reset/confirm/``, ``password/reset/complete/`` and + ``password/reset/done/``. + +The default registration backend already has an ``include()`` for +these URLs, so under the default setup it is not necessary to manually +include these views. Other backends may or may not include them; +consult a specific backend's documentation for details. + +""" + +from django.conf.urls.defaults import * + +from django.contrib.auth import views as auth_views + + +urlpatterns = patterns('', + 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'), +) diff --git a/src/django-registration/registration/backends/__init__.py b/src/django-registration/registration/backends/__init__.py new file mode 100644 index 0000000..0f2ec4b --- /dev/null +++ b/src/django-registration/registration/backends/__init__.py @@ -0,0 +1,32 @@ +from django.core.exceptions import ImproperlyConfigured + + +# Python 2.7 has an importlib with import_module; for older Pythons, +# Django's bundled copy provides it. +try: + from importlib import import_module +except ImportError: + from django.utils.importlib import import_module + +def get_backend(path): + """ + Return an instance of a registration backend, given the dotted + Python import path (as a string) to the backend class. + + If the backend cannot be located (e.g., because no such module + exists, or because the module does not contain a class of the + appropriate name), ``django.core.exceptions.ImproperlyConfigured`` + is raised. + + """ + i = path.rfind('.') + module, attr = path[:i], path[i+1:] + try: + mod = import_module(module) + except ImportError, e: + raise ImproperlyConfigured('Error loading registration backend %s: "%s"' % (module, e)) + try: + backend_class = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured('Module "%s" does not define a registration backend named "%s"' % (module, attr)) + return backend_class() diff --git a/src/django-registration/registration/backends/default/__init__.py b/src/django-registration/registration/backends/default/__init__.py new file mode 100644 index 0000000..59b3da7 --- /dev/null +++ b/src/django-registration/registration/backends/default/__init__.py @@ -0,0 +1,139 @@ +from django.conf import settings +from django.contrib.sites.models import RequestSite +from django.contrib.sites.models import Site + +from registration import signals +from registration.forms import RegistrationForm +from registration.models import RegistrationProfile + + +class DefaultBackend(object): + """ + A registration backend which follows a simple workflow: + + 1. User signs up, inactive account is created. + + 2. Email is sent to user with activation link. + + 3. User clicks activation link, account is now active. + + Using this backend requires that + + * ``registration`` be listed in the ``INSTALLED_APPS`` setting + (since this backend makes use of models defined in this + application). + + * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying + (as an integer) the number of days from registration during + which a user may activate their account (after that period + expires, activation will be disallowed). + + * The creation of the templates + ``registration/activation_email_subject.txt`` and + ``registration/activation_email.txt``, which will be used for + the activation email. See the notes for this backends + ``register`` method for details regarding these templates. + + Additionally, registration can be temporarily closed by adding the + setting ``REGISTRATION_OPEN`` and setting it to + ``False``. Omitting this setting, or setting it to ``True``, will + be interpreted as meaning that registration is currently open and + permitted. + + Internally, this is accomplished via storing an activation key in + an instance of ``registration.models.RegistrationProfile``. See + that model and its custom manager for full documentation of its + fields and supported operations. + + """ + def register(self, request, **kwargs): + """ + Given a username, email address and password, register a new + user account, which will initially be inactive. + + Along with the new ``User`` object, a new + ``registration.models.RegistrationProfile`` will be created, + tied to that ``User``, containing the activation key which + will be used for this account. + + An email will be sent to the supplied email address; this + email should contain an activation link. The email will be + rendered using two templates. See the documentation for + ``RegistrationProfile.send_activation_email()`` for + information about these templates and the contexts provided to + them. + + After the ``User`` and ``RegistrationProfile`` are created and + the activation email is sent, the signal + ``registration.signals.user_registered`` will be sent, with + the new ``User`` as the keyword argument ``user`` and the + class of this backend as the sender. + + """ + username, email, password = kwargs['username'], kwargs['email'], kwargs['password1'] + if Site._meta.installed: + site = Site.objects.get_current() + else: + site = RequestSite(request) + new_user = RegistrationProfile.objects.create_inactive_user(username, email, + password, site) + signals.user_registered.send(sender=self.__class__, + user=new_user, + request=request) + return new_user + + def activate(self, request, activation_key): + """ + Given an an activation key, look up and activate the user + account corresponding to that key (if possible). + + After successful activation, the signal + ``registration.signals.user_activated`` will be sent, with the + newly activated ``User`` as the keyword argument ``user`` and + the class of this backend as the sender. + + """ + activated = RegistrationProfile.objects.activate_user(activation_key) + if activated: + signals.user_activated.send(sender=self.__class__, + user=activated, + request=request) + return activated + + def registration_allowed(self, request): + """ + Indicate whether account registration is currently permitted, + based on the value of the setting ``REGISTRATION_OPEN``. This + is determined as follows: + + * If ``REGISTRATION_OPEN`` is not specified in settings, or is + set to ``True``, registration is permitted. + + * If ``REGISTRATION_OPEN`` is both specified and set to + ``False``, registration is not permitted. + + """ + return getattr(settings, 'REGISTRATION_OPEN', True) + + def get_form_class(self, request): + """ + Return the default form class used for user registration. + + """ + return RegistrationForm + + def post_registration_redirect(self, request, user): + """ + Return the name of the URL to redirect to after successful + user registration. + + """ + return ('registration_complete', (), {}) + + def post_activation_redirect(self, request, user): + """ + Return the name of the URL to redirect to after successful + account activation. + + """ + return ('registration_activation_complete', (), {}) diff --git a/src/django-registration/registration/backends/default/urls.py b/src/django-registration/registration/backends/default/urls.py new file mode 100644 index 0000000..c1c75a2 --- /dev/null +++ b/src/django-registration/registration/backends/default/urls.py @@ -0,0 +1,54 @@ +""" +URLconf for registration and activation, using django-registration's +default backend. + +If the default behavior of these 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.backends.default.urls')), + +This will also automatically set up the views in +``django.contrib.auth`` at sensible default locations. + +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. + +""" + + +from django.conf.urls.defaults import * +from django.views.generic.simple import direct_to_template + +from registration.views import activate +from registration.views import register + + +urlpatterns = patterns('', + url(r'^activate/complete/$', + direct_to_template, + {'template': 'registration/activation_complete.html'}, + name='registration_activation_complete'), + # 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, + {'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_activate'), + url(r'^register/$', + register, + {'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_register'), + url(r'^register/complete/$', + direct_to_template, + {'template': 'registration/registration_complete.html'}, + name='registration_complete'), + url(r'^register/closed/$', + direct_to_template, + {'template': 'registration/registration_closed.html'}, + name='registration_disallowed'), + (r'', include('registration.auth_urls')), + ) diff --git a/src/django-registration/registration/backends/simple/__init__.py b/src/django-registration/registration/backends/simple/__init__.py new file mode 100644 index 0000000..5e8c35b --- /dev/null +++ b/src/django-registration/registration/backends/simple/__init__.py @@ -0,0 +1,64 @@ +from django.conf import settings +from django.contrib.auth import authenticate +from django.contrib.auth import login +from django.contrib.auth.models import User + +from registration import signals +from registration.forms import RegistrationForm + + +class SimpleBackend(object): + """ + A registration backend which implements the simplest possible + workflow: a user supplies a username, email address and password + (the bare minimum for a useful account), and is immediately signed + up and logged in. + + """ + def register(self, request, **kwargs): + """ + Create and immediately log in a new user. + + """ + username, email, password = kwargs['username'], kwargs['email'], kwargs['password1'] + User.objects.create_user(username, email, password) + + # authenticate() always has to be called before login(), and + # will return the user we just created. + new_user = authenticate(username=username, password=password) + login(request, new_user) + signals.user_registered.send(sender=self.__class__, + user=new_user, + request=request) + return new_user + + def activate(self, **kwargs): + raise NotImplementedError + + def registration_allowed(self, request): + """ + Indicate whether account registration is currently permitted, + based on the value of the setting ``REGISTRATION_OPEN``. This + is determined as follows: + + * If ``REGISTRATION_OPEN`` is not specified in settings, or is + set to ``True``, registration is permitted. + + * If ``REGISTRATION_OPEN`` is both specified and set to + ``False``, registration is not permitted. + + """ + return getattr(settings, 'REGISTRATION_OPEN', True) + + def get_form_class(self, request): + return RegistrationForm + + def post_registration_redirect(self, request, user): + """ + After registration, redirect to the user's account page. + + """ + return (user.get_absolute_url(), (), {}) + + def post_activation_redirect(self, request, user): + raise NotImplementedError diff --git a/src/django-registration/registration/backends/simple/urls.py b/src/django-registration/registration/backends/simple/urls.py new file mode 100644 index 0000000..0e733cd --- /dev/null +++ b/src/django-registration/registration/backends/simple/urls.py @@ -0,0 +1,38 @@ +""" +URLconf for registration and activation, using django-registration's +one-step backend. + +If the default behavior of these 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.backends.simple.urls')), + +This will also automatically set up the views in +``django.contrib.auth`` at sensible default locations. + +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. + +""" + + +from django.conf.urls.defaults import * +from django.views.generic.simple import direct_to_template + +from registration.views import activate +from registration.views import register + + +urlpatterns = patterns('', + url(r'^register/$', + register, + {'backend': 'registration.backends.simple.SimpleBackend'}, + name='registration_register'), + url(r'^register/closed/$', + direct_to_template, + {'template': 'registration/registration_closed.html'}, + name='registration_disallowed'), + (r'', include('registration.auth_urls')), + ) diff --git a/src/django-registration/registration/forms.py b/src/django-registration/registration/forms.py new file mode 100644 index 0000000..4161183 --- /dev/null +++ b/src/django-registration/registration/forms.py @@ -0,0 +1,123 @@ +""" +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 _ + + +# 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 avoid defining a ``save()`` method -- the actual + saving of collected user data is delegated to the active + registration backend. + + """ + username = forms.RegexField(regex=r'^\w+$', + max_length=30, + widget=forms.TextInput(attrs=attrs_dict), + label=_("Username"), + error_messages={'invalid': _("This value must contain only letters, numbers and underscores.")}) + email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, + maxlength=75)), + label=_("Email address")) + password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_("Password")) + password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), + label=_("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(_("A user with that username already exists.")) + + 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(_("The two password fields didn't match.")) + return self.cleaned_data + + +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': _("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(_("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', + 'yahoo.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(_("Registration using free email addresses is prohibited. Please supply a different email address.")) + return self.cleaned_data['email'] diff --git a/src/django-registration/registration/locale/ar/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/ar/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..07bc79f1242872c701e463e947846ef4e77f8ceb GIT binary patch literal 2135 zcmb`GO>Y}j6oxO*QffYhKrCQ!#Dcy6I+Tvl^ALK%-lJj?>YYCZ?1GEo`4N|6c3G!#`-*whp((Yy+m z-Kr90Rd=-srEvqF+S>K&w8ZwRDP50btrjY+l_pnHD-0U$E!U`8n&vzuwIbbawY(LQ zRCAY>RH%G2>X;Ul20TZCaVY6=c`M{{PW8Cq;1c?>sfHsNd0Y8MfvSxlKzY&+&~%s< z3w;kwRq0dUqvmSh8;Sg$GDd~^BKhs+Ej+}Uwf!0%s{xu9H-k1c+uDo@2_FavRl`_7 z6&~A}l@|1d*qUo>Nv*#O!Wt=AZIE%BO312lmlMTrs}(V#ju_YN1^9MlBqu` z3}eal)QN{$utM<<%OvK);0skXPNC*3qAg51OLMuYPjWZ%w3si?7iMQtWz`Bo)NRVSxU{#R-7r!ir2%LmPTdiQYQ1hlbLYFCTMIT`)+OY?*SF{c@gpRgwgbFt8Js8F>X~IztA(6go@3S{MAyi!7zXaki z`?ib9SJPtHfr}r`&fN@Gz>eI+M)JVgbpEe0pa?4w3p@}92mg_=6F0I0Ju$062%PoO ziTdj-=q`RB&d+EWA|2cDEQeAJX4!#dFIu(VvSp8Z~sGVt;dyNyAm~cwR)@sXJ^ro7AAbs!, 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/src/django-registration/registration/locale/bg/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/bg/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..be9adf4d3defce5ee8274e2cb996d8c63100a637 GIT binary patch literal 2302 zcmb7D&u<$=6doW@Fi;QzaR9^<5~875V>f~(ZmF7vP(`Gvl{yh{sV4TsUSjWByJOP` zA(6DAr3iwAdZ{XbxNzX&{4lZNB)uWH&7P6C@E7nG!1reTBZ0IME3dzqH*eni-uK@A z@yx(2f#+$wFXFv}_jz7FfImD}fDUj8cp3O3a2j~zK_T7(&H+yWzXHAn{0%q={0n## z_`*X%JPCXq_$Y7$$hpRV&jM$F&jE|T0pO=V_FDml$n_;~9{ay>_!DscVQ>K+eME>4 zfj5Ak0RIG*fR~TNe0~KI_5%p^67W^v6Torc%fKv)zd)B%POgAO_ox=SUXd2qUsa@ACRr#1DhyRfZb;R@FS+xsR)r*G z%Swid!dkUjULr{acVR&V%F_ogCPl7F<(e>{w z=$I^m=%9!*by|gHEVyNLs4*0*ko{wsL^kk0QhDu67MwYhg-&NEJ2w8_*!c;Xo0z#Y zd2u>1qpE(OoeN>nEjZ_D#n8$58A@a?=A3c#ipRrwM{1R!6RFfmCpGG%M=3p;8BRH= zH&ZD%Iy0*7a`3+2h?5$|F{MvrhEE<(;bvk=hT6#m(hJK{`$2~0%Cg{MQ>WAQ?lM_% zwO>D5(==_0mZO_yhfJ%xvW5-QHjQW*9=otp zbQSBi*)!{=6|F`qra@+l|C(kSCwJ{xgYD7h>>QV38zq2l?C4Dw%aKUWaiL?lvNOZGl6}*0j4XSdV5K z{@a$z9s=$%_q)*G3)2whn_g;I?Gc3ew?7xxyJH!)Yzg25TxXv5*S$l>O^8Fs#qL1Y4YX*5 zplBl=gU#qB!u}jv*Fb!mTR%j$z1MJrCgBGOQ5XgZ#X%qVY@3!aKVZ8GYEY#YGj2UP z*BveH`u#>L=E4KR`t)b1g*{JA6GeW@XVDF0<=(`!7=lZ!h414IQ&Y_AwX~$h^OT_-o)f, 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/src/django-registration/registration/locale/da/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..9478680094ac7936d9bc9c4ee8fc684061f52a87 GIT binary patch literal 1803 zcmb7^&u$z=5XKuY5SIT591tMY1!60iu}Ln*gvfDhkfj(bvx!75sCTD!wzECmtL~n4 z_P`s!5y6cYKnSiJf@DrS0*VxIL*jzOi6dXl?5?wdOIn`&&GdA4ee+e7ADmtJN@1ME z^#-o*aJ`A^%47J!_yJr4e*|9u?}N{Se}WnK4|oQA`*EdS0@uOUz-{m|@HY4s_!IaM z_&azNTz{h7=fLxLJ_hCdZ^2i<@4;8WU%(acH}DK%JpeD``43FK2)_PgtLFl^isyGh z(bEH821lUi`5e3rehm`%H@FR+drGNIunTs;FToA)8&LND3Z4V+gQDv%5PxdrX{8`X zJ&Q}cdk)up$al;KmMKVXJd-)`NCv_$#xuB+STbNwGbD!Sk#CV99?18qYg9)LbZpX) z(om=7(dmjw+rYY*65lm3#avzMCo|EBn-x**RoYn6MG-hgwNFDmVUiuB9j-DkQ}Q^I zsmq~?9`%o-yXjPZmxHWaeS!CJY1~c9fOQ481C3FOxWUh|Jl{AnT z&Fi@ij$|T@gCClnNnGS~Xjw<5SdYhcN}38Y7;s>hmN(|A3!&-Q(|D$h28L}Bv7vD1 z6ID9(hq4OiFNKtVbE}Lf<3|dL-4ktVrmBvK`rak@K;A*D<&-$Yi{$F6hnvRO+7-C% zd$^vfn@FAHN`30<_JAedu^YZ438C?hgL=r;5l>Y+Kl2o>4UFagos3GVL>&fyhx;kp zFS1)uflO>saYwt-XG=$INer}uAmKgc#u*GYVoOSb3wzCg)s z(I)Duqjn);V2}#Qy+u70C`3oSP?va9aY2P7Z#Lod#G!vi=pVdo7qQyQq_B0 zAbWBTRp3k1f1k(5pRDJE$ZRFooG)5taYL&mzDbvB>O*#I^R$t$D=s$=2WcCTS4z@n zl{}LW2*J!~B&BFgnR2>ya?h4DVTVV^!Uv+Y@!K3a7rx7MY0)$Twh+BI2zqjO<&e3D z_sIK&ZKg3KryX|F^xt4PDaZ(gLEP%(3mVmq#Q34N@Vw_C4F7n-MM~O=ai{%}tDPnt x;=bCgDUPsW;p?)kH1Lp=7LCI5Y>9{N, 2007-2009. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: django-registration 0.8 \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Rune Bromer \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin.py:23 +msgid "Activate users" +msgstr "Aktiver brugere" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "Gensend aktiveringsemails" + +#: forms.py:35 +msgid "Username" +msgstr "Brugernavn" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "V¾rdien mŒ kun indeholde bogstaver, tal og underscore." + +#: forms.py:39 +msgid "Email address" +msgstr "E-mailadresse" + +#: forms.py:41 +msgid "Password" +msgstr "Password" + +#: forms.py:43 +msgid "Password (again)" +msgstr "Password (gentag)" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "Der findes allerede en bruger med dette brugernavn." + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "De 2 passwordfelter er ikke ens." + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "I har l¾st og accepterer betingelserne." + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "Du skal acceptere betingelserne for at registere" + +#: forms.py:95 +msgid "" +"This email address is already in use. Please supply a different email " +"address." +msgstr "" +"Denne emailadresse er allerede i brug. Benyt venligst en anden. " + +#: forms.py:122 +msgid "" +"Registration using free email addresses is prohibited. Please supply a " +"different email address." +msgstr "" +"Registrering med gratis emailadresser er ikke muligt. V¾lg venligst en " +"anden emailadresse" + +#: models.py:165 +msgid "user" +msgstr "bruger" + +#: models.py:166 +msgid "activation key" +msgstr "Aktiveringsn¿gle" + +#: models.py:171 +msgid "registration profile" +msgstr "Registreringsprofil" + +#: models.py:172 +msgid "registration profiles" +msgstr "Registreringprofiler" diff --git a/src/django-registration/registration/locale/de/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..b272d4463c4efb5dec112c20a9fec3364013adfc GIT binary patch literal 1999 zcmbW1O>Z1E7{?8ix8=RONJt<(97Jg6dO_ZqXJ_2ZcviM2 z+vLnAK;p!KFMz6Y0SR%7#F0BfsyO$=kt6?Sb~kCNT)>j|XV2Px{(fHk;Ov=i71~+! zchG-8e;0l63H+el2QPv@f-i%Af-iv&K@I)`J_o-4q*AYfv*6p{GWZpE8$1X80$vCI z0++zqr^fpncpmc+DCd6%EA={f1C)IUcp3Dd=(z{J z1^x`a2mTI5@NaMi}0M zCMLP8!ucmmiovO?tSICEWE8viOi?qHb%>NyF2WB~IfyMdM)qNbTwV4tXdGL+6vL!~ z*V}3bp_5ptFROZdzzM%&H~fwu_{Mka)gx}*<$X2&KJh8MHn0Vs`Y|ZU61C;4JDfzl zk?Jp?0+HxaddIk|(kG7Uv=^wg&BMw^y%{o_>eV_6x>t3nwRNMXuOLq(j(QFG)TQ}O z=aQc5=(z=&pX+`&|3L>|uuyOFo)s&{>psy~I)91gKJI?h8Lzu$LexEPTqsPee3w2q z&cUtM*rr_2BJ^RpTr|_Rb%ScDbq$(pld@1;Ih$=-&Piq9fmpv%><>x=cxKeBk)$PVcH-I9?~3kZgM0B~^-q?a~6WvZdB6 zOUpIuu`myp>-@mWb+wXQc&5PGF4JXRafotr)*QJJpe zz}jU2C$M#W<1wL(3)n+yqOL-;C2HH|o(}41`Ng9FT^LzLg5_1gsK%9vRXI|R?Gp6D zTO?HqF}Mm%Dii9&T4_;Q*5Q7;Re-;WN^GAL-Q2c@H+?W!Y}2Ymrb8$0OgC|&?3ZlE zEgs)#;1x02mvB02UXsI~JdPr~2`M?7, 2007-2009. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: django-registration 0.8 \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-10-18 21:32+0200\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" + +#: admin.py:23 +msgid "Activate users" +msgstr "Benutzer aktivieren" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "Aktivierungs-E-Mail erneut senden" + +#: forms.py:35 +msgid "Username" +msgstr "Benutzername" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Dieser Wert darf nur Buchstaben, Ziffern und Unterstriche enthalten." + +#: forms.py:39 +msgid "Email address" +msgstr "E-Mail-Adresse" + +#: forms.py:41 +msgid "Password" +msgstr "Passwort" + +#: forms.py:43 +msgid "Password (again)" +msgstr "Passwort (wiederholen)" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "Dieser Benutzername ist bereits vergeben." + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "Die beiden Passwörter sind nicht identisch." + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "Ich habe die Nutzungsvereinbarung gelesen und stimme ihr zu" + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "Sie müssen der Nutzungsvereinbarung zustimmen, um sich zu registrieren" + +#: forms.py:95 +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:122 +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:165 +msgid "user" +msgstr "Benutzer" + +#: models.py:166 +msgid "activation key" +msgstr "Aktivierungsschlüssel" + +#: models.py:171 +msgid "registration profile" +msgstr "Registrierungsprofil" + +#: models.py:172 +msgid "registration profiles" +msgstr "Registrierungsprofile" diff --git a/src/django-registration/registration/locale/el/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..acc972683e0c03dee9cf816301d9653f1f8bccc3 GIT binary patch literal 2424 zcmbtUO>Y}j6n#LUU_Mn55CWvjiner&-4aOLQq?4G72%{Iae}&n7yHE?YR_0Rr3E=*#C^fI`E}Oh1drE3j7@S z^Ay7hpLKr003n)neQLJQGD1v#e3Q!+==!JGG#qQIq~ zpeUofl27g^4JvQU&MGmW^0ps%GO%5TD!%RHX_Wm{N!mq{xtynbU-@MFRQBA0Jz@tc z7p4B9lD;CpQZ5(ANm9-p9aWxkg2NZ1B2&Q4L%}$dEHb@uvN@-E&~UioIkKbm(g!D+h>kt>HD9$UXGN^7AUYwO2}+rk2N}eU5$%F z-4XZvTMIfV^B{UkG%__ug<*`^MRlan7u+H9!)+4%p8JW)23Akb8b(=|bb|VmUGFEa zq-Z!bFxYdoFEXIYt`}Ine%{Vm?^W`?m2ndk>A#w>x-cu2ht(|um7ue+*gICN(~5Ue zyfbkwX2sfLF*sTSYRu-~2mRu4EB+RpjVIb;Z^Upjl9qm8WjyKlMH#qWf-VoG)6|#j zP0@u^Z?Y$SDcRjUkQyAk2v;Xxk$Gihlq@AEo$R|Z#FQ_j)0c{N)b;WgBfUMnsr{nj z(O9GlbA=AA45pBvK-~!5EEmzg^OP+}&sV{_Lz&A~$G#tPfp)EwlXY{@e}Xz7@`%vi z=q+8ovVa;dD5wcf+}GUf07V(z|+-!Wq36&W2N@7sAQr61Ey!eheqD znADpHvWiesLf<64sn_*7tZU(%Ug03ih&xYuBb;Ynq^)Cv{F}&jCtO6XX{?cxbWQKT zV>_JTT)GaYZRA{J7Hi=b@ZT^8AclnCMKDi*`#LtvV-YW0^;VShEu4XcscnbL*$9`w zWClgSR>i$N#7FT}B;C=qD6=;$SjRcDn8Z2ggGcQi<3%u@HH=|;V74e>5*?d1arc@G zP)dU{=@s;)_TQ*~g(1y^3uayvE`akMxUZ2(xnk;p-79&Gyq~(CEY~Z!T!`R$l`<%-gBm1RRIfs7F)Qt z%HLPrG>tXS8eTPu!UrjuU)BH8s4!o^KUm$zOeghSOs=l0r$jhmW;+K$JAeBZ0Jr;| PvNps)m9q2E`W1fx4LxjP literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/el/LC_MESSAGES/django.po b/src/django-registration/registration/locale/el/LC_MESSAGES/django.po new file mode 100644 index 0000000..cd38eb1 --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/en/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..87b6226b0474fd7c3200c643a899749a0a765975 GIT binary patch literal 367 zcmYL^K~KUk7=|%=+R?Lz9=z#?9gzeo5-KaW*llDC61`QZa|YX`D@K2af6w3Ix5UVs zJZY0Y{rdLj^yIsPIYQ2mbL1GgMA{6HJ{}HnZJqxtoPE<95Ahb(+BKCmj4b%{fzJh5 zi+mYpX^`vMIuA)xR$I8+mkkt_kzkP(Fm+mayabW*nvou*LkKB^JrZ6s+|xd#C_=73 zs&@FF_b7M{Nd^%o_Zds#i>E9VfmDr$!YR}2l(&wN*-A>1@Rm@;;@Y*gf+JP_|yRA&g$l$s1LFX3&>0-11 literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/en/LC_MESSAGES/django.po b/src/django-registration/registration/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..e357a4c --- /dev/null +++ b/src/django-registration/registration/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,89 @@ +# 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: 2009-10-12 14:09-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" + +#: admin.py:23 +msgid "Activate users" +msgstr "" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "" + +#: forms.py:35 +msgid "username" +msgstr "" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "" + +#: forms.py:39 +msgid "Email address" +msgstr "" + +#: forms.py:41 +msgid "Password" +msgstr "" + +#: forms.py:43 +msgid "Password (again)" +msgstr "" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "" + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "" + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "" + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "" + +#: forms.py:95 +msgid "" +"This email address is already in use. Please supply a different email " +"address." +msgstr "" + +#: forms.py:122 +msgid "" +"Registration using free email addresses is prohibited. Please supply a " +"different email address." +msgstr "" + +#: models.py:165 +msgid "user" +msgstr "" + +#: models.py:166 +msgid "activation key" +msgstr "" + +#: models.py:171 +msgid "registration profile" +msgstr "" + +#: models.py:172 +msgid "registration profiles" +msgstr "" diff --git a/src/django-registration/registration/locale/es/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3872adf0a0eed30b1ec9fa6410addb3c6db915cf GIT binary patch literal 1909 zcmb7^zmFU>6vqt&0tegqGU+h77t!JFWZ;78!eM}>GBybfLfzX4wZe+4(dzrkn0R~{4M6!<#$ zB)A1eU+;l0fCu1F{1NXF zZN>rf0-<&z#=jiVCZrGuv(uvoK7}cEXe=j8j%7j8V3v-Vf~7EK%GuSP?1-+in`p)2 zfJ^OzlR;ZUt=FccQQXh9)D_91aO^#M(w-V;$NEqQE>haBSb8SkHcd4pNrfJb*s%%g z2UC%cadORAG$pGT-jsCo$^X|JjyNN0UbPhDEjITIsj;;PPa2C$yHs3TobaTiA!`t` zvL;CQuQ&vD{ydqsKE$HatThFe%Hs0k6WdbV`min}&Ok`0>N)}09q$X%26{tmA7gB! z_n%o;5KA?tplcRV1wEN7ev7AKO&zh^e{VtOWQjmG#N5*&RY=B2SNyLZy@(2Rk0_Ja zclL-?NOp?kIT=Udyi}TgUrigedJ~Xp}9`9s}A!5A?)` zjMAC?Tv$T=D{c^ZWl<5cpIogCRs{;6Ycg%cuv*lKvnY6UC17ILI95u}?wYt8<>uHD zSICvax2QuI(~So5VfOv90SlY%TSp@~!4q|Wd?~0c$)b-}Y^Gv&_4U78Oy$D7*W3l> zWg*c?OBWCIF!X`R*!s|MwBPzxIt@vdHmzzKiGYvI!I`op$6&44g--L+onDLMp8V`? zWvOYoVAFLf8+Nf(os6A2`=w@wqf;td+#Ekohw{jJk>dt<`Lspr$COB%S<6Wyq0qAC zUEtLd+90B$RT_sR)!Nsxa}Ad~yMr}kp$UI3R26?;aoc$xcli?!r1HK@iuil8Ftxg- fb6wV8cSAJn(9_ZKB1F6RggdQ%T*xFI&|UlkAoEAZ literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/es/LC_MESSAGES/django.po b/src/django-registration/registration/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..ba0384f --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ce8b4e56c8250021193dd307b05b803d3fbba025 GIT binary patch literal 1849 zcmb7^&2Jk;7{&)E6wFttKp=s{dus!%aX^K{O{18^ZLQi#&=%4NF8bRH{P9j=ACEW*AFgV_)4H% zLVpeYYxI}H_z^tN?t>9H13v=41vkNqj|%Y~xCdSbzXY#3R>7aZ9{4A?2HtpL zzW--n(EqOHFW}So{X6&y_yD{N{#Ac(T*R61`*l2C0Iz`9zG@->N8%jtXlgYF~LynzWsLqYE6<1pDVc@vW~9QN{IGIZVztcqw33(iSRV_;6Jrpb)CPyPO|e_Aa1={TMkD6f zXfLsU#@@4aZ;>wZeGDqkN}XUB8ysHTH6`Vx^Jk638W;&zZDk&g zAw8lE>A6ksv|8^+t>tKOnHHDZ@3x}WwN?ugqajaK5U=Om?RJLIU@O|_(Cw}Ep!ep7 zTbtcRUpgO+tkf=(-q<$X-0k;ivoq+@N_Wud_18KZ8^i9-&MKzrw3I1FBbIra`kl>N zyCLM2et#`fO=Hv5#-KOoo*Zhi*=nrgUXh2<2)EEC&-eY?MF#(_Q#_H@vA?l9x*08< z%nPv~ccZS3O@jPy(-M-rA#O8r%_1!R);_8YC)-qqpGe_++wMaJrF+p=BTm~i3B#5#&U`$T)&pt9gPPzbxnGihtQH{sFN^CdB{% literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.po b/src/django-registration/registration/locale/es_AR/LC_MESSAGES/django.po new file mode 100644 index 0000000..fb746b5 --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/fr/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f8911c7ec65960e02435383ea87d2d79adc420db GIT binary patch literal 1883 zcmb7^%WfP+6oxAh2n_cK#DXB5-NcX{+KvEwVxk0-fRPQBGq%JERl3gfl+#_+)McHPwJu=c?WJODojAAz5MmmU-19dH-C0e%bi!C%1z@GtOr@U_Q@$I z%iuQn3Rr>{!LPt{?rU%zvAzLU@%=mgSb~?Iz&`j8O#8opTi}H!g;)c(!LzhzY*T(Ov^(8Tx<|4}E7>5`cBTA} z7u*O)A&_RPM-O}&k65RPoH99VPCEJsz`T6Xp#EVl;u}oU`Og zRw=y$(kUkYUw1HZM%H}RQ;-kXoH!~b)*?M=EH3Q^V&}-hQy~pmgPaR%f<*j^Lty8x zk%{$vytJA{qwrc-TwZ);Bh}G|c_Co~A)%^k1!Q-6E*vz_8)EyEV)gq)_{lWD;A>?r{;ab(QVn zTB!7p)Sfh@&E|aOgX`4W=Ek~^ZTeEH?EP5!Y-ESj+xm2rt)XbCPqGhW;2|yL`MX)Z zk}a;#;>z%Pp5<@nISyvqJk=@6xpPZ7E#^4)X1<7X8`6htD=f?2$x6t&ZKTN)N0nZ}v9VH}9NYba9aP z)=+EoW;Q})h7@=|ywz0D^ad3Z={$$`c1Cxz<&Fs+0w5|F(L08(hs)>!hHokDWX=e>HT2M4-(r(0# zhD7zFL2uSgU@B4Ts4-G#K8+hV#K5rZa@1AD4~Y%7mHr~K>paEacp%nNN1t<>T&UUM z-t0$;ZA!Dl|Ky1p&r#Vng>&}viD2ST^OOh4E{zTJerJqJHXK7ca%^x28IyuOY4$K; z*H8xh|G--kwqgva!;H*+a+o0-D_ug-f!MVXlJXQc@5INolggOnWAUNhso>Pu=xCa( zI^i9Q6YWlfL%4eOGX}M`kf@tiWQPW5ohy#}sY~j{i=slgRsVE+#a!*gSr2m`bajfB g&|_V+ov4mQ|9dWdoy5{We@r5`#(djAv0Y}F-M*si- literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/fr/LC_MESSAGES/django.po b/src/django-registration/registration/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..34b520b --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/he/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/he/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..be936503238a6df8192233f1fe242e7e60d41895 GIT binary patch literal 1896 zcmb7C&u<$=6ds@uFh9i)Ayf|UMpL@R2?7Nd5KxMUs38h&MGqC4>^`rT*t^!uIIRy{ zxFRG+wEM2 z%$G5Tm@mru0sJs-00UqL_$BZF_$hGdL8aaVUICs5eg}L7_#1E;_!sag;OU2ydJ=dR z_$Y7 z1HOfA5BMDLci>CFd%yzl@9Fu{(xlGQK)HV%DEAfM)4(r)2%ith{|QXVPwtL})baRq z16qYt^C9^k4bUh^p^#>-hs1acQ>{~7?=TtG5$O~&Hq7KQa&@LEo2I3#MxV3UNkUee z94FQp?UF2|woTHQYGTh#ois>Ckzs4uQevrPvU;+WIF5?6(O_+vY`fKJbVyT_)M{)v zb&HNgRjtEwflR1$L(=O|A~E^@(!s@~y2Aryg*v4y zMb2TCI*s@Zc8-lbM`^pcg+;DeJB_dmGZe3`W^HP=ty>flJ`fVBnp{9OGdtI5L2rm{ zCC8Sw_IhR_Vjb4WB~4a3bji*{@ony?1$ESs{qcg%=opDEt4XA3tI&*E(%=&htrCUu zpU9*(O!gIrE?AF(D<}({E>F{*kQFw$l^GXQY@9^F2kqDf)vQc~jnAsV1vEF-e^p z3BBFK?!D%=&1$X~X2qoOZsC$n0{n9e7#UvuUwp!vQjJ+E})xueL)r4 zm&x%B_gbp~)y`8`*T%AY=W_L7t=6{@aoI7hNrFkfj{(JKlTIiec$tU z{Vl&Y*$x4BaEF_oANc{!`+lUbImBj!&293#{%8L^4#p%-*kW-LS6zQd_zl7TBd+^k z0?!XHxdWbom~|1X?+=S4Q3$4Y{k}gSBrwK#&eVkmxQlB3ur~|PyFbJjBz;izglPA_ z>E{wXiZha;dPs4EEby1Ia>D!Qc99#>mpb5#6i2y0C~VGofF$}TZ6LHm5Z}UbNGJ-0 zc5x-5;eU?u>P09J^r2cGU+y&qy$AvU{cQ!gh3%&an{;bReR8kRr-|i3?sijx=F&@K zNF)s(VD8CgALP=TJkB1r2rVXZj@;Eu_kT53%~, 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/src/django-registration/registration/locale/is/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/is/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..bccb71f63a9f5c116e21763deb0bd560da518ba5 GIT binary patch literal 1476 zcmb7@&yN&E6vs2W<_Fy*35q(O+uT6>*k1@m@S> zPmQyszM+F;U0SPzy^tR_O*JK^Oy{{cG2vifR}D)<9!M5baTUv(l8$@I%cet!GhEBF znF5c*JWZ6A)}lN%7EQaZ`qqxA9{WIH+F%wKgpctJdwl0lYiit{*yKCN9^x_ar# zGHoueZw#(q>#R#-T}W1ap|j-jxbVr)_NlXWeV8m^j`8S{&pAk+7J9vNNpC(`SfKfZ z{wL=??#=gla7@-^qGR&^^;=;dlA&YcD-PE6>GD>4&l$SvAQ5f6heSTTv1OeZIeoE+ z3hAb{{;adYrWkV}$xyiN(;$@!%F}6Qb+Ed;-`9M%*IBYAKqko$2hpb>KZG+)g%O^o zv}ETcT=;tUMY6c>7t4XPl4XTQVt7ImOzmBqZUZG633+?Z6kXaxhg?@uU@h~}-$BNC7`r(&Yr$a3>>AhJ&D%Q&e9lXDDvl9n{DiX> F)PM38!N~vs literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/is/LC_MESSAGES/django.po b/src/django-registration/registration/locale/is/LC_MESSAGES/django.po new file mode 100644 index 0000000..479e792 --- /dev/null +++ b/src/django-registration/registration/locale/is/LC_MESSAGES/django.po @@ -0,0 +1,74 @@ +# Icelandic translation of django-registration +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the django-registration +# package. +# Björn Kristinsson , 2009. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-01-22 12:49+0100\n" +"PO-Revision-Date: 2009-01-22 12:49+0100\n" +"Last-Translator: Björn Kristinsson \n" +"Language-Team: Icelandic\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: forms.py:36 +msgid "username" +msgstr "notandanafn" + +#: forms.py:39 +msgid "email address" +msgstr "netfang" + +#: forms.py:41 +msgid "password" +msgstr "lykilorð" + +#: forms.py:43 +msgid "password (again)" +msgstr "lykilorð (aftur)" + +#: forms.py:55 +msgid "This username is already taken. Please choose another." +msgstr "Þetta notendanafn er þegar á skrá. Vinsamlega reyndu annað." + +#: forms.py:67 +msgid "You must type the same password each time" +msgstr "Lykilorðin verða að vera eins " + +#: forms.py:90 +msgid "I have read and agree to the Terms of Service" +msgstr "Ég hef lesið og samþykki skilmálana" + +#: forms.py:107 +msgid "" +"This email address is already in use. Please supply a different email " +"address." +msgstr "Þetta netfang er þegar á skrá. Vinsamlegast notaðu annað netfang." + +#: forms.py:133 +msgid "" +"Registration using free email addresses is prohibited. Please supply a " +"different email address." +msgstr "Óheimilt er að nota ókeypis netföng. Vinsamlegast notaðu annað netfang." + +#: models.py:218 +msgid "user" +msgstr "notandi" + +#: models.py:219 +msgid "activation key" +msgstr "einkennislykill" + +#: models.py:224 +msgid "registration profile" +msgstr "skráningarprófíll" + +#: models.py:225 +msgid "registration profiles" +msgstr "skráningarprófílar" diff --git a/src/django-registration/registration/locale/it/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..83ec9ddb1646693415fb7b3a37786f84d642c655 GIT binary patch literal 1864 zcmb7^OLH7G5XS`x1eRyDM_5DFa>`A zqut-Z7r;NkX!im5GWa+6I(X*Xgcm@3Qp?~o;8hUUw=MerEPC`W+M2caj<`3rcowd< zE#5P0Fry%af}5=#9q?&%wM7FS2|3|{*r1nAgo33o5bBE?da?&}OWa83qV}ZJJ~$5A z8fv^YB^|{5GGtv57ljk=#gq0_J3G+(I!KYyZYAu6d{fuen3xKEa3D@hIDIfx{Q*v% zG8Rp772O+?j(5tVn!^!icqk_=1wIrrHh4w3;=hz%aLXy!yg6G;Dl0EhNrBNT}*s0mU8f3*#DkLu?;?tl9gott&`4 zA5hRkQJe=onkarKV|7X$HQPTQ&;plmbWu%inuZF&IM9{+??UOUr-PNSG zO1;(Woo>=y?sl;;*^`luHjnqMU@cj?LcQgzyL_>Wlbvn$A?Z6dzT#kAMmKeCE2eFB z)-zo-n0^rCFn&&rg!gd5lns}X^o55RZ3V70;@R2R+SxpQMlbDlt|5}hyrd7^GYWDq zT&gQ5wnq7YotLnFyMH5DIo=oDK(;2ECbtDLKBE<+b?5WsBQXMfqko@l@V->kOMAWa za%Z<{99PK=i=byjrf%nceQAv*!}SG2Z>&>qajm1S>wKW`E))f!5?z~OmZY862;7LB z;3L8DLLWgo9hcgQ#7u4TG^rfNMTx13N-4C{M@M>EOl8aiPXDfRtdCPir<$&|6k^d?3@=4KiXB~!YUOIc~W zV&+eZe<_#txIX^5-);$-iBbKDGrT8RzulYNg%0dUwc~` zCO#=Kq?<~tHm2*kRVYS)$%m-gagD-&rje}zs~AK4jm8*;Sgvg-)I*xhi*!Dq1)MOA d9oa=SsnIqMW{ys*OcvUxpI(?qqE5)E{sRa2Dzg9p literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/it/LC_MESSAGES/django.po b/src/django-registration/registration/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000..00129b0 --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/ja/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/ja/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e0332b0e7cce033c22f9b774b117cf5d78e6becd GIT binary patch literal 2035 zcmbu8%WoS+9LEPJl$!Do0)YgF;Y0(hS+_hAH&lg^Ng zr0i}=X&!2uCWHV|X@I08O+zW~0y!WdapjD-O#I-;f53OPb{s=fff#B0*`578zrXSC z_ivjaSodK+iv0ohL+be!{9p}(8dw5f0~f(p!R@ya@*H>++zU>EkAuH}ZQ!5aJ>Vm^ z5pp;91b8Rd4ys%)f)9ZG;DewEZUf&0m0bWHM6PjA<@psK$G{!86H)}H!3-F?gOC*X zI@ksN40eJ$w-fRh*bS=qgW$cO4?YZ@t#hf)pTHeB{|(#;RzReWma1Q!srpom#!`LU zRewQRf>NWU>TfKBA&`Qg+(?fYsPd3*nq@G%+A%Bj09(To4)Gp?a;~~y6`(i77OKVq6XFfWO;gT{EcL8BC(Q7yq3end@)BuLhcxUr9_TJ+qR=*S zJyU&D7)Hj*@f#irq7;gLluV@0bq2WMY29hoC;%`H-cu zH0|0oJ)!MM(1f1ctv{)Ez^;c0PfNMX7CGiQZjv6(T6T%iLxY$a?HnE!St0h97$zAv zocKUtA6#s+$V{%KILjyLE3Ck5jxl%k^z6@BamO|H#d^DYyP91l;(F`=291lUr7)Hx z_4u&&bRh>p_fjLvT*18;j-(E1?M*vX6E3sXWgAW!e~2V)$E}YM8GI?j?`3#S2H%$7 z{4fc1WICZ{zRkiMd_oy#_$^R zn3DlIIxhns5+QVb^8RvT;L4!9cA~Zb0}L#X!B{g2jHLgr49}{8hpW*oIEBfVPkd4y zdtcp?n>ec?1NgipgO6l57Zv}t3>RgH`d9EuZg>@N+LG???{rsn{=3@JWE-jX7|zNN X;V}0LGWb}A%Uget4XF{dDLVNJiZWT^ literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/ja/LC_MESSAGES/django.po b/src/django-registration/registration/locale/ja/LC_MESSAGES/django.po new file mode 100644 index 0000000..afaaf94 --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/ko/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/ko/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a29c7c3fb6f8ea2e27496d03402814559d11bb77 GIT binary patch literal 1947 zcmb7?%WoS+9LEPJFY_)Bfke^o0!>8LaUzh42~phCgor$>)Tz{7+O2o&EVXyd&N^uh zNFj1VlvpBAyG=?QC2FD)5s5@`MX1vMfCCp!NEH&|;vL_SxbPj@u@k8W7-{x1GduHp ze1E?O$Bz{l#&OIyF}E;JV0Jx%55_jw3hsc--1E#Pp}1i>&aSvec;R3kJf2|PhMMlN7|O2FP7TOY9SDc{FjelVHcAVn6AMvB zaEB&LcZ}RI-K}mdJ;g~+I$SpO6{opCe9Swt6N!gh?tf?D*1Zd$EuglmGU_cdpxZ4p1y`uiXbF31#=cI+|pvgvZePmv_o1t*b7r<0SUlVQf=+~Jmc z^r4?c5vV(1Q@S1-#Z8_x1RfaHNtaT(8yi!%VE>3qIh3Q;)RM;i}q0E)6Srcg47uZe4up%w2n^dcrS=`;Qc@V7qt;S zZYtyTd*{QU5p8f-I}@T$hJ%Cs?_L-l3i}3h;c8Jww?tBRZ6`<&13l3lbuNvQtu$Lv%$-dKr@p5R)P>!~0OgogS?RqR~@13gL8Z##)@-(de>xS3stKj7;{ zQP412bTW;oU4GSVPbX2O4=FaLJA%6(jYdD#PBrhTpwMJm*oxT(8Z}6#(2YJOizV;J zJt}W6$>J2rLRKB*^WNGr$>}Y5Yg4W)l((nIyT0SC6}^Q;d80&fWmeAJ_2y^2`E@_5 zEG>IqFEy`MZEogeai8SveL0h3vT(m#nv%sV$>M!^bGE#@O68yS$eS)H4>uPG24r!u zQrJ8&+Hg*l-1l;BU4EDIt}nC08)}g&TXN-^x4O})e3Dmpx{BCWvvOvQd0Qp#b`D-k z^?&8vtXwU~<$aZ4EvHIhQO>WEoLwY&bEcUWAvtejulZQTfA9nvAhqnCyp=x^lafki zm#gv>_vOz>X;I!$!p=1z^@Ead3P5|dUJWC@&l^Y zMi<*iE`I54p}c!jIPvb}Q0OUdZsV}fwc0dlKq}&Ed0E(3*AHDpnPqmTvXrOF^g62v YL6v+KxmI#HRQsW4jXJW%s@Y}iU&H$5Jpcdz literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/ko/LC_MESSAGES/django.po b/src/django-registration/registration/locale/ko/LC_MESSAGES/django.po new file mode 100644 index 0000000..d466420 --- /dev/null +++ b/src/django-registration/registration/locale/ko/LC_MESSAGES/django.po @@ -0,0 +1,89 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Young Gyu Park , 2009. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-10-12 14:09-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Young Gyu Park \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin.py:23 +msgid "Activate users" +msgstr "활동 사용자" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "이 메일 제 전송" + +#: forms.py:35 +msgid "username" +msgstr "사용자 아이디" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "이 곳에는 숫자, _, 영문 글자만 가능합니다." + +#: forms.py:39 +msgid "Email address" +msgstr "이메일 주소" + +#: forms.py:41 +msgid "Password" +msgstr "사용자 패스워드" + +#: forms.py:43 +msgid "Password (again)" +msgstr "패스워드 (재입력)" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "이미 같은 아이디로 사용자가 등록되어 있습니다." + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "패스워드가 서로 일치하지 않습니다." + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "약관을 읽었고 그 내용에 동의합니다." + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "약관에 동의 하셔야만 합니다." + +#: forms.py:95 +msgid "" +"This email address is already in use. Please supply a different email " +"address." +msgstr "이메일이 이미 사용중입니다. 다른 이메일을 등록해 주세요." + +#: forms.py:122 +msgid "" +"Registration using free email addresses is prohibited. Please supply a " +"different email address." +msgstr "무료 이메일 계정으로 등록하실 수 없습니다. 다른 이메일을 등록해 주세요" + +#: models.py:165 +msgid "user" +msgstr "사용자" + +#: models.py:166 +msgid "activation key" +msgstr "활성화 키" + +#: models.py:171 +msgid "registration profile" +msgstr "등록 프로파일" + +#: models.py:172 +msgid "registration profiles" +msgstr "등록 프로파일" diff --git a/src/django-registration/registration/locale/nl/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/nl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..9e84eb3ed60d06c9e37b1d48fa0edf3b5410f230 GIT binary patch literal 1898 zcmbW1&u<$=6vqcBl$xKaia5aGAr2(aHBJgB+9XxeG>rmINrO{_IH2+F^Lpalnbpj! zT~~qw2QG*sH}3o$9QhA8@h5<|bKpC>c5I^xsf@h-%*?)d^XB{J?eAAF{V330#q%bf zpYXgM`cL5x?I9R}Q}8SBXYd|)`Dr0O0v~|e;1A$C;IH61_!syx_{K9ryac`rJ`Zkz zVXr;#8h8r624>(T@M|#GeG4Yo>wEA9#(&~vAAI{+A?}0UfuDoFfyZFyIU#O?-+}8h91s_1Sm_yn^w4FvR^Oi0$hZ`~)8%zE|p*<}aM%h1nSH z1wyS`h=1PTMnDRIFl)bc4B_Pw4ds~0vP?;8Jeg%CZ^#dsdTa|vW{aF2q<$=O)Ic z#4;I@R|N~1cr|VmAMsSIs3Yd~7adxY83J7w%}%paAsGXe^J6ES2nyAIK_+ox%{eDN zI!dDlI2JM;&%$n;wNAM-)ai?h>h9e;Jli`wpq*~_R<7E{W;a{MN5=OK~e{RH0%j(u(~&BcY0@ zz?g$|ND%5LnpGq2W1Buv4ACkSk@HnQS3GEpQS5A2ZN(jhcT1~7$)LPb6m$ryZ!0x= zLXSAfd?hZEma_OCPXFzqEe@MtYL^9$4rw$X^E?Q#T%|=gC8kuCF^)|5d@+~j_(=5` zWrfrSX$u1lXHr9TlzkBO@%b?Yd!g#4mYo, 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/src/django-registration/registration/locale/pl/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1f2a228861c28105aae351cdeded9976e68bbd76 GIT binary patch literal 1769 zcmb7^&u=3&6vquLEE|3=AP#VNH@46TN!hY(cByt*id58=s-%nHf}EL`iIW*SvOUet zNN}h?NFWXzIH2Xmf&YM0xits)12}Ty58yxG>q+`cMMzk2J|53|&(Ggy&!1N>eJ{|S zMSlhTNA#D%_#ynE-3KGE1V06T2Dib>4-4@Ycn`b@eha<|{su09e}hkhFFzv0Q{Zdh zf+=_j{0t0s2Vfg(eFKKLzv5+B|1WS2Tz^!E8{ik z!t)*QIWPmC06z!u6JO8gzXPx0`6uvs@E0)H{XU=n1H|%m3;92Z9`bvpo|*lHeFUG- zU@nkq-9rAy?J@?CLLj|bj|O-JU2M=m?lW1I2}zBfT4wTw{D7&;Hg{zD^dZ}Q6|>mo zR5@>@S4LCeluoH1>^YYzBbg+YonuGJ(b$@S>M74jlXfzej>#3{aaNL~MD_b@S^M*j zP0<~|^IWhHN@gLwl2lle|8F?BSS@ot8_CNN>ytq7z!;<_wZW!sQ|!$>9K}+T(a1SA z+DojTvG;7IgX`s z6Jrx%84t*-oP~_N+Mg*t;!>PbM;zOq4CtCnk?4Y$tu!wciqTgY|Ldd^L81CD$Ru{G z8FK8SjU>8 zwN|6{Dz#TTZ?>Y=a;pWyXqWd@2zb`6y%e>VslC*>zWjQt4ZBV0eAKm4yG(jxJM_M^ zJfcrhlSsNX3=hpJJlsyhscXh2UxSlQ3z>4%Wtn$q$7IS4=+@@u?MyX|P1hP*8(ZtA z8)`ROjk~BR&S2C<1v=#UzJFt!LA#q252SVM-`?xK7p&c{ zC{}S?m0nH{I1eQ*GMVGBD3YU?$G#XI{XnS^+lncdl$+^crY2_kAXcy*a=20PP~pl{ zB^A@dGFAm8(&lEuslm0v!766gqDgyrKg3ng7hZ`j>zVQV3WdltM8G=eMC$Ut-6d&R zO=NBDM`ohcNYZJLN@5>gHtD0Xr`T2@iK8!@V*8>~*dkLUC$N)8Uy(1fk)aG<16wXq zT=p$)GgVrSuxpcyEKeU~td$g7_^P-Ht~2S(B)FeQx=6BDl2g#L!a=B|t4)smCS&F5 z1x>h51|K&!JuoyO(<`u2hFc{@SrJz#jV~uME{D1lwZb#e#LQz3x;8dC2*C?tc8AUu UY(5pfo+m{Vp?-7m#6>y9KORXKn*aa+ literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/pl/LC_MESSAGES/django.po b/src/django-registration/registration/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..498fd5b --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e81b6207be3808b1553a40605d4c5f7ea270a843 GIT binary patch literal 1796 zcmbu9O>Y}T7{>=FZ*HMbKuCzgb0ZO5;}i;wTdJC5Qw)BI96M5xS~T5#yqdFT=>u0aT1jaVx-yMdOXj|{O5W0w{xey5*TMO zU&s6s^Ht0pMqb5J@7B^U2x}dAufZTgKvO8g6rV#;Pc?=Cxmzod<}d7 zTmxSQH^EoH9(W2&!Dm1PUW9K8Ucm2%_)~+wfH%R9o?OIx2yWx|AK*LS`cpz|fVaSx zz%Rga;J4t5;1A37pTQ9SS1`o;bIHF!gssLIJWpeWypE5cQ8-f=*e;M_HG-eR@ibm= zbb++0bJxIUF-4mua>is?rX)3HW|_$w@)M>Z+rp6<(;nNIN>~gyQ_frImC;l>r863b z{ai?ulT1^~&aorqXll(w-BzB{I_>5x9g{1k)BJ!WrD{B8%i5nbtc&3UmM5GAS27Rj z9gqq!`MS z+jyxoD|L$3#NhDahAF8ioj)lgY#=05wUvNukM{Y4DfEWeF620s&V6QVN-UEJc~!8G ziC43Q;&=H#oKQ!s_OHnd`K^mZfaMM04#q0ye_eDU2va?RI%3zFJDm8aoksgO4KBDz zyREH{Ti0XSj|Y40ey=v*sj)ulx=f|f2W94>p=nZWw?B-wa7CdiqHXE9Nf#Q8_oBvT zw6RGWo6WZyQR8BxfsN6CXDT>f?z<7U22r;kZMW#dezV(t^OJrru63mI(a=ima_Nn2 z($1*Up!XnJl}_hcuIk2SS8LsN zH$FPlM!iwn!gZqjq9Md@lIMH=t!WPZE>kj**0FzoG~9_U9qkLbpk$+1CniPNH|Y{; zyC&k2^7;3~p+HaosliJ@##OBYq)a1c2l}g?}#4 zR{zJlHb?}qOIObCTV<&7eGgxX(5y!}GkPSSNHV3jrY?FgtB$?0lT+3bpAM5EryvX4 z&~a9VhMWIXur+u?pjE?(eUr?;LvVb5!y1j+&ta7GmQOwJ$7zcJ!bQN_Y|O`9273hA$lWeWz=Wow$l Qwd(Av#X}L$kqZ^YKLzI-!vFvP literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.po b/src/django-registration/registration/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..9e8addb --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/ru/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1635b4ed687d4d256776033f8b02f48ae394b644 GIT binary patch literal 2470 zcmbtTOK%%h6uv-tnRitr5FieV(nifVPE=58(kLczON5<7iBqW+2u4>gu;k&qN}4q80wlI~mI$e^<`=N!J9q4~iBgG*E8Y3-wAJ9rJt4H!yo1!3U!bYy&O>p9lT{d=B_G&;tGgd;S$B>;rxR zJO?}s+yo8*{{r>`J06SPxxgdXPXXEg67Uf4N8roAUw{XIzXRVvth>Mw><>LI#Brbm zwgbNbehmB#_$=`76A_Ot;0f$Az(0YPfZf32lR{hvE&)B@aU}63@H^l~z+Zu{0pEH$ z;&-x%68H+vF9ShGJcG&Fam?1>JX!48;0h&7luEa~t9po_sG(`-PwdKJY zyugbT)s*yU$_XYYn6Lx0b?u5IyX;H5FirA;qXHEdseIr}+JQ6{N~9~cQzpAm@TF2> zkS6R&N&JFr7qjF`Nr4BSl5*0oDDsLlCjCh#FU5$h)RgBJb{2HhF4>OTCPt;DB)^Y> zIi5?B11a2;z{9r#KC3CmEm4tUnClh~smM`O^}Pw_yc5VmoJPvhR+3b$S}jkLO$Db| zl)iL>-4Ej;2cp50N7W`bDmt=UPdx`M?@1SZBZjl}OS^s{g~(=`@{5kB$uv z55-1h)$;=@t4dD6dcRguR?bUOY-BiR^`kwweAWQkC`nz3#0jf2VRdz4ne6O3mUuUj zfT1-iCmnX)v^$$ljau1ZYam4*3@5XL$IcB8rDGXe1y;_tT~)RN&ri~+@l1w>QrR^1 zq_e5POkZkXU^G28)(ca&RI^Lc%1OJDq)ck)^f*)Q$z=ML*FL;;9?u|HidKgre23dI2V4Y*MYNo1&8b5Y+UHC z^d|NjaJCU%Y&m6zbKyLj=;R5#TV;0FlrmgS_6C&2EDL_5E1g|*aT%)HAp}$4URZiTb zXl%fXIj|V}u#QBZLEwg7#$00w!!LF;VNT|N(*gGt^TlCPWE`z?p+KP?hg7h?2|`;a z*)3DNdOP6}p20OMit3;oxL$=Rw6Fj7>YxFxH9c{>X07kEG-WZ+L{SM=kStu|?uzN0 z9}v0`&OTJURx|F_E^0>PcJ=?|i);)jBQ^IWp+{If^l_BKn$a3^nl|7BOwVoV2I*zc z*yPf*6E{NmIW%411~f%pGrz+{^Mj$KAPd@4=o|Vrcj=xs;G)1W?yoZtmvnCvv14>4 zYR4o%65>ZBTfL6jhKsC<>9$?JOw{|$F5ahy1$g4WFcq5T^#dsEwZq@GFIDk?3>U?} Dr?6*Q literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/ru/LC_MESSAGES/django.po b/src/django-registration/registration/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..072e146 --- /dev/null +++ b/src/django-registration/registration/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,92 @@ +# 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: 2009-10-21 20:12+0600\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" + +#: admin.py:23 +msgid "Activate users" +msgstr "Активировать учетные записи" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "Выслать ключи активации заново" + +#: forms.py:35 +msgid "Username" +msgstr "Имя пользователя" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Это поле может содержать только буквы, цифры и подчеркивания" + +#: forms.py:39 +msgid "Email address" +msgstr "Адрес электронной почты" + +#: forms.py:41 +msgid "Password" +msgstr "Пароль" + +#: forms.py:43 +msgid "Password (again)" +msgstr "Пароль (снова)" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "Пользователь с таким именем уже существует." + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "Введенные пароли не совпадают." + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "Я прочитал Правила Использования и согласен с ними" + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "Для регистрации Вы должны согласиться с Правилами" + +#: forms.py:95 +msgid "" +"This email address is already in use. Please supply a different email " +"address." +msgstr "" +"Этот адрес электронной почты уже используется. Пожалуйста, введите другой " +"адрес." + +#: forms.py:122 +msgid "" +"Registration using free email addresses is prohibited. Please supply a " +"different email address." +msgstr "" +"Регистрация с использованием свободных почтовых серверов запрещена. " +"Пожалуйста, введите другой адрес электронной почты." + +#: models.py:165 +msgid "user" +msgstr "пользователь" + +#: models.py:166 +msgid "activation key" +msgstr "ключ активации" + +#: models.py:171 +msgid "registration profile" +msgstr "карточка регистрации" + +#: models.py:172 +msgid "registration profiles" +msgstr "карточки регистрации" diff --git a/src/django-registration/registration/locale/sl/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/sl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..036163f3fe0788878d1bc028b88e0f5413b77e0e GIT binary patch literal 1903 zcmb7^&2Jk;7{&)EU*@|7BqWet2|*f>b?lIe)U;JYYN3dvwGtDxJ%GmE*X!}_&R8?E zn>q*ngPaiDd!Q!{aP6Td=fa5#7my;(`~{p4&)Cja>4lNUzunn)=6&YbdH3-Ax$gwp zdGvSDe?)%|{mN7LL;DGw2Y&`%1^)nF0sjIc@Ne)1@WZEtcpY2>-vO_KUxRnS55R}u zP4G|f8o2n35Obgg!@A#tZ-PI7Z-EcNbKtLFSpPRLN3KJ#j{A*gr}5u_LHoC0(ER|! zPmJ;R8u$zNKKMI$2mA*N`@H>}5H+v>KLHPsMZ=k=7e$;|LM-5>Dl8;-^6dGh4x3F$lGc?#UX^3I_2L^GEvBN@k*ofGTSmnBn}K~ke9mYKZ4 znoMoBxg*n~ZMLQAvS>-?c8!gXFX*C7q|)URwdXWFQzIEx)7 z#CpzCE`7HjqOks%lp*1fRVpas|CJQ8OPLi+dEq>DjrQ-3A1`C<0lR}5e~=XFB}QcvSz?t zAFapH4piVxG^kcxsn$E}Wo3(p#`0_#2YAj#=s8&bZhIBq^Td7?py|E3tVRF{= zg*kX6EnSJj-SwEus#Dhxtdl|}9JN{I4cg93$y!PMc--dtX7glI^=hrMhIfH;617J| zNcMcsFAg)joKLCSm)5brTKHbHauOF5;cP`s-8C`JXMEIEQ={PS35+$0VM3t3; zEh66Q))9WTGNZk z64{_28FI<48n|>;gnV417?q?IHM)tZ^zgRBCpp zT8eFvoQbI-dj^Snlt7ybvNgU#0~Dgiwwser(SRprl(UVfh43Bt&$^so!j9!w8`N7S z`zi7|?qD%;5+cU?HsuBCDtuiCr8qP(hTtz(#a%h8DH}F!f{q;T2$Jz-3Xb}q@r<85 jeJN9;6s53kynos#m#QEXHTdLFb#e~GsS{wr0TBNJ-VQEw literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/sl/LC_MESSAGES/django.po b/src/django-registration/registration/locale/sl/LC_MESSAGES/django.po new file mode 100644 index 0000000..c587c70 --- /dev/null +++ b/src/django-registration/registration/locale/sl/LC_MESSAGES/django.po @@ -0,0 +1,87 @@ +# 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: 0.8.1beta\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-10-12 14:09-0500\n" +"PO-Revision-Date: 2009-10-23 15:49+0100\n" +"Last-Translator: Domen Kožar \n" +"Language-Team: Slovenian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Slovenian\n" +"X-Poedit-Country: SLOVENIA\n" + +#: admin.py:23 +msgid "Activate users" +msgstr "Aktiviraj uporabnike" + +#: admin.py:43 +msgid "Re-send activation emails" +msgstr "Ponovno pošlju aktivacijske emaile" + +#: forms.py:35 +msgid "username" +msgstr "uporabniško ime" + +#: forms.py:36 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Vrednost lahko vsebuje samo črke, cifre in podčrtaje." + +#: forms.py:39 +msgid "Email address" +msgstr "Elektronska pošta" + +#: forms.py:41 +msgid "Password" +msgstr "Geslo" + +#: forms.py:43 +msgid "Password (again)" +msgstr "Geslo (ponovno)" + +#: forms.py:55 +msgid "A user with that username already exists." +msgstr "Uporabnik z tem uporabniškim imenom že obstaja." + +#: forms.py:67 +msgid "The two password fields didn't match." +msgstr "Polji z gesli se ne ujemata." + +#: forms.py:78 +msgid "I have read and agree to the Terms of Service" +msgstr "Strinjam se z pogoji uporable" + +#: forms.py:79 +msgid "You must agree to the terms to register" +msgstr "Za registracijo se morate strinjati z pogoji uporabe" + +#: forms.py:95 +msgid "This email address is already in use. Please supply a different email address." +msgstr "Email je že v uporabi, prosimo vnesite drugega." + +#: forms.py:122 +msgid "Registration using free email addresses is prohibited. Please supply a different email address." +msgstr "Registracija ni mogoča z brezplačnimi email naslovi. Prosimo vnesite drug email naslov." + +#: models.py:165 +msgid "user" +msgstr "Uporabnik" + +#: models.py:166 +msgid "activation key" +msgstr "Aktivacijski ključ" + +#: models.py:171 +msgid "registration profile" +msgstr "Registracijski profil" + +#: models.py:172 +msgid "registration profiles" +msgstr "Registracijski profili" + diff --git a/src/django-registration/registration/locale/sr/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/sr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1699326553efe848408441bb04e452d14f341774 GIT binary patch literal 1966 zcmb7^O>Y}T7{>=F6wIqC5USwtP>GVzu30B7ik!L-`huc1ZIn0_(-_#C_gu7dmEC*YspBKR-(7WlzSLc9rn3cd=i zfFai!_%65wz6WOD3GjO`*!>9pgIqs@%lOtW3z34qfj7XDuL#isx4{kYC-55h7kC;x zeNu>1;4=6Icpb!$*aqJQzXe1791Qt?07KqK)A3(Hq_113Kg0<21>ac<^LTyw5n`j% zx`jBihA;wB2$Wsx(Ewk=Bi5-eM@*JwN>by=EHimSzR%QUTRJkkw9R&;5*AyWDd(;9 z%4n*b(i!ardoHCaNT#V}=h%^QG_!UzP-x!o9wZWuqQ|wGV93@hd(Wp5w+Dqgw z*n76_Jn5?Jp;K#C=@i|>VDjRwsi>@+pBEB75E81|T0pkPc78mB-Vob`8i&%k?~F}} zWzr|FN)|HlYBW)Nz+*9|j+ogWb!b6mD0ERwGEJ8Xi?OQ;e&$anf#H8yW|qbpdouu-C`(sP@Z z;&>&BFGTT0YAv@fw$8=)1H)*GM=GRwhTVmB9G{C@u)8UpkGfWBS4eMcn{IK>o6ahkanxm5qOOhgjcdo#YBl4=6|5|FV${Vtw8`^* z|JksBf~%DDrFHB(JKgKi%CTLj0lPQ4rW2Fm1hi=d+q|(^R8|(zb%T{|lOEQeuCu&K zlWs?U+=@G$7M(pyp&NhHX|?DJiV4>EzT8=w4PEM72;GI+>{2VH2M;DLu!$Gp(}K^^ zYU7(|({QSMG@E5R9MqnY`grJyskFD_Hr?I%`u6tCwL9x;jj+TA`^rlbHXSK~riXuU zN#Tr2oUy`;R4Hj-tU7#r@Q`&bkB)w#^0^VX_1Hl&uT@4IO>Y961xY#6p6o%eoV9Gy zhQW4Zsx*5=sjaeV&c14j+ao#ms}3>ZgNIa6H8kFGPaVYx`l}lR`2xlIN)x4hxFLd<-M~4j(Jrvtdw&a9FKM$U(Rl y5*!>wgCegE_K)s{Aik)5W}t, 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/src/django-registration/registration/locale/sv/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/sv/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..50eca67e21301f5081b881b054ec648a67e25509 GIT binary patch literal 1687 zcmb7^&2A$_5XT!>STLWbWfg3^`kvMRS#T(=W=EO_Dl`C(+zsF7-qrEW7%&%u$RbBnBs{Hx-jb8+=*Kog! z`#0Qg`}I?J;Cc)O;1v8C{2e?5Z$2%=C*Ub~7yKD~AN&Jc1OEYE0pEE>h?l_+z~{j# z==Z9FZ-QO$EieXefZu`M?g#Kw?DZ4)9^P~OxC8zT-T~L26=Dlya3A~?+y?&w34G%@ zA#Q;mfiHpk;0xd}==c8$#Gg=j`2EIU3H%=P`ThuE`{MHNK8DZl)#A(i;p4oxc!#+_ zs>S8wU0ye_fD{606?*tRd>*1n136(bEF+Q%cWju+X>tRm9-GXP?$a@wNfNT?a-3La zq)W7-u}xG=eQ(d1Oj43jWY}7^lvo-WJxI3eCnU!ZOr2ym+X`l#Q)h6%sxW5~`X)KsHM|HyuH5h;4n2BWdlo z+C;=M9FR*g7BY0nWUly-r(#7NacO_GpxZJ=qHAKl)1p);Mn6gUi65=-3Kb78lQ=T^ z8xCF2jDk}f3ze?XQGNHz`ay$E8{Ok(=dje}kv1-9+c=4WopEe~o~}{psM8B}Q7hjb z!Jc$nqpeD%8dSD}t!>(@);_+oUfHZvU>J0HlK9{YyN8W>H)wZ)y*ho~skNKyk2;5q zQcGGF^o&$Cl}?))H8S+sv15fU%r7#!$Jv9S8a=QBfR(nw^hc#zN1RMMFqT9=j|U)6b{E84ibH z4?~g9EKYc($)zL+dI5c~<)UMu7yd!SVke(P5^7#pR(>KD0VaO?G#N@!A7U`rpafP; k!y%`laZOgyy7XMG=yn2y)_jX&92P+DU!9VdORtak7w$#!*8l(j literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/sv/LC_MESSAGES/django.po b/src/django-registration/registration/locale/sv/LC_MESSAGES/django.po new file mode 100644 index 0000000..dec76e2 --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/locale/zh_CN/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/zh_CN/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ece5cc97b10d0ace9a2ba33ce927e95d8e48ec49 GIT binary patch literal 1669 zcmb7@?@t^>7{{ktt)4&AXnav$%nPGdyXOK?;iwIWNKl}J9whq4O!tPpwRgLhojEKq zCI=P-%LPQMMri^KRMOg9qeLiBc;yTK3E%W)x$_P2Kkz%Z2iHq{)5-39W@evxetc*4 z@8d_W5VU9UzKC}L?+bc-1RdH%&;UolPrzTmKJeH>guDd~fvsR3dCj!2cH86z~@05JPLjRYP)f;1+gxJFJb;CKK6tEfFFRZkA!(mf+pr` z;0aKH+WyF+gggnpTxAo8hqR$P4t7=7Kd#aS@eqmbaqx2x;VVt&uYDmjd8V=wcDjxy zs&l;;saBfK|DYYi08$X7Rna2?YX790CfNw5K4%HaT)ei=Ih7ujNlxS3PYdb|({tP( zaV$;-xa|n(GwFCP%?ii0>9DrvY38ITOC)?Q1Q*m1G~;_o=e#3%B1-#HoC!`vHj_z> zQbrTb@G$qeE9*B#Nj!<2bMEfeYYy-&F%jqZdogtBnbG1}kW@nL&cCmre>IM;o)FEYS0 zo-d7FVLJ)q-K;H)xEG_5{)%3X~ccziWHNcAEU{v%tD_uJ$*20v-RDJT3-4L z%w0RnY;MFkOUGzWdtcX}PWyCEPg}}~dcJ)o(%aqJSu3m|YDPM6wz!K%948T@l3$c> zWKz(um0C&W3ohRojK6O**X(pYxW7iHYk3L$12Ni+iyk4t)HiDVxAKn@rNWlF^M{(7 z2`RRsQpl%H*1Pjx}&CM{z1G++1!PL5% z%fn6S+D(;T#7gJ`DU@^5VLCc+&2;ug>C3xnWpCBgWr+MOsbZH3B&rB-D*{8rleR!yuFH, 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/src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.mo b/src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..24a3534958925d49ab1e1032f3cd2d50e28cd3e8 GIT binary patch literal 1669 zcmb7@?@t^>7{{ktt)4&AXnav$%nPGd-E)DcaMT7wBq&fq4-$Q2rhCKQ+PmG$&K#B) zlYz5_j$aFc%Reb1L)AsfCe}YehmHu4uFRqAmmMO1Z)TM;7j0N;8E~j@JaB< zgM>T*z5+f1wt_lVC-@9F1U?Je;6d!XO5#cEY;dMsv6N14oH{xtzh8IQ;=3%(@AV|vY3}YjvXY*M^qA|R zXg^AZYdZwBm`gnuIa{798RDn7l-w7uQ8$}Dg+W!btee2l@=!ea(96(#nu?Ipz zRlh1A_v?0YJOjNUw$M3dm=K?Oeu8plC8>1MoG?o|W1-@w`8a7%hwRz!59rIxMxsYa z7^!wtIE+yz#s7Cv5Uo(P(=w4k-}{7H(&$YXBPa_e9ixMtT_1GzbkmXUp_9EQ1|mZ| z$H#c^>w72sOQ_qBmKSo-SxtnqGqHEXN$XN#BmZaD)|}t zdL{)8+o_dgzTooh;rM$-Yu!%ggZpcAyOx*0KM

xabiQ%v@BrHY!(sEB~4+6_(Y) zTySo_yt)xA=GE-i!P2$hmo2ihJP}-9Ds67>Tv}06`SQjc+Fkv7)Zz_wEf@U0qNXqG z7U#-qv%&mAY3rL(A*XV)YJOS$aAoJ}xd!XIxk-Wm4QogtSUg|4eLIYCpRSNqF!P66 z$iq!}X|1$*2`ixwq)?eCgz4zOb<_Eu%V#&$+>}~aQ`f%=*7J9B6T#&I#_G$tQejqI zIJ>6+nG?Au+*9?``^mNf|~kKO|4cY^4f0YdlaqKr+1c$B-qXcH}7Cl pxp;%zs~V{pgxD?4RKCcot<~M)c@jn`ZGRU`tT#@={Oe_q{{ZHmUoijx literal 0 HcmV?d00001 diff --git a/src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.po b/src/django-registration/registration/locale/zh_TW/LC_MESSAGES/django.po new file mode 100644 index 0000000..7cc090d --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/management/__init__.py b/src/django-registration/registration/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/django-registration/registration/management/commands/__init__.py b/src/django-registration/registration/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/django-registration/registration/management/commands/cleanupregistration.py b/src/django-registration/registration/management/commands/cleanupregistration.py new file mode 100644 index 0000000..abec5ae --- /dev/null +++ b/src/django-registration/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/src/django-registration/registration/models.py b/src/django-registration/registration/models.py new file mode 100644 index 0000000..359454a --- /dev/null +++ b/src/django-registration/registration/models.py @@ -0,0 +1,257 @@ +import datetime +import random +import re + +from django.conf import settings +from django.contrib.auth.models import User +from django.db import models +from django.db import transaction +from django.template.loader import render_to_string +from django.utils.hashcompat import sha_constructor +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. + + """ + # 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() + return user + return False + + def create_inactive_user(self, username, email, password, + site, send_email=True): + """ + Create a new, inactive ``User``, generate a + ``RegistrationProfile`` and email its activation key to the + ``User``, returning the new ``User``. + + By default, an activation email will be sent to the new + user. To disable this, pass ``send_email=False``. + + """ + 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: + registration_profile.send_activation_email(site) + + 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_constructor(str(random.random())).hexdigest()[:5] + username = user.username + if isinstance(username, unicode): + username = username.encode('utf-8') + activation_key = sha_constructor(salt+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 + + def send_activation_email(self, site): + """ + Send an activation email to the user associated with this + ``RegistrationProfile``. + + 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. 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. + + These templates will each receive the following context + variables: + + ``activation_key`` + The activation key for the new account. + + ``expiration_days`` + The number of days remaining during which the account may + be activated. + + ``site`` + An object representing the site on which the user + registered; depending on whether ``django.contrib.sites`` + is installed, this may be an instance of either + ``django.contrib.sites.models.Site`` (if the sites + application is installed) or + ``django.contrib.sites.models.RequestSite`` (if + not). Consult the documentation for the Django sites + framework for details regarding these objects' interfaces. + + """ + ctx_dict = {'activation_key': self.activation_key, + 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, + 'site': site} + subject = render_to_string('registration/activation_email_subject.txt', + ctx_dict) + # Email subject *must not* contain newlines + subject = ''.join(subject.splitlines()) + + message = render_to_string('registration/activation_email.txt', + ctx_dict) + + self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) + diff --git a/src/django-registration/registration/signals.py b/src/django-registration/registration/signals.py new file mode 100644 index 0000000..343e3a5 --- /dev/null +++ b/src/django-registration/registration/signals.py @@ -0,0 +1,8 @@ +from django.dispatch import Signal + + +# A new user has registered. +user_registered = Signal(providing_args=["user", "request"]) + +# A user has activated his or her account. +user_activated = Signal(providing_args=["user", "request"]) diff --git a/src/django-registration/registration/tests/__init__.py b/src/django-registration/registration/tests/__init__.py new file mode 100644 index 0000000..3272c57 --- /dev/null +++ b/src/django-registration/registration/tests/__init__.py @@ -0,0 +1,45 @@ +from django.test import TestCase + +import registration + +from registration.tests.backends import * +from registration.tests.forms import * +from registration.tests.models import * +from registration.tests.views import * + + +class RegistrationVersionInfoTests(TestCase): + """ + Test django-registration's internal version-reporting + infrastructure. + + """ + def setUp(self): + self.version = registration.VERSION + + def tearDown(self): + registration.VERSION = self.version + + def test_get_version(self): + """ + Test the version-info reporting. + + """ + versions = [ + {'version': (1, 0, 0, 'alpha', 0), + 'expected': "1.0 pre-alpha"}, + {'version': (1, 0, 1, 'alpha', 1), + 'expected': "1.0.1 alpha 1"}, + {'version': (1, 1, 0, 'beta', 2), + 'expected': "1.1 beta 2"}, + {'version': (1, 2, 1, 'rc', 3), + 'expected': "1.2.1 rc 3"}, + {'version': (1, 3, 0, 'final', 0), + 'expected': "1.3"}, + {'version': (1, 4, 1, 'beta', 0), + 'expected': "1.4.1 beta"}, + ] + + for version_dict in versions: + registration.VERSION = version_dict['version'] + self.assertEqual(registration.get_version(), version_dict['expected']) diff --git a/src/django-registration/registration/tests/backends.py b/src/django-registration/registration/tests/backends.py new file mode 100644 index 0000000..9237b2c --- /dev/null +++ b/src/django-registration/registration/tests/backends.py @@ -0,0 +1,476 @@ +import datetime + +from django.conf import settings +from django.contrib import admin +from django.contrib.auth.models import User +from django.contrib.sessions.middleware import SessionMiddleware +from django.contrib.sites.models import Site +from django.core import mail +from django.core.exceptions import ImproperlyConfigured +from django.core.handlers.wsgi import WSGIRequest +from django.test import Client +from django.test import TestCase + +from registration import forms +from registration import signals +from registration.admin import RegistrationAdmin +from registration.backends import get_backend +from registration.backends.default import DefaultBackend +from registration.backends.simple import SimpleBackend +from registration.models import RegistrationProfile + + +class _MockRequestClient(Client): + """ + A ``django.test.Client`` subclass which can return mock + ``HttpRequest`` objects. + + """ + def request(self, **request): + """ + Rather than issuing a request and returning the response, this + simply constructs an ``HttpRequest`` object and returns it. + + """ + environ = { + 'HTTP_COOKIE': self.cookies, + 'PATH_INFO': '/', + 'QUERY_STRING': '', + 'REMOTE_ADDR': '127.0.0.1', + 'REQUEST_METHOD': 'GET', + 'SCRIPT_NAME': '', + 'SERVER_NAME': 'testserver', + 'SERVER_PORT': '80', + 'SERVER_PROTOCOL': 'HTTP/1.1', + 'wsgi.version': (1,0), + 'wsgi.url_scheme': 'http', + 'wsgi.errors': self.errors, + 'wsgi.multiprocess': True, + 'wsgi.multithread': False, + 'wsgi.run_once': False, + } + environ.update(self.defaults) + environ.update(request) + request = WSGIRequest(environ) + + # We have to manually add a session since we'll be bypassing + # the middleware chain. + session_middleware = SessionMiddleware() + session_middleware.process_request(request) + return request + + +def _mock_request(): + """ + Construct and return a mock ``HttpRequest`` object; this is used + in testing backend methods which expect an ``HttpRequest`` but + which are not being called from views. + + """ + return _MockRequestClient().request() + + +class BackendRetrievalTests(TestCase): + """ + Test that utilities for retrieving the active backend work + properly. + + """ + def test_get_backend(self): + """ + Verify that ``get_backend()`` returns the correct value when + passed a valid backend. + + """ + self.failUnless(isinstance(get_backend('registration.backends.default.DefaultBackend'), + DefaultBackend)) + + def test_backend_error_invalid(self): + """ + Test that a nonexistent/unimportable backend raises the + correct exception. + + """ + self.assertRaises(ImproperlyConfigured, get_backend, + 'registration.backends.doesnotexist.NonExistentBackend') + + def test_backend_attribute_error(self): + """ + Test that a backend module which exists but does not have a + class of the specified name raises the correct exception. + + """ + self.assertRaises(ImproperlyConfigured, get_backend, + 'registration.backends.default.NonexistentBackend') + + +class DefaultRegistrationBackendTests(TestCase): + """ + Test the default registration backend. + + Running these tests successfull will require two templates to be + created for the sending of activation emails; details on these + templates and their contexts may be found in the documentation for + the default backend. + + """ + backend = DefaultBackend() + + def setUp(self): + """ + Create an instance of the default backend for use in testing, + and set ``ACCOUNT_ACTIVATION_DAYS`` if it's not set already. + + """ + self.old_activation = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', None) + if self.old_activation is None: + settings.ACCOUNT_ACTIVATION_DAYS = 7 + + def tearDown(self): + """ + Yank out ``ACCOUNT_ACTIVATION_DAYS`` back out if it wasn't + originally set. + + """ + if self.old_activation is None: + settings.ACCOUNT_ACTIVATION_DAYS = self.old_activation + + def test_registration(self): + """ + Test the registration process: registration creates a new + inactive account and a new profile with activation key, + populates the correct account data and sends an activation + email. + + """ + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + # Details of the returned user must match what went in. + self.assertEqual(new_user.username, 'bob') + self.failUnless(new_user.check_password('secret')) + self.assertEqual(new_user.email, 'bob@example.com') + + # New user must not be active. + self.failIf(new_user.is_active) + + # A registration profile was created, and an activation email + # was sent. + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertEqual(len(mail.outbox), 1) + + def test_registration_no_sites(self): + """ + Test that registration still functions properly when + ``django.contrib.sites`` is not installed; the fallback will + be a ``RequestSite`` instance. + + """ + Site._meta.installed = False + + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + self.assertEqual(new_user.username, 'bob') + self.failUnless(new_user.check_password('secret')) + self.assertEqual(new_user.email, 'bob@example.com') + + self.failIf(new_user.is_active) + + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertEqual(len(mail.outbox), 1) + + Site._meta.installed = True + + def test_valid_activation(self): + """ + Test the activation process: activating within the permitted + window sets the account's ``is_active`` field to ``True`` and + resets the activation key. + + """ + valid_user = self.backend.register(_mock_request(), + username='alice', + email='alice@example.com', + password1='swordfish') + + valid_profile = RegistrationProfile.objects.get(user=valid_user) + activated = self.backend.activate(_mock_request(), + valid_profile.activation_key) + self.assertEqual(activated.username, valid_user.username) + self.failUnless(activated.is_active) + + # Fetch the profile again to verify its activation key has + # been reset. + valid_profile = RegistrationProfile.objects.get(user=valid_user) + self.assertEqual(valid_profile.activation_key, + RegistrationProfile.ACTIVATED) + + def test_invalid_activation(self): + """ + Test the activation process: trying to activate outside the + permitted window fails, and leaves the account inactive. + + """ + expired_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + expired_user.date_joined = expired_user.date_joined - datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS) + expired_user.save() + expired_profile = RegistrationProfile.objects.get(user=expired_user) + self.failIf(self.backend.activate(_mock_request(), + expired_profile.activation_key)) + self.failUnless(expired_profile.activation_key_expired()) + + def test_allow(self): + """ + Test that the setting ``REGISTRATION_OPEN`` appropriately + controls whether registration is permitted. + + """ + old_allowed = getattr(settings, 'REGISTRATION_OPEN', True) + settings.REGISTRATION_OPEN = True + self.failUnless(self.backend.registration_allowed(_mock_request())) + + settings.REGISTRATION_OPEN = False + self.failIf(self.backend.registration_allowed(_mock_request())) + settings.REGISTRATION_OPEN = old_allowed + + def test_form_class(self): + """ + Test that the default form class returned is + ``registration.forms.RegistrationForm``. + + """ + self.failUnless(self.backend.get_form_class(_mock_request()) is forms.RegistrationForm) + + def test_post_registration_redirect(self): + """ + Test that the default post-registration redirect is the named + pattern ``registration_complete``. + + """ + self.assertEqual(self.backend.post_registration_redirect(_mock_request(), User()), + ('registration_complete', (), {})) + + def test_registration_signal(self): + """ + Test that registering a user sends the ``user_registered`` + signal. + + """ + def receiver(sender, **kwargs): + self.failUnless('user' in kwargs) + self.assertEqual(kwargs['user'].username, 'bob') + self.failUnless('request' in kwargs) + self.failUnless(isinstance(kwargs['request'], WSGIRequest)) + received_signals.append(kwargs.get('signal')) + + received_signals = [] + signals.user_registered.connect(receiver, sender=self.backend.__class__) + + self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + self.assertEqual(len(received_signals), 1) + self.assertEqual(received_signals, [signals.user_registered]) + + def test_activation_signal_success(self): + """ + Test that successfully activating a user sends the + ``user_activated`` signal. + + """ + def receiver(sender, **kwargs): + self.failUnless('user' in kwargs) + self.assertEqual(kwargs['user'].username, 'bob') + self.failUnless('request' in kwargs) + self.failUnless(isinstance(kwargs['request'], WSGIRequest)) + received_signals.append(kwargs.get('signal')) + + received_signals = [] + signals.user_activated.connect(receiver, sender=self.backend.__class__) + + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + profile = RegistrationProfile.objects.get(user=new_user) + self.backend.activate(_mock_request(), profile.activation_key) + + self.assertEqual(len(received_signals), 1) + self.assertEqual(received_signals, [signals.user_activated]) + + def test_activation_signal_failure(self): + """ + Test that an unsuccessful activation attempt does not send the + ``user_activated`` signal. + + """ + receiver = lambda sender, **kwargs: received_signals.append(kwargs.get('signal')) + + received_signals = [] + signals.user_activated.connect(receiver, sender=self.backend.__class__) + + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + new_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1) + new_user.save() + profile = RegistrationProfile.objects.get(user=new_user) + self.backend.activate(_mock_request(), profile.activation_key) + + self.assertEqual(len(received_signals), 0) + + def test_email_send_action(self): + """ + Test re-sending of activation emails via admin action. + + """ + admin_class = RegistrationAdmin(RegistrationProfile, admin.site) + + alice = self.backend.register(_mock_request(), + username='alice', + email='alice@example.com', + password1='swordfish') + + admin_class.resend_activation_email(_mock_request(), + RegistrationProfile.objects.all()) + self.assertEqual(len(mail.outbox), 2) # One on registering, one more on the resend. + + RegistrationProfile.objects.filter(user=alice).update(activation_key=RegistrationProfile.ACTIVATED) + admin_class.resend_activation_email(_mock_request(), + RegistrationProfile.objects.all()) + self.assertEqual(len(mail.outbox), 2) # No additional email because the account has activated. + + def test_activation_action(self): + """ + Test manual activation of users view admin action. + + """ + admin_class = RegistrationAdmin(RegistrationProfile, admin.site) + + alice = self.backend.register(_mock_request(), + username='alice', + email='alice@example.com', + password1='swordfish') + + admin_class.activate_users(_mock_request(), + RegistrationProfile.objects.all()) + self.failUnless(User.objects.get(username='alice').is_active) + + +class SimpleRegistrationBackendTests(TestCase): + """ + Test the simple registration backend, which does signup and + immediate activation. + + """ + backend = SimpleBackend() + + def test_registration(self): + """ + Test the registration process: registration creates a new + inactive account and a new profile with activation key, + populates the correct account data and sends an activation + email. + + """ + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + # Details of the returned user must match what went in. + self.assertEqual(new_user.username, 'bob') + self.failUnless(new_user.check_password('secret')) + self.assertEqual(new_user.email, 'bob@example.com') + + # New user must not be active. + self.failUnless(new_user.is_active) + + def test_allow(self): + """ + Test that the setting ``REGISTRATION_OPEN`` appropriately + controls whether registration is permitted. + + """ + old_allowed = getattr(settings, 'REGISTRATION_OPEN', True) + settings.REGISTRATION_OPEN = True + self.failUnless(self.backend.registration_allowed(_mock_request())) + + settings.REGISTRATION_OPEN = False + self.failIf(self.backend.registration_allowed(_mock_request())) + settings.REGISTRATION_OPEN = old_allowed + + def test_form_class(self): + """ + Test that the default form class returned is + ``registration.forms.RegistrationForm``. + + """ + self.failUnless(self.backend.get_form_class(_mock_request()) is forms.RegistrationForm) + + def test_post_registration_redirect(self): + """ + Test that the default post-registration redirect is the public + URL of the new user account. + + """ + new_user = self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + self.assertEqual(self.backend.post_registration_redirect(_mock_request(), new_user), + (new_user.get_absolute_url(), (), {})) + + def test_registration_signal(self): + """ + Test that registering a user sends the ``user_registered`` + signal. + + """ + def receiver(sender, **kwargs): + self.failUnless('user' in kwargs) + self.assertEqual(kwargs['user'].username, 'bob') + self.failUnless('request' in kwargs) + self.failUnless(isinstance(kwargs['request'], WSGIRequest)) + received_signals.append(kwargs.get('signal')) + + received_signals = [] + signals.user_registered.connect(receiver, sender=self.backend.__class__) + + self.backend.register(_mock_request(), + username='bob', + email='bob@example.com', + password1='secret') + + self.assertEqual(len(received_signals), 1) + self.assertEqual(received_signals, [signals.user_registered]) + + def test_activation(self): + """ + Test that activating against this backend is an error. + + """ + self.assertRaises(NotImplementedError, self.backend.activate, + request=_mock_request()) + + def test_post_activation_redirect(self): + """ + Test that asking for a post-activation redirect from this + backend is an error. + + """ + self.assertRaises(NotImplementedError, self.backend.post_activation_redirect, + request=_mock_request(), user=User()) diff --git a/src/django-registration/registration/tests/forms.py b/src/django-registration/registration/tests/forms.py new file mode 100644 index 0000000..505374f --- /dev/null +++ b/src/django-registration/registration/tests/forms.py @@ -0,0 +1,119 @@ +from django.contrib.auth.models import User +from django.test import TestCase + +from registration import forms + + +class RegistrationFormTests(TestCase): + """ + Test the default registration forms. + + """ + def test_registration_form(self): + """ + Test that ``RegistrationForm`` enforces username constraints + and matching passwords. + + """ + # Create a user so we can verify that duplicate usernames aren't + # permitted. + User.objects.create_user('alice', 'alice@example.com', 'secret') + + invalid_data_dicts = [ + # Non-alphanumeric username. + {'data': {'username': 'foo/bar', + 'email': 'foo@example.com', + 'password1': 'foo', + 'password2': 'foo'}, + 'error': ('username', [u"This value must contain only letters, numbers and underscores."])}, + # Already-existing username. + {'data': {'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'secret', + 'password2': 'secret'}, + 'error': ('username', [u"A user with that username already exists."])}, + # Mismatched passwords. + {'data': {'username': 'foo', + 'email': 'foo@example.com', + 'password1': 'foo', + 'password2': 'bar'}, + 'error': ('__all__', [u"The two password fields didn't match."])}, + ] + + 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. + + """ + # Create a user so we can verify that duplicate addresses + # aren't permitted. + User.objects.create_user('alice', 'alice@example.com', 'secret') + + 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 forms.RegistrationFormNoFreeEmail.bad_domains: + 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()) diff --git a/src/django-registration/registration/tests/models.py b/src/django-registration/registration/tests/models.py new file mode 100644 index 0000000..f763cb2 --- /dev/null +++ b/src/django-registration/registration/tests/models.py @@ -0,0 +1,225 @@ +import datetime +import re + +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.core import mail +from django.core import management +from django.test import TestCase +from django.utils.hashcompat import sha_constructor + +from registration.models import RegistrationProfile + + +class RegistrationModelTests(TestCase): + """ + Test the model and manager used in the default backend. + + """ + user_info = {'username': 'alice', + 'password': 'swordfish', + 'email': 'alice@example.com'} + + def setUp(self): + self.old_activation = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', None) + settings.ACCOUNT_ACTIVATION_DAYS = 7 + + def tearDown(self): + settings.ACCOUNT_ACTIVATION_DAYS = self.old_activation + + def test_profile_creation(self): + """ + Creating a registration profile for a user populates the + profile with the correct user and a SHA1 hash to use as + activation key. + + """ + new_user = User.objects.create_user(**self.user_info) + profile = RegistrationProfile.objects.create_profile(new_user) + + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertEqual(profile.user.id, new_user.id) + self.failUnless(re.match('^[a-f0-9]{40}$', profile.activation_key)) + self.assertEqual(unicode(profile), + "Registration information for alice") + + def test_activation_email(self): + """ + ``RegistrationProfile.send_activation_email`` sends an + email. + + """ + new_user = User.objects.create_user(**self.user_info) + profile = RegistrationProfile.objects.create_profile(new_user) + profile.send_activation_email(Site.objects.get_current()) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].to, [self.user_info['email']]) + + def test_user_creation(self): + """ + Creating a new user populates the correct data, and sets the + user's account inactive. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + self.assertEqual(new_user.username, 'alice') + self.assertEqual(new_user.email, 'alice@example.com') + self.failUnless(new_user.check_password('swordfish')) + self.failIf(new_user.is_active) + + def test_user_creation_email(self): + """ + By default, creating a new user sends an activation email. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + self.assertEqual(len(mail.outbox), 1) + + def test_user_creation_no_email(self): + """ + Passing ``send_email=False`` when creating a new user will not + send an activation email. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + send_email=False, + **self.user_info) + self.assertEqual(len(mail.outbox), 0) + + def test_unexpired_account(self): + """ + ``RegistrationProfile.activation_key_expired()`` is ``False`` + within the activation window. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + profile = RegistrationProfile.objects.get(user=new_user) + self.failIf(profile.activation_key_expired()) + + def test_expired_account(self): + """ + ``RegistrationProfile.activation_key_expired()`` is ``True`` + outside the activation window. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + new_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1) + new_user.save() + profile = RegistrationProfile.objects.get(user=new_user) + self.failUnless(profile.activation_key_expired()) + + def test_valid_activation(self): + """ + Activating a user within the permitted window makes the + account active, and resets the activation key. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + profile = RegistrationProfile.objects.get(user=new_user) + activated = RegistrationProfile.objects.activate_user(profile.activation_key) + + self.failUnless(isinstance(activated, User)) + self.assertEqual(activated.id, new_user.id) + self.failUnless(activated.is_active) + + profile = RegistrationProfile.objects.get(user=new_user) + self.assertEqual(profile.activation_key, RegistrationProfile.ACTIVATED) + + def test_expired_activation(self): + """ + Attempting to activate outside the permitted window does not + activate the account. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + new_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1) + new_user.save() + + profile = RegistrationProfile.objects.get(user=new_user) + activated = RegistrationProfile.objects.activate_user(profile.activation_key) + + self.failIf(isinstance(activated, User)) + self.failIf(activated) + + new_user = User.objects.get(username='alice') + self.failIf(new_user.is_active) + + profile = RegistrationProfile.objects.get(user=new_user) + self.assertNotEqual(profile.activation_key, RegistrationProfile.ACTIVATED) + + def test_activation_invalid_key(self): + """ + Attempting to activate with a key which is not a SHA1 hash + fails. + + """ + self.failIf(RegistrationProfile.objects.activate_user('foo')) + + def test_activation_already_activated(self): + """ + Attempting to re-activate an already-activated account fails. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + profile = RegistrationProfile.objects.get(user=new_user) + RegistrationProfile.objects.activate_user(profile.activation_key) + + profile = RegistrationProfile.objects.get(user=new_user) + self.failIf(RegistrationProfile.objects.activate_user(profile.activation_key)) + + def test_activation_nonexistent_key(self): + """ + Attempting to activate with a non-existent key (i.e., one not + associated with any account) fails. + + """ + # Due to the way activation keys are constructed during + # registration, this will never be a valid key. + invalid_key = sha_constructor('foo').hexdigest() + self.failIf(RegistrationProfile.objects.activate_user(invalid_key)) + + def test_expired_user_deletion(self): + """ + ``RegistrationProfile.objects.delete_expired_users()`` only + deletes inactive users whose activation window has expired. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + expired_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + username='bob', + password='secret', + email='bob@example.com') + expired_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1) + expired_user.save() + + RegistrationProfile.objects.delete_expired_users() + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertRaises(User.DoesNotExist, User.objects.get, username='bob') + + def test_management_command(self): + """ + The ``cleanupregistration`` management command properly + deletes expired accounts. + + """ + new_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + **self.user_info) + expired_user = RegistrationProfile.objects.create_inactive_user(site=Site.objects.get_current(), + username='bob', + password='secret', + email='bob@example.com') + expired_user.date_joined -= datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS + 1) + expired_user.save() + + management.call_command('cleanupregistration') + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertRaises(User.DoesNotExist, User.objects.get, username='bob') diff --git a/src/django-registration/registration/tests/urls.py b/src/django-registration/registration/tests/urls.py new file mode 100644 index 0000000..02ef609 --- /dev/null +++ b/src/django-registration/registration/tests/urls.py @@ -0,0 +1,82 @@ +""" +URLs used in the unit tests for django-registration. + +You should not attempt to use these URLs in any sort of real or +development environment; instead, use +``registration/backends/default/urls.py``. This URLconf includes those +URLs, and also adds several additional URLs which serve no purpose +other than to test that optional keyword arguments are properly +handled. + +""" + +from django.conf.urls.defaults import * +from django.views.generic.simple import direct_to_template + +from registration.views import activate +from registration.views import register + + +urlpatterns = patterns('', + # Test the 'activate' view with custom template + # name. + url(r'^activate-with-template-name/(?P\w+)/$', + activate, + {'template_name': 'registration/test_template_name.html', + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_activate_template_name'), + # Test the 'activate' view with + # extra_context_argument. + url(r'^activate-extra-context/(?P\w+)/$', + activate, + {'extra_context': {'foo': 'bar', 'callable': lambda: 'called'}, + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_activate_extra_context'), + # Test the 'activate' view with success_url argument. + url(r'^activate-with-success-url/(?P\w+)/$', + activate, + {'success_url': 'registration_test_custom_success_url', + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_activate_success_url'), + # Test the 'register' view with custom template + # name. + url(r'^register-with-template-name/$', + register, + {'template_name': 'registration/test_template_name.html', + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_register_template_name'), + # Test the'register' view with extra_context + # argument. + url(r'^register-extra-context/$', + register, + {'extra_context': {'foo': 'bar', 'callable': lambda: 'called'}, + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_register_extra_context'), + # Test the 'register' view with custom URL for + # closed registration. + url(r'^register-with-disallowed-url/$', + register, + {'disallowed_url': 'registration_test_custom_disallowed', + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_register_disallowed_url'), + # Set up a pattern which will correspond to the + # custom 'disallowed_url' above. + url(r'^custom-disallowed/$', + direct_to_template, + {'template': 'registration/registration_closed.html'}, + name='registration_test_custom_disallowed'), + # Test the 'register' view with custom redirect + # on successful registration. + url(r'^register-with-success_url/$', + register, + {'success_url': 'registration_test_custom_success_url', + 'backend': 'registration.backends.default.DefaultBackend'}, + name='registration_test_register_success_url' + ), + # Pattern for custom redirect set above. + url(r'^custom-success/$', + direct_to_template, + {'template': 'registration/test_template_name.html'}, + name='registration_test_custom_success_url'), + (r'', include('registration.backends.default.urls')), + ) diff --git a/src/django-registration/registration/tests/views.py b/src/django-registration/registration/tests/views.py new file mode 100644 index 0000000..17d3ad5 --- /dev/null +++ b/src/django-registration/registration/tests/views.py @@ -0,0 +1,246 @@ +import datetime + +from django.conf import settings +from django.contrib.auth.models import User +from django.core import mail +from django.core.urlresolvers import reverse +from django.test import TestCase + +from registration import forms +from registration.models import RegistrationProfile + + +class RegistrationViewTests(TestCase): + """ + Test the registration views. + + """ + urls = 'registration.tests.urls' + + def setUp(self): + """ + These tests use the default backend, since we know it's + available; that needs to have ``ACCOUNT_ACTIVATION_DAYS`` set. + + """ + self.old_activation = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', None) + if self.old_activation is None: + settings.ACCOUNT_ACTIVATION_DAYS = 7 + + def tearDown(self): + """ + Yank ``ACCOUNT_ACTIVATION_DAYS`` back out if it wasn't + originally set. + + """ + if self.old_activation is None: + settings.ACCOUNT_ACTIVATION_DAYS = self.old_activation + + def test_registration_view_initial(self): + """ + A ``GET`` to the ``register`` view uses the appropriate + template and populates the registration form into the context. + + """ + response = self.client.get(reverse('registration_register')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, + 'registration/registration_form.html') + self.failUnless(isinstance(response.context['form'], + forms.RegistrationForm)) + + def test_registration_view_success(self): + """ + A ``POST`` to the ``register`` view with valid data properly + creates a new user and issues a redirect. + + """ + response = self.client.post(reverse('registration_register'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish'}) + self.assertRedirects(response, + 'http://testserver%s' % reverse('registration_complete')) + self.assertEqual(RegistrationProfile.objects.count(), 1) + self.assertEqual(len(mail.outbox), 1) + + def test_registration_view_failure(self): + """ + A ``POST`` to the ``register`` view with invalid data does not + create a user, and displays appropriate error messages. + + """ + response = self.client.post(reverse('registration_register'), + data={'username': 'bob', + 'email': 'bobe@example.com', + 'password1': 'foo', + 'password2': 'bar'}) + self.assertEqual(response.status_code, 200) + self.failIf(response.context['form'].is_valid()) + self.assertFormError(response, 'form', field=None, + errors=u"The two password fields didn't match.") + self.assertEqual(len(mail.outbox), 0) + + def test_registration_view_closed(self): + """ + Any attempt to access the ``register`` view when registration + is closed fails and redirects. + + """ + old_allowed = getattr(settings, 'REGISTRATION_OPEN', True) + settings.REGISTRATION_OPEN = False + + closed_redirect = 'http://testserver%s' % reverse('registration_disallowed') + + response = self.client.get(reverse('registration_register')) + self.assertRedirects(response, closed_redirect) + + # Even if valid data is posted, it still shouldn't work. + response = self.client.post(reverse('registration_register'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish'}) + self.assertRedirects(response, closed_redirect) + self.assertEqual(RegistrationProfile.objects.count(), 0) + + settings.REGISTRATION_OPEN = old_allowed + + def test_registration_template_name(self): + """ + Passing ``template_name`` to the ``register`` view will result + in that template being used. + + """ + response = self.client.get(reverse('registration_test_register_template_name')) + self.assertTemplateUsed(response, + 'registration/test_template_name.html') + + def test_registration_extra_context(self): + """ + Passing ``extra_context`` to the ``register`` view will + correctly populate the context. + + """ + response = self.client.get(reverse('registration_test_register_extra_context')) + self.assertEqual(response.context['foo'], 'bar') + # Callables in extra_context are called to obtain the value. + self.assertEqual(response.context['callable'], 'called') + + def test_registration_disallowed_url(self): + """ + Passing ``disallowed_url`` to the ``register`` view will + result in a redirect to that URL when registration is closed. + + """ + old_allowed = getattr(settings, 'REGISTRATION_OPEN', True) + settings.REGISTRATION_OPEN = False + + closed_redirect = 'http://testserver%s' % reverse('registration_test_custom_disallowed') + + response = self.client.get(reverse('registration_test_register_disallowed_url')) + self.assertRedirects(response, closed_redirect) + + settings.REGISTRATION_OPEN = old_allowed + + def test_registration_success_url(self): + """ + Passing ``success_url`` to the ``register`` view will result + in a redirect to that URL when registration is successful. + + """ + success_redirect = 'http://testserver%s' % reverse('registration_test_custom_success_url') + response = self.client.post(reverse('registration_test_register_success_url'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish'}) + self.assertRedirects(response, success_redirect) + + def test_valid_activation(self): + """ + Test that the ``activate`` view properly handles a valid + activation (in this case, based on the default backend's + activation window). + + """ + success_redirect = 'http://testserver%s' % reverse('registration_activation_complete') + + # First, register an account. + self.client.post(reverse('registration_register'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish'}) + profile = RegistrationProfile.objects.get(user__username='alice') + response = self.client.get(reverse('registration_activate', + kwargs={'activation_key': profile.activation_key})) + self.assertRedirects(response, success_redirect) + self.failUnless(User.objects.get(username='alice').is_active) + + def test_invalid_activation(self): + """ + Test that the ``activate`` view properly handles an invalid + activation (in this case, based on the default backend's + activation window). + + """ + # Register an account and reset its date_joined to be outside + # the activation window. + self.client.post(reverse('registration_register'), + data={'username': 'bob', + 'email': 'bob@example.com', + 'password1': 'secret', + 'password2': 'secret'}) + expired_user = User.objects.get(username='bob') + expired_user.date_joined = expired_user.date_joined - datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS) + expired_user.save() + + expired_profile = RegistrationProfile.objects.get(user=expired_user) + response = self.client.get(reverse('registration_activate', + kwargs={'activation_key': expired_profile.activation_key})) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['activation_key'], + expired_profile.activation_key) + self.failIf(User.objects.get(username='bob').is_active) + + def test_activation_success_url(self): + """ + Passing ``success_url`` to the ``activate`` view and + successfully activating will result in that URL being used for + the redirect. + + """ + success_redirect = 'http://testserver%s' % reverse('registration_test_custom_success_url') + self.client.post(reverse('registration_register'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish'}) + profile = RegistrationProfile.objects.get(user__username='alice') + response = self.client.get(reverse('registration_test_activate_success_url', + kwargs={'activation_key': profile.activation_key})) + self.assertRedirects(response, success_redirect) + + def test_activation_template_name(self): + """ + Passing ``template_name`` to the ``activate`` view will result + in that template being used. + + """ + response = self.client.get(reverse('registration_test_activate_template_name', + kwargs={'activation_key': 'foo'})) + self.assertTemplateUsed(response, 'registration/test_template_name.html') + + def test_activation_extra_context(self): + """ + Passing ``extra_context`` to the ``activate`` view will + correctly populate the context. + + """ + response = self.client.get(reverse('registration_test_activate_extra_context', + kwargs={'activation_key': 'foo'})) + self.assertEqual(response.context['foo'], 'bar') + # Callables in extra_context are called to obtain the value. + self.assertEqual(response.context['callable'], 'called') diff --git a/src/django-registration/registration/urls.py b/src/django-registration/registration/urls.py new file mode 100644 index 0000000..af41026 --- /dev/null +++ b/src/django-registration/registration/urls.py @@ -0,0 +1,15 @@ +""" +Backwards-compatible URLconf for existing django-registration +installs; this allows the standard ``include('registration.urls')`` to +continue working, but that usage is deprecated and will be removed for +django-registration 1.0. For new installs, use +``include('registration.backends.default.urls')``. + +""" + +import warnings + +warnings.warn("include('registration.urls') is deprecated; use include('registration.backends.default.urls') instead.", + PendingDeprecationWarning) + +from registration.backends.default.urls import * diff --git a/src/django-registration/registration/views.py b/src/django-registration/registration/views.py new file mode 100644 index 0000000..1783e8d --- /dev/null +++ b/src/django-registration/registration/views.py @@ -0,0 +1,204 @@ +""" +Views which allow users to create and activate accounts. + +""" + + +from django.shortcuts import redirect +from django.shortcuts import render_to_response +from django.template import RequestContext + +from registration.backends import get_backend + + +def activate(request, backend, + template_name='registration/activate.html', + success_url=None, extra_context=None, **kwargs): + """ + Activate a user's account. + + The actual activation of the account will be delegated to the + backend specified by the ``backend`` keyword argument (see below); + the backend's ``activate()`` method will be called, passing any + keyword arguments captured from the URL, and will be assumed to + return a ``User`` if activation was successful, or a value which + evaluates to ``False`` in boolean context if not. + + Upon successful activation, the backend's + ``post_activation_redirect()`` method will be called, passing the + ``HttpRequest`` and the activated ``User`` to determine the URL to + redirect the user to. To override this, pass the argument + ``success_url`` (see below). + + On unsuccessful activation, will render the template + ``registration/activate.html`` to display an error message; to + override thise, pass the argument ``template_name`` (see below). + + **Arguments** + + ``backend`` + The dotted Python import path to the backend class to + use. Required. + + ``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. Optional. + + ``success_url`` + The name of a URL pattern to redirect to on successful + acivation. This is optional; if not specified, this will be + obtained by calling the backend's + ``post_activation_redirect()`` method. + + ``template_name`` + A custom template to use. This is optional; if not specified, + this will default to ``registration/activate.html``. + + ``\*\*kwargs`` + Any keyword arguments captured from the URL, such as an + activation key, which will be passed to the backend's + ``activate()`` method. + + **Context:** + + The context will be populated from the keyword arguments captured + in the URL, and any extra variables supplied in the + ``extra_context`` argument (see above). + + **Template:** + + registration/activate.html or ``template_name`` keyword argument. + + """ + backend = get_backend(backend) + account = backend.activate(request, **kwargs) + + if account: + if success_url is None: + to, args, kwargs = backend.post_activation_redirect(request, account) + return redirect(to, *args, **kwargs) + else: + return redirect(success_url) + + 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, + kwargs, + context_instance=context) + + +def register(request, backend, success_url=None, form_class=None, + disallowed_url='registration_disallowed', + template_name='registration/registration_form.html', + extra_context=None): + """ + Allow a new user to register an account. + + The actual registration of the account will be delegated to the + backend specified by the ``backend`` keyword argument (see below); + it will be used as follows: + + 1. The backend's ``registration_allowed()`` method will be called, + passing the ``HttpRequest``, to determine whether registration + of an account is to be allowed; if not, a redirect is issued to + the view corresponding to the named URL pattern + ``registration_disallowed``. To override this, see the list of + optional arguments for this view (below). + + 2. The form to use for account registration will be obtained by + calling the backend's ``get_form_class()`` method, passing the + ``HttpRequest``. To override this, see the list of optional + arguments for this view (below). + + 3. If valid, the form's ``cleaned_data`` will be passed (as + keyword arguments, and along with the ``HttpRequest``) to the + backend's ``register()`` method, which should return the new + ``User`` object. + + 4. Upon successful registration, the backend's + ``post_registration_redirect()`` method will be called, passing + the ``HttpRequest`` and the new ``User``, to determine the URL + to redirect the user to. To override this, see the list of + optional arguments for this view (below). + + **Required arguments** + + None. + + **Optional arguments** + + ``backend`` + The dotted Python import path to the backend class to use. + + ``disallowed_url`` + URL to redirect to if registration is not permitted for the + current ``HttpRequest``. Must be a value which can legally be + passed to ``django.shortcuts.redirect``. If not supplied, this + will be whatever URL corresponds to the named URL pattern + ``registration_disallowed``. + + ``form_class`` + The form class to use for registration. If not supplied, this + will be retrieved from the registration backend. + + ``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`` + URL to redirect to after successful registration. Must be a + value which can legally be passed to + ``django.shortcuts.redirect``. If not supplied, this will be + retrieved from the registration backend. + + ``template_name`` + A custom template to use. If not supplied, this will default + to ``registration/registration_form.html``. + + **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. + + """ + backend = get_backend(backend) + if not backend.registration_allowed(request): + return redirect(disallowed_url) + if form_class is None: + form_class = backend.get_form_class(request) + + if request.method == 'POST': + form = form_class(data=request.POST, files=request.FILES) + if form.is_valid(): + new_user = backend.register(request, **form.cleaned_data) + if success_url is None: + to, args, kwargs = backend.post_registration_redirect(request, new_user) + return redirect(to, *args, **kwargs) + else: + return redirect(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}, + context_instance=context) diff --git a/src/django-registration/setup.py b/src/django-registration/setup.py new file mode 100644 index 0000000..35a57a4 --- /dev/null +++ b/src/django-registration/setup.py @@ -0,0 +1,48 @@ +from distutils.core import setup +import os + +from registration import get_version + + +# Compile the list of packages available, because distutils doesn't have +# an easy way to do this. +packages, data_files = [], [] +root_dir = os.path.dirname(__file__) +if root_dir: + os.chdir(root_dir) + +for dirpath, dirnames, filenames in os.walk('registration'): + # Ignore dirnames that start with '.' + for i, dirname in enumerate(dirnames): + if dirname.startswith('.'): del dirnames[i] + if '__init__.py' in filenames: + pkg = dirpath.replace(os.path.sep, '.') + if os.path.altsep: + pkg = pkg.replace(os.path.altsep, '.') + packages.append(pkg) + elif filenames: + prefix = dirpath[13:] # Strip "registration/" or "registration\" + for f in filenames: + data_files.append(os.path.join(prefix, f)) + + +setup(name='django-registration', + version=get_version().replace(' ', '-'), + description='An extensible user-registration application for Django', + author='James Bennett', + author_email='james@b-list.org', + url='http://www.bitbucket.org/ubernostrum/django-registration/wiki/', + download_url='http://www.bitbucket.org/ubernostrum/django-registration/get/v0.7.gz', + package_dir={'registration': 'registration'}, + packages=packages, + package_data={'registration': data_files}, + classifiers=['Development Status :: 4 - Beta', + 'Environment :: Web Environment', + 'Framework :: Django', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Utilities'], + )