Exemple #1
0
def voting(request):

    conf, talks, voting_allowed = get_data_for_context(request)

    if not settings.VOTING_OPENED(conf, request.user):
        if settings.VOTING_CLOSED:
            return redirect(settings.VOTING_CLOSED)
        else:
            raise http.Http404()

    if request.method == 'POST':
        if not voting_allowed:
            return http.HttpResponseBadRequest('anonymous user not allowed')

        data = dict((x.id, x) for x in talks)
        for k, v in filter(lambda x: x[0].startswith('vote-'),
                           request.POST.items()):
            try:
                talk = data[int(k[5:])]
            except KeyError:
                return http.HttpResponseBadRequest('invalid talk')
            except ValueError:
                return http.HttpResponseBadRequest('id malformed')
            if not v:
                models.VotoTalk.objects.filter(user=request.user,
                                               talk=talk).delete()
            else:
                try:
                    vote = Decimal(v)
                except ValueError:
                    return http.HttpResponseBadRequest('vote malformed')
                try:
                    o = models.VotoTalk.objects.get(user=request.user,
                                                    talk=talk)
                except models.VotoTalk.DoesNotExist:
                    o = models.VotoTalk(user=request.user, talk=talk)
                if not vote:
                    if o.id:
                        o.delete()
                else:
                    o.vote = vote
                    o.save()
        if request.is_ajax():
            return http.HttpResponse('')
        else:
            return HttpResponseRedirectSeeOther(
                reverse('conference-voting') + '?' + request.GET.urlencode())
    else:
        from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer

        class OptionForm(forms.Form):
            abstracts = forms.ChoiceField(
                choices=(
                    ('not-voted', 'Not yet voted'),
                    ('all', 'All'),
                ),
                required=False,
                initial='not-voted',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            talk_type = forms.ChoiceField(
                label=u'Session type',
                choices=(('all', 'All'), ) +
                tuple(settings.TALK_TYPES_TO_BE_VOTED),
                required=False,
                initial='all',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            language = forms.ChoiceField(
                choices=(('all', 'All'), ) +
                tuple(settings.TALK_SUBMISSION_LANGUAGES),
                required=False,
                initial='all',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            order = forms.ChoiceField(
                choices=(
                    ('random', 'Random order'),
                    ('vote', 'Vote'),
                    ('speaker', 'Speaker name'),
                ),
                required=False,
                initial='random',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            tags = TagField(
                required=False,
                widget=ReadonlyTagWidget(),
            )

        # I want to associate with each talk a "unique" number to display next to the title to be able to easily find.
        ordinal = dict()
        for ix, t in enumerate(
                talks.order_by('created').values_list('id', flat=True)):
            ordinal[t] = ix

        user_votes = models.VotoTalk.objects.filter(user=request.user.id)

        # Start by sorting talks by name
        talks = talks.order_by('speakers__user__first_name',
                               'speakers__user__last_name')

        if request.GET:
            form = OptionForm(data=request.GET)
            form.is_valid()
            options = form.cleaned_data
        else:
            form = OptionForm()
            options = {
                'abstracts': 'not-voted',
                'talk_type': 'all',
                'language': 'all',
                'tags': '',
                'order': 'random',
            }
        # if options['abstracts'] == 'not-voted':
        #     talks = talks.exclude(id__in=user_votes.values('talk_id'))
        if options['talk_type'] in (
                tchar for (tchar, tdef) in settings.TALK_TYPES_TO_BE_VOTED):
            talks = talks.filter(type__startswith=options['talk_type'])

        if options['language'] in (
                lcode for (lcode, ldef) in settings.TALK_SUBMISSION_LANGUAGES):
            talks = talks.filter(language=options['language'])

        if options['tags']:
            # if options['tags'] ends us a tag not associated with any talk I results
            # in a query that results from scratch; to avoid this limit the usable tag
            # as a filter to those associated with talk.
            allowed = set()
            ctt = ContentType.objects.get_for_model(models.Talk)
            for t, usage in dataaccess.tags().items():
                for cid, oid in usage:
                    if cid == ctt.id:
                        allowed.add(t.name)
                        break
            tags = set(options['tags']) & allowed
            if tags:
                talks = talks.filter(id__in=models.ConferenceTaggedItem.objects\
                    .filter(
                        content_type__app_label='conference', content_type__model='talk',
                        tag__name__in=tags)\
                    .values('object_id')
                )

        talk_order = options['order']
        votes = dict((x.talk_id, x) for x in user_votes)

        # As talks are sorted by a model connected via a m2m can I have repeated the talk, and
        # distinct does not apply in these case.
        #
        # It can only filtered in python, at this point I take this opportunity to engage
        # votes user using a single loop.
        dups = set()

        def filter_vote(t):
            if t['id'] in dups:
                return False
            dups.add(t['id'])
            t['user_vote'] = votes.get(t['id'])
            t['ordinal'] = ordinal[t['id']]
            return True

        talks = filter(filter_vote, talks.values('id'))

        # Fix talk order, if necessary
        if talk_order == 'vote':

            def key(x):
                if x['user_vote']:
                    return x['user_vote'].vote
                else:
                    return Decimal('-99.99')

            talks = reversed(sorted(reversed(talks), key=key))
        elif talk_order == 'random':
            random.shuffle(talks)
        elif talk_order == 'speaker':
            # Already sorted
            pass

        ctx = {
            'voting_allowed': voting_allowed,
            'talks': list(talks),
            'form': form,
        }
        if request.is_ajax():
            tpl = 'conference/ajax/voting.html'
        else:
            tpl = 'conference/voting.html'
        return render(request, tpl, ctx)
Exemple #2
0
def filter_talks_in_context(request, talks, voting_allowed):
    # Want to associate each talk with a "unique" number, easily find.
    ordinal = dict()
    for ix, t in enumerate(
            talks.order_by('created').values_list('id', flat=True)):
        ordinal[t] = ix
    user_votes = models.VotoTalk.objects.filter(user=request.user.id)
    talks = talks.order_by('speakers__user__first_name',
                           'speakers__user__last_name')
    if request.GET:
        form = OptionForm(data=request.GET)
        form.is_valid()
        options = form.cleaned_data
    else:
        form = OptionForm()
        options = {
            'abstracts': 'not-voted',
            'talk_type': '',
            'language': '',
            'tags': '',
            'order': 'vote',
        }
    if options['abstracts'] != 'all':
        talks = talks.exclude(id__in=user_votes.values('talk_id'))
    if options['talk_type'] in ('s', 't', 'p'):
        talks = talks.filter(type=options['talk_type'])
    if options['language'] in ('en', 'it'):
        talks = talks.filter(language=options['language'])
    if options['tags']:
        # if options['tags'] ends us a tag not associated with any talk.
        # I have a query that results in zero results; to avoid this limit the usable
        # tag as a filter to those associated with talk.
        allowed = set()
        ctt = ContentType.objects.get_for_model(models.Talk)
        for t, usage in dataaccess.tags().items():
            for cid, oid in usage:
                if cid == ctt.id:
                    allowed.add(t.name)
                    break
        tags = set(options['tags']) & allowed
        if tags:
            talks = talks.filter(id__in=models.ConferenceTaggedItem.objects \
                                 .filter(
                content_type__app_label='conference', content_type__model='talk',
                tag__name__in=tags) \
                                 .values('object_id')
            )
    talk_order = options['order']
    votes = dict((x.talk_id, x) for x in user_votes)
    # As talks are sorted by a linked model through a m2m can I have repeated
    # the talk and distinct does not apply in these cases.
    #
    # I can only filter in Python, at this point I take this opportunity to
    # engage votes user using a single loop.
    dups = set()

    def filter_vote(t):
        if t['id'] in dups:
            return False
        dups.add(t['id'])
        t['user_vote'] = votes.get(t['id'])
        t['ordinal'] = ordinal[t['id']]
        return True

    talks = filter(filter_vote, talks.values('id'))
    if talk_order != 'speaker':

        def key(x):
            if x['user_vote']:
                return x['user_vote'].vote
            else:
                return Decimal('-99.99')

        talks = reversed(sorted(reversed(talks), key=key))
    ctx = {
        'voting_allowed': voting_allowed,
        'talks': list(talks),
        'form': form,
    }
    return ctx
Exemple #3
0
def voting(request):

    conf, talks, voting_allowed = get_data_for_context(request)

    if not settings.VOTING_OPENED(conf, request.user):
        if settings.VOTING_CLOSED:
            return redirect(settings.VOTING_CLOSED)
        else:
            raise http.Http404()

    if request.method == 'POST':
        if not voting_allowed:
            return http.HttpResponseBadRequest('anonymous user not allowed')

        data = dict((x.id, x) for x in talks)
        for k, v in filter(lambda x: x[0].startswith('vote-'),
                           request.POST.items()):
            try:
                talk = data[int(k[5:])]
            except KeyError:
                return http.HttpResponseBadRequest('invalid talk')
            except ValueError:
                return http.HttpResponseBadRequest('id malformed')
            if not v:
                models.VotoTalk.objects.filter(user=request.user,
                                               talk=talk).delete()
            else:
                try:
                    vote = Decimal(v)
                except ValueError:
                    return http.HttpResponseBadRequest('vote malformed')
                try:
                    o = models.VotoTalk.objects.get(user=request.user,
                                                    talk=talk)
                except models.VotoTalk.DoesNotExist:
                    o = models.VotoTalk(user=request.user, talk=talk)
                if not vote:
                    if o.id:
                        o.delete()
                else:
                    o.vote = vote
                    o.save()
        if request.is_ajax():
            return http.HttpResponse('')
        else:
            return HttpResponseRedirectSeeOther(
                reverse('conference-voting') + '?' + request.GET.urlencode())
    else:
        from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer

        class OptionForm(forms.Form):
            abstracts = forms.ChoiceField(
                choices=(
                    ('not-voted', 'To be voted'),
                    ('all', 'All'),
                ),
                required=False,
                initial='not-voted',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            talk_type = forms.ChoiceField(
                choices=settings.TALK_TYPES_TO_BE_VOTED,
                required=False,
                initial='all',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            language = forms.ChoiceField(
                choices=(
                    ('all', 'All'),
                    ('en', 'English'),
                    ('it', 'Italian'),
                ),
                required=False,
                initial='all',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            order = forms.ChoiceField(
                choices=(
                    ('vote', 'Vote'),
                    ('speaker', 'Speaker name'),
                ),
                required=False,
                initial='vote',
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            tags = TagField(
                required=False,
                widget=ReadonlyTagWidget(),
            )

        # voglio poter associare ad ogni talk un numero "univoco" da mostrare
        # accanto al titolo per poterlo individuare facilmente.
        ordinal = dict()
        for ix, t in enumerate(
                talks.order_by('created').values_list('id', flat=True)):
            ordinal[t] = ix

        user_votes = models.VotoTalk.objects.filter(user=request.user.id)
        talks = talks.order_by('speakers__user__first_name',
                               'speakers__user__last_name')

        if request.GET:
            form = OptionForm(data=request.GET)
            form.is_valid()
            options = form.cleaned_data
        else:
            form = OptionForm()
            options = {
                'abstracts': 'not-voted',
                'talk_type': '',
                'language': '',
                'tags': '',
                'order': 'vote',
            }
        if options['abstracts'] != 'all':
            talks = talks.exclude(id__in=user_votes.values('talk_id'))
        if options['talk_type'] in ('s', 't', 'p'):
            talks = talks.filter(type=options['talk_type'])

        if options['language'] in ('en', 'it'):
            talks = talks.filter(language=options['language'])

        if options['tags']:
            # se in options['tags'] ci finisce un tag non associato ad alcun
            # talk ho come risultato una query che da zero risultati; per
            # evitare questo limito i tag usabili come filtro a quelli
            # associati ai talk.
            allowed = set()
            ctt = ContentType.objects.get_for_model(models.Talk)
            for t, usage in dataaccess.tags().items():
                for cid, oid in usage:
                    if cid == ctt.id:
                        allowed.add(t.name)
                        break
            tags = set(options['tags']) & allowed
            if tags:
                talks = talks.filter(id__in=models.ConferenceTaggedItem.objects\
                    .filter(
                        content_type__app_label='conference', content_type__model='talk',
                        tag__name__in=tags)\
                    .values('object_id')
                )

        talk_order = options['order']

        votes = dict((x.talk_id, x) for x in user_votes)

        # Poichè talks è ordinato per un modello collegato tramite una
        # ManyToMany posso avere dei talk ripetuti, e il distinct non si
        # applica in questi casi.
        #
        # Non mi rimane che filtrare in python, a questo punto ne approfitto
        # per agganciare i voti dell'utente utilizzando un unico loop.
        dups = set()

        def filter_vote(t):
            if t['id'] in dups:
                return False
            dups.add(t['id'])
            t['user_vote'] = votes.get(t['id'])
            t['ordinal'] = ordinal[t['id']]
            return True

        talks = filter(filter_vote, talks.values('id'))

        if talk_order != 'speaker':

            def key(x):
                if x['user_vote']:
                    return x['user_vote'].vote
                else:
                    return Decimal('-99.99')

            talks = reversed(sorted(reversed(talks), key=key))

        ctx = {
            'voting_allowed': voting_allowed,
            'talks': list(talks),
            'form': form,
        }
        if request.is_ajax():
            tpl = 'conference/ajax/voting.html'
        else:
            tpl = 'conference/voting.html'
        return render(request, tpl, ctx)
Exemple #4
0
def filter_talks_in_context(request, talks, voting_allowed):
    # voglio poter associare ad ogni talk un numero "univoco" da mostrare
    # accanto al titolo per poterlo individuare facilmente.
    ordinal = dict()
    for ix, t in enumerate(
            talks.order_by('created').values_list('id', flat=True)):
        ordinal[t] = ix
    user_votes = models.VotoTalk.objects.filter(user=request.user.id)
    talks = talks.order_by('speakers__user__first_name',
                           'speakers__user__last_name')
    if request.GET:
        form = OptionForm(data=request.GET)
        form.is_valid()
        options = form.cleaned_data
    else:
        form = OptionForm()
        options = {
            'abstracts': 'not-voted',
            'talk_type': '',
            'language': '',
            'tags': '',
            'order': 'vote',
        }
    if options['abstracts'] != 'all':
        talks = talks.exclude(id__in=user_votes.values('talk_id'))
    if options['talk_type'] in ('s', 't', 'p'):
        talks = talks.filter(type=options['talk_type'])
    if options['language'] in ('en', 'it'):
        talks = talks.filter(language=options['language'])
    if options['tags']:
        # se in options['tags'] ci finisce un tag non associato ad alcun
        # talk ho come risultato una query che da zero risultati; per
        # evitare questo limito i tag usabili come filtro a quelli
        # associati ai talk.
        allowed = set()
        ctt = ContentType.objects.get_for_model(models.Talk)
        for t, usage in dataaccess.tags().items():
            for cid, oid in usage:
                if cid == ctt.id:
                    allowed.add(t.name)
                    break
        tags = set(options['tags']) & allowed
        if tags:
            talks = talks.filter(id__in=models.ConferenceTaggedItem.objects \
                                 .filter(
                content_type__app_label='conference', content_type__model='talk',
                tag__name__in=tags) \
                                 .values('object_id')
            )
    talk_order = options['order']
    votes = dict((x.talk_id, x) for x in user_votes)
    # Poichè talks è ordinato per un modello collegato tramite una
    # ManyToMany posso avere dei talk ripetuti, e il distinct non si
    # applica in questi casi.
    #
    # Non mi rimane che filtrare in python, a questo punto ne approfitto
    # per agganciare i voti dell'utente utilizzando un unico loop.
    dups = set()

    def filter_vote(t):
        if t['id'] in dups:
            return False
        dups.add(t['id'])
        t['user_vote'] = votes.get(t['id'])
        t['ordinal'] = ordinal[t['id']]
        return True

    talks = filter(filter_vote, talks.values('id'))
    if talk_order != 'speaker':

        def key(x):
            if x['user_vote']:
                return x['user_vote'].vote
            else:
                return Decimal('-99.99')

        talks = reversed(sorted(reversed(talks), key=key))
    ctx = {
        'voting_allowed': voting_allowed,
        'talks': list(talks),
        'form': form,
    }
    return ctx
Exemple #5
0
def voting(request):

    conf, talks, voting_allowed = get_data_for_context(request)

    if not settings.VOTING_OPENED(conf, request.user):
        if settings.VOTING_CLOSED:
            return redirect(settings.VOTING_CLOSED)
        else:
            raise http.Http404()

    if request.method == "POST":
        if not voting_allowed:
            return http.HttpResponseBadRequest("anonymous user not allowed")

        data = dict((x.id, x) for x in talks)
        for k, v in filter(lambda x: x[0].startswith("vote-"), request.POST.items()):
            try:
                talk = data[int(k[5:])]
            except KeyError:
                return http.HttpResponseBadRequest("invalid talk")
            except ValueError:
                return http.HttpResponseBadRequest("id malformed")
            if not v:
                models.VotoTalk.objects.filter(user=request.user, talk=talk).delete()
            else:
                try:
                    vote = Decimal(v)
                except ValueError:
                    return http.HttpResponseBadRequest("vote malformed")
                try:
                    o = models.VotoTalk.objects.get(user=request.user, talk=talk)
                except models.VotoTalk.DoesNotExist:
                    o = models.VotoTalk(user=request.user, talk=talk)
                if not vote:
                    if o.id:
                        o.delete()
                else:
                    o.vote = vote
                    o.save()
        if request.is_ajax():
            return http.HttpResponse("")
        else:
            return HttpResponseRedirectSeeOther(reverse("conference-voting") + "?" + request.GET.urlencode())
    else:
        from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer

        class OptionForm(forms.Form):
            abstracts = forms.ChoiceField(
                choices=(("not-voted", "To be voted"), ("all", "All")),
                required=False,
                initial="not-voted",
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            talk_type = forms.ChoiceField(
                choices=settings.TALK_TYPES_TO_BE_VOTED,
                required=False,
                initial="all",
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            language = forms.ChoiceField(
                choices=(("all", "All"), ("en", "English"), ("it", "Italian")),
                required=False,
                initial="all",
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            order = forms.ChoiceField(
                choices=(("vote", "Vote"), ("speaker", "Speaker name")),
                required=False,
                initial="vote",
                widget=forms.RadioSelect(renderer=PseudoRadioRenderer),
            )
            tags = TagField(required=False, widget=ReadonlyTagWidget())

        # voglio poter associare ad ogni talk un numero "univoco" da mostrare
        # accanto al titolo per poterlo individuare facilmente.
        ordinal = dict()
        for ix, t in enumerate(talks.order_by("created").values_list("id", flat=True)):
            ordinal[t] = ix

        user_votes = models.VotoTalk.objects.filter(user=request.user.id)
        talks = talks.order_by("speakers__user__first_name", "speakers__user__last_name")

        if request.GET:
            form = OptionForm(data=request.GET)
            form.is_valid()
            options = form.cleaned_data
        else:
            form = OptionForm()
            options = {"abstracts": "not-voted", "talk_type": "", "language": "", "tags": "", "order": "vote"}
        if options["abstracts"] != "all":
            talks = talks.exclude(id__in=user_votes.values("talk_id"))
        if options["talk_type"] in ("s", "t", "p"):
            talks = talks.filter(type=options["talk_type"])

        if options["language"] in ("en", "it"):
            talks = talks.filter(language=options["language"])

        if options["tags"]:
            # se in options['tags'] ci finisce un tag non associato ad alcun
            # talk ho come risultato una query che da zero risultati; per
            # evitare questo limito i tag usabili come filtro a quelli
            # associati ai talk.
            allowed = set()
            ctt = ContentType.objects.get_for_model(models.Talk)
            for t, usage in dataaccess.tags().items():
                for cid, oid in usage:
                    if cid == ctt.id:
                        allowed.add(t.name)
                        break
            tags = set(options["tags"]) & allowed
            if tags:
                talks = talks.filter(
                    id__in=models.ConferenceTaggedItem.objects.filter(
                        content_type__app_label="conference", content_type__model="talk", tag__name__in=tags
                    ).values("object_id")
                )

        talk_order = options["order"]

        votes = dict((x.talk_id, x) for x in user_votes)

        # Poichè talks è ordinato per un modello collegato tramite una
        # ManyToMany posso avere dei talk ripetuti, e il distinct non si
        # applica in questi casi.
        #
        # Non mi rimane che filtrare in python, a questo punto ne approfitto
        # per agganciare i voti dell'utente utilizzando un unico loop.
        dups = set()

        def filter_vote(t):
            if t["id"] in dups:
                return False
            dups.add(t["id"])
            t["user_vote"] = votes.get(t["id"])
            t["ordinal"] = ordinal[t["id"]]
            return True

        talks = filter(filter_vote, talks.values("id"))

        if talk_order != "speaker":

            def key(x):
                if x["user_vote"]:
                    return x["user_vote"].vote
                else:
                    return Decimal("-99.99")

            talks = reversed(sorted(reversed(talks), key=key))

        ctx = {"voting_allowed": voting_allowed, "talks": list(talks), "form": form}
        if request.is_ajax():
            tpl = "conference/ajax/voting.html"
        else:
            tpl = "conference/voting.html"
        return render(request, tpl, ctx)
Exemple #6
0
def filter_talks_in_context(request, talks, voting_allowed):
    # voglio poter associare ad ogni talk un numero "univoco" da mostrare
    # accanto al titolo per poterlo individuare facilmente.
    ordinal = dict()
    for ix, t in enumerate(talks.order_by("created").values_list("id", flat=True)):
        ordinal[t] = ix
    user_votes = models.VotoTalk.objects.filter(user=request.user.id)
    talks = talks.order_by("speakers__user__first_name", "speakers__user__last_name")
    if request.GET:
        form = OptionForm(data=request.GET)
        form.is_valid()
        options = form.cleaned_data
    else:
        form = OptionForm()
        options = {"abstracts": "not-voted", "talk_type": "", "language": "", "tags": "", "order": "vote"}
    if options["abstracts"] != "all":
        talks = talks.exclude(id__in=user_votes.values("talk_id"))
    if options["talk_type"] in ("s", "t", "p"):
        talks = talks.filter(type=options["talk_type"])
    if options["language"] in ("en", "it"):
        talks = talks.filter(language=options["language"])
    if options["tags"]:
        # se in options['tags'] ci finisce un tag non associato ad alcun
        # talk ho come risultato una query che da zero risultati; per
        # evitare questo limito i tag usabili come filtro a quelli
        # associati ai talk.
        allowed = set()
        ctt = ContentType.objects.get_for_model(models.Talk)
        for t, usage in dataaccess.tags().items():
            for cid, oid in usage:
                if cid == ctt.id:
                    allowed.add(t.name)
                    break
        tags = set(options["tags"]) & allowed
        if tags:
            talks = talks.filter(
                id__in=models.ConferenceTaggedItem.objects.filter(
                    content_type__app_label="conference", content_type__model="talk", tag__name__in=tags
                ).values("object_id")
            )
    talk_order = options["order"]
    votes = dict((x.talk_id, x) for x in user_votes)
    # Poichè talks è ordinato per un modello collegato tramite una
    # ManyToMany posso avere dei talk ripetuti, e il distinct non si
    # applica in questi casi.
    #
    # Non mi rimane che filtrare in python, a questo punto ne approfitto
    # per agganciare i voti dell'utente utilizzando un unico loop.
    dups = set()

    def filter_vote(t):
        if t["id"] in dups:
            return False
        dups.add(t["id"])
        t["user_vote"] = votes.get(t["id"])
        t["ordinal"] = ordinal[t["id"]]
        return True

    talks = filter(filter_vote, talks.values("id"))
    if talk_order != "speaker":

        def key(x):
            if x["user_vote"]:
                return x["user_vote"].vote
            else:
                return Decimal("-99.99")

        talks = reversed(sorted(reversed(talks), key=key))
    ctx = {"voting_allowed": voting_allowed, "talks": list(talks), "form": form}
    return ctx