from functools import reduce

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.db.models import Q, Count
from django.shortcuts import get_object_or_404, redirect, render
from django.views.generic import CreateView, DetailView, ListView, UpdateView
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse, Http404

from ponyconf.mixins import OnSiteFormMixin

from accounts.models import Participation
from accounts.mixins import OrgaRequiredMixin, StaffRequiredMixin
from accounts.decorators import orga_required, staff_required
from accounts.utils import is_staff, is_orga

from conversations.models import ConversationWithParticipant, ConversationAboutTalk, Message

from planning.models import Room

from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm, SubscribeForm
from .models import Talk, Track, Topic, Vote, Conference, Attendee
from .signals import talk_added, talk_edited
from .utils import markdown_to_html


@login_required
@require_http_methods(["POST"])
def markdown_preview(request):
    content = request.POST.get('data', '')
    return HttpResponse(markdown_to_html(content))


def home(request):
    return render(request, 'proposals/home.html')


@staff_required
def staff(request):
    return render(request, 'staff.html')


@orga_required
def conference(request):
    conference = Conference.objects.get(site=get_current_site(request))
    form = ConferenceForm(request.POST or None, instance=conference)
    if request.method == 'POST' and form.is_valid():
        form.save()
        messages.success(request, 'Conference updated!')
        return redirect(reverse('edit-conference'))
    return render(request, 'proposals/conference.html', {
        'form': form,
    })

@login_required
def participate(request):
    site = get_current_site(request)
    talks = Talk.objects.filter(site=site)
    my_talks = talks.filter(speakers=request.user)
    proposed_talks = talks.exclude(speakers=request.user).filter(proposer=request.user)
    return render(request, 'proposals/participate.html', {
        'my_talks': my_talks,
        'proposed_talks': proposed_talks,
    })

@staff_required
def talk_list(request):
    show_filters = False
    talks = Talk.objects.filter(site=get_current_site(request))
    filter_form = TalkFilterForm(request.GET or None, site=get_current_site(request))
    # Filtering
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['kind']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk) for pk in data['kind']]))
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
        if data['vote'] != None:
            show_filters = True
            if data['vote']:
                talks = talks.filter(vote__user=request.user)
            else:
                talks = talks.exclude(vote__user=request.user)
        if data['room'] != None:
            show_filters = True
            talks = talks.filter(room__isnull=not data['room'])
        if data['scheduled'] != None:
            show_filters = True
            talks = talks.filter(start_date__isnull=not data['scheduled'])
        if data['materials'] != None:
            show_filters = True
            talks = talks.filter(materials__isnull=not data['materials'])
        if data['video'] != None:
            show_filters = True
            if data['video']:
                talks = talks.exclude(video__exact='')
            else:
                talks = talks.filter(video__exact='')
    # Action
    action_form = TalkActionForm(request.POST or None, talks=talks, site=get_current_site(request))
    if not is_orga(request, request.user):
        action_form.fields.pop('track')
        action_form.fields.pop('room')
    if request.method == 'POST':
        if action_form.is_valid():
            data = action_form.cleaned_data
            permission_error = False
            for talk in data['talks']:
                talk = Talk.objects.get(site=get_current_site(request), slug=talk)
                if data['decision'] != None:
                    if not talk.is_moderable_by(request.user):
                        permission_error = True
                        continue
                    # TODO: merge with talk_decide code
                    conversation = ConversationAboutTalk.objects.get(talk=talk)
                    if data['decision']:
                        note = "The talk has been accepted."
                    else:
                        note = "The talk has been declined."
                    Message.objects.create(conversation=conversation, author=request.user, content=note)
                    talk.accepted = data['decision']
                if data['track']:
                    talk.track = Track.objects.get(site=get_current_site(request), slug=data['track'])
                if data['room']:
                    talk.room = Room.objects.get(site=get_current_site(request), slug=data['room'])
                talk.save()
            if permission_error:
                messages.warning(request, 'Some actions were ignored due to missing permissions.')
            return redirect(request.get_full_path())
    # Sorting
    if request.GET.get('order') == 'desc':
        reverse = True
    else:
        reverse = False
    SORT_MAPPING = {
        'title': 'title',
        'kind': 'event',
        'status': 'accepted',
    }
    sort = request.GET.get('sort')
    if sort in SORT_MAPPING.keys():
        if reverse:
            talks = talks.order_by('-' + SORT_MAPPING[sort])
        else:
            talks = talks.order_by(SORT_MAPPING[sort])
    # Sorting URLs
    sort_urls = dict()
    sort_glyphicons = dict()
    for c in SORT_MAPPING.keys():
        url = request.GET.copy()
        url['sort'] = c
        if c == sort:
            if reverse:
                del url['order']
                glyphicon = 'sort-by-attributes-alt'
            else:
                url['order'] = 'desc'
                glyphicon = 'sort-by-attributes'
        else:
            glyphicon = 'sort'
        sort_urls[c] = url.urlencode()
        sort_glyphicons[c] = glyphicon
    return render(request, 'proposals/talk_list.html', {
        'show_filters': show_filters,
        'talk_list': talks,
        'filter_form': filter_form,
        'action_form': action_form,
        'sort_urls': sort_urls,
        'sort_glyphicons': sort_glyphicons,
    })

@login_required
def talk_edit(request, talk=None):
    site = get_current_site(request)
    if talk: # edit existing talk
        talk = get_object_or_404(Talk, slug=talk, site=site)
        if not talk.is_editable_by(request.user):
            raise PermissionDenied
    else: # add new talk
        conf = Conference.objects.get(site=site)
        if not is_orga(request, request.user) and not conf.cfp_is_open():
            raise PermissionDenied
    staff = talk.is_moderable_by(request.user) if talk else is_orga(request, request.user)
    form = TalkForm(request.POST or None, request.FILES or None, instance=talk, site=site, staff=staff)
    if talk:
        form.fields['topics'].disabled = True
        if 'duration' in form.fields and talk.event.duration:
            form.fields['duration'].help_text = 'Default value if zero: %d min' % talk.duration
        if 'attendees_limit' in form.fields and talk.is_editable_by(request.user) and talk.room and talk.room.capacity:
            form.fields['attendees_limit'].help_text=ungettext_lazy(
                    "Note: the room %(room)s has %(capacity)s seat.",
                    "Note: the room %(room)s has %(capacity)s seats.",
                    talk.room.capacity) % {'room': talk.room.name, 'capacity': talk.room.capacity}
    else:
        form.fields.pop('materials')
        form.fields.pop('video')
        form.fields['speakers'].initial = [request.user]
    if request.method == 'POST' and form.is_valid():
        if hasattr(talk, 'id'):
            talk = form.save()
            if request.user == talk.proposer or request.user in talk.speakers.all():
                talk_edited.send(talk.__class__, instance=talk, author=request.user)
            messages.success(request, _('Talk modified successfully!'))
        else:
            form.instance.site = get_current_site(request)
            form.instance.proposer = request.user
            talk = form.save()
            talk_added.send(talk.__class__, instance=talk, author=request.user)
            messages.success(request, _('Talk proposed successfully!'))
        return redirect(talk.get_absolute_url())
    return render(request, 'proposals/talk_edit.html', {
        'base_template': 'staff.html' if staff else 'base.html',
        'talk': talk,
        'form': form,
    })


@login_required
def talk_assign_to_track(request, talk, track):
    talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    track = get_object_or_404(Track, slug=track, site=get_current_site(request))
    talk.track = track
    talk.save()
    messages.success(request, _('Talk assigned to track successfully!'))
    next_url = request.GET.get('next') or reverse('show-talk', kwargs={'slug': talk.slug})
    return redirect(next_url)


class TalkDetail(LoginRequiredMixin, DetailView):
    def get_queryset(self):
        return Talk.objects.filter(site=get_current_site(self.request)).all()

    def get_context_data(self, **ctx):
        if self.object.is_moderable_by(self.request.user):
            vote = Vote.objects.filter(talk=self.object, user=self.request.user).first()
            ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
                       form_url=reverse('talk-conversation', kwargs={'talk': self.object.slug}))
        else:
            ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
        if is_staff(self.request, self.request.user):
            ctx.update(base_template='staff.html')
        else:
            ctx.update(base_template='base.html')
        return super().get_context_data(**ctx)


class TopicMixin(object):
    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):
    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


@login_required
def vote(request, talk, score):
    talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
    vote.vote = int(score)
    vote.save()
    messages.success(request, _('Vote successfully created') if created else _('Vote successfully updated'))
    return redirect(talk.get_absolute_url())


@login_required
def talk_decide(request, talk, accepted):
    site = get_current_site(request)
    talk = get_object_or_404(Talk, site=site, slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    if request.method == 'POST':
        # Does we need to send a notification to the proposer?
        m = request.POST.get('message', '').strip()
        if m:
            participation = Participation.objects.get(site=site, user=talk.proposer)
            conversation = ConversationWithParticipant.objects.get(participation=participation)
            Message.objects.create(conversation=conversation, author=request.user, content=m)
        # Save the decision in the talk's conversation
        conversation = ConversationAboutTalk.objects.get(talk=talk)
        if accepted:
            note = "The talk has been accepted."
        else:
            note = "The talk has been declined."
        Message.objects.create(conversation=conversation, author=request.user, content=note)
        talk.accepted = accepted
        talk.save()
        messages.success(request, _('Decision taken in account'))
        return redirect('show-talk', slug=talk.slug)
    return render(request, 'proposals/talk_decide.html', {
        'talk': talk,
        'accept': accepted,
    })


@staff_required
def speaker_list(request):
    show_filters = False
    site = get_current_site(request)
    filter_form = SpeakerFilterForm(request.GET or None, site=site)
    talks = Talk.objects.filter(site=site)
    # Filtering
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
    speakers = Participation.objects.filter(site=site,user__talk__in=talks).order_by('pk').distinct()
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['transport']):
            show_filters = True
            q = Q()
            if 'unanswered' in data['transport']:
                data['transport'].remove('unanswered')
                q |= Q(need_transport=None)
            if 'unspecified' in data['transport']:
                data['transport'].remove('unspecified')
                speakers = speakers.annotate(transport_count=Count('transport'))
                q |= Q(need_transport=True, transport_count=0)
            if len(data['transport']):
                q |= (Q(need_transport=True) & Q(reduce(lambda x, y: x | y, [Q(transport__pk=pk) for pk in data['transport']])))
            speakers = speakers.filter(q)
        if len(data['accommodation']):
            show_filters = True
            accommodations = list(map(lambda x: None if x == 'unknown' else x, data['accommodation']))
            speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(accommodation=value) for value in accommodations]))
        if data['sound'] != None:
            show_filters = True
            speakers = speakers.filter(sound=data['sound'])
        if data['transport_booked'] != None:
            show_filters = True
            speakers = speakers.filter(need_transport=True).filter(transport_booked=data['transport_booked'])
        if data['accommodation_booked'] != None:
            show_filters = True
            speakers = speakers.exclude(accommodation=Participation.ACCOMMODATION_NO).filter(accommodation_booked=data['accommodation_booked'])
    contact_link = 'mailto:' + ','.join([speaker.user.email for speaker in speakers.all() if speaker.user.email])
    return render(request, 'proposals/speaker_list.html', {
        'speaker_list': speakers,
        'filter_form': filter_form,
        'show_filters': show_filters,
        'contact_link': contact_link,
    })


def talk_registrable_list(request):
    site = get_current_site(request)
    if not Conference.objects.get(site=site).subscriptions_open:
        raise Http404
    talks = Talk.objects.filter(site=site, registration_required=True)
    if request.user.is_authenticated():
        attendee = Attendee.objects.filter(user=request.user).first() # None if it does not exists
    else:
        attendee = None
    return render(request, 'proposals/talk_registrable_list.html', {
        'talks': talks,
        'attendee': attendee,
    })


def talk_register(request, talk):
    talk = get_object_or_404(Talk, site=get_current_site(request), registration_required=True, slug=talk)

    form = SubscribeForm(request.POST or None)

    if request.user.is_authenticated() or (request.method == 'POST' and form.is_valid()):
        if request.user.is_authenticated():
            attendee, created = Attendee.objects.get_or_create(user=request.user)
        else:
            attendee, created = Attendee.objects.get_or_create(email=form.cleaned_data['email'], name=form.cleaned_data['name'])
        if attendee in talk.attendees.all():
            if request.user.is_authenticated():
                talk.attendees.remove(attendee)
                messages.success(request, _("Unregistered :-("))
            else:
                messages.error(request, _("Already registered!"))
        elif talk.remaining_attendees == 0:
            raise PermissionDenied
        else:
            talk.attendees.add(attendee)
            messages.success(request, _("Registered!"))
        talk.save()
        return redirect('list-registrable-talks')

    return render(request, 'proposals/talk_register.html', {
        'talk': talk,
        'form': form,
    })

ccb1f179167900cc2e23c9b95dea3f96a52e9c75
<mask token>


class TopicMixin(object):

    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):

    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


<mask token>

<mask token>


@login_required
def participate(request):
    site = get_current_site(request)
    talks = Talk.objects.filter(site=site)
    my_talks = talks.filter(speakers=request.user)
    proposed_talks = talks.exclude(speakers=request.user).filter(proposer=
        request.user)
    return render(request, 'proposals/participate.html', {'my_talks':
        my_talks, 'proposed_talks': proposed_talks})


<mask token>


class TalkDetail(LoginRequiredMixin, DetailView):

    def get_queryset(self):
        return Talk.objects.filter(site=get_current_site(self.request)).all()

    def get_context_data(self, **ctx):
        if self.object.is_moderable_by(self.request.user):
            vote = Vote.objects.filter(talk=self.object, user=self.request.user
                ).first()
            ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
                form_url=reverse('talk-conversation', kwargs={'talk': self.
                object.slug}))
        else:
            ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
        if is_staff(self.request, self.request.user):
            ctx.update(base_template='staff.html')
        else:
            ctx.update(base_template='base.html')
        return super().get_context_data(**ctx)


class TopicMixin(object):

    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):

    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


@login_required
def vote(request, talk, score):
    talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
    vote.vote = int(score)
    vote.save()
    messages.success(request, _('Vote successfully created') if created else
        _('Vote successfully updated'))
    return redirect(talk.get_absolute_url())


@login_required
def talk_decide(request, talk, accepted):
    site = get_current_site(request)
    talk = get_object_or_404(Talk, site=site, slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    if request.method == 'POST':
        m = request.POST.get('message', '').strip()
        if m:
            participation = Participation.objects.get(site=site, user=talk.
                proposer)
            conversation = ConversationWithParticipant.objects.get(
                participation=participation)
            Message.objects.create(conversation=conversation, author=
                request.user, content=m)
        conversation = ConversationAboutTalk.objects.get(talk=talk)
        if accepted:
            note = 'The talk has been accepted.'
        else:
            note = 'The talk has been declined.'
        Message.objects.create(conversation=conversation, author=request.
            user, content=note)
        talk.accepted = accepted
        talk.save()
        messages.success(request, _('Decision taken in account'))
        return redirect('show-talk', slug=talk.slug)
    return render(request, 'proposals/talk_decide.html', {'talk': talk,
        'accept': accepted})


<mask token>

<mask token>


@login_required
@require_http_methods(['POST'])
def markdown_preview(request):
    content = request.POST.get('data', '')
    return HttpResponse(markdown_to_html(content))


def home(request):
    return render(request, 'proposals/home.html')


@staff_required
def staff(request):
    return render(request, 'staff.html')


<mask token>


@login_required
def participate(request):
    site = get_current_site(request)
    talks = Talk.objects.filter(site=site)
    my_talks = talks.filter(speakers=request.user)
    proposed_talks = talks.exclude(speakers=request.user).filter(proposer=
        request.user)
    return render(request, 'proposals/participate.html', {'my_talks':
        my_talks, 'proposed_talks': proposed_talks})


@staff_required
def talk_list(request):
    show_filters = False
    talks = Talk.objects.filter(site=get_current_site(request))
    filter_form = TalkFilterForm(request.GET or None, site=get_current_site
        (request))
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['kind']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk
                ) for pk in data['kind']]))
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=
                dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug
                =topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
        if data['vote'] != None:
            show_filters = True
            if data['vote']:
                talks = talks.filter(vote__user=request.user)
            else:
                talks = talks.exclude(vote__user=request.user)
        if data['room'] != None:
            show_filters = True
            talks = talks.filter(room__isnull=not data['room'])
        if data['scheduled'] != None:
            show_filters = True
            talks = talks.filter(start_date__isnull=not data['scheduled'])
        if data['materials'] != None:
            show_filters = True
            talks = talks.filter(materials__isnull=not data['materials'])
        if data['video'] != None:
            show_filters = True
            if data['video']:
                talks = talks.exclude(video__exact='')
            else:
                talks = talks.filter(video__exact='')
    action_form = TalkActionForm(request.POST or None, talks=talks, site=
        get_current_site(request))
    if not is_orga(request, request.user):
        action_form.fields.pop('track')
        action_form.fields.pop('room')
    if request.method == 'POST':
        if action_form.is_valid():
            data = action_form.cleaned_data
            permission_error = False
            for talk in data['talks']:
                talk = Talk.objects.get(site=get_current_site(request),
                    slug=talk)
                if data['decision'] != None:
                    if not talk.is_moderable_by(request.user):
                        permission_error = True
                        continue
                    conversation = ConversationAboutTalk.objects.get(talk=talk)
                    if data['decision']:
                        note = 'The talk has been accepted.'
                    else:
                        note = 'The talk has been declined.'
                    Message.objects.create(conversation=conversation,
                        author=request.user, content=note)
                    talk.accepted = data['decision']
                if data['track']:
                    talk.track = Track.objects.get(site=get_current_site(
                        request), slug=data['track'])
                if data['room']:
                    talk.room = Room.objects.get(site=get_current_site(
                        request), slug=data['room'])
                talk.save()
            if permission_error:
                messages.warning(request,
                    'Some actions were ignored due to missing permissions.')
            return redirect(request.get_full_path())
    if request.GET.get('order') == 'desc':
        reverse = True
    else:
        reverse = False
    SORT_MAPPING = {'title': 'title', 'kind': 'event', 'status': 'accepted'}
    sort = request.GET.get('sort')
    if sort in SORT_MAPPING.keys():
        if reverse:
            talks = talks.order_by('-' + SORT_MAPPING[sort])
        else:
            talks = talks.order_by(SORT_MAPPING[sort])
    sort_urls = dict()
    sort_glyphicons = dict()
    for c in SORT_MAPPING.keys():
        url = request.GET.copy()
        url['sort'] = c
        if c == sort:
            if reverse:
                del url['order']
                glyphicon = 'sort-by-attributes-alt'
            else:
                url['order'] = 'desc'
                glyphicon = 'sort-by-attributes'
        else:
            glyphicon = 'sort'
        sort_urls[c] = url.urlencode()
        sort_glyphicons[c] = glyphicon
    return render(request, 'proposals/talk_list.html', {'show_filters':
        show_filters, 'talk_list': talks, 'filter_form': filter_form,
        'action_form': action_form, 'sort_urls': sort_urls,
        'sort_glyphicons': sort_glyphicons})


<mask token>


class TalkDetail(LoginRequiredMixin, DetailView):

    def get_queryset(self):
        return Talk.objects.filter(site=get_current_site(self.request)).all()

    def get_context_data(self, **ctx):
        if self.object.is_moderable_by(self.request.user):
            vote = Vote.objects.filter(talk=self.object, user=self.request.user
                ).first()
            ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
                form_url=reverse('talk-conversation', kwargs={'talk': self.
                object.slug}))
        else:
            ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
        if is_staff(self.request, self.request.user):
            ctx.update(base_template='staff.html')
        else:
            ctx.update(base_template='base.html')
        return super().get_context_data(**ctx)


class TopicMixin(object):

    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):

    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


@login_required
def vote(request, talk, score):
    talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
    vote.vote = int(score)
    vote.save()
    messages.success(request, _('Vote successfully created') if created else
        _('Vote successfully updated'))
    return redirect(talk.get_absolute_url())


@login_required
def talk_decide(request, talk, accepted):
    site = get_current_site(request)
    talk = get_object_or_404(Talk, site=site, slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    if request.method == 'POST':
        m = request.POST.get('message', '').strip()
        if m:
            participation = Participation.objects.get(site=site, user=talk.
                proposer)
            conversation = ConversationWithParticipant.objects.get(
                participation=participation)
            Message.objects.create(conversation=conversation, author=
                request.user, content=m)
        conversation = ConversationAboutTalk.objects.get(talk=talk)
        if accepted:
            note = 'The talk has been accepted.'
        else:
            note = 'The talk has been declined.'
        Message.objects.create(conversation=conversation, author=request.
            user, content=note)
        talk.accepted = accepted
        talk.save()
        messages.success(request, _('Decision taken in account'))
        return redirect('show-talk', slug=talk.slug)
    return render(request, 'proposals/talk_decide.html', {'talk': talk,
        'accept': accepted})


@staff_required
def speaker_list(request):
    show_filters = False
    site = get_current_site(request)
    filter_form = SpeakerFilterForm(request.GET or None, site=site)
    talks = Talk.objects.filter(site=site)
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=
                dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug
                =topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
    speakers = Participation.objects.filter(site=site, user__talk__in=talks
        ).order_by('pk').distinct()
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['transport']):
            show_filters = True
            q = Q()
            if 'unanswered' in data['transport']:
                data['transport'].remove('unanswered')
                q |= Q(need_transport=None)
            if 'unspecified' in data['transport']:
                data['transport'].remove('unspecified')
                speakers = speakers.annotate(transport_count=Count('transport')
                    )
                q |= Q(need_transport=True, transport_count=0)
            if len(data['transport']):
                q |= Q(need_transport=True) & Q(reduce(lambda x, y: x | y,
                    [Q(transport__pk=pk) for pk in data['transport']]))
            speakers = speakers.filter(q)
        if len(data['accommodation']):
            show_filters = True
            accommodations = list(map(lambda x: None if x == 'unknown' else
                x, data['accommodation']))
            speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(
                accommodation=value) for value in accommodations]))
        if data['sound'] != None:
            show_filters = True
            speakers = speakers.filter(sound=data['sound'])
        if data['transport_booked'] != None:
            show_filters = True
            speakers = speakers.filter(need_transport=True).filter(
                transport_booked=data['transport_booked'])
        if data['accommodation_booked'] != None:
            show_filters = True
            speakers = speakers.exclude(accommodation=Participation.
                ACCOMMODATION_NO).filter(accommodation_booked=data[
                'accommodation_booked'])
    contact_link = 'mailto:' + ','.join([speaker.user.email for speaker in
        speakers.all() if speaker.user.email])
    return render(request, 'proposals/speaker_list.html', {'speaker_list':
        speakers, 'filter_form': filter_form, 'show_filters': show_filters,
        'contact_link': contact_link})


def talk_registrable_list(request):
    site = get_current_site(request)
    if not Conference.objects.get(site=site).subscriptions_open:
        raise Http404
    talks = Talk.objects.filter(site=site, registration_required=True)
    if request.user.is_authenticated():
        attendee = Attendee.objects.filter(user=request.user).first()
    else:
        attendee = None
    return render(request, 'proposals/talk_registrable_list.html', {'talks':
        talks, 'attendee': attendee})


def talk_register(request, talk):
    talk = get_object_or_404(Talk, site=get_current_site(request),
        registration_required=True, slug=talk)
    form = SubscribeForm(request.POST or None)
    if request.user.is_authenticated(
        ) or request.method == 'POST' and form.is_valid():
        if request.user.is_authenticated():
            attendee, created = Attendee.objects.get_or_create(user=request
                .user)
        else:
            attendee, created = Attendee.objects.get_or_create(email=form.
                cleaned_data['email'], name=form.cleaned_data['name'])
        if attendee in talk.attendees.all():
            if request.user.is_authenticated():
                talk.attendees.remove(attendee)
                messages.success(request, _('Unregistered :-('))
            else:
                messages.error(request, _('Already registered!'))
        elif talk.remaining_attendees == 0:
            raise PermissionDenied
        else:
            talk.attendees.add(attendee)
            messages.success(request, _('Registered!'))
        talk.save()
        return redirect('list-registrable-talks')
    return render(request, 'proposals/talk_register.html', {'talk': talk,
        'form': form})

<mask token>


@login_required
@require_http_methods(['POST'])
def markdown_preview(request):
    content = request.POST.get('data', '')
    return HttpResponse(markdown_to_html(content))


def home(request):
    return render(request, 'proposals/home.html')


@staff_required
def staff(request):
    return render(request, 'staff.html')


<mask token>


@login_required
def participate(request):
    site = get_current_site(request)
    talks = Talk.objects.filter(site=site)
    my_talks = talks.filter(speakers=request.user)
    proposed_talks = talks.exclude(speakers=request.user).filter(proposer=
        request.user)
    return render(request, 'proposals/participate.html', {'my_talks':
        my_talks, 'proposed_talks': proposed_talks})


@staff_required
def talk_list(request):
    show_filters = False
    talks = Talk.objects.filter(site=get_current_site(request))
    filter_form = TalkFilterForm(request.GET or None, site=get_current_site
        (request))
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['kind']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk
                ) for pk in data['kind']]))
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=
                dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug
                =topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
        if data['vote'] != None:
            show_filters = True
            if data['vote']:
                talks = talks.filter(vote__user=request.user)
            else:
                talks = talks.exclude(vote__user=request.user)
        if data['room'] != None:
            show_filters = True
            talks = talks.filter(room__isnull=not data['room'])
        if data['scheduled'] != None:
            show_filters = True
            talks = talks.filter(start_date__isnull=not data['scheduled'])
        if data['materials'] != None:
            show_filters = True
            talks = talks.filter(materials__isnull=not data['materials'])
        if data['video'] != None:
            show_filters = True
            if data['video']:
                talks = talks.exclude(video__exact='')
            else:
                talks = talks.filter(video__exact='')
    action_form = TalkActionForm(request.POST or None, talks=talks, site=
        get_current_site(request))
    if not is_orga(request, request.user):
        action_form.fields.pop('track')
        action_form.fields.pop('room')
    if request.method == 'POST':
        if action_form.is_valid():
            data = action_form.cleaned_data
            permission_error = False
            for talk in data['talks']:
                talk = Talk.objects.get(site=get_current_site(request),
                    slug=talk)
                if data['decision'] != None:
                    if not talk.is_moderable_by(request.user):
                        permission_error = True
                        continue
                    conversation = ConversationAboutTalk.objects.get(talk=talk)
                    if data['decision']:
                        note = 'The talk has been accepted.'
                    else:
                        note = 'The talk has been declined.'
                    Message.objects.create(conversation=conversation,
                        author=request.user, content=note)
                    talk.accepted = data['decision']
                if data['track']:
                    talk.track = Track.objects.get(site=get_current_site(
                        request), slug=data['track'])
                if data['room']:
                    talk.room = Room.objects.get(site=get_current_site(
                        request), slug=data['room'])
                talk.save()
            if permission_error:
                messages.warning(request,
                    'Some actions were ignored due to missing permissions.')
            return redirect(request.get_full_path())
    if request.GET.get('order') == 'desc':
        reverse = True
    else:
        reverse = False
    SORT_MAPPING = {'title': 'title', 'kind': 'event', 'status': 'accepted'}
    sort = request.GET.get('sort')
    if sort in SORT_MAPPING.keys():
        if reverse:
            talks = talks.order_by('-' + SORT_MAPPING[sort])
        else:
            talks = talks.order_by(SORT_MAPPING[sort])
    sort_urls = dict()
    sort_glyphicons = dict()
    for c in SORT_MAPPING.keys():
        url = request.GET.copy()
        url['sort'] = c
        if c == sort:
            if reverse:
                del url['order']
                glyphicon = 'sort-by-attributes-alt'
            else:
                url['order'] = 'desc'
                glyphicon = 'sort-by-attributes'
        else:
            glyphicon = 'sort'
        sort_urls[c] = url.urlencode()
        sort_glyphicons[c] = glyphicon
    return render(request, 'proposals/talk_list.html', {'show_filters':
        show_filters, 'talk_list': talks, 'filter_form': filter_form,
        'action_form': action_form, 'sort_urls': sort_urls,
        'sort_glyphicons': sort_glyphicons})


@login_required
def talk_edit(request, talk=None):
    site = get_current_site(request)
    if talk:
        talk = get_object_or_404(Talk, slug=talk, site=site)
        if not talk.is_editable_by(request.user):
            raise PermissionDenied
    else:
        conf = Conference.objects.get(site=site)
        if not is_orga(request, request.user) and not conf.cfp_is_open():
            raise PermissionDenied
    staff = talk.is_moderable_by(request.user) if talk else is_orga(request,
        request.user)
    form = TalkForm(request.POST or None, request.FILES or None, instance=
        talk, site=site, staff=staff)
    if talk:
        form.fields['topics'].disabled = True
        if 'duration' in form.fields and talk.event.duration:
            form.fields['duration'
                ].help_text = 'Default value if zero: %d min' % talk.duration
        if 'attendees_limit' in form.fields and talk.is_editable_by(request
            .user) and talk.room and talk.room.capacity:
            form.fields['attendees_limit'].help_text = ungettext_lazy(
                'Note: the room %(room)s has %(capacity)s seat.',
                'Note: the room %(room)s has %(capacity)s seats.', talk.
                room.capacity) % {'room': talk.room.name, 'capacity': talk.
                room.capacity}
    else:
        form.fields.pop('materials')
        form.fields.pop('video')
        form.fields['speakers'].initial = [request.user]
    if request.method == 'POST' and form.is_valid():
        if hasattr(talk, 'id'):
            talk = form.save()
            if (request.user == talk.proposer or request.user in talk.
                speakers.all()):
                talk_edited.send(talk.__class__, instance=talk, author=
                    request.user)
            messages.success(request, _('Talk modified successfully!'))
        else:
            form.instance.site = get_current_site(request)
            form.instance.proposer = request.user
            talk = form.save()
            talk_added.send(talk.__class__, instance=talk, author=request.user)
            messages.success(request, _('Talk proposed successfully!'))
        return redirect(talk.get_absolute_url())
    return render(request, 'proposals/talk_edit.html', {'base_template': 
        'staff.html' if staff else 'base.html', 'talk': talk, 'form': form})


<mask token>


class TalkDetail(LoginRequiredMixin, DetailView):

    def get_queryset(self):
        return Talk.objects.filter(site=get_current_site(self.request)).all()

    def get_context_data(self, **ctx):
        if self.object.is_moderable_by(self.request.user):
            vote = Vote.objects.filter(talk=self.object, user=self.request.user
                ).first()
            ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
                form_url=reverse('talk-conversation', kwargs={'talk': self.
                object.slug}))
        else:
            ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
        if is_staff(self.request, self.request.user):
            ctx.update(base_template='staff.html')
        else:
            ctx.update(base_template='base.html')
        return super().get_context_data(**ctx)


class TopicMixin(object):

    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):

    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


@login_required
def vote(request, talk, score):
    talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
    vote.vote = int(score)
    vote.save()
    messages.success(request, _('Vote successfully created') if created else
        _('Vote successfully updated'))
    return redirect(talk.get_absolute_url())


@login_required
def talk_decide(request, talk, accepted):
    site = get_current_site(request)
    talk = get_object_or_404(Talk, site=site, slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    if request.method == 'POST':
        m = request.POST.get('message', '').strip()
        if m:
            participation = Participation.objects.get(site=site, user=talk.
                proposer)
            conversation = ConversationWithParticipant.objects.get(
                participation=participation)
            Message.objects.create(conversation=conversation, author=
                request.user, content=m)
        conversation = ConversationAboutTalk.objects.get(talk=talk)
        if accepted:
            note = 'The talk has been accepted.'
        else:
            note = 'The talk has been declined.'
        Message.objects.create(conversation=conversation, author=request.
            user, content=note)
        talk.accepted = accepted
        talk.save()
        messages.success(request, _('Decision taken in account'))
        return redirect('show-talk', slug=talk.slug)
    return render(request, 'proposals/talk_decide.html', {'talk': talk,
        'accept': accepted})


@staff_required
def speaker_list(request):
    show_filters = False
    site = get_current_site(request)
    filter_form = SpeakerFilterForm(request.GET or None, site=site)
    talks = Talk.objects.filter(site=site)
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=
                dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug
                =topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
    speakers = Participation.objects.filter(site=site, user__talk__in=talks
        ).order_by('pk').distinct()
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['transport']):
            show_filters = True
            q = Q()
            if 'unanswered' in data['transport']:
                data['transport'].remove('unanswered')
                q |= Q(need_transport=None)
            if 'unspecified' in data['transport']:
                data['transport'].remove('unspecified')
                speakers = speakers.annotate(transport_count=Count('transport')
                    )
                q |= Q(need_transport=True, transport_count=0)
            if len(data['transport']):
                q |= Q(need_transport=True) & Q(reduce(lambda x, y: x | y,
                    [Q(transport__pk=pk) for pk in data['transport']]))
            speakers = speakers.filter(q)
        if len(data['accommodation']):
            show_filters = True
            accommodations = list(map(lambda x: None if x == 'unknown' else
                x, data['accommodation']))
            speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(
                accommodation=value) for value in accommodations]))
        if data['sound'] != None:
            show_filters = True
            speakers = speakers.filter(sound=data['sound'])
        if data['transport_booked'] != None:
            show_filters = True
            speakers = speakers.filter(need_transport=True).filter(
                transport_booked=data['transport_booked'])
        if data['accommodation_booked'] != None:
            show_filters = True
            speakers = speakers.exclude(accommodation=Participation.
                ACCOMMODATION_NO).filter(accommodation_booked=data[
                'accommodation_booked'])
    contact_link = 'mailto:' + ','.join([speaker.user.email for speaker in
        speakers.all() if speaker.user.email])
    return render(request, 'proposals/speaker_list.html', {'speaker_list':
        speakers, 'filter_form': filter_form, 'show_filters': show_filters,
        'contact_link': contact_link})


def talk_registrable_list(request):
    site = get_current_site(request)
    if not Conference.objects.get(site=site).subscriptions_open:
        raise Http404
    talks = Talk.objects.filter(site=site, registration_required=True)
    if request.user.is_authenticated():
        attendee = Attendee.objects.filter(user=request.user).first()
    else:
        attendee = None
    return render(request, 'proposals/talk_registrable_list.html', {'talks':
        talks, 'attendee': attendee})


def talk_register(request, talk):
    talk = get_object_or_404(Talk, site=get_current_site(request),
        registration_required=True, slug=talk)
    form = SubscribeForm(request.POST or None)
    if request.user.is_authenticated(
        ) or request.method == 'POST' and form.is_valid():
        if request.user.is_authenticated():
            attendee, created = Attendee.objects.get_or_create(user=request
                .user)
        else:
            attendee, created = Attendee.objects.get_or_create(email=form.
                cleaned_data['email'], name=form.cleaned_data['name'])
        if attendee in talk.attendees.all():
            if request.user.is_authenticated():
                talk.attendees.remove(attendee)
                messages.success(request, _('Unregistered :-('))
            else:
                messages.error(request, _('Already registered!'))
        elif talk.remaining_attendees == 0:
            raise PermissionDenied
        else:
            talk.attendees.add(attendee)
            messages.success(request, _('Registered!'))
        talk.save()
        return redirect('list-registrable-talks')
    return render(request, 'proposals/talk_register.html', {'talk': talk,
        'form': form})

from functools import reduce

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.db.models import Q, Count
from django.shortcuts import get_object_or_404, redirect, render
from django.views.generic import CreateView, DetailView, ListView, UpdateView
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse, Http404

from ponyconf.mixins import OnSiteFormMixin

from accounts.models import Participation
from accounts.mixins import OrgaRequiredMixin, StaffRequiredMixin
from accounts.decorators import orga_required, staff_required
from accounts.utils import is_staff, is_orga

from conversations.models import ConversationWithParticipant, ConversationAboutTalk, Message

from planning.models import Room

from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm, SubscribeForm
from .models import Talk, Track, Topic, Vote, Conference, Attendee
from .signals import talk_added, talk_edited
from .utils import markdown_to_html


@login_required
@require_http_methods(["POST"])
def markdown_preview(request):
    content = request.POST.get('data', '')
    return HttpResponse(markdown_to_html(content))


def home(request):
    return render(request, 'proposals/home.html')


@staff_required
def staff(request):
    return render(request, 'staff.html')


@orga_required
def conference(request):
    conference = Conference.objects.get(site=get_current_site(request))
    form = ConferenceForm(request.POST or None, instance=conference)
    if request.method == 'POST' and form.is_valid():
        form.save()
        messages.success(request, 'Conference updated!')
        return redirect(reverse('edit-conference'))
    return render(request, 'proposals/conference.html', {
        'form': form,
    })

@login_required
def participate(request):
    site = get_current_site(request)
    talks = Talk.objects.filter(site=site)
    my_talks = talks.filter(speakers=request.user)
    proposed_talks = talks.exclude(speakers=request.user).filter(proposer=request.user)
    return render(request, 'proposals/participate.html', {
        'my_talks': my_talks,
        'proposed_talks': proposed_talks,
    })

@staff_required
def talk_list(request):
    show_filters = False
    talks = Talk.objects.filter(site=get_current_site(request))
    filter_form = TalkFilterForm(request.GET or None, site=get_current_site(request))
    # Filtering
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['kind']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk) for pk in data['kind']]))
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
        if data['vote'] != None:
            show_filters = True
            if data['vote']:
                talks = talks.filter(vote__user=request.user)
            else:
                talks = talks.exclude(vote__user=request.user)
        if data['room'] != None:
            show_filters = True
            talks = talks.filter(room__isnull=not data['room'])
        if data['scheduled'] != None:
            show_filters = True
            talks = talks.filter(start_date__isnull=not data['scheduled'])
        if data['materials'] != None:
            show_filters = True
            talks = talks.filter(materials__isnull=not data['materials'])
        if data['video'] != None:
            show_filters = True
            if data['video']:
                talks = talks.exclude(video__exact='')
            else:
                talks = talks.filter(video__exact='')
    # Action
    action_form = TalkActionForm(request.POST or None, talks=talks, site=get_current_site(request))
    if not is_orga(request, request.user):
        action_form.fields.pop('track')
        action_form.fields.pop('room')
    if request.method == 'POST':
        if action_form.is_valid():
            data = action_form.cleaned_data
            permission_error = False
            for talk in data['talks']:
                talk = Talk.objects.get(site=get_current_site(request), slug=talk)
                if data['decision'] != None:
                    if not talk.is_moderable_by(request.user):
                        permission_error = True
                        continue
                    # TODO: merge with talk_decide code
                    conversation = ConversationAboutTalk.objects.get(talk=talk)
                    if data['decision']:
                        note = "The talk has been accepted."
                    else:
                        note = "The talk has been declined."
                    Message.objects.create(conversation=conversation, author=request.user, content=note)
                    talk.accepted = data['decision']
                if data['track']:
                    talk.track = Track.objects.get(site=get_current_site(request), slug=data['track'])
                if data['room']:
                    talk.room = Room.objects.get(site=get_current_site(request), slug=data['room'])
                talk.save()
            if permission_error:
                messages.warning(request, 'Some actions were ignored due to missing permissions.')
            return redirect(request.get_full_path())
    # Sorting
    if request.GET.get('order') == 'desc':
        reverse = True
    else:
        reverse = False
    SORT_MAPPING = {
        'title': 'title',
        'kind': 'event',
        'status': 'accepted',
    }
    sort = request.GET.get('sort')
    if sort in SORT_MAPPING.keys():
        if reverse:
            talks = talks.order_by('-' + SORT_MAPPING[sort])
        else:
            talks = talks.order_by(SORT_MAPPING[sort])
    # Sorting URLs
    sort_urls = dict()
    sort_glyphicons = dict()
    for c in SORT_MAPPING.keys():
        url = request.GET.copy()
        url['sort'] = c
        if c == sort:
            if reverse:
                del url['order']
                glyphicon = 'sort-by-attributes-alt'
            else:
                url['order'] = 'desc'
                glyphicon = 'sort-by-attributes'
        else:
            glyphicon = 'sort'
        sort_urls[c] = url.urlencode()
        sort_glyphicons[c] = glyphicon
    return render(request, 'proposals/talk_list.html', {
        'show_filters': show_filters,
        'talk_list': talks,
        'filter_form': filter_form,
        'action_form': action_form,
        'sort_urls': sort_urls,
        'sort_glyphicons': sort_glyphicons,
    })

@login_required
def talk_edit(request, talk=None):
    site = get_current_site(request)
    if talk: # edit existing talk
        talk = get_object_or_404(Talk, slug=talk, site=site)
        if not talk.is_editable_by(request.user):
            raise PermissionDenied
    else: # add new talk
        conf = Conference.objects.get(site=site)
        if not is_orga(request, request.user) and not conf.cfp_is_open():
            raise PermissionDenied
    staff = talk.is_moderable_by(request.user) if talk else is_orga(request, request.user)
    form = TalkForm(request.POST or None, request.FILES or None, instance=talk, site=site, staff=staff)
    if talk:
        form.fields['topics'].disabled = True
        if 'duration' in form.fields and talk.event.duration:
            form.fields['duration'].help_text = 'Default value if zero: %d min' % talk.duration
        if 'attendees_limit' in form.fields and talk.is_editable_by(request.user) and talk.room and talk.room.capacity:
            form.fields['attendees_limit'].help_text=ungettext_lazy(
                    "Note: the room %(room)s has %(capacity)s seat.",
                    "Note: the room %(room)s has %(capacity)s seats.",
                    talk.room.capacity) % {'room': talk.room.name, 'capacity': talk.room.capacity}
    else:
        form.fields.pop('materials')
        form.fields.pop('video')
        form.fields['speakers'].initial = [request.user]
    if request.method == 'POST' and form.is_valid():
        if hasattr(talk, 'id'):
            talk = form.save()
            if request.user == talk.proposer or request.user in talk.speakers.all():
                talk_edited.send(talk.__class__, instance=talk, author=request.user)
            messages.success(request, _('Talk modified successfully!'))
        else:
            form.instance.site = get_current_site(request)
            form.instance.proposer = request.user
            talk = form.save()
            talk_added.send(talk.__class__, instance=talk, author=request.user)
            messages.success(request, _('Talk proposed successfully!'))
        return redirect(talk.get_absolute_url())
    return render(request, 'proposals/talk_edit.html', {
        'base_template': 'staff.html' if staff else 'base.html',
        'talk': talk,
        'form': form,
    })


@login_required
def talk_assign_to_track(request, talk, track):
    talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    track = get_object_or_404(Track, slug=track, site=get_current_site(request))
    talk.track = track
    talk.save()
    messages.success(request, _('Talk assigned to track successfully!'))
    next_url = request.GET.get('next') or reverse('show-talk', kwargs={'slug': talk.slug})
    return redirect(next_url)


class TalkDetail(LoginRequiredMixin, DetailView):
    def get_queryset(self):
        return Talk.objects.filter(site=get_current_site(self.request)).all()

    def get_context_data(self, **ctx):
        if self.object.is_moderable_by(self.request.user):
            vote = Vote.objects.filter(talk=self.object, user=self.request.user).first()
            ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
                       form_url=reverse('talk-conversation', kwargs={'talk': self.object.slug}))
        else:
            ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
        if is_staff(self.request, self.request.user):
            ctx.update(base_template='staff.html')
        else:
            ctx.update(base_template='base.html')
        return super().get_context_data(**ctx)


class TopicMixin(object):
    def get_queryset(self):
        return Topic.objects.filter(site=get_current_site(self.request)).all()


class TopicFormMixin(OnSiteFormMixin):
    form_class = TopicForm


class TopicList(LoginRequiredMixin, TopicMixin, ListView):
    pass


class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
    model = Topic


class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
    pass


class TrackFormMixin(OnSiteFormMixin):
    form_class = TrackForm


class TrackMixin(object):
    def get_queryset(self):
        return Track.objects.filter(site=get_current_site(self.request)).all()


class TrackList(LoginRequiredMixin, TrackMixin, ListView):
    pass


class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
    model = Track


class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
    pass


@login_required
def vote(request, talk, score):
    talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
    vote.vote = int(score)
    vote.save()
    messages.success(request, _('Vote successfully created') if created else _('Vote successfully updated'))
    return redirect(talk.get_absolute_url())


@login_required
def talk_decide(request, talk, accepted):
    site = get_current_site(request)
    talk = get_object_or_404(Talk, site=site, slug=talk)
    if not talk.is_moderable_by(request.user):
        raise PermissionDenied
    if request.method == 'POST':
        # Does we need to send a notification to the proposer?
        m = request.POST.get('message', '').strip()
        if m:
            participation = Participation.objects.get(site=site, user=talk.proposer)
            conversation = ConversationWithParticipant.objects.get(participation=participation)
            Message.objects.create(conversation=conversation, author=request.user, content=m)
        # Save the decision in the talk's conversation
        conversation = ConversationAboutTalk.objects.get(talk=talk)
        if accepted:
            note = "The talk has been accepted."
        else:
            note = "The talk has been declined."
        Message.objects.create(conversation=conversation, author=request.user, content=note)
        talk.accepted = accepted
        talk.save()
        messages.success(request, _('Decision taken in account'))
        return redirect('show-talk', slug=talk.slug)
    return render(request, 'proposals/talk_decide.html', {
        'talk': talk,
        'accept': accepted,
    })


@staff_required
def speaker_list(request):
    show_filters = False
    site = get_current_site(request)
    filter_form = SpeakerFilterForm(request.GET or None, site=site)
    talks = Talk.objects.filter(site=site)
    # Filtering
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['status']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
        if len(data['topic']):
            show_filters = True
            talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
        if len(data['track']):
            show_filters = True
            q = Q()
            if 'none' in data['track']:
                data['track'].remove('none')
                q |= Q(track__isnull=True)
            if len(data['track']):
                q |= Q(track__slug__in=data['track'])
            talks = talks.filter(q)
    speakers = Participation.objects.filter(site=site,user__talk__in=talks).order_by('pk').distinct()
    if filter_form.is_valid():
        data = filter_form.cleaned_data
        if len(data['transport']):
            show_filters = True
            q = Q()
            if 'unanswered' in data['transport']:
                data['transport'].remove('unanswered')
                q |= Q(need_transport=None)
            if 'unspecified' in data['transport']:
                data['transport'].remove('unspecified')
                speakers = speakers.annotate(transport_count=Count('transport'))
                q |= Q(need_transport=True, transport_count=0)
            if len(data['transport']):
                q |= (Q(need_transport=True) & Q(reduce(lambda x, y: x | y, [Q(transport__pk=pk) for pk in data['transport']])))
            speakers = speakers.filter(q)
        if len(data['accommodation']):
            show_filters = True
            accommodations = list(map(lambda x: None if x == 'unknown' else x, data['accommodation']))
            speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(accommodation=value) for value in accommodations]))
        if data['sound'] != None:
            show_filters = True
            speakers = speakers.filter(sound=data['sound'])
        if data['transport_booked'] != None:
            show_filters = True
            speakers = speakers.filter(need_transport=True).filter(transport_booked=data['transport_booked'])
        if data['accommodation_booked'] != None:
            show_filters = True
            speakers = speakers.exclude(accommodation=Participation.ACCOMMODATION_NO).filter(accommodation_booked=data['accommodation_booked'])
    contact_link = 'mailto:' + ','.join([speaker.user.email for speaker in speakers.all() if speaker.user.email])
    return render(request, 'proposals/speaker_list.html', {
        'speaker_list': speakers,
        'filter_form': filter_form,
        'show_filters': show_filters,
        'contact_link': contact_link,
    })


def talk_registrable_list(request):
    site = get_current_site(request)
    if not Conference.objects.get(site=site).subscriptions_open:
        raise Http404
    talks = Talk.objects.filter(site=site, registration_required=True)
    if request.user.is_authenticated():
        attendee = Attendee.objects.filter(user=request.user).first() # None if it does not exists
    else:
        attendee = None
    return render(request, 'proposals/talk_registrable_list.html', {
        'talks': talks,
        'attendee': attendee,
    })


def talk_register(request, talk):
    talk = get_object_or_404(Talk, site=get_current_site(request), registration_required=True, slug=talk)

    form = SubscribeForm(request.POST or None)

    if request.user.is_authenticated() or (request.method == 'POST' and form.is_valid()):
        if request.user.is_authenticated():
            attendee, created = Attendee.objects.get_or_create(user=request.user)
        else:
            attendee, created = Attendee.objects.get_or_create(email=form.cleaned_data['email'], name=form.cleaned_data['name'])
        if attendee in talk.attendees.all():
            if request.user.is_authenticated():
                talk.attendees.remove(attendee)
                messages.success(request, _("Unregistered :-("))
            else:
                messages.error(request, _("Already registered!"))
        elif talk.remaining_attendees == 0:
            raise PermissionDenied
        else:
            talk.attendees.add(attendee)
            messages.success(request, _("Registered!"))
        talk.save()
        return redirect('list-registrable-talks')

    return render(request, 'proposals/talk_register.html', {
        'talk': talk,
        'form': form,
    })
