Beispiel #1
0
def result_notification_prepare(request, section_slug, status):
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    proposal_pks = []
    try:
        for pk in request.POST.getlist("_selected_action"):
            proposal_pks.append(int(pk))
    except ValueError:
        return HttpResponseBadRequest()
    model = get_proposal_model_from_section_slug(section_slug)
    proposals = model.objects.filter(result__status=status, )
    proposals = proposals.filter(pk__in=proposal_pks)

    notification_template_pk = request.POST.get("notification_template", "")
    if notification_template_pk:
        notification_template = NotificationTemplate.objects.get(
            pk=notification_template_pk)
    else:
        notification_template = None

    ctx = {
        "section_slug": section_slug,
        "status": status,
        "notification_template": notification_template,
        "proposals": proposals,
        "proposal_pks": ",".join([str(pk) for pk in proposal_pks]),
    }
    return render(request, "reviews/result_notification_prepare.html", ctx)
Beispiel #2
0
def review_list(request, section_slug, user_pk):

    # if they're not a reviewer admin and they aren't the person whose
    # review list is being asked for, don't let them in
    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        if not request.user.pk == user_pk:
            return access_not_permitted(request)

    reviewed = LatestVote.objects.filter(user__pk=user_pk).values_list(
        "proposal", flat=True)
    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.filter(pk__in=reviewed)
    proposals = queryset.order_by("submitted")

    admin = request.user.has_perm("reviews.can_manage_%s" % section_slug)

    proposals = proposals_list(request,
                               proposals,
                               user_pk=user_pk,
                               check_speaker=not admin)

    ctx = {
        "proposals": proposals,
        "section_slug": section_slug,
    }
    return render(request, "reviews/review_list.html", ctx)
Beispiel #3
0
def result_notification_prepare(request, section_slug, status):
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    proposal_pks = []
    try:
        for pk in request.POST.getlist("_selected_action"):
            proposal_pks.append(int(pk))
    except ValueError:
        return HttpResponseBadRequest()
    model = get_proposal_model_from_section_slug(section_slug)
    # proposals = model.objects.filter(
    #     result__status=status,
    # )
    status_code = STATUS_MAP[status]
    proposals = model.objects.filter(overall_status=status_code)
    proposals = proposals.filter(pk__in=proposal_pks)

    notification_template_pk = request.POST.get("notification_template", "")
    if notification_template_pk:
        notification_template = NotificationTemplate.objects.get(pk=notification_template_pk)
    else:
        notification_template = None

    ctx = {
        "section_slug": section_slug,
        "status": status,
        "notification_template": notification_template,
        "proposals": proposals,
        "proposal_pks": ",".join([str(pk) for pk in proposal_pks]),
    }
    return render(request, "reviews/result_notification_prepare.html", ctx)
Beispiel #4
0
def review_status(request, section_slug, key=None):

    if not request.user.has_perm("reviews.can_review_%s" % section_slug):
        return access_not_permitted(request)

    VOTE_THRESHOLD = settings.SYMPOSION_VOTE_THRESHOLD

    ctx = {
        "section_slug": section_slug,
        "vote_threshold": VOTE_THRESHOLD,
    }

    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.filter(kind__section__slug=section_slug)
    queryset = queryset.exclude(cancelled=True)

    proposals = {
        # proposals with at least VOTE_THRESHOLD reviews and at least one +1 and no -1s,
        # sorted by the 'score'
        "positive": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                                    result__plus_one__gt=0, result__minus_one=0
                                    ).order_by("-result__score"),
        # proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s,
        # reverse sorted by the 'score'
        "negative": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                                    result__minus_one__gt=0, result__plus_one=0
                                    ).order_by("result__score"),
        # proposals with at least VOTE_THRESHOLD reviews and neither a +1 or a -1, sorted
        # by total votes (lowest first)
        "indifferent": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                                       result__minus_one=0, result__plus_one=0
                                       ).order_by("result__vote_count"),
        # proposals with at least VOTE_THRESHOLD reviews and both a +1 and -1, sorted by
        # total votes (highest first)
        "controversial": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                                         result__plus_one__gt=0, result__minus_one__gt=0
                                         ).order_by("-result__vote_count"),
        # proposals with fewer than VOTE_THRESHOLD reviews
        "too_few": queryset.filter(result__vote_count__lt=VOTE_THRESHOLD
                                   ).order_by("result__vote_count"),
    }

    admin = request.user.has_perm("reviews.can_manage_%s" % section_slug)

    for status in proposals:
        if key and key != status:
            continue
        proposals[status] = proposals_list(request, proposals[status], check_speaker=not admin)

    if key:
        ctx.update({
            "key": key,
            "proposals": proposals[key],
        })
    else:
        ctx["proposals"] = proposals

    return render(request, "reviews/review_stats.html", ctx)
Beispiel #5
0
def result_notification_send(request, section_slug, status):
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    if not all([
            k in request.POST
            for k in ["proposal_pks", "from_address", "subject", "body"]
    ]):
        return HttpResponseBadRequest()

    try:
        proposal_pks = [
            int(pk) for pk in request.POST["proposal_pks"].split(",")
        ]
    except ValueError:
        return HttpResponseBadRequest()

    model = get_proposal_model_from_section_slug(section_slug)
    # proposals = model.objects.filter(
    #     result__status=status,
    # )
    status_code = STATUS_MAP[status]
    proposals = model.objects.filter(overall_status=status_code)
    proposals = proposals.filter(pk__in=proposal_pks)

    notification_template_pk = request.POST.get("notification_template", "")
    if notification_template_pk:
        notification_template = NotificationTemplate.objects.get(
            pk=notification_template_pk)
    else:
        notification_template = None

    emails = []

    for proposal in proposals:
        rn = ResultNotification()
        rn.proposal = proposal
        rn.template = notification_template
        rn.to_address = proposal.speaker_email
        rn.from_address = request.POST["from_address"]
        rn.subject = request.POST["subject"]
        rn.body = Template(request.POST["body"]).render(
            Context({"proposal": proposal.notification_email_context()}))
        rn.save()
        emails.append(rn.email_args)

    send_mass_mail(emails)

    return redirect("result_notification",
                    section_slug=section_slug,
                    status=status)
Beispiel #6
0
def review_section(request, section_slug, assigned=False):
    """
    :param request:
    :param section_slug: slug of the Section
    :param assigned:
    :return:
    """

    if not request.user.has_perm("reviews.can_review_%s" % section_slug):
        return access_not_permitted(request)

    can_manage = False
    if request.user.has_perm("reviews.can_manage_%s" % section_slug):
        can_manage = True
    section = get_object_or_404(Section,
                                slug=section_slug,
                                conference=current_conference())
    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.all()

    if request.method == "POST" and can_manage:
        pk_string = request.POST.get('pk', request.POST.get('pks', ''))
        if pk_string != '':
            pk_list = [int(i) for i in pk_string.split(',')]
            for pk in pk_list:
                status = request.POST['status']
                proposal = queryset.get(pk=pk)
                proposal.overall_status = status
                proposal.save()
        else:
            messages.error(request,
                           _("Please select at least one application"))

        url_name = "review_section_assignments" if assigned else "review_section"
        return redirect(
            reverse(url_name, kwargs={'section_slug': section_slug}))

    if assigned:
        assignments = ReviewAssignment.objects.filter(
            user=request.user).values_list("proposal__id")
        queryset = queryset.filter(id__in=assignments)

    proposals = proposals_list(request, queryset)
    ctx = {
        "proposals": proposals,
        "section": section,
        "section_slug": section_slug,
        "can_manage": can_manage,
        "status_options": PyConProposal.STATUS_OPTIONS
    }

    return render(request, "reviews/review_list.html", ctx)
Beispiel #7
0
def result_notification_send(request, section_slug, status):
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    if not all([k in request.POST for k in ["proposal_pks", "from_address", "subject", "body"]]):
        return HttpResponseBadRequest()

    try:
        proposal_pks = [int(pk) for pk in request.POST["proposal_pks"].split(",")]
    except ValueError:
        return HttpResponseBadRequest()

    model = get_proposal_model_from_section_slug(section_slug)
    # proposals = model.objects.filter(
    #     result__status=status,
    # )
    status_code = STATUS_MAP[status]
    proposals = model.objects.filter(overall_status=status_code)
    proposals = proposals.filter(pk__in=proposal_pks)

    notification_template_pk = request.POST.get("notification_template", "")
    if notification_template_pk:
        notification_template = NotificationTemplate.objects.get(pk=notification_template_pk)
    else:
        notification_template = None

    emails = []

    for proposal in proposals:
        rn = ResultNotification()
        rn.proposal = proposal
        rn.template = notification_template
        rn.to_address = proposal.speaker_email
        rn.from_address = request.POST["from_address"]
        rn.subject = request.POST["subject"]
        rn.body = Template(request.POST["body"]).render(
            Context({
                "proposal": proposal.notification_email_context()
            })
        )
        rn.save()
        emails.append(rn.email_args)

    send_mass_mail(emails)

    return redirect("result_notification", section_slug=section_slug, status=status)
Beispiel #8
0
def result_notification(request, section_slug, status):
    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    model = get_proposal_model_from_section_slug(section_slug)
    proposals = model.objects.filter(
        result__status=status).prefetch_related('notifications')
    notification_templates = NotificationTemplate.objects.all()

    ctx = {
        "section_slug": section_slug,
        "status": status,
        "proposals": proposals,
        "notification_templates": notification_templates,
    }
    return render(request, "reviews/result_notification.html", ctx)
Beispiel #9
0
def proposal_counts(request):
    model = ProposalBase
    proposal_type = request.GET.get('type', 'talk')
    if proposal_type in PROPOSAL_TYPES:
        try:
            model = get_proposal_model_from_section_slug(proposal_type + 's')
        except ValueError:
            return ({ 'error': 'unrecognized proposal type' }, 400)
    else:
        return ({ 'error': 'unrecognized proposal type' }, 400)

    submitted = model.objects.filter(submitted=True, cancelled=False, kind__slug=proposal_type).count()
    draft = model.objects.filter(submitted=False, cancelled=False, kind__slug=proposal_type).count()
    cancelled = model.objects.filter(cancelled=True, kind__slug=proposal_type).count()

    return {"submitted": submitted, "draft": draft, "cancelled": cancelled}
Beispiel #10
0
def review_section(request, section_slug, assigned=False):
    """
    :param request:
    :param section_slug: slug of the Section
    :param assigned:
    :return:
    """

    if not request.user.has_perm("reviews.can_review_%s" % section_slug):
        return access_not_permitted(request)

    can_manage = False
    if request.user.has_perm("reviews.can_manage_%s" % section_slug):
        can_manage = True
    section = get_object_or_404(Section, slug=section_slug, conference=current_conference())
    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.all()

    if request.method == "POST" and can_manage:
        pk_string = request.POST.get('pk', request.POST.get('pks', ''))
        if pk_string != '':
            pk_list = [int(i) for i in pk_string.split(',')]
            for pk in pk_list:
                status = request.POST['status']
                proposal = queryset.get(pk=pk)
                proposal.overall_status = status
                proposal.save()
        else:
            messages.error(request, _("Please select at least one application"))

        url_name = "review_section_assignments" if assigned else "review_section"
        return redirect(reverse(url_name, kwargs={'section_slug': section_slug}))

    if assigned:
        assignments = ReviewAssignment.objects.filter(user=request.user).values_list("proposal__id")
        queryset = queryset.filter(id__in=assignments)

    proposals = proposals_list(request, queryset)
    ctx = {
        "proposals": proposals,
        "section": section,
        "section_slug": section_slug,
        "can_manage": can_manage,
        "status_options": PyConProposal.STATUS_OPTIONS
    }

    return render(request, "reviews/review_list.html", ctx)
Beispiel #11
0
def result_notification(request, section_slug, status):
    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    model = get_proposal_model_from_section_slug(section_slug)
    # This use to be crazy and complicated and involved something
    # involving voting periods:
    #proposals = model.objects.filter(result__status=status).prefetch_related('notifications')
    # Now it is just driven directly by the PyCon-specific "overall" status:
    status_code = STATUS_MAP[status]
    proposals = (model.objects.filter(
        overall_status=status_code).prefetch_related('notifications'))
    notification_templates = NotificationTemplate.objects.all()

    ctx = {
        "section_slug": section_slug,
        "status": status,
        "proposals": proposals,
        "notification_templates": notification_templates,
    }
    return render(request, "reviews/result_notification.html", ctx)
Beispiel #12
0
def proposal_counts(request):
    model = ProposalBase
    proposal_type = request.GET.get('type', 'talk')
    if proposal_type in PROPOSAL_TYPES:
        try:
            model = get_proposal_model_from_section_slug(proposal_type + 's')
        except ValueError:
            return ({'error': 'unrecognized proposal type'}, 400)
    else:
        return ({'error': 'unrecognized proposal type'}, 400)

    submitted = model.objects.filter(submitted=True,
                                     cancelled=False,
                                     kind__slug=proposal_type).count()
    draft = model.objects.filter(submitted=False,
                                 cancelled=False,
                                 kind__slug=proposal_type).count()
    cancelled = model.objects.filter(cancelled=True,
                                     kind__slug=proposal_type).count()

    return {"submitted": submitted, "draft": draft, "cancelled": cancelled}
Beispiel #13
0
def result_notification(request, section_slug, status):
    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        return access_not_permitted(request)

    model = get_proposal_model_from_section_slug(section_slug)
    # This use to be crazy and complicated and involved something
    # involving voting periods:
    #proposals = model.objects.filter(result__status=status).prefetch_related('notifications')
    # Now it is just driven directly by the PyCon-specific "overall" status:
    status_code = STATUS_MAP[status]
    proposals = (model.objects
                 .filter(overall_status=status_code)
                 .prefetch_related('notifications'))
    notification_templates = NotificationTemplate.objects.all()

    ctx = {
        "section_slug": section_slug,
        "status": status,
        "proposals": proposals,
        "notification_templates": notification_templates,
    }
    return render(request, "reviews/result_notification.html", ctx)
Beispiel #14
0
def review_list(request, section_slug, user_pk):

    # if they're not a reviewer admin and they aren't the person whose
    # review list is being asked for, don't let them in
    if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
        if not request.user.pk == user_pk:
            return access_not_permitted(request)

    reviewed = LatestVote.objects.filter(user__pk=user_pk).values_list("proposal", flat=True)
    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.filter(pk__in=reviewed)
    proposals = queryset.order_by("submitted")

    admin = request.user.has_perm("reviews.can_manage_%s" % section_slug)

    proposals = proposals_list(request, proposals, user_pk=user_pk, check_speaker=not admin)

    ctx = {
        "proposals": proposals,
        "section_slug": section_slug,
    }
    return render(request, "reviews/review_list.html", ctx)
Beispiel #15
0
def review_status(request, section_slug, key=None):

    if not request.user.has_perm("reviews.can_review_%s" % section_slug):
        return access_not_permitted(request)

    VOTE_THRESHOLD = settings.SYMPOSION_VOTE_THRESHOLD

    ctx = {
        "section_slug": section_slug,
        "vote_threshold": VOTE_THRESHOLD,
    }

    model = get_proposal_model_from_section_slug(section_slug)
    queryset = model.objects.filter(kind__section__slug=section_slug)
    queryset = queryset.exclude(cancelled=True)

    proposals = {
        # proposals with at least VOTE_THRESHOLD reviews and at least one +1 and no -1s,
        # sorted by the 'score'
        "positive":
        queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                        result__plus_one__gt=0,
                        result__minus_one=0).order_by("-result__score"),
        # proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s,
        # reverse sorted by the 'score'
        "negative":
        queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                        result__minus_one__gt=0,
                        result__plus_one=0).order_by("result__score"),
        # proposals with at least VOTE_THRESHOLD reviews and neither a +1 or a -1, sorted
        # by total votes (lowest first)
        "indifferent":
        queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
                        result__minus_one=0,
                        result__plus_one=0).order_by("result__vote_count"),
        # proposals with at least VOTE_THRESHOLD reviews and both a +1 and -1, sorted by
        # total votes (highest first)
        "controversial":
        queryset.filter(
            result__vote_count__gte=VOTE_THRESHOLD,
            result__plus_one__gt=0,
            result__minus_one__gt=0).order_by("-result__vote_count"),
        # proposals with fewer than VOTE_THRESHOLD reviews
        "too_few":
        queryset.filter(result__vote_count__lt=VOTE_THRESHOLD).order_by(
            "result__vote_count"),
    }

    admin = request.user.has_perm("reviews.can_manage_%s" % section_slug)

    for status in proposals:
        if key and key != status:
            continue
        proposals[status] = proposals_list(request,
                                           proposals[status],
                                           check_speaker=not admin)

    if key:
        ctx.update({
            "key": key,
            "proposals": proposals[key],
        })
    else:
        ctx["proposals"] = proposals

    return render(request, "reviews/review_stats.html", ctx)
Beispiel #16
0
def proposal_list(request):
    """Retrieve and return a list of proposals, optionally
    filtered by the given acceptance status.

    Requires API Key.

    URL: /<YEAR>/pycon_api/proposals/

    To filter by proposal type, add a GET query param "type" with
    a value of "talk", "tutorial", "lightning", or "poster", e.g.::

        GET /<YEAR>/pycon_api/proposals/?type=tutorial

    To filter by proposal status, add a GET query param "status" with
    a value of "undecided", "rejected", "accepted", or "standby".

    So if you wanted to filter by both type and status, you might use::

        GET /<YEAR>/pycon_api/proposals/?type=tutorial&status=accepted


    The return data, in JSON, looks like::

        {
            'code': 200,
            'data': [<item>, <item>, ..., <item>]
        }

    where each <item> looks like::

        {
            'id': 13,  # proposal key
            'speakers': [<speaker>, <speaker>, ..., <speaker>],
            'status': "undecided"|"accepted"|"rejected"|"standby"
            'title': "Title of talk"
        }

    and a <speaker> looks like::

        {
            'name': "Speaker Name",
            'email': "*****@*****.**"
        }
    """
    # What model should we be pulling from?
    model = ProposalBase
    proposal_type = request.GET.get('type', 'talk')
    if proposal_type in PROPOSAL_TYPES:
        try:
            model = get_proposal_model_from_section_slug(proposal_type + 's')
        except ValueError:
            return ({ 'error': 'unrecognized proposal type' }, 400)
    else:
        return ({ 'error': 'unrecognized proposal type' }, 400)

    # See if there is such a proposal
    proposals = model.objects.select_related('result').order_by('pk')
    proposals = proposals.filter(kind__slug=proposal_type)

    # Don't look at unsubmitted proposals
    proposals = proposals.exclude(submitted=False)

    # Don't look at cancelled proposals.
    proposals = proposals.exclude(cancelled=True)

    # If specific proposal status is being requested, filter on that.
    desired_status = request.GET.get('status', None)
    if desired_status == 'undecided':
        proposals = proposals.filter(Q(result__status=desired_status) |
                                     Q(result=None))
    else:
        proposals = proposals.filter(result__status=desired_status)

    # We may be asking only for ungrouped talks; if so, limit to these.
    ungrouped = request.GET.get('ungrouped', '').lower() in ('true', '1')
    if ungrouped:
        proposals = proposals.filter(thunderdome_group=None)

    # If there's a limit parameter provided, limit to those objects.
    if 'limit' in request.GET:
        proposals = proposals[0:request.GET['limit']]

    # Return the proposal data objects.
    return [i.as_dict() for i in proposals]
Beispiel #17
0
def proposal_list(request):
    """Retrieve and return a list of proposals, optionally
    filtered by the given acceptance status.

    Requires API Key.

    URL: /<YEAR>/pycon_api/proposals/

    To filter by proposal type, add a GET query param "type" with
    a value of "talk", "tutorial", "lightning", or "poster", e.g.::

        GET /<YEAR>/pycon_api/proposals/?type=tutorial

    To filter by proposal status, add a GET query param "status" with
    a value of "undecided", "rejected", "accepted", or "standby".

    So if you wanted to filter by both type and status, you might use::

        GET /<YEAR>/pycon_api/proposals/?type=tutorial&status=accepted


    The return data, in JSON, looks like::

        {
            'code': 200,
            'data': [<item>, <item>, ..., <item>]
        }

    where each <item> looks like::

        {
            'id': 13,  # proposal key
            'speakers': [<speaker>, <speaker>, ..., <speaker>],
            'status': "undecided"|"accepted"|"rejected"|"standby"
            'title': "Title of talk"
        }

    and a <speaker> looks like::

        {
            'name': "Speaker Name",
            'email': "*****@*****.**"
        }
    """
    # What model should we be pulling from?
    model = ProposalBase
    proposal_type = request.GET.get('type', 'talk')
    if proposal_type in PROPOSAL_TYPES:
        try:
            model = get_proposal_model_from_section_slug(proposal_type + 's')
        except ValueError:
            return ({'error': 'unrecognized proposal type'}, 400)
    else:
        return ({'error': 'unrecognized proposal type'}, 400)

    # See if there is such a proposal
    proposals = model.objects.select_related('result').order_by('pk')
    proposals = proposals.filter(kind__slug=proposal_type)

    # Don't look at unsubmitted proposals
    proposals = proposals.exclude(submitted=False)

    # Don't look at cancelled proposals.
    proposals = proposals.exclude(cancelled=True)

    # If specific proposal status is being requested, filter on that.
    desired_status = request.GET.get('status', None)
    if desired_status == 'undecided':
        proposals = proposals.filter(
            Q(result__status=desired_status) | Q(result=None))
    else:
        proposals = proposals.filter(result__status=desired_status)

    # We may be asking only for ungrouped talks; if so, limit to these.
    ungrouped = request.GET.get('ungrouped', '').lower() in ('true', '1')
    if ungrouped:
        proposals = proposals.filter(thunderdome_group=None)

    # If there's a limit parameter provided, limit to those objects.
    if 'limit' in request.GET:
        proposals = proposals[0:request.GET['limit']]

    # Return the proposal data objects.
    return [i.as_dict() for i in proposals]