예제 #1
0
def submit_akismet_spam(request):
    """
    Creates SPAM Akismet record for revision.
    Return json object with Akismet Record data.

    TODO: Create Submitting as HAM record for revision
    """

    submission = RevisionAkismetSubmission(sender=request.user, type="spam")
    data = RevisionAkismetSubmissionSpamForm(data=request.POST, instance=submission, request=request)

    if data.is_valid():
        data.save()

        revision = data.cleaned_data['revision']
        akismet_revisions = (RevisionAkismetSubmission.objects.filter(revision=revision)
                                                              .order_by('id')
                                                              .values('sender__username', 'sent', 'type'))

        data = [
            {
                "sender": rev["sender__username"],
                "sent": format_date_time(value=rev["sent"],
                                         format='datetime', request=request)[0],
                "type": rev["type"]}
            for rev in akismet_revisions]

        return HttpResponse(json.dumps(data, sort_keys=True),
                            content_type='application/json; charset=utf-8', status=201)

    return HttpResponseBadRequest()
예제 #2
0
파일: views.py 프로젝트: bychek-ru/kuma
def submit_akismet_spam(request):
    """
    Submit a published revision as spam.

    If successful, the revision dashboard is loaded again, and displays that
    the revision was marked as spam. On failure, no errors are returned, just
    reloads the dashboard.
    """
    url = request.POST.get('next')
    if url is None or not is_safe_url(url, request.get_host()):
        url = reverse('dashboards.revisions')

    submission = RevisionAkismetSubmission(sender=request.user, type='spam')
    form = RevisionAkismetSubmissionSpamForm(data=request.POST,
                                             instance=submission,
                                             request=request)
    if form.is_valid():
        form.save()

    return redirect(url)
예제 #3
0
def submit_akismet_spam(request):
    """
    Submit a published revision as spam.

    If successful, the revision dashboard is loaded again, and displays that
    the revision was marked as spam. On failure, no errors are returned, just
    reloads the dashboard.
    """
    url = request.POST.get('next')
    if url is None or not is_safe_url(url, request.get_host()):
        url = reverse('dashboards.revisions')

    submission = RevisionAkismetSubmission(sender=request.user, type='spam')
    form = RevisionAkismetSubmissionSpamForm(data=request.POST,
                                             instance=submission,
                                             request=request)
    if form.is_valid():
        form.save()

    return redirect(url)
예제 #4
0
def submit_akismet_spam(request):
    """
    Creates SPAM Akismet record for revision.
    Return json object with Akismet Record data.

    TODO: Create Submitting as HAM record for revision
    """

    submission = RevisionAkismetSubmission(sender=request.user, type="spam")
    data = RevisionAkismetSubmissionSpamForm(data=request.POST,
                                             instance=submission,
                                             request=request)

    if data.is_valid():
        data.save()

        revision = data.cleaned_data['revision']
        akismet_revisions = (RevisionAkismetSubmission.objects.filter(
            revision=revision).order_by('id').values('sender__username',
                                                     'sent', 'type'))

        data = [{
            "sender":
            rev["sender__username"],
            "sent":
            format_date_time(value=rev["sent"],
                             format='datetime',
                             request=request)[0],
            "type":
            rev["type"]
        } for rev in akismet_revisions]

        return HttpResponse(json.dumps(data, sort_keys=True),
                            content_type='application/json; charset=utf-8',
                            status=201)

    return HttpResponseBadRequest()
예제 #5
0
def ban_user_and_cleanup_summary(request, username):
    """
    A summary page of actions taken when banning a user and reverting revisions
    This method takes all the revisions from the last three days,
    sends back the list of revisions that were successfully reverted/deleted
    and submitted to Akismet, and also a list of
    revisions where no action was taken (revisions needing follow up).
    """
    user = get_object_or_404(User, username=username)

    # Is this user already banned?
    user_ban = UserBan.objects.filter(user=user, is_active=True)

    # If the user is not banned, ban user; else, update 'by' and 'reason'
    if not user_ban.exists():
        ban = UserBan(user=user,
                      by=request.user,
                      reason='Spam',
                      is_active=True)
        ban.save()
    else:
        user_ban.update(by=request.user, reason='Spam')

    date_three_days_ago = datetime.now().date() - timedelta(days=3)
    revisions_from_last_three_days = user.created_revisions.prefetch_related('document')
    revisions_from_last_three_days = revisions_from_last_three_days.defer('content', 'summary').order_by('-id')
    revisions_from_last_three_days = revisions_from_last_three_days.filter(created__gte=date_three_days_ago)

    """ The "Actions Taken" section """
    # The revisions to be submitted to Akismet and reverted,
    # these must be sorted descending so that they are reverted accordingly
    revisions_to_mark_as_spam_and_revert = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist('revision-id')).order_by('-id')

    # 1. Submit revisions to Akismet as spam
    # 2. If this is the most recent revision for a document:
    #    Revert revision if it has a previous version OR
    #    Delete revision if it is a new document
    submitted_to_akismet = []
    not_submitted_to_akismet = []
    revisions_reverted_list = []
    revisions_not_reverted_list = []
    revisions_deleted_list = []
    revisions_not_deleted_list = []
    latest_is_not_spam = [
        rev for rev in revision_by_distinct_doc(revisions_to_mark_as_spam_and_revert)
        if rev.document.current_revision != rev
    ]
    previous_good_rev = {}

    for revision in revisions_to_mark_as_spam_and_revert:
        submission = RevisionAkismetSubmission(sender=request.user, type="spam")
        akismet_submission_data = {'revision': revision.id}

        data = RevisionAkismetSubmissionSpamForm(
            data=akismet_submission_data,
            instance=submission,
            request=request)
        # Submit to Akismet or note that validation & sending to Akismet failed
        if data.is_valid():
            data.save()
            # Since we only want to display 1 revision per document, only add to
            # this list if this is one of the revisions for a distinct document
            submitted_to_akismet.append(revision)
        else:
            not_submitted_to_akismet.append(revision)

        # If there is a current revision and the revision is not in the spam list,
        # to be reverted, do not revert any revisions
        try:
            revision.document.refresh_from_db(fields=['current_revision'])
        except Document.DoesNotExist:
            continue  # This document was previously deleted in this loop, continue
        if revision.document.current_revision not in revisions_to_mark_as_spam_and_revert:
            if revision.document_id not in previous_good_rev:
                previous_good_rev[revision.document_id] = revision.document.current_revision

            continue  # This document has a more current revision, no need to revert

        # Loop through all previous revisions to find the oldest spam
        # revision on a specific document from this request.
        while revision.previous in revisions_to_mark_as_spam_and_revert:
            revision = revision.previous
        # If this is a new revision on an existing document, revert it
        if revision.previous:
            previous_good_rev[revision.document_id] = revision.previous

            reverted = revert_document(request=request,
                                       revision_id=revision.previous.id)
            if reverted:
                revisions_reverted_list.append(revision)
            else:
                # If the revert was unsuccessful, include this in the follow-up list
                revisions_not_reverted_list.append(revision)

        # If this is a new document/translation, delete it
        else:
            deleted = delete_document(request=request,
                                      document=revision.document)
            if deleted:
                revisions_deleted_list.append(revision)
            else:
                # If the delete was unsuccessful, include this in the follow-up list
                revisions_not_deleted_list.append(revision)

    # Find just the latest revision for each document
    submitted_to_akismet_by_distinct_doc = revision_by_distinct_doc(submitted_to_akismet)
    not_submitted_to_akismet_by_distinct_doc = revision_by_distinct_doc(not_submitted_to_akismet)
    revisions_reverted_by_distinct_doc = revision_by_distinct_doc(revisions_reverted_list)
    revisions_not_reverted_by_distinct_doc = revision_by_distinct_doc(revisions_not_reverted_list)
    revisions_deleted_by_distinct_doc = revision_by_distinct_doc(revisions_deleted_list)
    revisions_not_deleted_by_distinct_doc = revision_by_distinct_doc(revisions_not_deleted_list)

    actions_taken = {
        'revisions_reported_as_spam': submitted_to_akismet_by_distinct_doc,
        'revisions_reverted_list': revisions_reverted_by_distinct_doc,
        'revisions_deleted_list': revisions_deleted_by_distinct_doc
    }

    """ The "Needs followup" section """
    # TODO: Phase V: If user made actions while reviewer was banning them
    new_action_by_user = []
    skipped_revisions = [rev for rev in revisions_to_mark_as_spam_and_revert
                         if rev.document_id in previous_good_rev and
                         rev.id < previous_good_rev[rev.document_id].id]
    skipped_revisions = revision_by_distinct_doc(skipped_revisions)

    needs_follow_up = {
        'manual_revert': new_action_by_user,
        'skipped_revisions': skipped_revisions,
        'not_submitted_to_akismet': not_submitted_to_akismet_by_distinct_doc,
        'not_reverted_list': revisions_not_reverted_by_distinct_doc,
        'not_deleted_list': revisions_not_deleted_by_distinct_doc
    }

    """ The "No Actions Taken" section """
    revisions_already_spam = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist('revision-already-spam')
    )
    revisions_already_spam = list(revisions_already_spam)
    revisions_already_spam_by_distinct_doc = revision_by_distinct_doc(revisions_already_spam)

    identified_as_not_spam = [rev for rev in revisions_from_last_three_days
                              if rev not in revisions_already_spam and
                              rev not in revisions_to_mark_as_spam_and_revert]
    identified_as_not_spam_by_distinct_doc = revision_by_distinct_doc(identified_as_not_spam)

    no_actions_taken = {
        'latest_revision_is_not_spam': latest_is_not_spam,
        'revisions_already_identified_as_spam': revisions_already_spam_by_distinct_doc,
        'revisions_identified_as_not_spam': identified_as_not_spam_by_distinct_doc
    }

    context = {'detail_user': user,
               'form': UserBanForm(),
               'actions_taken': actions_taken,
               'needs_follow_up': needs_follow_up,
               'no_actions_taken': no_actions_taken}

    # Send an email to the spam watch mailing list.
    ban_and_revert_notification(user, request.user, context)

    return render(request,
                  'users/ban_user_and_cleanup_summary.html',
                  context)
예제 #6
0
def ban_user_and_cleanup_summary(request, username):
    """
    A summary page of actions taken when banning a user and reverting revisions
    This method takes all the revisions from the last three days,
    sends back the list of revisions that were successfully reverted/deleted
    and submitted to Akismet, and also a list of
    revisions where no action was taken (revisions needing follow up).
    """
    user = get_object_or_404(User, username=username)

    # Is this user already banned?
    user_ban = UserBan.objects.filter(user=user, is_active=True)

    # If the user is not banned, ban user; else, update 'by' and 'reason'
    if not user_ban.exists():
        ban = UserBan(user=user, by=request.user, reason="Spam", is_active=True)
        ban.save()
    else:
        user_ban.update(by=request.user, reason="Spam")

    date_three_days_ago = datetime.now().date() - timedelta(days=3)
    revisions_from_last_three_days = user.created_revisions.prefetch_related("document")
    revisions_from_last_three_days = revisions_from_last_three_days.defer(
        "content", "summary"
    ).order_by("-id")
    revisions_from_last_three_days = revisions_from_last_three_days.filter(
        created__gte=date_three_days_ago
    )

    """ The "Actions Taken" section """
    # The revisions to be submitted to Akismet and reverted,
    # these must be sorted descending so that they are reverted accordingly
    revisions_to_mark_as_spam_and_revert = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist("revision-id")
    ).order_by("-id")

    # 1. Submit revisions to Akismet as spam
    # 2. If this is the most recent revision for a document:
    #    Revert revision if it has a previous version OR
    #    Delete revision if it is a new document
    submitted_to_akismet = []
    not_submitted_to_akismet = []
    revisions_reverted_list = []
    revisions_not_reverted_list = []
    revisions_deleted_list = []
    revisions_not_deleted_list = []
    latest_is_not_spam = [
        rev
        for rev in revision_by_distinct_doc(revisions_to_mark_as_spam_and_revert)
        if rev.document.current_revision != rev
    ]
    previous_good_rev = {}

    for revision in revisions_to_mark_as_spam_and_revert:
        submission = RevisionAkismetSubmission(sender=request.user, type="spam")
        akismet_submission_data = {"revision": revision.id}

        data = RevisionAkismetSubmissionSpamForm(
            data=akismet_submission_data, instance=submission, request=request
        )
        # Submit to Akismet or note that validation & sending to Akismet failed
        if data.is_valid():
            data.save()
            # Since we only want to display 1 revision per document, only add to
            # this list if this is one of the revisions for a distinct document
            submitted_to_akismet.append(revision)
        else:
            not_submitted_to_akismet.append(revision)

        # If there is a current revision and the revision is not in the spam list,
        # to be reverted, do not revert any revisions
        try:
            revision.document.refresh_from_db(fields=["current_revision"])
        except Document.DoesNotExist:
            continue  # This document was previously deleted in this loop, continue
        if (
            revision.document.current_revision
            not in revisions_to_mark_as_spam_and_revert
        ):
            if revision.document_id not in previous_good_rev:
                previous_good_rev[
                    revision.document_id
                ] = revision.document.current_revision

            continue  # This document has a more current revision, no need to revert

        # Loop through all previous revisions to find the oldest spam
        # revision on a specific document from this request.
        while revision.previous in revisions_to_mark_as_spam_and_revert:
            revision = revision.previous
        # If this is a new revision on an existing document, revert it
        if revision.previous:
            previous_good_rev[revision.document_id] = revision.previous

            reverted = revert_document(
                request=request, revision_id=revision.previous.id
            )
            if reverted:
                revisions_reverted_list.append(revision)
            else:
                # If the revert was unsuccessful, include this in the follow-up list
                revisions_not_reverted_list.append(revision)

        # If this is a new document/translation, delete it
        else:
            deleted = delete_document(request=request, document=revision.document)
            if deleted:
                revisions_deleted_list.append(revision)
            else:
                # If the delete was unsuccessful, include this in the follow-up list
                revisions_not_deleted_list.append(revision)

    # Find just the latest revision for each document
    submitted_to_akismet_by_distinct_doc = revision_by_distinct_doc(
        submitted_to_akismet
    )
    not_submitted_to_akismet_by_distinct_doc = revision_by_distinct_doc(
        not_submitted_to_akismet
    )
    revisions_reverted_by_distinct_doc = revision_by_distinct_doc(
        revisions_reverted_list
    )
    revisions_not_reverted_by_distinct_doc = revision_by_distinct_doc(
        revisions_not_reverted_list
    )
    revisions_deleted_by_distinct_doc = revision_by_distinct_doc(revisions_deleted_list)
    revisions_not_deleted_by_distinct_doc = revision_by_distinct_doc(
        revisions_not_deleted_list
    )

    actions_taken = {
        "revisions_reported_as_spam": submitted_to_akismet_by_distinct_doc,
        "revisions_reverted_list": revisions_reverted_by_distinct_doc,
        "revisions_deleted_list": revisions_deleted_by_distinct_doc,
    }

    """ The "Needs followup" section """
    # TODO: Phase V: If user made actions while reviewer was banning them
    new_action_by_user = []
    skipped_revisions = [
        rev
        for rev in revisions_to_mark_as_spam_and_revert
        if rev.document_id in previous_good_rev
        and rev.id < previous_good_rev[rev.document_id].id
    ]
    skipped_revisions = revision_by_distinct_doc(skipped_revisions)

    needs_follow_up = {
        "manual_revert": new_action_by_user,
        "skipped_revisions": skipped_revisions,
        "not_submitted_to_akismet": not_submitted_to_akismet_by_distinct_doc,
        "not_reverted_list": revisions_not_reverted_by_distinct_doc,
        "not_deleted_list": revisions_not_deleted_by_distinct_doc,
    }

    """ The "No Actions Taken" section """
    revisions_already_spam = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist("revision-already-spam")
    )
    revisions_already_spam = list(revisions_already_spam)
    revisions_already_spam_by_distinct_doc = revision_by_distinct_doc(
        revisions_already_spam
    )

    identified_as_not_spam = [
        rev
        for rev in revisions_from_last_three_days
        if rev not in revisions_already_spam
        and rev not in revisions_to_mark_as_spam_and_revert
    ]
    identified_as_not_spam_by_distinct_doc = revision_by_distinct_doc(
        identified_as_not_spam
    )

    no_actions_taken = {
        "latest_revision_is_not_spam": latest_is_not_spam,
        "revisions_already_identified_as_spam": revisions_already_spam_by_distinct_doc,
        "revisions_identified_as_not_spam": identified_as_not_spam_by_distinct_doc,
    }

    context = {
        "detail_user": user,
        "form": UserBanForm(),
        "actions_taken": actions_taken,
        "needs_follow_up": needs_follow_up,
        "no_actions_taken": no_actions_taken,
    }

    # Send an email to the spam watch mailing list.
    ban_and_revert_notification(user, request.user, context)

    return render(request, "users/ban_user_and_cleanup_summary.html", context)
예제 #7
0
파일: views.py 프로젝트: digisu/kuma
def ban_user_and_cleanup_summary(request, user_id):
    """
    A summary page of actions taken when banning a user and reverting revisions
    """
    try:
        user = User.objects.get(pk=user_id)
    except User.DoesNotExist:
        raise Http404

    # Is this user already banned?
    user_ban = UserBan.objects.filter(user=user, is_active=True)

    # If the user is not banned, ban user; else, update 'by' and 'reason'
    if not user_ban.exists():
        ban = UserBan(user=user,
                      by=request.user,
                      reason='Spam',
                      is_active=True)
        ban.save()
    else:
        user_ban.update(by=request.user, reason='Spam')

    date_three_days_ago = datetime.now().date() - timedelta(days=3)
    revisions_from_last_three_days = user.created_revisions.prefetch_related('document')
    revisions_from_last_three_days = revisions_from_last_three_days.defer('content', 'summary').order_by('-id')
    revisions_from_last_three_days = revisions_from_last_three_days.filter(created__gte=date_three_days_ago)

    distinct_doc_rev_ids = list(
        Document.objects
        .filter(revisions__in=revisions_from_last_three_days)
        .annotate(latest_rev=Max('revisions'))
        .values_list('latest_rev', flat=True))
    revisions_from_last_three_days_by_distinct_doc = revisions_from_last_three_days.filter(id__in=distinct_doc_rev_ids)
    # TODO: Phase III: In the future we will take the revisions out of request.POST
    # and either revert them or not.

    """ The "Actions Taken" section """
    # The revisions to be submitted to Akismet
    revisions_to_be_submitted_to_akismet = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist('revision-id'))
    # Submit revisions to Akismet as spam
    submitted_to_akismet = []
    not_submitted_to_akismet = []
    for revision in revisions_to_be_submitted_to_akismet:
        submission = RevisionAkismetSubmission(sender=request.user, type="spam")
        akismet_submission_data = {'revision': revision.id}

        data = RevisionAkismetSubmissionSpamForm(
            data=akismet_submission_data,
            instance=submission,
            request=request)
        # Submit to Akismet or note that validation & sending to Akismet failed
        if data.is_valid():
            data.save()
            # Since we only want to display 1 revision per document, only add to
            # this list if this is one of the revisions for a distinct document
            submitted_to_akismet.append(revision)
        else:
            not_submitted_to_akismet.append(revision)
    # Find just the latest revision for each document
    if len(submitted_to_akismet) > 0:
        distinct_submitted_to_akismet_rev_ids = list(
            Document.objects
            .filter(revisions__in=submitted_to_akismet)
            .annotate(latest_rev=Max('revisions'))
            .values_list('latest_rev', flat=True))
        submitted_to_akismet_by_distinct_doc = [rev for rev in submitted_to_akismet if rev.id in distinct_submitted_to_akismet_rev_ids]
    else:
        submitted_to_akismet_by_distinct_doc = []
    if len(not_submitted_to_akismet) > 0:
        distinct_not_submitted_to_akismet_rev_ids = list(
            Document.objects
            .filter(revisions__in=not_submitted_to_akismet)
            .annotate(latest_rev=Max('revisions'))
            .values_list('latest_rev', flat=True))
        not_submitted_to_akismet_by_distinct_doc = [rev for rev in not_submitted_to_akismet if rev.id in distinct_not_submitted_to_akismet_rev_ids]
    else:
        not_submitted_to_akismet_by_distinct_doc = []
    actions_taken = {'revisions_reported_as_spam': submitted_to_akismet_by_distinct_doc}

    """ The "Needs followup" section """
    # TODO: Phase III: needs_follow_up will include revisions that have not been reverted
    # TODO: Phase IV: If user made actions while reviewer was banning them
    new_action_by_user = []
    needs_follow_up = {
        'manual_revert': new_action_by_user,
        'not_submitted_to_akismet': not_submitted_to_akismet_by_distinct_doc
    }

    """ The "No Actions Taken" section """
    revisions_already_spam = revisions_from_last_three_days.filter(
        id__in=request.POST.getlist('revision-already-spam')
    )
    distinct_already_spam_rev_ids = list(
        Document.objects
        .filter(revisions__in=revisions_already_spam)
        .annotate(latest_rev=Max('revisions'))
        .values_list('latest_rev', flat=True))
    revisions_already_spam_by_distinct_doc = revisions_already_spam.filter(id__in=distinct_already_spam_rev_ids)
    not_identified_as_spam = revisions_from_last_three_days.exclude(
        id__in=revisions_already_spam.values_list('id', flat=True)).exclude(
        id__in=revisions_to_be_submitted_to_akismet.values_list('id', flat=True))
    distinct_not_identified_as_spam_rev_ids = list(
        Document.objects
        .filter(revisions__in=not_identified_as_spam)
        .annotate(latest_rev=Max('revisions'))
        .values_list('latest_rev', flat=True))
    not_identified_as_spam_by_distinct_doc = not_identified_as_spam.filter(id__in=distinct_not_identified_as_spam_rev_ids)
    # TODO: Phase III: Remove the "Not deleted not reverted" section, after adding the "Reverted" and "Deleted" sections
    not_deleted_not_reverted = revisions_from_last_three_days_by_distinct_doc
    no_actions_taken = {
        'revisions_already_identified_as_spam': revisions_already_spam_by_distinct_doc,
        'revisions_not_identified_as_spam': not_identified_as_spam_by_distinct_doc,
        'revisions_not_deleted_not_reverted': not_deleted_not_reverted
    }

    context = {'detail_user': user,
               'form': UserBanForm(),
               'actions_taken': actions_taken,
               'needs_follow_up': needs_follow_up,
               'no_actions_taken': no_actions_taken}

    return render(request,
                  'users/ban_user_and_cleanup_summary.html',
                  context)