def appeal()

in src/olympia/abuse/views.py [0:0]


def appeal(request, *, abuse_report_id, decision_cinder_id, **kwargs):
    appealable_decisions = tuple(DECISION_ACTIONS.APPEALABLE_BY_AUTHOR.values) + tuple(
        DECISION_ACTIONS.APPEALABLE_BY_REPORTER.values
    )
    cinder_decision = get_object_or_404(
        ContentDecision.objects.filter(action__in=appealable_decisions),
        cinder_id=decision_cinder_id,
    )

    if abuse_report_id:
        abuse_report = get_object_or_404(
            AbuseReport.objects.filter(cinder_job__isnull=False),
            id=abuse_report_id,
            cinder_job=cinder_decision.cinder_job,
        )
    else:
        abuse_report = None
    # Reporter appeal: we need an abuse report.
    if (
        abuse_report is None
        and cinder_decision.action in DECISION_ACTIONS.APPEALABLE_BY_REPORTER
    ):
        raise Http404

    target = cinder_decision.target
    context_data = {
        'decision_cinder_id': decision_cinder_id,
    }
    post_data = request.POST if request.method == 'POST' else None
    valid_user_or_email_provided = False
    appeal_email_form = None
    if cinder_decision.action in DECISION_ACTIONS.APPEALABLE_BY_REPORTER or (
        cinder_decision.action == DECISION_ACTIONS.AMO_BAN_USER
    ):
        # Only person would should be appealing an approval is the reporter.
        if (
            cinder_decision.action in DECISION_ACTIONS.APPEALABLE_BY_REPORTER
            and abuse_report
            and abuse_report.reporter
        ):
            # Authenticated reporter is the easy case, they should just be
            # authenticated with the right account.
            if not request.user.is_authenticated:
                return redirect_for_login(request)
            valid_user_or_email_provided = request.user == abuse_report.reporter
        elif cinder_decision.action == DECISION_ACTIONS.AMO_BAN_USER or (
            abuse_report and abuse_report.reporter_email
        ):
            # Anonymous reporter appealing or banned user appealing is tricky,
            # we need the email to be submitted via POST to match. If there was
            # no POST, then we show a form for it instead of showing the appeal
            # form. We do the same for ban appeals, since the user would no
            # longer be able to log in.
            expected_email = (
                target.email
                if cinder_decision.action == DECISION_ACTIONS.AMO_BAN_USER
                else abuse_report.reporter_email
            )
            appeal_email_form = AbuseAppealEmailForm(
                post_data, expected_email=expected_email, request=request
            )
            if appeal_email_form.is_bound and appeal_email_form.is_valid():
                valid_user_or_email_provided = True
                # We'll be re-using the form, but the user shouldn't change
                # the email (that would prevent submission, it would no
                # longer be valid), so make the input hidden.
                appeal_email_form.fields['email'].widget = forms.HiddenInput()
            context_data['appeal_email_form'] = appeal_email_form
    else:
        # Only person would should be appealing anything else than an approval
        # is the author of the content.
        if not request.user.is_authenticated:
            return redirect_for_login(request)

        allowed_users = []
        if hasattr(target, 'authors'):
            allowed_users = target.authors.all()
        elif hasattr(target, 'author'):
            allowed_users = [target.author]
        elif hasattr(target, 'user'):
            allowed_users = [target.user]
        valid_user_or_email_provided = request.user in allowed_users

    if not valid_user_or_email_provided and not appeal_email_form:
        # At this point we should either have a valid user/email provided, or
        # we are just showing the email form. Anything else should result in a
        # 403.
        raise PermissionDenied

    if valid_user_or_email_provided:
        # After this point, the user is either authenticated or has entered the
        # right email address, we can start testing whether or not they can
        # actually appeal, and show the form if they indeed can.
        is_reporter = cinder_decision.action in DECISION_ACTIONS.APPEALABLE_BY_REPORTER
        if cinder_decision.can_be_appealed(
            is_reporter=is_reporter, abuse_report=abuse_report
        ):
            appeal_form = AbuseAppealForm(post_data, request=request)
            if appeal_form.is_bound and appeal_form.is_valid():
                appeal_to_cinder.delay(
                    decision_cinder_id=cinder_decision.cinder_id,
                    abuse_report_id=abuse_report.id if abuse_report else None,
                    appeal_text=appeal_form.cleaned_data['reason'],
                    user_id=request.user.pk,
                    is_reporter=is_reporter,
                )
                context_data['appeal_processed'] = True
            context_data['appeal_form'] = appeal_form
        else:
            # We can't appeal this, remove email form if it was there (which at
            # this point should only contain the hidden email input) if the
            # report can't be appealed. No form should be left on the page.
            context_data.pop('appeal_email_form', None)
            if hasattr(cinder_decision, 'overridden_by'):
                # The reason we can't appeal this is that the decision has already been
                # overriden by a new decision. We want a specific error message in this
                # case.
                context_data['appealed_decision_overridden'] = True
            elif (
                is_reporter
                and not hasattr(abuse_report, 'cinderappeal')
                and cinder_decision.appealed_decision_already_made()
            ):
                # The reason we can't appeal this is that there was already an
                # appeal made for which we have a decision. We want a specific
                # error message in this case.
                context_data['appealed_decision_already_made'] = True
                context_data['appealed_decision_affirmed'] = (
                    cinder_decision.appeal_job.final_decision.action
                    == cinder_decision.action
                )

    return TemplateResponse(request, 'abuse/appeal.html', context=context_data)