spicycms/spicy.core

View on GitHub
src/spicy/core/profile/views.py

Summary

Maintainability
D
2 days
Test Coverage
# -*- coding: utf-8 -*-
import random
import string
import logging
from uuid import uuid4

from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import PermissionDenied
from django.contrib.auth import logout as auth_logout, login as auth_login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_protect

from django.views.decorators.cache import never_cache

from spicy.utils.printing import print_warning
from spicy.utils.models import get_custom_model_class
from spicy.core.service import api
from spicy.core.siteskin.decorators import render_to, ajax_request, multi_view
from . import defaults, models, forms
from .models import BlacklistedIP

Profile = get_custom_model_class(defaults.CUSTOM_USER_MODEL)


def generate_random_password(length=10):
    chars = string.letters + string.digits
    return ''.join([random.choice(chars) for i in range(length)])


@render_to('spicy.core.profile/profile.html')
def profile(request, username):
    user = get_object_or_404(Profile, username=username)
    if request.user != user:
        raise PermissionDenied()
    return dict(user=user)


@login_required
@render_to('spicy.core.profile/edit.html')
def edit(request, username):
    messages = ''
    user = get_object_or_404(Profile, username=username)

    if request.user != user:
        raise PermissionDenied()

    form = forms.PublicProfileForm(instance=user)

    if request.POST:
        form = forms.PublicProfileForm(request.POST, instance=user)
        if form.is_valid():
            form.save()

    return dict(
        user=user,
        form=form,
        messages=messages)


@login_required
@render_to('spicy.core.profile/passwd.html')
def passwd(request, username):
    # Dublicate in the spicy.core.profile.admin
    # TODO: use service
    print_warning('Deprecated method spicy.core.profile.views.passwd')

    message = ''
    user = get_object_or_404(Profile, username=username)

    if request.user != user:
        raise PermissionDenied()

    form = PasswordChangeForm(user)
    if request.POST:
        form = PasswordChangeForm(user, request.POST)
        if form.is_valid():
            form.save()
            message = _('Password has been change successful')

    return dict(user=user, form=form, message=message)


@ajax_request
def check_unic_username(request):
    # Dublicate in the spicy.core.profile.admin
    # TODO: use service
    print_warning(
        'Deprecated method spicy.core.profile.views.check_unic_username')

    mssgs = dict(error='error', success='ok')
    username = request.POST.get('username', None)

    if username is None:
        return dict(result=mssgs['error'])
    try:
        Profile.objects.get(username=username)
    except:
        response_txt = mssgs['success']
    else:
        response_txt = mssgs['error']
    return dict(result=response_txt)


@csrf_protect
@render_to('spicy.core.profile/activate.html')
def activate(request, profile_id, activation_key):
    next_url = request.GET.get('next', '/')
    profile = Profile.objects.activate_user(activation_key)
    return dict(profile=profile, next_url=next_url)


@render_to('spicy.core.profile/user_agreement.html')
def user_agreement(request):
    return dict()


@csrf_protect
@render_to('spicy.core.profile/restore_password.html')
def restorepass(request):
    return api.register['profile'].restore(request)


@login_required
def signout(request):
    redirect_to = request.GET.get('next', settings.LOGIN_REDIRECT_URL)
    try:
        del request.session['openid']
    except KeyError:
        pass
    auth_logout(request)
    return HttpResponseRedirect(redirect_to)


@login_required
@render_to('spicy.core.profile/set_email.html')
def set_email(request):
    if request.user.email:
        return {'msg': _('Email address is already set')}
    if request.method == 'POST':
        form = forms.SetEmailForm(request.POST)
        if form.is_valid():
            # Send validation email.
            request.user.email_confirm(form.cleaned_data['email'])
            return {'msg': _('Validation email has been sent')}
    elif all(request.GET.get(key) for key in ('email', 'hash')):
        hash_key = request.GET['hash']
        email = request.GET['email']
        if request.user.get_hash(email) == hash_key:
            request.user.email = email
            request.user.save()
            return HttpResponseRedirect(
                reverse('profile:public:index', args=[request.user.username]))
    else:
        form = forms.SetEmailForm()
    return {'form': form}


@never_cache
@render_to('spicy.core.profile/signin.html')
def signin(request):
    result = api.register['profile'].login(request)
    if result['status'] == 'ok':
        return HttpResponseRedirect(
            result.get('redirect') or user_redirect_uri)
    else:
        if defaults.LOGIN_WARNING and request.POST.get('username'):
            logger = logging.getLogger(__name__)
            logger.error('Error auth %s', request.POST.get('username'))
        return result


@never_cache
@multi_view()
@render_to('spicy.core.profile/signup.html')
def signup(request):
    result = api.register['profile'].register(request)
    if result['status'] == 'ok':
        return HttpResponseRedirect(
            '%s?next=%s' % (
                reverse('profile:public:success-signup'),
                result['redirect']))
    return result


@never_cache
@render_to('spicy.core.profile/login.html')
def signin_or_register(request):
    result = api.register['profile'].login_or_register(request)
    if result['status'] == 'ok' and result['action'] == 'authenticated':
        return HttpResponseRedirect(reverse('profile:public:index', kwargs={'username': request.user.username}))
    elif result['status'] == 'ok' and result['action'] == 'login':
        return HttpResponseRedirect(result.get('redirect'))
    elif result['status'] == 'ok' and result['action'] == 'register':
        return HttpResponseRedirect(reverse('profile:public:success-signup'))
    else:
        return result


@render_to('spicy.core.profile/widgets/signin_form.html')
def login_widget(request):
    result = api.register['profile'].login(request)
    if result['status'] == 'ok':
        result['redirect_now'] = True
    return result


@render_to('spicy.core.profile/widgets/signup_form.html')
def registration_widget(request):
    result = api.register['profile'].register(request)
    if result['status'] == 'ok':
        result['redirect_now'] = True
    return result


@render_to('spicy.core.profile/success_signup.html')
def success_signup(request):
    next_url = request.GET.get(REDIRECT_FIELD_NAME, '/')
    email = request.session.get('profile_email', '')
    return dict(next=next_url, email=email)


@render_to('spicy.core.profile/social/signin.html')
def signin_social(request, backend):
    real_ip = request.META.get('REMOTE_ADDR')
    if real_ip and BlacklistedIP.objects.filter(ip=real_ip).exists():
        return HttpResponseRedirect(reverse('profile:public:signup'))

    request.session.set_test_cookie()
    # Set redirect to previous URL unless it's already set in session.
    redirect_to = request.REQUEST.get(
        REDIRECT_FIELD_NAME, request.META.get('HTTP_REFERER', ''))
    if redirect_to and not request.session.get(REDIRECT_FIELD_NAME):
        request.session[REDIRECT_FIELD_NAME] = redirect_to
        request.session['newuser-next'] = redirect_to

    from social_auth import views as sa_views
    return sa_views.auth(request, backend)


@render_to("spicy.core.profile/social/new_user.html")
def new_social_user(request):
    new_user = request.session.get('NEW_USER')
    if not new_user:
        return HttpResponseRedirect(reverse('profile:public:signin'))
    elif not (new_user.is_active and new_user.is_authenticated()):
        new_user.is_active = True
        new_user.save()
        user = auth_login(request, new_user)

    if request.method == 'POST':
        if request.POST.get('signin'):
            # Associate with existing account.
            login_form = forms.LoginForm(
                request, request.POST, prefix='associate')
            update_form = forms.SocialProfileUpdateForm(
                instance=new_user, prefix='newuser')
            if login_form.is_valid():
                old_user = login_form.get_user()
                social_user = new_user.social_auth.get()
                social_user.user = old_user
                social_user.save()
                new_user.delete(trash=False)

                # Make session copy and login.
                session_copy = dict(
                    (k, v) for k, v in request.session.iteritems()
                    if not k.startswith('_'))
                redirect_to = session_copy.pop(REDIRECT_FIELD_NAME, None)
                if not redirect_to:
                    redirect_to = session_copy.pop('newuser-next', None)
                del session_copy['NEW_USER']
                request.session.delete()
                auth_login(request, old_user)

                # Update session from saved copy.
                for k, v in session_copy.iteritems():
                    request.session[k] = v
                request.session[
                    defaults.PASSWORD_HASH_KEY] = old_user.password
                if login_form.cleaned_data['is_remember']:
                    request.session.set_expiry(1209600)
                return HttpResponseRedirect(
                    redirect_to or reverse(
                        'profile:public:index',
                        args=[old_user.username]))
        else:
            login_form = forms.LoginForm(request, prefix='associate')
            update_form = forms.SocialProfileUpdateForm(
                request.POST, instance=new_user, prefix='newuser')

            old_email = new_user.email
            # Django bug - this field would be overridden with form data if
            # we save user used as form instance. So save email in advance.

            if update_form.is_valid():
                email = update_form.cleaned_data['email']
                user = update_form.save(commit=False)
                user.username = update_form.cleaned_data['username']
                # Email address requires validation first, don't save it!
                user.email = old_email
                user.activate()

                # tag, exists = api.register['xtag'].get_or_create_by_term_name(
                #    user.screenname, vocabulary='persons', user=user)
                # tag.save()

                # Login.
                redirect_to = request.session.pop(REDIRECT_FIELD_NAME, None)
                if not redirect_to:
                    redirect_to = request.session.pop('newuser-next', None)

                request.session[
                    defaults.PASSWORD_HASH_KEY] = new_user.password

                if user.email != email:
                    user.email_confirm(email)
                    if not redirect_to:
                        return {'msg': _('Validation email has been sent')}
                return HttpResponseRedirect(
                    redirect_to or reverse(
                        'profile:public:index', args=[user.username]))
    else:
        new_user.sites = Site.objects.all()
        login_form = forms.LoginForm(request, prefix='associate')
        update_form = forms.SocialProfileUpdateForm(
            instance=new_user, prefix='newuser')

    return {
        'login_form': login_form, 'update_form': update_form,
        'next_url': settings.LOGIN_URL}


def sa_get_username(details, user=None, *args, **kwargs):
    """
    Return an username for new user.

    Returns current user username if user was given.
    """
    if user:
        return {'username': user.username}

    from social_auth.backends.pipeline import USERNAME
    if details.get(USERNAME):
        username = details[USERNAME]
    else:
        username = uuid4().get_hex()

    final_username = models.Profile.objects.get_available_username(username)
    return {'username': final_username}


def sa_set_new_user_inactive(
        backend, details, response, uid, username, user=None, *args, **kwargs):
    if user:
        return {'user': user}
    if not username:
        return None

    email = details.get('email')
    user = Profile.objects.create_user(username=username, email=email)
    user.accept_agreement = True
    user.is_active = False
    user.save()
    kwargs['request'].session['NEW_USER'] = user
    return {'user': user, 'is_new': True}