views.py 8.06 KB
#!/usr/bin/env python
# encoding: utf-8

import datetime

from collections import OrderedDict

from django.contrib import messages
from django.db import transaction
from django.db.models import Count
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext as _
from django.shortcuts import render, redirect, get_object_or_404
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
from django.views.generic import DetailView, UpdateView
from django.utils.decorators import method_decorator

from conversejs import xmpp
from conversejs.models import XMPPAccount
from haystack.query import SearchQuerySet

from super_archives.models import EmailAddress, Message
from super_archives.utils.email import send_email_lists
from search.utils import trans
from proxy.models import WikiCollabCount, TicketCollabCount
from .forms import (UserCreationForm, ListsForm, UserUpdateForm,
                    ChangeXMPPPasswordForm)
from .errors import XMPPChangePwdException
from .utils import mailman


class UserProfileBaseMixin(object):
    model = get_user_model()
    slug_field = 'username'
    slug_url_kwarg = 'username'
    context_object_name = 'user_'


class UserProfileUpdateView(UserProfileBaseMixin, UpdateView):
    template_name = 'accounts/user_update_form.html'
    form_class = UserUpdateForm

    def get_success_url(self):
        return reverse('user_profile', kwargs={'username': self.object.username})

    def get_object(self, *args, **kwargs):
        obj = super(UserProfileUpdateView, self).get_object(*args, **kwargs)
        if self.request.user != obj and not self.request.user.is_superuser:
            raise PermissionDenied

        return obj


class UserProfileDetailView(UserProfileBaseMixin, DetailView):
    template_name = 'accounts/user_detail.html'

    def get_context_data(self, **kwargs):
        user = self.object
        context = {}

        count_types = OrderedDict()

        fields_or_lookup = (
            {'collaborators__contains': user.username},
            {'fullname_and_username__contains': user.username},
        )

        counter_class = {
            'wiki': WikiCollabCount,
            'ticket': TicketCollabCount,
        }

        messages = Message.objects.filter(from_address__user__pk=user.pk)
        for type in ['thread', 'ticket', 'wiki', 'changeset', 'attachment']:
            CounterClass = counter_class.get(type)
            if CounterClass:
                try:
                    counter = CounterClass.objects.get(author=user.username)
                except CounterClass.DoesNotExist:
                    count_types[trans(type)] = 0
                else:
                    count_types[trans(type)] = counter.count
            elif type == 'thread':
                count_types[trans(type)] = messages.count()
            else:
                sqs = SearchQuerySet()
                for filter_or in fields_or_lookup:
                    sqs = sqs.filter_or(type=type, **filter_or)
                count_types[trans(type)] = sqs.count()

        context['type_count'] = count_types

        sqs = SearchQuerySet()
        for filter_or in fields_or_lookup:
            sqs = sqs.filter_or(**filter_or).exclude(type='thread')

        context['results'] = sqs.order_by('-modified', '-created')[:10]

        email_pks = [addr.pk for addr in user.emails.iterator()]
        query = Message.objects.filter(from_address__in=email_pks)
        query = query.order_by('-received_time')
        context['emails'] = query[:10]

        count_by = 'thread__mailinglist__name'
        context['list_activity'] = dict(messages.values_list(count_by)\
                                           .annotate(Count(count_by))\
                                           .order_by(count_by))

        context.update(kwargs)
        return super(UserProfileDetailView, self).get_context_data(**context)


def signup(request):
    # If the request method is GET just return the form
    if request.method == 'GET':
        user_form = UserCreationForm()
        lists_form = ListsForm()
        return render(request, 'accounts/user_create_form.html',
                      {'user_form': user_form, 'lists_form': lists_form})

    user_form = UserCreationForm(request.POST)
    lists_form = ListsForm(request.POST)

    if not user_form.is_valid() or not lists_form.is_valid():
        return render(request, 'accounts/user_create_form.html',
                      {'user_form': user_form, 'lists_form': lists_form})

    user = user_form.save()

    mailing_lists = lists_form.cleaned_data.get('lists')
    if mailing_lists:
        send_email_lists(user, mailing_lists)

    # Check if the user's email have been used previously
    #   in the mainling lists to link the user to old messages
    email_addr, created = EmailAddress.objects.get_or_create(address=user.email)
    if created:
        email_addr.real_name = user.get_full_name()

    email_addr.user = user
    email_addr.save()

    messages.success(request, _('Your profile has been created!'))
    messages.warning(request, _('You must login to validated your profile. '
                                'Profiles not validated are deleted in 24h.'))

    return redirect('user_profile', username=user.username)


class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView):
    http_method_names = [u'get', u'post']
    template_name = u'accounts/manage_subscriptions.html'

    def get_object(self, *args, **kwargs):
        obj = super(ManageUserSubscriptionsView, self).get_object(*args,
                                                                  **kwargs)
        if self.request.user != obj and not self.request.user.is_superuser:
            raise PermissionDenied

        return obj

    def post(self, request, *args, **kwargs):
        user = self.get_object()
        for email in user.emails.values_list('address', flat=True):
            lists = self.request.POST.getlist(email)
            user.update_subscription(email, lists)

        return redirect('user_profile', username=user.username)

    def get_context_data(self, **kwargs):
        context = {}
        context['membership'] = {}

        user = self.get_object()
        emails = user.emails.values_list('address', flat=True)
        all_lists = mailman.all_lists(description=True)

        for email in emails:
            lists = []
            lists_for_address = mailman.address_lists(email)
            for listname, description in all_lists:
                if listname in lists_for_address:
                    checked = True
                else:
                    checked = False
                lists.append((
                    {'listname': listname, 'description': description},
                    checked
                ))

            context['membership'].update({email: lists})

        context.update(kwargs)

        return super(ManageUserSubscriptionsView, self).get_context_data(**context)


class ChangeXMPPPasswordView(UpdateView):
    model = XMPPAccount
    form_class = ChangeXMPPPasswordForm
    fields = ['password', ]
    template_name = 'accounts/change_password.html'

    def get_success_url(self):
        return reverse('user_profile', kwargs={
            'username': self.request.user.username
        })

    def get_object(self, queryset=None):
        obj = get_object_or_404(XMPPAccount, user=self.request.user.pk)
        self.old_password = obj.password
        return obj

    def form_valid(self, form):
        transaction.set_autocommit(False)

        response = super(ChangeXMPPPasswordView, self).form_valid(form)

        changed = xmpp.change_password(
            self.object.jid,
            self.old_password,
            form.cleaned_data['password1']
        )

        if not changed:
            messages.error(
                self.request,
                _(u'Could not change your password. Please, try again later.')
            )
            transaction.rollback()
            return response
        else:
            transaction.commit()

        messages.success(
            self.request,
            _("You've changed your password successfully!")
        )
        return response