Commits

offline committed f278e5f

application renamed to openauth

Comments (0)

Files changed (19)

auth/__init__.py

-from auth import settings

auth/forms.py

-from django import forms
-from django.contrib.auth.models import User
-from django.contrib.auth import authenticate, login
-from django.utils.translation import ugettext as _
-from django.template import loader
-
-from annoying.functions import get_object_or_None
-from annoying.decorators import autostrip
-
-import auth
-from auth.models import Confirmation
-
-
-
-class UsernameField(forms.CharField):
-    """
-    Form field for username handling.
-    """
-
-    def __init__(self, *args, **kwargs):
-        super(UsernameField, self).__init__(*args, **kwargs)
-        self.label = _(u'Login')
-
-
-    def clean(self, value):
-        super(UsernameField, self).clean(value)
-
-        if len(value) < auth.settings.USERNAME_MIN_LENGTH:
-            raise forms.ValidationError(_(u'Login length is less than %(min)d') % {'min': auth.settings.USERNAME_MIN_LENGTH})
-        if len(value) > auth.settings.USERNAME_MAX_LENGTH:
-            raise forms.ValidationError(_(u'Login length is more than %(max)d') % {'max': auth.settings.USERNAME_MAX_LENGTH})
-        if not auth.settings.USERNAME_REGEX.match(value):
-            raise forms.ValidationError(_(u'Login contains restricted symbols'))
-
-        if auth.settings.UNIQUE_USERNAME and get_object_or_None(User, username=value):
-            raise forms.ValidationError(_(u'This login already registered'))
-        return value
-
-
-class PasswordField(forms.CharField):
-    """
-    Form field for password handling.
-    """
-
-    def __init__(self, *args, **kwargs):
-        super(PasswordField, self).__init__(*args, **kwargs)
-        self.widget = forms.PasswordInput()
-        self.help_text = ''
-
-
-    def clean(self, value):
-        super(PasswordField, self).clean(value)
-        if len(value) < auth.settings.PASSWORD_MIN_LENGTH:
-            raise forms.ValidationError(_(u'Password length is less than %(min)d') % {'min': PASSWORD_MIN_LENGTH})
-        if len(value) > auth.settings.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 = UsernameField()
-    email = forms.EmailField(label=_('Email'))
-    password = PasswordField(label=_('Password'))
-    password_dup = PasswordField(label=_('Password (confirmation)'))
-
-    
-    def clean_email(self):
-        #return self.cleaned_data.get('email','')
-        try:
-            User.objects.get(email__exact=self.cleaned_data['email'].lower())
-        except User.DoesNotExist:
-            return self.cleaned_data['email']
-        except KeyError:
-            pass
-        else:
-            raise forms.ValidationError(_(u'This email already registered'))
-
-    
-    def clean(self):
-        pwd1 = self.cleaned_data.get('password')
-        pwd2 = self.cleaned_data.get('password_dup')
-        if pwd1 and pwd2:
-            if pwd1 != pwd2:
-                raise forms.ValidationError(_(u'Passwords do not match'))
-        return self.cleaned_data
-
-
-    def save(self):
-        username = self.cleaned_data['username']
-        email = self.cleaned_data['email'].lower()
-        password = self.cleaned_data['password']
-        user = User.objects.create_user(username, email, password=password)
-        return user
-
-RegistrationForm = autostrip(RegistrationForm)
-
-
-class RestorePasswordForm(forms.Form):
-    email = forms.EmailField(label=_('Email'), widget=forms.TextInput(attrs={'class': 'field_input'}))
-
-    def clean_email(self):
-        if 'email' in self.cleaned_data:
-            email = self.cleaned_data['email'].lower()
-            if User.objects.filter(email=email).count():
-                return email
-            else:
-                raise forms.ValidationError(_(u'This email is not registered'))
-
-
-RestorePasswordForm = autostrip(RestorePasswordForm)
-
-
-class LoginForm(forms.Form):
-    email = forms.EmailField(label=_('Email'))
-    password = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
-
-    def __init__(self, *args, **kwargs):
-        self.request = kwargs.pop('request')
-        self.base_fields['email'].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():
-            email = self.cleaned_data['email'].lower()
-            password = self.cleaned_data['password']
-            user = get_object_or_None(User, email=email)
-            if user and  user.check_password(password):
-                if user.is_active:
-                    user.backend = 'django.contrib.auth.backends.ModelBackend'
-                    login(self.request, user)
-                    return self.cleaned_data
-                else:
-                    raise forms.ValidationError(_(u'Your account is not active. Please activate it.'))
-            else:
-                raise forms.ValidationError(_(u'Incorrect email or password'))
-
-LoginForm = autostrip(LoginForm)
-
-
-class NewPasswordForm(forms.Form):
-    """
-    Form for changing user's password.
-    """
-
-    password = PasswordField(label=_(u'Password'))
-    password_confirmation = PasswordField(label=_(u'Password (confirmation)'))
-
-
-
-    def clean_password_confirmation(self):
-        pass1 = self.cleaned_data['password']
-        pass2 = self.cleaned_data['password_confirmation']
-        if pass1 != pass2:
-            raise forms.ValidationError(_(u'The passwords do not match'))
-        else:
-            return pass1
-
-
-    def save(self, user):
-        user.set_password(self.cleaned_data['password'])
-        user.save()
-        return user
-
-NewPasswordForm = autostrip(NewPasswordForm)
-
-
-class NewEmailForm(forms.Form):
-    """
-    Form for email chanage.
-    """
-
-    email = forms.EmailField(label=_(u'New email'))
-
-    def save(self):
-        pass
-
-
-class EditUserForm(forms.Form):
-    def __init__(self, user, *args, **kwargs):
-        super(EditUserForm, self).__init__(*args, **kwargs)
-        self.user = user
-
-    username = forms.CharField(widget=forms.TextInput(attrs={'class':'field_input'}))
-    country = forms.CharField(widget=forms.TextInput(attrs={'class':'field_input'}), required=False)
-    jabber = forms.EmailField(widget=forms.TextInput(attrs={'class':'field_input'}), required=False)
-    about = forms.CharField(widget=forms.Textarea(attrs={'class':'field_input f130', 'style': 'height: 250px'}), required=False)
-
-
-
-    def save(self):
-        user = self.user
-        profile = user.profile
-        user.username = self.cleaned_data['username']
-        profile.country = self.cleaned_data['country']
-        profile.jabber = self.cleaned_data['jabber']
-        profile.about = self.cleaned_data['about']
-        user.save()
-        profile.save()
-        return user
-
-EditUserForm = autostrip(EditUserForm)

auth/models.py

-from django.db import models
-from django.contrib.auth.models import User
-
-from annoying.fields import AutoOneToOneField
-
-import auth
-from auth.utils import unicode_urlencode, generate_hash
-
-User.username = models.CharField(max_length=30, unique=auth.settings.UNIQUE_USERNAME)
-
-
-class Profile(models.Model):
-    user = AutoOneToOneField(User, primary_key=True)
-    country = models.CharField(max_length=50, blank=True)
-    about = models.TextField(blank=True)
-    
-    def get_gravatar(self, size=None):
-        """
-        Get gravatar image src with specified size (width, height), or use default
-        """
-        if not size:
-            size = auth.settings.GRAVATAR_SIZE
-        auth.settings.GRAVATAR_URL += unicode_urlencode({
-                                    'gravatar_id': generate_hash(self.user.email.lower()),
-                                    'size': size,
-                                    'default': auth.settings.GRAVATAR_TYPE,
-                                    })
-        return auth.settings.GRAVATAR_URL
-
-    
-    def __unicode__(self):
-        return self.user.username
-
-
-
-class Confirmation(models.Model):
-    """
-    Can be used for user activation, but also for
-    other purposes where confirmation is required.
-    """
-    user = models.ForeignKey(User)
-    key = models.CharField(max_length=32)
-    confirmation_type = models.IntegerField(default=1)
-
-    def __unicode__(self):
-        """
-        return:
-
-        vasya@pupkin: 36799bbfa2d074b5ffc1e8a55fb7f539
-        """
-        return "%s: %s" % (self.user.email, self.key)
-
-

auth/settings.py

-import re
-
-from annoying.functions import get_config
-
-
-MESSAGE_TYPE = get_config("MESSAGE_TYPE", "flash")
-CUSTOM_CONFIRMATION = get_config("CUSTOM_CONFIRMATION", None) # custom confirmation function
-REGISTRATION_ALLOWED = get_config("REGISTRATION_ALLOWED", True)
-REGISTRATION_FORM = get_config("REGISTRATION_FORM", "auth.forms.RegistrationForm")
-UNIQUE_USERNAME = get_config("UNIQUE_USERNAME", True)
-
-GRAVATAR_URL = get_config("GRAVATAR_URL", "http://www.gravatar.com/avatar.php?")
-GRAVATAR_SIZE = get_config("GRAVATAR_SIZE", (25, 25))
-GRAVATAR_TYPE = get_config("GRAVATAR_TYPE", "identicon")
-
-ACTIVATION_REQUIRED = get_config("ACTIVATION_REQUIRED", True)
-ACTIVATION_AUTO_LOGIN = get_config("ACTIVATION_AUTO_LOGIN", True)
-
-ACTIVATION_CONFIRMATION_TYPE = get_config("ACTIVATION_CONFIRMATION_TYPE", 1)
-PASSWORD_RESET_CONFIRMATION_TYPE = get_config("PASSWORD_RESET_CONFIRMATION_TYPE", 2)
-
-LOGIN_REDIRECT_URL = get_config("LOGIN_REDIRECT_URL", "/auth/login/")
-
-USERNAME_REGEX = get_config("USERNAME_REGEX", re.compile(r"[a-z0-9][_a-z0-9]*[a-z0-9]$", re.I))
-USERNAME_MIN_LENGTH = get_config("ACCOUNT_USERNAME_MIN_LENGTH", 3)
-USERNAME_MAX_LENGTH = get_config("ACCOUNT_USERNAME_MAX_LENGTH", 30)
-
-PASSWORD_MIN_LENGTH = get_config("ACCOUNT_PASSWORD_MIN_LENGTH", 1)
-PASSWORD_MAX_LENGTH = get_config("ACCOUNT_PASSWORD_MAX_LENGTH", 30)
-PASSWORD_FIELD_ATTRIBUTES = get_config("PASSWORD_FIELD_ATTRIBUTES", {})

auth/templates/auth/mail/registration.txt

-{% load i18n %}{% blocktrans %}Registration on {{ domain }}{% endblocktrans %}
-{% blocktrans %}Thanks for registration on {{ domain }}{% endblocktrans %}.
-{% blocktrans %}Please use following link to activate your account: {{ url }}{% endblocktrans %}

auth/templates/auth/registration.html

-{% extends 'base.html' %}
-{% block content %}
-<form action='.' method='post'>
-{{ form.as_table }}
-<input type='submit' value='submit' />
-</form>
-{% endblock %}

auth/urls.py

-from django.conf.urls.defaults import *
-from django.views.generic.simple import direct_to_template
-
-from auth import views
-
-
-urlpatterns = patterns('',
-    url(r'^registration/$', views.registration, name='auth-registration'),
-    url(r'^login/$', views.login, name='auth-login'),
-    url(r'^logout/$', views.logout, name='auth-logout'),
-    url(r'^reset_password/$', views.reset_password, name='auth-reset-password'),
-    url(r'^change_password/$', views.change_password, name='auth-change-password'),
-    url(r'^confirm/$', views.confirm, name='auth-confirm'),
-    url(r'^user/(\d+)/$', views.show_user, name='show-user'),
-    #url(r'^edit/(\d+)/$', views.edit_user, name='edit-user'),
-    #url(r'^email_changed/$', views.email_changed, name='auth_email_changed'),
-)

auth/utils.py

-def unicode_urlencode(params):
-    """A unicode aware version of urllib.urlencode"""
-    from urllib import urlencode
-
-    if isinstance(params, dict):
-        params = params.items()
-    return urlencode([(k, isinstance(v, unicode) and v.encode('utf-8') or v) for k, v in params])
-
-
-def generate_hash(string=None):
-    import time
-    try:                                                           
-        from hashlib import md5                                    
-    except ImportError:                                            
-        import md5                                                 
-        md5 = md5.new
-
-    if not string:
-        string = str(time.time())
-    hash = md5(string).hexdigest()
-    return hash
-
-
-def build_redirect_url(request, default_url):
-    """
-    Retrieve redirect url from session.
-
-    Use default if retrieved one is broken or not safe.
-    """
-    url = request.session.get('login_redirect_url')
-    if not url or '//' in url or ' ' in url:
-        url = default_url
-    try:
-        del request.session['login_redirect_url']
-    except KeyError:
-        pass
-    return url
-
-
-def parse_template(template_path, **kwargs):
-    """                                     
-    Load and render template.               
-
-    First line of template should contain the subject of email.
-    Return tuple with subject and content.                     
-    """                                                        
-    import re
-
-    from django.template.loader import get_template
-    from django.template import Context
-
-    template = get_template(template_path)
-    context = Context(kwargs)             
-    data = template.render(context).strip()
-    subject, content = re.split(r'\r?\n', data, 1)
-    return (subject.strip(), content.strip())     
-
-
-def email_template(rcpt, template_path, **kwargs):
-    """
-    Load, render and email template.
-
-    **kwargs may contain variables for template rendering.
-    """
-    from django.conf import settings
-    from django.core.mail import send_mail 
-
-    subject, content = parse_template(template_path, **kwargs)
-    count = send_mail(subject, content, settings.DEFAULT_FROM_EMAIL,
-                      [rcpt], fail_silently=True)
-    return bool(count)
-
-def str_to_class(str):
-    mod_str, cls_str = str.rsplit('.', 1)
-    mod = __import__(mod_str, globals(), locals(), ['foobar'])
-    cls = getattr(mod, cls_str)
-    return cls

auth/views.py

-import time
-
-from datetime import datetime, timedelta, date
-
-from django.conf import settings
-from django.contrib.auth.models import User
-from django.core.urlresolvers import reverse
-from django.contrib.auth.decorators import login_required
-from django.contrib.auth import login as proccess_login
-from django.shortcuts import get_object_or_404, redirect
-from django.utils.translation import ugettext as _
-from django.http import HttpResponseRedirect
-from django.db.models import Q
-
-from annoying.decorators import ajax_request, render_to
-from ninjapaginator.util import NinjaPaginator
-
-
-import auth                          
-from auth.forms import RestorePasswordForm, NewPasswordForm, LoginForm, NewEmailForm, EditUserForm
-from auth.utils import email_template, build_redirect_url, str_to_class, generate_hash
-from auth.models import Confirmation
-
-
-def message(request, msg, priority, redirect_name, args=None, kwargs=None):
-    """
-    Shortcut that prepare data for message view.
-    """
-    if auth.settings.MESSAGE_TYPE == 'flash':
-        request.flash[priority] = msg
-        return redirect(redirect_name, args=args, kwargs=kwargs)
-    return {'TEMPLATE': 'auth/message.html', 'message': msg}
-
-
-@render_to()
-def confirm(request):
-    """
-    Check confirmation key, proccess confirmation and delete key.
-    """
-    key = request.GET.get("key")
-    confirmation_type = int(request.GET.get("type", 1))
-    confirmation = get_object_or_404(Confirmation, key=key, confirmation_type=confirmation_type)
-    if confirmation_type == auth.settings.ACTIVATION_CONFIRMATION_TYPE:
-        user = confirmation.user
-        user.is_active = True
-        user.save()
-        if auth.settings.ACTIVATION_AUTO_LOGIN:
-            confirmation.user.backend = 'django.contrib.auth.backends.ModelBackend'
-            proccess_login(request, user)
-
-        confirmation.delete()
-        return message(request, _('Your account successfully activated'), 'success', 'show-user', args=[user.id])
-    elif confiramtion_type == auth.settings.PASSWORD_RESET_CONFIRMATION_TYPE:
-        confirmation.user.backend = 'django.contrib.auth.backends.ModelBackend'                                                                                  
-        proccess_login(request, confirmation.user)      
-        confirmation.delete()
-        return message(request, _("Now you can change your password"), "notice", "auth-reset-form")
-    else:
-        return auth.settings.CUSTOM_CONFIRMATION(request)
-
-
-@render_to('auth/registration.html')
-def registration(request):
-    """
-    Only anonymous users can view this page
-    Registration should be allowed in REGISTRATION_ALLOWED setting
-    """
-    if request.user.is_authenticated():
-        return message(request, _('You have to logout before registration'), 'notice', '/')
-
-    if not auth.settings.REGISTRATION_ALLOWED: 
-        request.flash['notice'] = 'Sorry. Registration is disabled.'
-        return message(request, _('We are sorry, but registration is disabled. Come back later'), 'notice', '/')
-
-    if request.POST:
-        form = str_to_class(auth.settings.REGISTRATION_FORM)(request.POST)
-        if form.is_valid():
-            user = form.save()
-            if auth.settings.ACTIVATION_REQUIRED:
-                user.is_active = False
-            user.save()
-
-            if auth.settings.ACTIVATION_REQUIRED:
-                confirmation = Confirmation(user=user, key=generate_hash(), confirmation_type=auth.settings.ACTIVATION_CONFIRMATION_TYPE)
-                confirmation.save()
-                url = request.build_absolute_uri(reverse('auth-confirm'))
-                url += '?key=%s&type=%s' % (confirmation.key, confirmation.confirmation_type)
-                params = {'domain': request.get_host(), 'email': user.email, 'url': url}
-                if email_template(user.email, 'auth/mail/registration.txt', **params):
-                    return message(request, _("You have successfully registered. Check your inbox for email with activation link."), "success", "/")
-                else:
-                    user.delete()
-                    return message(request, _('The error was occuried while sending email with activation code. Account was not created. Please, try later.'), "error", "/")
-            else:
-                return message(request, _("You have successfully registered. You can login now"), "success", "login")
-
-    else:
-        form = str_to_class(auth.settings.REGISTRATION_FORM)()
-    return {'form': form}
-
-
-@render_to('auth/reset_password.html')
-def reset_password(request):
-    if request.POST:
-        form = ResetPasswordForm(request.POST)
-        if form.is_valid():
-            user = User.objects.get(email=form.cleaned_data['email'].lower())
-            confirmation = Confirmation(user=user, key=generate_hash(), confirmation_type=PASSWORD_RESET_CONFIRMATION_TYPE)
-            confirmation.save()
-            url = request.build_redirect_url(reverse('auth-confirmation'))
-            url += '?key=%s&type=%s' % (confirmation.key, auth.settings.PASSWORD_RESET_CONFIRMATION_TYPE)
-            args = {'domain': request.get_host(), 'url': url}
-            if email_template(user.email, 'auth/mail/reset_password.txt', **args):
-                return message(request, _('Check your email please'), 'notice', '/')
-            else:
-                return message(request, _('Unfortunately we could not send you email in current time. Please, try later'), 'error', '/')
-    else:
-        form = RestorePasswordForm()
-    return {'form': form}
-
-
-@render_to('auth/login.html')
-def login(request):
-    if request.user.is_authenticated():
-        return message(request, _('You are already authenticated'), 'notice', '/')
-
-    if request.POST:
-        form = LoginForm(request.POST, request=request)
-        request.session['login_redirect_url'] = request.GET.get('next')
-        if form.is_valid():
-            redirect_url = build_redirect_url(request, auth.settings.LOGIN_REDIRECT_URL)
-            return message(request, _('You have successfully logged-in'), 'success', redirect_url)
-    else:
-        form = LoginForm(request=request)
-    return {'form': form}
-
-
-@login_required
-@render_to('account/new_password.html')
-def change_password(request):
-    if 'POST' == request.method:
-        form = NewPasswordForm(request.POST)
-    else:
-        form = NewPasswordForm()
-
-    if form.is_valid():
-        form.save(request.user)
-        request.flash['notice'] = _('Password was changed')
-        return HttpResponseRedirect("/")
-    return {'form': form}
-
-
-@render_to('account/message.html')
-def logout(request):
-    auth.logout(request)
-    request.flash['notice'] = "You have been logged out"
-    return HttpResponseReload(request)
-
-
-@render_to('account/edit_user.html')
-def edit_user(request, user_id):
-    user = get_object_or_404(User, pk=user_id)
-    if not request.user.is_authenticated() or user != request.user and not request.user.is_staff:
-        return HttpResponseReload(request)
-    if request.POST:
-        form = EditUserForm(user, request.POST, request.FILES)
-        if form.is_valid():
-            form.save()
-            request.flash['notice'] = "User details successfully changed"
-            return HttpResponseRedirect(reverse('show-user', args=[user.id]))
-    else:
-        initial = {'username': user.username, 
-                    'country': user.profile.country,
-                    'jabber': user.profile.jabber,
-                    'about': user.profile.about}
-        form = EditUserForm(user, initial=initial)
-    return {'form': form, 'user': user}
-
-
-
-@render_to('auth/profile.html')
-def show_user(request, user_id):
-    """
-    Show user profile 
-    """
-    
-    user = get_object_or_404(User, pk=user_id)
-    return {'user': user}
-
- 
-
-
-@render_to('account/users.html')
-@NinjaPaginator(style='filmfeed', per_page=16) 
-def users(request):
-    users = User.objects.all()
-    users = order_by(request, users)
-    return {'object_list': users}
-

openauth/__init__.py

+from openauth import settings

openauth/forms.py

+from django import forms
+from django.contrib.auth.models import User
+from django.contrib.auth import authenticate, login
+from django.utils.translation import ugettext as _
+from django.template import loader
+
+from annoying.functions import get_object_or_None
+from annoying.decorators import autostrip
+
+import openauth
+from openauth.models import Confirmation
+
+
+
+class UsernameField(forms.CharField):
+    """
+    Form field for username handling.
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(UsernameField, self).__init__(*args, **kwargs)
+        self.label = _(u'Login')
+
+
+    def clean(self, value):
+        super(UsernameField, self).clean(value)
+
+        if len(value) < openauth.settings.USERNAME_MIN_LENGTH:
+            raise forms.ValidationError(_(u'Login length is less than %(min)d') % {'min': openauth.settings.USERNAME_MIN_LENGTH})
+        if len(value) > openauth.settings.USERNAME_MAX_LENGTH:
+            raise forms.ValidationError(_(u'Login length is more than %(max)d') % {'max': openauth.settings.USERNAME_MAX_LENGTH})
+        if not openauth.settings.USERNAME_REGEX.match(value):
+            raise forms.ValidationError(_(u'Login contains restricted symbols'))
+
+        if openauth.settings.UNIQUE_USERNAME and get_object_or_None(User, username=value):
+            raise forms.ValidationError(_(u'This login already registered'))
+        return value
+
+
+class PasswordField(forms.CharField):
+    """
+    Form field for password handling.
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(PasswordField, self).__init__(*args, **kwargs)
+        self.widget = forms.PasswordInput()
+        self.help_text = ''
+
+
+    def clean(self, value):
+        super(PasswordField, self).clean(value)
+        if len(value) < openauth.settings.PASSWORD_MIN_LENGTH:
+            raise forms.ValidationError(_(u'Password length is less than %(min)d') % {'min': PASSWORD_MIN_LENGTH})
+        if len(value) > openauth.settings.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 = UsernameField()
+    email = forms.EmailField(label=_('Email'))
+    password = PasswordField(label=_('Password'))
+    password_dup = PasswordField(label=_('Password (confirmation)'))
+
+    
+    def clean_email(self):
+        #return self.cleaned_data.get('email','')
+        try:
+            User.objects.get(email__exact=self.cleaned_data['email'].lower())
+        except User.DoesNotExist:
+            return self.cleaned_data['email']
+        except KeyError:
+            pass
+        else:
+            raise forms.ValidationError(_(u'This email already registered'))
+
+    
+    def clean(self):
+        pwd1 = self.cleaned_data.get('password')
+        pwd2 = self.cleaned_data.get('password_dup')
+        if pwd1 and pwd2:
+            if pwd1 != pwd2:
+                raise forms.ValidationError(_(u'Passwords do not match'))
+        return self.cleaned_data
+
+
+    def save(self):
+        username = self.cleaned_data['username']
+        email = self.cleaned_data['email'].lower()
+        password = self.cleaned_data['password']
+        user = User.objects.create_user(username, email, password=password)
+        return user
+
+RegistrationForm = autostrip(RegistrationForm)
+
+
+class RestorePasswordForm(forms.Form):
+    email = forms.EmailField(label=_('Email'), widget=forms.TextInput(attrs={'class': 'field_input'}))
+
+    def clean_email(self):
+        if 'email' in self.cleaned_data:
+            email = self.cleaned_data['email'].lower()
+            if User.objects.filter(email=email).count():
+                return email
+            else:
+                raise forms.ValidationError(_(u'This email is not registered'))
+
+
+RestorePasswordForm = autostrip(RestorePasswordForm)
+
+
+class LoginForm(forms.Form):
+    email = forms.EmailField(label=_('Email'))
+    password = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
+
+    def __init__(self, *args, **kwargs):
+        self.request = kwargs.pop('request')
+        self.base_fields['email'].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():
+            email = self.cleaned_data['email'].lower()
+            password = self.cleaned_data['password']
+            user = get_object_or_None(User, email=email)
+            if user and  user.check_password(password):
+                if user.is_active:
+                    user.backend = 'django.contrib.auth.backends.ModelBackend'
+                    login(self.request, user)
+                    return self.cleaned_data
+                else:
+                    raise forms.ValidationError(_(u'Your account is not active. Please activate it.'))
+            else:
+                raise forms.ValidationError(_(u'Incorrect email or password'))
+
+LoginForm = autostrip(LoginForm)
+
+
+class NewPasswordForm(forms.Form):
+    """
+    Form for changing user's password.
+    """
+
+    password = PasswordField(label=_(u'Password'))
+    password_confirmation = PasswordField(label=_(u'Password (confirmation)'))
+
+
+
+    def clean_password_confirmation(self):
+        pass1 = self.cleaned_data['password']
+        pass2 = self.cleaned_data['password_confirmation']
+        if pass1 != pass2:
+            raise forms.ValidationError(_(u'The passwords do not match'))
+        else:
+            return pass1
+
+
+    def save(self, user):
+        user.set_password(self.cleaned_data['password'])
+        user.save()
+        return user
+
+NewPasswordForm = autostrip(NewPasswordForm)
+
+
+class NewEmailForm(forms.Form):
+    """
+    Form for email chanage.
+    """
+
+    email = forms.EmailField(label=_(u'New email'))
+
+    def save(self):
+        pass
+
+
+class EditUserForm(forms.Form):
+    def __init__(self, user, *args, **kwargs):
+        super(EditUserForm, self).__init__(*args, **kwargs)
+        self.user = user
+
+    username = forms.CharField(widget=forms.TextInput(attrs={'class':'field_input'}))
+    country = forms.CharField(widget=forms.TextInput(attrs={'class':'field_input'}), required=False)
+    jabber = forms.EmailField(widget=forms.TextInput(attrs={'class':'field_input'}), required=False)
+    about = forms.CharField(widget=forms.Textarea(attrs={'class':'field_input f130', 'style': 'height: 250px'}), required=False)
+
+
+
+    def save(self):
+        user = self.user
+        profile = user.profile
+        user.username = self.cleaned_data['username']
+        profile.country = self.cleaned_data['country']
+        profile.jabber = self.cleaned_data['jabber']
+        profile.about = self.cleaned_data['about']
+        user.save()
+        profile.save()
+        return user
+
+EditUserForm = autostrip(EditUserForm)

openauth/models.py

+from django.db import models
+from django.contrib.auth.models import User
+
+from annoying.fields import AutoOneToOneField
+
+import openauth
+from openauth.utils import unicode_urlencode, generate_hash
+
+User.username = models.CharField(max_length=30, unique=openauth.settings.UNIQUE_USERNAME)
+
+
+class Profile(models.Model):
+    user = AutoOneToOneField(User, primary_key=True)
+    country = models.CharField(max_length=50, blank=True)
+    about = models.TextField(blank=True)
+    
+    def get_gravatar(self, size=None):
+        """
+        Get gravatar image src with specified size (width, height), or use default
+        """
+        if not size:
+            size = openauth.settings.GRAVATAR_SIZE
+        openauth.settings.GRAVATAR_URL += unicode_urlencode({
+                                    'gravatar_id': generate_hash(self.user.email.lower()),
+                                    'size': size,
+                                    'default': openauth.settings.GRAVATAR_TYPE,
+                                    })
+        return openauth.settings.GRAVATAR_URL
+
+    
+    def __unicode__(self):
+        return self.user.username
+
+
+
+class Confirmation(models.Model):
+    """
+    Can be used for user activation, but also for
+    other purposes where confirmation is required.
+    """
+    user = models.ForeignKey(User)
+    key = models.CharField(max_length=32)
+    confirmation_type = models.IntegerField(default=1)
+
+    def __unicode__(self):
+        """
+        return:
+
+        vasya@pupkin: 36799bbfa2d074b5ffc1e8a55fb7f539
+        """
+        return "%s: %s" % (self.user.email, self.key)
+
+

openauth/settings.py

+import re
+
+from annoying.functions import get_config
+
+
+MESSAGE_TYPE = get_config("MESSAGE_TYPE", "flash")
+CUSTOM_CONFIRMATION = get_config("CUSTOM_CONFIRMATION", None) # custom confirmation function
+REGISTRATION_ALLOWED = get_config("REGISTRATION_ALLOWED", True)
+REGISTRATION_FORM = get_config("REGISTRATION_FORM", "auth.forms.RegistrationForm")
+UNIQUE_USERNAME = get_config("UNIQUE_USERNAME", True)
+
+GRAVATAR_URL = get_config("GRAVATAR_URL", "http://www.gravatar.com/avatar.php?")
+GRAVATAR_SIZE = get_config("GRAVATAR_SIZE", (25, 25))
+GRAVATAR_TYPE = get_config("GRAVATAR_TYPE", "identicon")
+
+ACTIVATION_REQUIRED = get_config("ACTIVATION_REQUIRED", True)
+ACTIVATION_AUTO_LOGIN = get_config("ACTIVATION_AUTO_LOGIN", True)
+
+ACTIVATION_CONFIRMATION_TYPE = get_config("ACTIVATION_CONFIRMATION_TYPE", 1)
+PASSWORD_RESET_CONFIRMATION_TYPE = get_config("PASSWORD_RESET_CONFIRMATION_TYPE", 2)
+
+LOGIN_REDIRECT_URL = get_config("LOGIN_REDIRECT_URL", "/auth/login/")
+
+USERNAME_REGEX = get_config("USERNAME_REGEX", re.compile(r"[a-z0-9][_a-z0-9]*[a-z0-9]$", re.I))
+USERNAME_MIN_LENGTH = get_config("ACCOUNT_USERNAME_MIN_LENGTH", 3)
+USERNAME_MAX_LENGTH = get_config("ACCOUNT_USERNAME_MAX_LENGTH", 30)
+
+PASSWORD_MIN_LENGTH = get_config("ACCOUNT_PASSWORD_MIN_LENGTH", 1)
+PASSWORD_MAX_LENGTH = get_config("ACCOUNT_PASSWORD_MAX_LENGTH", 30)
+PASSWORD_FIELD_ATTRIBUTES = get_config("PASSWORD_FIELD_ATTRIBUTES", {})

openauth/templates/openuath/mail/registration.txt

+{% load i18n %}{% blocktrans %}Registration on {{ domain }}{% endblocktrans %}
+{% blocktrans %}Thanks for registration on {{ domain }}{% endblocktrans %}.
+{% blocktrans %}Please use following link to activate your account: {{ url }}{% endblocktrans %}

openauth/templates/openuath/registration.html

+{% extends 'base.html' %}
+{% block content %}
+<form action='.' method='post'>
+{{ form.as_table }}
+<input type='submit' value='submit' />
+</form>
+{% endblock %}
+from django.conf.urls.defaults import *
+from django.views.generic.simple import direct_to_template
+
+from openauth import views
+
+
+urlpatterns = patterns('',
+    url(r'^registration/$', views.registration, name='openauth-registration'),
+    url(r'^login/$', views.login, name='openauth-login'),
+    url(r'^logout/$', views.logout, name='openauth-logout'),
+    url(r'^reset_password/$', views.reset_password, name='openauth-reset-password'),
+    url(r'^change_password/$', views.change_password, name='openauth-change-password'),
+    url(r'^confirm/$', views.confirm, name='openauth-confirm'),
+    url(r'^user/(\d+)/$', views.show_user, name='show-user'),
+    #url(r'^edit/(\d+)/$', views.edit_user, name='edit-user'),
+    #url(r'^email_changed/$', views.email_changed, name='auth_email_changed'),
+)

openauth/utils.py

+def unicode_urlencode(params):
+    """A unicode aware version of urllib.urlencode"""
+    from urllib import urlencode
+
+    if isinstance(params, dict):
+        params = params.items()
+    return urlencode([(k, isinstance(v, unicode) and v.encode('utf-8') or v) for k, v in params])
+
+
+def generate_hash(string=None):
+    import time
+    try:                                                           
+        from hashlib import md5                                    
+    except ImportError:                                            
+        import md5                                                 
+        md5 = md5.new
+
+    if not string:
+        string = str(time.time())
+    hash = md5(string).hexdigest()
+    return hash
+
+
+def build_redirect_url(request, default_url):
+    """
+    Retrieve redirect url from session.
+
+    Use default if retrieved one is broken or not safe.
+    """
+    url = request.session.get('login_redirect_url')
+    if not url or '//' in url or ' ' in url:
+        url = default_url
+    try:
+        del request.session['login_redirect_url']
+    except KeyError:
+        pass
+    return url
+
+
+def parse_template(template_path, **kwargs):
+    """                                     
+    Load and render template.               
+
+    First line of template should contain the subject of email.
+    Return tuple with subject and content.                     
+    """                                                        
+    import re
+
+    from django.template.loader import get_template
+    from django.template import Context
+
+    template = get_template(template_path)
+    context = Context(kwargs)             
+    data = template.render(context).strip()
+    subject, content = re.split(r'\r?\n', data, 1)
+    return (subject.strip(), content.strip())     
+
+
+def email_template(rcpt, template_path, **kwargs):
+    """
+    Load, render and email template.
+
+    **kwargs may contain variables for template rendering.
+    """
+    from django.conf import settings
+    from django.core.mail import send_mail 
+
+    subject, content = parse_template(template_path, **kwargs)
+    count = send_mail(subject, content, settings.DEFAULT_FROM_EMAIL,
+                      [rcpt], fail_silently=True)
+    return bool(count)
+
+def str_to_class(str):
+    mod_str, cls_str = str.rsplit('.', 1)
+    mod = __import__(mod_str, globals(), locals(), ['foobar'])
+    cls = getattr(mod, cls_str)
+    return cls

openauth/views.py

+import time
+
+from datetime import datetime, timedelta, date
+
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import login as proccess_login
+from django.shortcuts import get_object_or_404, redirect
+from django.utils.translation import ugettext as _
+from django.http import HttpResponseRedirect
+from django.db.models import Q
+
+from annoying.decorators import ajax_request, render_to
+from ninjapaginator.util import NinjaPaginator
+
+
+import openauth                          
+from openauth.forms import RestorePasswordForm, NewPasswordForm, LoginForm, NewEmailForm, EditUserForm
+from openauth.utils import email_template, build_redirect_url, str_to_class, generate_hash
+from openauth.models import Confirmation
+
+
+def message(request, msg, priority, redirect_name, args=None, kwargs=None):
+    """
+    Shortcut that prepare data for message view.
+    """
+    if openauth.settings.MESSAGE_TYPE == 'flash':
+        request.flash[priority] = msg
+        return redirect(redirect_name, args=args, kwargs=kwargs)
+    return {'TEMPLATE': 'openauth/message.html', 'message': msg}
+
+
+@render_to()
+def confirm(request):
+    """
+    Check confirmation key, proccess confirmation and delete key.
+    """
+    key = request.GET.get("key")
+    confirmation_type = int(request.GET.get("type", 1))
+    confirmation = get_object_or_404(Confirmation, key=key, confirmation_type=confirmation_type)
+    if confirmation_type == openauth.settings.ACTIVATION_CONFIRMATION_TYPE:
+        user = confirmation.user
+        user.is_active = True
+        user.save()
+        if openauth.settings.ACTIVATION_AUTO_LOGIN:
+            confirmation.user.backend = 'django.contrib.auth.backends.ModelBackend'
+            proccess_login(request, user)
+
+        confirmation.delete()
+        return message(request, _('Your account successfully activated'), 'success', 'show-user', args=[user.id])
+    elif confiramtion_type == openauth.settings.PASSWORD_RESET_CONFIRMATION_TYPE:
+        confirmation.user.backend = 'django.contrib.auth.backends.ModelBackend'                                                                                  
+        proccess_login(request, confirmation.user)      
+        confirmation.delete()
+        return message(request, _("Now you can change your password"), "notice", "openauth-reset-form")
+    else:
+        return openauth.settings.CUSTOM_CONFIRMATION(request)
+
+
+@render_to('openauth/registration.html')
+def registration(request):
+    """
+    Only anonymous users can view this page
+    Registration should be allowed in REGISTRATION_ALLOWED setting
+    """
+    if request.user.is_authenticated():
+        return message(request, _('You have to logout before registration'), 'notice', '/')
+
+    if not openauth.settings.REGISTRATION_ALLOWED: 
+        request.flash['notice'] = 'Sorry. Registration is disabled.'
+        return message(request, _('We are sorry, but registration is disabled. Come back later'), 'notice', '/')
+
+    if request.POST:
+        form = str_to_class(openauth.settings.REGISTRATION_FORM)(request.POST)
+        if form.is_valid():
+            user = form.save()
+            if openauth.settings.ACTIVATION_REQUIRED:
+                user.is_active = False
+            user.save()
+
+            if openauth.settings.ACTIVATION_REQUIRED:
+                confirmation = Confirmation(user=user, key=generate_hash(), confirmation_type=openauth.settings.ACTIVATION_CONFIRMATION_TYPE)
+                confirmation.save()
+                url = request.build_absolute_uri(reverse('openauth-confirm'))
+                url += '?key=%s&type=%s' % (confirmation.key, confirmation.confirmation_type)
+                params = {'domain': request.get_host(), 'email': user.email, 'url': url}
+                if email_template(user.email, 'openauth/mail/registration.txt', **params):
+                    return message(request, _("You have successfully registered. Check your inbox for email with activation link."), "success", "/")
+                else:
+                    user.delete()
+                    return message(request, _('The error was occuried while sending email with activation code. Account was not created. Please, try later.'), "error", "/")
+            else:
+                return message(request, _("You have successfully registered. You can login now"), "success", "login")
+
+    else:
+        form = str_to_class(openauth.settings.REGISTRATION_FORM)()
+    return {'form': form}
+
+
+@render_to('openauth/reset_password.html')
+def reset_password(request):
+    if request.POST:
+        form = ResetPasswordForm(request.POST)
+        if form.is_valid():
+            user = User.objects.get(email=form.cleaned_data['email'].lower())
+            confirmation = Confirmation(user=user, key=generate_hash(), confirmation_type=PASSWORD_RESET_CONFIRMATION_TYPE)
+            confirmation.save()
+            url = request.build_redirect_url(reverse('openauth-confirmation'))
+            url += '?key=%s&type=%s' % (confirmation.key, openauth.settings.PASSWORD_RESET_CONFIRMATION_TYPE)
+            args = {'domain': request.get_host(), 'url': url}
+            if email_template(user.email, 'openauth/mail/reset_password.txt', **args):
+                return message(request, _('Check your email please'), 'notice', '/')
+            else:
+                return message(request, _('Unfortunately we could not send you email in current time. Please, try later'), 'error', '/')
+    else:
+        form = RestorePasswordForm()
+    return {'form': form}
+
+
+@render_to('openauth/login.html')
+def login(request):
+    if request.user.is_authenticated():
+        return message(request, _('You are already authenticated'), 'notice', '/')
+
+    if request.POST:
+        form = LoginForm(request.POST, request=request)
+        request.session['login_redirect_url'] = request.GET.get('next')
+        if form.is_valid():
+            redirect_url = build_redirect_url(request, openauth.settings.LOGIN_REDIRECT_URL)
+            return message(request, _('You have successfully logged-in'), 'success', redirect_url)
+    else:
+        form = LoginForm(request=request)
+    return {'form': form}
+
+
+@login_required
+@render_to('account/new_password.html')
+def change_password(request):
+    if 'POST' == request.method:
+        form = NewPasswordForm(request.POST)
+    else:
+        form = NewPasswordForm()
+
+    if form.is_valid():
+        form.save(request.user)
+        request.flash['notice'] = _('Password was changed')
+        return HttpResponseRedirect("/")
+    return {'form': form}
+
+
+@render_to('account/message.html')
+def logout(request):
+    auth.logout(request)
+    request.flash['notice'] = "You have been logged out"
+    return HttpResponseReload(request)
+
+
+@render_to('account/edit_user.html')
+def edit_user(request, user_id):
+    user = get_object_or_404(User, pk=user_id)
+    if not request.user.is_authenticated() or user != request.user and not request.user.is_staff:
+        return HttpResponseReload(request)
+    if request.POST:
+        form = EditUserForm(user, request.POST, request.FILES)
+        if form.is_valid():
+            form.save()
+            request.flash['notice'] = "User details successfully changed"
+            return HttpResponseRedirect(reverse('show-user', args=[user.id]))
+    else:
+        initial = {'username': user.username, 
+                    'country': user.profile.country,
+                    'jabber': user.profile.jabber,
+                    'about': user.profile.about}
+        form = EditUserForm(user, initial=initial)
+    return {'form': form, 'user': user}
+
+
+
+@render_to('openauth/profile.html')
+def show_user(request, user_id):
+    """
+    Show user profile 
+    """
+    
+    user = get_object_or_404(User, pk=user_id)
+    return {'user': user}
+
+ 
+
+
+@render_to('account/users.html')
+@NinjaPaginator(style='filmfeed', per_page=16) 
+def users(request):
+    users = User.objects.all()
+    users = order_by(request, users)
+    return {'object_list': users}
+
 from setuptools import setup, find_packages
 
 setup(
-    name = "django-auth",
+    name = "django-openauth",
     version = "0.0.1",
     packages = find_packages(),
     author = "Anderson",