Commit 93e9a013 authored by chris's avatar chris

Added account and urlauth modules

parent b69208eb
Nuages - Easy poll sharing
=========================
==========================
Nuages aims to provide a collaborative meeting poll system, similar to doodle or rdvz. It is build in python, using the django framework and a little of javascript. This application was named after Django's famous song. Feedback and collaboration are welcome at nuage@ domainepublic.net
The project uses the following django modules:
- django-urlauth: http://bitbucket.org/lorien/django-urlauth/
- django-account: http://bitbucket.org/lorien/django-account/
The project uses the following javascripts:
- jquery, jquery-ui: http://www.jquery.com/
- jquery-dynamic-formset: http://code.google.com/p/django-dynamic-formset/
......
# -*- coding: utf-8
import re
from django import forms
from django.conf import settings
from django.contrib.auth import authenticate, login
from django.utils.translation import ugettext as _
from django.template import loader
from django.contrib.auth.models import User
from django.utils.safestring import mark_safe
from account.util import load_class
UserModel = load_class(settings.ACCOUNT_USER_MODEL)
if settings.ACCOUNT_CAPTCHA_ENABLED:
CaptchaField = load_class(settings.ACCOUNT_CAPTCHA_FIELD)
RE_USERNAME = getattr(settings, 'ACCOUNT_RE_USERNAME',
re.compile(r'[a-z0-9][_a-z0-9]*[a-z0-9]$', re.I))
USERNAME_MIN_LENGTH = getattr(settings, 'ACCOUNT_USERNAME_MIN_LENGTH', 3)
USERNAME_MAX_LENGTH = getattr(settings, 'ACCOUNT_USERNAME_MAX_LENGTH', 20)
PASSWORD_MIN_LENGTH = getattr(settings, 'ACCOUNT_PASSWORD_MIN_LENGTH', 3)
PASSWORD_MAX_LENGTH = getattr(settings, 'ACCOUNT_PASSWORD_MAX_LENGTH', 15)
class PasswordField(forms.CharField):
"""
Form field for password handling.
"""
def __init__(self, *args, **kwargs):
super(PasswordField, self).__init__(*args, **kwargs)
self.widget = forms.PasswordInput(render_value=False)
self.help_text = ''
def clean(self, value):
super(PasswordField, self).clean(value)
if len(value) < PASSWORD_MIN_LENGTH:
raise forms.ValidationError(_(u'Password length is less than %(min)d') % {'min': PASSWORD_MIN_LENGTH})
if len(value) > PASSWORD_MAX_LENGTH:
raise forms.ValidationError(_(u'Password length is more than %(max)d') % {'max': PASSWORD_MAX_LENGTH})
return value
class RegistrationForm(forms.Form):
username = forms.CharField(label=_(u'Login'), help_text=_(u'You can use a-z, 0-9 and underscore. Login length could be from %(min)s to %(max)s chars.') % {'min': USERNAME_MIN_LENGTH, 'max': USERNAME_MAX_LENGTH})
email = forms.EmailField(label=_('Email'))
password = PasswordField(label=_('Password'))
password_dup = PasswordField(label=_('Password (confirmation)'))
default_error_messages = {
'short_login': _(u'Login length is less than %(min)d'),
'long_login': _(u'Login length is more than %(max)d'),
'invalid_login': _(u'Login contains restricted symbols'),
'taken_login': _(u'This login already registered'),
'taken_email': _(u'This email already registered.'),
'mismatched_passwords': _('Passwords do not match'),
}
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
if settings.ACCOUNT_CAPTCHA_ENABLED:
self.fields['captcha'] = CaptchaField(label=settings.ACCOUNT_CAPTCHA_LABEL)
def clean_username(self):
if 'username' in self.cleaned_data:
value = self.cleaned_data['username']
if len(value) < USERNAME_MIN_LENGTH:
raise forms.ValidationError(self.default_error_messages['short_login'] % {'min': USERNAME_MIN_LENGTH})
if len(value) > USERNAME_MAX_LENGTH:
raise forms.ValidationError(self.default_error_messages['long_login'] % {'max': USERNAME_MAX_LENGTH})
if not RE_USERNAME.match(value):
raise forms.ValidationError(self.default_error_messages['invalid_login'])
try:
UserModel.objects.get(username__exact=value)
except UserModel.DoesNotExist:
return value
else:
raise forms.ValidationError(self.default_error_messages['taken_login'])
def clean_email(self):
#return self.cleaned_data.get('email','')
if 'email' in self.cleaned_data:
email = self.cleaned_data['email']
try:
UserModel.objects.get(email__exact=email)
except UserModel.DoesNotExist:
return email
else:
raise forms.ValidationError(self.default_error_messages['taken_email'])
def clean(self):
pwd1 = self.cleaned_data.get('password')
pwd2 = self.cleaned_data.get('password_dup')
if pwd1 and pwd2:
if pwd1 != pwd2:
# show error on top of password_dup field
self._errors['password_dup'] = [self.default_error_messages['mismatched_passwords']]
return self.cleaned_data
def save(self):
username = self.cleaned_data['username']
email = self.cleaned_data['email']
password = self.cleaned_data['password']
user = UserModel.objects.create_user(username, email, password)
if settings.ACCOUNT_ACTIVATION_REQUIRED:
user.is_active = False
user.save()
return user
class PasswordResetForm(forms.Form):
email = forms.EmailField(label=_('Email'))
default_error_messages = {'taken_email': _(u'This email is not registered')}
def clean_email(self):
if 'email' in self.cleaned_data:
email = self.cleaned_data['email']
if UserModel.objects.filter(email=email).count():
return email
else:
raise forms.ValidationError(self.default_error_messages['taken_email'])
class LoginForm(forms.Form):
username = forms.CharField(label=_('Username'))
password = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
default_error_messages = {
'invalid_account': _(u'Incorrect login or password'),
'inactive_account': _(u'Sorry. You account is not active. Maybe you didn\'t activate it.'),
}
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.base_fields['username'].help_text = ''
#self.base_fields['password'].widget = forms.PasswordInput()
self.base_fields['password'].help_text = ''
super(LoginForm, self).__init__(*args, **kwargs)
def clean(self):
super(LoginForm, self).clean()
if self.is_valid():
user = authenticate(
username=self.cleaned_data['username'],
password=self.cleaned_data['password'])
if not user is None:
if user.is_active:
login(self.request, user)
return self.cleaned_data
else:
raise forms.ValidationError(self.default_error_messages['inactive_account'])
else:
raise forms.ValidationError(self.default_error_messages['invalid_account'])
# TODO: REWRITE THIS HELL HORROR
class PasswordChangeForm(forms.Form):
"""
Form for changing user's password.
"""
old_password = PasswordField(label=_(u'Old password'))
password = PasswordField(label=_(u'Password'))
password_confirmation = PasswordField(label=_(u'Password (confirmation)'))
authkey = forms.CharField(widget=forms.HiddenInput, required=False)
uid = forms.CharField(widget=forms.HiddenInput, required=False)
default_error_messages = {
'invalid_password': _('Incorrect old password'),
'mismatched_passwords': _(u'The passwords do not match'),
}
def __init__(self, *args, **kwargs):
self.require_old = kwargs.pop('require_old', True)
self.user = kwargs.pop('user')
if not self.require_old:
self.base_fields['old_password'] = forms.Field(widget=forms.HiddenInput, required=False)
super(PasswordChangeForm, self).__init__(*args, **kwargs)
def clean(self):
if 'old_password' in self.cleaned_data and 'uid' in self.cleaned_data:
password = self.cleaned_data['old_password']
uid = self.cleaned_data['uid']
if password:
test_user = authenticate(username=self.user.username, password=password)
if not test_user:
del self.cleaned_data['old_password']
self._errors['old_password'] = [self.default_error_messages['invalid_password']]
return self.cleaned_data
def clean_password_confirmation(self):
pass1 = self.cleaned_data['password']
pass2 = self.cleaned_data['password_confirmation']
if pass1 != pass2:
raise forms.ValidationError(self.default_error_messages['mismatched_passwords'])
else:
return pass1
def clean_uid(self):
if self.require_old:
return self.cleaned_data['uid']
else:
try:
user = User.objects.get(pk=self.cleaned_data['uid'])
self.user = user
return self.cleaned_data['uid']
except User.DoesNotExist:
raise forms.ValidationError(_(u'Invalid username'))
def save(self):
self.user.set_password(self.cleaned_data['password'])
self.user.save()
return self.user
class EmailChangeForm(forms.Form):
"""
Form for email chanage.
"""
email = forms.EmailField(label=_(u'New email'))
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-24 08:32+0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:35
msgid "Login"
msgstr "Логин"
#: forms.py:36
#, python-format
msgid ""
"You can use a-z, 0-9 and underscore. Login length should be between %(min)s "
"and %(max)s"
msgstr ""
"Вы можете использовать символы a-z, 0-9 и подчёркивание. Длина логина должна "
"быть между %(min)s и %(max)s"
#: forms.py:44
#, python-format
msgid "Login length is less than %(min)d"
msgstr "Длина логина меньше, чем %(min)d"
#: forms.py:46
#, python-format
msgid "Login length is more than %(max)d"
msgstr "Длина логина больше, чем %(max)d"
#: forms.py:48
msgid "Login contains restricted symbols"
msgstr "Логин содержит запрещённые символы"
#: forms.py:55
msgid "This login already registered"
msgstr "Этот логин уже занят"
#: forms.py:72
#, python-format
msgid "Password length is less than %(min)d"
msgstr "Длина пароля меньше, чем %(min)d"
#: forms.py:74
#, python-format
msgid "Password length is more than %(max)d"
msgstr "Длина пароля больше, чем %(max)d"
#: forms.py:80 forms.py:121
msgid "Email"
msgstr "Электронная почта"
#: forms.py:81 forms.py:136 forms.py:170
msgid "Password"
msgstr "Пароль"
#: forms.py:82 forms.py:171
msgid "Password (confirmation)"
msgstr "Пароль (подтверждение)"
#: forms.py:99
msgid "This email already registered"
msgstr "Этот email уже зарегистрирован"
#: forms.py:108
msgid "Passwords do not match"
msgstr "Пароли не совпадают"
#: forms.py:123
msgid "This email is not registered"
msgstr "Этот email не зарегистрирован"
#: forms.py:135
msgid "Username"
msgstr "Логин"
#: forms.py:138
msgid "Incorrect login or password"
msgstr "Неправильный логин или пароль"
#: forms.py:159
msgid "Sorry. You account is not active. Maybe you didn't activate it."
msgstr ""
"Извините. Ваша учётная запись неактивна. Возможно, вы забыли активировать её."
#: forms.py:169
msgid "Old password"
msgstr "Старый пароль"
#: forms.py:190
msgid "Incorrect old password"
msgstr "Неправильный старый пароль"
#: forms.py:198
msgid "The passwords do not match"
msgstr "Пароли не совпадают"
#: forms.py:209
msgid "Invalid username"
msgstr ""
#: forms.py:223
msgid "New email"
msgstr ""
#: views.py:36
msgid "You have to logout before registration"
msgstr "Вы должны выйти перед регистрацией"
#: views.py:38
msgid "Sorry. Registration is disabled."
msgstr "Извините. Регистрация закрыта."
#: views.py:57
msgid ""
"The error was occuried while sending email with activation code. Account was "
"not created. Please, try later."
msgstr ""
"Во время отсылки email возникла ошибка. Учётная запись не создана. "
"Пожалуйста, попробуйте позже."
#: views.py:70 templates/account/password_changed.html:6
msgid "Password has been changed."
msgstr "Пароль был изменён."
#: views.py:84 views.py:148
msgid "Check the mail please"
msgstr "Проверьте почту, пожалуйста"
#: views.py:86 views.py:150
msgid ""
"Unfortunately we could not send you email in current time. Please, try later"
msgstr ""
"К сожалению, мы не можем выслать вам сейчас email. Пожалуйста, попробуйте "
"позже."
#: views.py:93
msgid "You are already authenticated"
msgstr "Вы уже вошли"
#: views.py:156
#, python-format
msgid "Your email has been changed to %s"
msgstr ""
#: views.py:173
msgid "You have successfully loged out"
msgstr "Вы успешно вышли"
#: templates/account/change_email.html:5
msgid "Change email"
msgstr ""
#: templates/account/change_email.html:8 templates/account/new_password.html:8
msgid "Save"
msgstr "Сохранить"
#: templates/account/created.html:5
msgid ""
"You have successfully registered in our site. Now you should activate your "
"account. Check email please."
msgstr ""
"Вы успешно зарегистрировались. Теперь вам нужно активировать вашу учётную "
"запись. Пожалуйста, проверьте почту."
#: templates/account/login.html:5
msgid "Authorization"
msgstr "Авторизация"
#: templates/account/login.html:6
msgid ""
"You should login to gain access to all site features. If you have not account"
msgstr ""
"Вы должны авторизоваться, чтобы получить доступ ко всем возможностям сайта. "
"Если у вас нет учётной записи,"
#: templates/account/login.html:6
msgid "register"
msgstr "пройдите регистрацию,"
#: templates/account/login.html:6
msgid "please"
msgstr "пожалуйста"
#: templates/account/login.html:9
msgid "login"
msgstr "войти"
#: templates/account/login.html:12
msgid "I forgot password"
msgstr "Я забыл пароль"
#: templates/account/message.html:5
msgid "Important information"
msgstr "Важная информация"
#: templates/account/new_password.html:5
msgid "New password"
msgstr "Новый пароль"
#: templates/account/password_changed.html:8
#, python-format
msgid ""
"Password has been changed. You can now <a href=\"%(login_url)s\">log on</a> "
"site."
msgstr ""
#: templates/account/registration.html:6
msgid "Registration"
msgstr "Регистрация"
#: templates/account/registration.html:9
#: templates/account/reset_password.html:8
msgid "Continue"
msgstr "Продолжить"
#: templates/account/reset_password.html:5
msgid "Password restore"
msgstr "Восстановление пароля"
#: templates/account/welcome.html:5
msgid "Welcome"
msgstr "Добро пожаловать"
#: templates/account/welcome.html:7
msgid ""
"Congratulations! You have successfully complete the registration on our site."
msgstr "Поздравляем! Вы успешно завершили регистрацию на нашем сайте."
#: templates/account/mail/reset_password.html:1
#, python-format
msgid "Password restore on %(domain)s"
msgstr "Восстановление пароля на сайте %(domain)s"
#: templates/account/mail/reset_password.html:2
#, python-format
msgid "You have requested password restore on %(domain)s"
msgstr "Вы запросили смену пароля на сайте %(domain)s"
#: templates/account/mail/reset_password.html:3
#, python-format
msgid ""
"After visiting the %(url)s, the new password will be set for your account"
msgstr ""
"После посещения ссылки %(url)s для вашего аккаунта будет установлен новый "
"пароль"
#: templates/account/mail/reset_password.html:4
#, python-format
msgid "New password: %(password)s"
msgstr "Новый пароль: %(password)s"
#~ msgid "\"Email change on %(domain)s"
#~ msgstr "Смена email на сайте %(domain)s"
#~ msgid "You have requested the change of email on %(domain)s"
#~ msgstr "Вы запросили смену email на сайте %(domain)s"
#~ msgid ""
#~ "After visiting the %(url)s, the new email will be set for your accont"
#~ msgstr ""
#~ "После посещения ссылки %(url)s для вашего аккаунта будет установлен новый "
#~ "пароль"
#~ msgid "New email: %(email)s"
#~ msgstr "Новый пароль: %(email)s"
#~ msgid "Registration on %(domain)s"
#~ msgstr "Регистрация на сайте %(domain)s"
#~ msgid "You have begun registration on %(domain)s"
#~ msgstr "Вы начали регистрация на сайте %(domain)s"
#~ msgid ""
#~ "If you want activate you account %(login)s, follow the link please: %(url)"
#~ "s"
#~ msgstr "Для активации аккаунта %(login)s откройте ссылку %(url)s"
#~ msgid "Successfuly registration on %(domain)s"
#~ msgstr "Успешная регистрация на сайте %(domain)s"
#~ msgid "You have registered on %(domain)s"
#~ msgstr "Вы зарегистрировались на сайте %(domain)s"
#~ msgid "Your login is %(login)s"
#~ msgstr "Ваш логин: %(login)s"
#~ msgid "foo %(min)s and %(max)s"
#~ msgstr "фуу %(min)s баррр %(max)s"
from datetime import datetime
from django.core.management.base import BaseCommand
from account.models import AuthKey
class Command(BaseCommand):
help = 'Purge expired AuthKey objects'
def handle(self, *args, **kwargs):
qs = AuthKey.objects.filter(expired__lt=datetime.now())
count = qs.count()
qs.delete()
print '%d keys deleted' % count
import account.signals
from django.utils.translation import ugettext_lazy as _
ACCOUNT_USER_MODEL = 'django.contrib.auth.models.User'
ACCOUNT_LOGIN_FORM = 'account.forms.LoginForm'
ACCOUNT_REGISTRATION_REDIRECT_URLNAME = 'registration_complete'
ACCOUNT_REGISTRATION_FORM = 'account.forms.RegistrationForm'
ACCOUNT_REGISTRATION_ENABLED = True
ACCOUNT_ACTIVATION_REQUIRED = True
ACCOUNT_AUTHENTICATION_WITH_EMAIL = False
ACCOUNT_PASSWORD_RESET_FORM = 'account.forms.PasswordResetForm'
ACCOUNT_PASSWORD_CHANGE_FORM = 'account.forms.PasswordChangeForm'
ACCOUNT_PASSWORD_CHANGE_REQUIRES_OLD = True
ACCOUNT_CAPTCHA_ENABLED = False
ACCOUNT_CAPTCHA_FIELD = 'captcha.fields.CaptchaField'
ACCOUNT_CAPTCHA_LABEL = _('Enter the text on the image')
from django.contrib import auth
from django.dispatch import Signal
from django.contrib.sites.models import Site
from urlauth.signals import key_user_found
from urlauth.models import AuthKey
from account.util import email_template
account_created = Signal(providing_args=['user', 'request'])
def key_user_found_handler(key, user, **kwargs):
extra = key.extra
action = extra.get('action')
if 'activation' == action:
if not user.is_active:
user.is_active = True
user.save()
email_template(user.email, 'account/mail/welcome',
user=user, domain=Site.objects.get_current().domain)
if user.is_active:
if 'new_email' == action:
if 'email' in extra:
user.email = args['email']
user.save()
key_user_found.connect(key_user_found_handler, sender=AuthKey)
{% extends 'base.html' %}
{% load i18n %}
{% block content %}
<p>{% trans "You have successfully registered in our site. Now you should activate your account. Check email please." %}</p>
{% endblock %}
{% extends 'base.html' %}
{% load i18n %}
{% block content %}
<h1>{% trans "Change email" %}</h1>
<form method="post" action="{% url auth_email_change %}">
<div class="wide">{{ form.as_p }}</div>
<p><input type="submit" value="{% trans "Save" %}" /></p>
</form>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h1>{% trans "Authorization" %}</h1>
<p>{% trans "You should login to gain access to all site features. If you have not account" %} <a href="{% url registration_register %}">{% trans "register" %}</a> {% trans "please" %}</p>
<form class="login-form" method="post">
<div class="wide">{{ form.as_p }}</div>
<p><input type="submit" value="{% trans "login" %}" /></p>
<input type="hidden" name="next" value="{{ next }}" />
</form>
<a href="{% url auth_password_reset %}">{% trans "I forgot password" %}</a>
{% endblock %}
{% load i18n %}
{% ifequal mode "html" %}
{% blocktrans %}You have begun registration on {{ domain }}{% endblocktrans %}.
{% blocktrans %}If you want activate you account {{ login }}, follow the <a href="{{ url }}">link</a> please.{% endblocktrans %}
{% else %}
{% blocktrans %}You have begun registration on {{ domain }}{% endblocktrans %}.
{% blocktrans %}If you want activate you account {{ login }}, follow the link please: {{ url }}{% endblocktrans %}
{% endifequal %}
{% load i18n %}{% blocktrans %}Registration on {{ domain }}{% endblocktrans %}
{% load i18n %}
{% ifequal mode "html" %}
{% blocktrans %}You have requested the change of email on {{ domain }}{% endblocktrans %}.
{% blocktrans %}After visiting <a href="{{ url }}">this url</a>, the new email will be set for your accont{% endblocktrans %}.
{% blocktrans %}New email: {{ email }}{% endblocktrans %}
{% else %}
{% blocktrans %}You have requested the change of email on {{ domain }}{% endblocktrans %}.
{% blocktrans %}After visiting the {{ url }}, the new email will be set for your accont{% endblocktrans %}.
{% blocktrans %}New email: {{ email }}{% endblocktrans %}
{% endif %}
{% load i18n %}
{% blocktrans %}"Email change on {{ domain }}{% endblocktrans %}
{% load i18n %}
{% ifequal mode "html" %}
{% blocktrans %}You have requested password restore on {{ domain }}.{% endblocktrans %}
{% blocktrans %}Click <a href="{{ url }}">this link</a> to change your password.{% endblocktrans %}
{% else %}
{% blocktrans %}Password restore on {{ domain }}{% endblocktrans %}
{% blocktrans %}You have requested password restore on {{ domain }}.{% endblocktrans %}
{% blocktrans %}Click this link {{ url }} to change your password.{% endblocktrans %}
{% endifequal %}
{% load i18n %}{% blocktrans %}Password restore on {{ domain }}{% endblocktrans %}
{% load i18n %}
{% ifequal mode "html" %}
Congratulations!
{% blocktrans %}You have registered on {{ domain }}{% endblocktrans %}.
{% blocktrans with user.username as username %}Your login is {{ username }}{% endblocktrans %}.
{% else %}