From d47931e68964d94f491408d6f2ca7578195306df Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 15:05:03 +0200 Subject: [PATCH 1/7] Abuse reports: add a form for resolving/dismissing a report --- abuse/admin.py | 10 ++-- abuse/forms.py | 30 ++++++++++++ ...010_abusereport_moderator_note_and_more.py | 31 +++++++++++++ abuse/models.py | 9 +++- abuse/templates/abuse/abusereport_detail.html | 46 +++++++++++++------ abuse/templates/abuse/abusereport_list.html | 7 ++- abuse/views.py | 21 ++++++--- 7 files changed, 127 insertions(+), 27 deletions(-) create mode 100644 abuse/migrations/0010_abusereport_moderator_note_and_more.py diff --git a/abuse/admin.py b/abuse/admin.py index 274c9aa0..3441dcb9 100644 --- a/abuse/admin.py +++ b/abuse/admin.py @@ -19,8 +19,7 @@ class AbuseReportTypeFilter(admin.SimpleListFilter): parameter_name = 'type' def lookups(self, request, model_admin): - """ - Returns a list of tuples. The first element in each + """Returns a list of tuples. The first element in each tuple is the coded value for the option that will appear in the URL query. The second element is the human-readable name for the option that will appear @@ -32,8 +31,7 @@ class AbuseReportTypeFilter(admin.SimpleListFilter): ) def queryset(self, request, queryset): - """ - Returns the filtered queryset based on the value + """Returns the filtered queryset based on the value provided in the query string and retrievable via `self.value()`. """ @@ -78,6 +76,8 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin): 'message', 'extension_version', 'version', + 'processed_by_moderator', + 'moderator_note', ) fieldsets = ( ('Abuse Report Core Information', {'fields': ('status', 'reason', 'message')}), @@ -89,6 +89,8 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin): 'date_modified', 'reporter', 'version', + 'processed_by_moderator', + 'moderator_note', ) }, ), diff --git a/abuse/forms.py b/abuse/forms.py index 3e7a4d0c..2772befc 100644 --- a/abuse/forms.py +++ b/abuse/forms.py @@ -41,3 +41,33 @@ class ReportRatingForm(forms.ModelForm): class Meta: model = abuse.models.AbuseReport fields = ('reason', 'message') + + +class ResolveReportForm(forms.ModelForm): + class Meta: + model = abuse.models.AbuseReport + fields = ('moderator_note',) + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request') + super().__init__(*args, **kwargs) + + def clean(self): + super().clean() + if 'dismiss' in self.data: + self.instance.status = self.instance.STATUSES.DISMISSED + if 'resolve' in self.data: + self.instance.status = self.instance.STATUSES.RESOLVED + self.instance.processed_by_moderator = self.request.user + return self.cleaned_data + + def clean_moderator_note(self, *args, **kwargs): + moderator_note = self.cleaned_data.get('moderator_note') + if not moderator_note: + raise forms.ValidationError('this field is required') + return moderator_note + + def is_valid(self, *args, **kwargs) -> bool: + if 'dismiss' not in self.data and 'resolve' not in self.data: + return False + return super().is_valid(*args, **kwargs) diff --git a/abuse/migrations/0010_abusereport_moderator_note_and_more.py b/abuse/migrations/0010_abusereport_moderator_note_and_more.py new file mode 100644 index 00000000..e9a597bb --- /dev/null +++ b/abuse/migrations/0010_abusereport_moderator_note_and_more.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.11 on 2024-06-07 12:40 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('abuse', '0009_alter_abusereport_user'), + ] + + operations = [ + migrations.AddField( + model_name='abusereport', + name='moderator_note', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='abusereport', + name='processed_by_moderator', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='abuse_reports_processed', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='abusereport', + name='status', + field=models.PositiveSmallIntegerField(choices=[(1, 'Untriaged'), (2, 'Dismissed'), (3, 'Resolved')], default=1), + ), + ] diff --git a/abuse/models.py b/abuse/models.py index 03a2cc9e..0114261a 100644 --- a/abuse/models.py +++ b/abuse/models.py @@ -29,7 +29,7 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model): STATUSES = Choices( ('UNTRIAGED', 1, 'Untriaged'), - ('CONFIRMED', 2, 'Confirmed'), + ('DISMISSED', 2, 'Dismissed'), ('RESOLVED', 3, 'Resolved'), ) @@ -68,6 +68,13 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model): ) status = models.PositiveSmallIntegerField(default=STATUSES.UNTRIAGED, choices=STATUSES.choices) + moderator_note = models.TextField(blank=True, null=True) + processed_by_moderator = models.ForeignKey( + User, + null=True, + related_name='abuse_reports_processed', + on_delete=models.PROTECT, + ) @classmethod def lookup_country_code_from_ip(cls, ip): diff --git a/abuse/templates/abuse/abusereport_detail.html b/abuse/templates/abuse/abusereport_detail.html index 90ce3add..0916763f 100644 --- a/abuse/templates/abuse/abusereport_detail.html +++ b/abuse/templates/abuse/abusereport_detail.html @@ -9,6 +9,7 @@
+ {% if user_is_moderator %} {% block hero_breadcrumbs %} {% endblock hero_breadcrumbs %} + {% endif %}

{{ object.get_type_display }} Report

@@ -73,12 +75,12 @@
-

Reason

-

"{{ object.get_reason_display }}"

{% if object.rating %} {% include "ratings/components/rating.html" with rating=object.rating classes="mb-3" %}
{% endif %} +

Reason

+

"{{ object.get_reason_display }}"

Message

{% if object.message %} @@ -96,30 +98,25 @@
Status
{% include "common/components/status.html" %}
+ {% if object.processed_by_moderator %} +
+
Processed by
+
{{ object.processed_by_moderator }}
+
+ {% endif %}
+ {% if extension %}
- {% if extension %}
{{ extension.get_type_display }}
{{ extension.name }}
- {% else %} -
Reported user
-
{{ object.name }}
- {% endif %} -
-
-
-
-
Compatibility
-
- {% if object.version %}Blender {{ object.version }}{% else %}Other{% endif %} -
+ {% endif %}
Submitted
@@ -145,4 +142,23 @@
+ {% if user_is_moderator %} +
+
+ {% csrf_token %} + {% with form=form|add_form_classes %} +
+
+ {% include "common/components/field.html" with field=form.moderator_note placeholder="Add a note..." required=True %} +
+
+ {% endwith %} + + +
+
+ {% elif object.moderator_note %} +

Moderator note

+

{{ object.moderator_note }}

+ {% endif %} {% endblock content %} diff --git a/abuse/templates/abuse/abusereport_list.html b/abuse/templates/abuse/abusereport_list.html index b2b0f6ad..c4110647 100644 --- a/abuse/templates/abuse/abusereport_list.html +++ b/abuse/templates/abuse/abusereport_list.html @@ -1,5 +1,5 @@ {% extends "common/base.html" %} -{% load i18n humanize filters %} +{% load common i18n humanize filters %} {% block page_title %}Approval queue{% endblock page_title %} @@ -25,6 +25,7 @@ {% trans "Reporter" %} {% trans "Submitted" %} {% trans "Status" %} + {% trans "Process by" %} @@ -50,6 +51,9 @@ {% include "common/components/status.html" with object=report classes="d-block" %} + + {{ report.processed_by_moderator|default:"-" }} + {% endfor %} @@ -58,4 +62,5 @@

{% trans "No extensions to review." %}

{% endif %} +{{ page_obj|paginator }} {% endblock content %} diff --git a/abuse/views.py b/abuse/views.py index 3cfe6be3..869a8e29 100644 --- a/abuse/views.py +++ b/abuse/views.py @@ -1,13 +1,12 @@ import logging from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin -from django.http import Http404 -from django.views.generic import DetailView +from django.http import Http404, HttpResponseForbidden from django.views.generic.list import ListView -from django.views.generic.edit import CreateView +from django.views.generic.edit import CreateView, UpdateView from django.shortcuts import get_object_or_404, redirect -from .forms import ReportExtensionForm, ReportRatingForm +from .forms import ReportExtensionForm, ReportRatingForm, ResolveReportForm from constants.base import ABUSE_TYPE_EXTENSION, ABUSE_TYPE_RATING from abuse.models import AbuseReport from ratings.models import Rating @@ -29,7 +28,7 @@ class ReportList( return self.request.user.is_moderator def get_queryset(self): - return AbuseReport.objects.all().order_by('-date_created') + return AbuseReport.objects.all().order_by('status', '-date_created') template_name = 'abuse/abusereport_list.html' @@ -123,8 +122,10 @@ class ReportRatingView( return self.object.get_absolute_url() -class ReportView(LoginRequiredMixin, DetailView): +class ReportView(LoginRequiredMixin, UpdateView): + form_class = ResolveReportForm model = AbuseReport + template_name = 'abuse/abusereport_detail.html' def get_object(self, *args, **kwargs): obj = super().get_object(*args, **kwargs) @@ -133,3 +134,11 @@ class ReportView(LoginRequiredMixin, DetailView): ): return obj raise Http404() + + def get_form(self): + return ResolveReportForm(**self.get_form_kwargs(), request=self.request) + + def post(self, *args, **kwargs): + if not self.request.user.is_moderator: + raise HttpResponseForbidden() + return super().post(*args, **kwargs) -- 2.30.2 From c8c7d1e389e2a031c401a8e4e3fd1ae630cd662e Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 15:12:32 +0200 Subject: [PATCH 2/7] simplify required field definition --- abuse/forms.py | 7 +------ abuse/templates/abuse/abusereport_detail.html | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/abuse/forms.py b/abuse/forms.py index 2772befc..b21807c3 100644 --- a/abuse/forms.py +++ b/abuse/forms.py @@ -51,6 +51,7 @@ class ResolveReportForm(forms.ModelForm): def __init__(self, *args, **kwargs): self.request = kwargs.pop('request') super().__init__(*args, **kwargs) + self.fields['moderator_note'].required = True def clean(self): super().clean() @@ -61,12 +62,6 @@ class ResolveReportForm(forms.ModelForm): self.instance.processed_by_moderator = self.request.user return self.cleaned_data - def clean_moderator_note(self, *args, **kwargs): - moderator_note = self.cleaned_data.get('moderator_note') - if not moderator_note: - raise forms.ValidationError('this field is required') - return moderator_note - def is_valid(self, *args, **kwargs) -> bool: if 'dismiss' not in self.data and 'resolve' not in self.data: return False diff --git a/abuse/templates/abuse/abusereport_detail.html b/abuse/templates/abuse/abusereport_detail.html index 0916763f..ff3702b9 100644 --- a/abuse/templates/abuse/abusereport_detail.html +++ b/abuse/templates/abuse/abusereport_detail.html @@ -149,7 +149,7 @@ {% with form=form|add_form_classes %}
- {% include "common/components/field.html" with field=form.moderator_note placeholder="Add a note..." required=True %} + {% include "common/components/field.html" with field=form.moderator_note placeholder="Add a note..." %}
{% endwith %} -- 2.30.2 From c1d35a3ed1a8b2818b514b886874bba423315ff1 Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 15:14:47 +0200 Subject: [PATCH 3/7] remove redundant form_class declaration --- abuse/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/abuse/views.py b/abuse/views.py index 869a8e29..91be2636 100644 --- a/abuse/views.py +++ b/abuse/views.py @@ -123,7 +123,6 @@ class ReportRatingView( class ReportView(LoginRequiredMixin, UpdateView): - form_class = ResolveReportForm model = AbuseReport template_name = 'abuse/abusereport_detail.html' -- 2.30.2 From 24c48a6439ecd8a8e7c02bbe4e56c0801e1b064f Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 16:26:41 +0200 Subject: [PATCH 4/7] add notifications on report resolution/dismissal --- abuse/signals.py | 5 ++++- abuse/views.py | 17 +++++++++++++++++ common/tests/factories/notifications.py | 2 ++ constants/activity.py | 3 +++ .../emails/components/new_activity_action | 4 ++++ .../templates/emails/new_activity_subject.txt | 4 ++++ notifications/signals.py | 2 ++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/abuse/signals.py b/abuse/signals.py index 3e266676..76c5a5c4 100644 --- a/abuse/signals.py +++ b/abuse/signals.py @@ -1,11 +1,12 @@ import logging from actstream import action +from actstream.actions import follow from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver from abuse.models import AbuseReport -from constants.activity import Verb +from constants.activity import Flag, Verb from constants.base import ( ABUSE_TYPE_EXTENSION, ABUSE_TYPE_RATING, @@ -45,6 +46,8 @@ def _create_action_from_report( target=instance.extension, action_object=instance, ) + # subscribe to the report object to get notifications about its resolution + follow(instance.reporter, instance, send_action=False, flag=Flag.REPORTER) @receiver(pre_delete, sender=AbuseReport) diff --git a/abuse/views.py b/abuse/views.py index 91be2636..acd7c91c 100644 --- a/abuse/views.py +++ b/abuse/views.py @@ -1,12 +1,15 @@ import logging +from actstream import action from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin +from django.db import transaction from django.http import Http404, HttpResponseForbidden from django.views.generic.list import ListView from django.views.generic.edit import CreateView, UpdateView from django.shortcuts import get_object_or_404, redirect from .forms import ReportExtensionForm, ReportRatingForm, ResolveReportForm +from constants.activity import Verb from constants.base import ABUSE_TYPE_EXTENSION, ABUSE_TYPE_RATING from abuse.models import AbuseReport from ratings.models import Rating @@ -137,6 +140,20 @@ class ReportView(LoginRequiredMixin, UpdateView): def get_form(self): return ResolveReportForm(**self.get_form_kwargs(), request=self.request) + @transaction.atomic + def form_valid(self, form): + response = super().form_valid(form) + if 'dismiss' in form.data: + verb = Verb.DISMISSED_ABUSE_REPORT + if 'resolve' in form.data: + verb = Verb.RESOLVED_ABUSE_REPORT + action.send( + self.request.user, + verb=verb, + target=form.instance, + ) + return response + def post(self, *args, **kwargs): if not self.request.user.is_moderator: raise HttpResponseForbidden() diff --git a/common/tests/factories/notifications.py b/common/tests/factories/notifications.py index bebd2a25..a7eb3339 100644 --- a/common/tests/factories/notifications.py +++ b/common/tests/factories/notifications.py @@ -56,6 +56,7 @@ def construct_fake_notifications() -> list['NotificationFactory']: type=reviewers.models.ApprovalActivity.ActivityType.COMMENT, message=fake.paragraph(nb_sentences=1), ), + Verb.DISMISSED_ABUSE_REPORT: None, Verb.RATED_EXTENSION: RatingFactory.build( text=fake.paragraph(nb_sentences=2), ), @@ -71,6 +72,7 @@ def construct_fake_notifications() -> list['NotificationFactory']: type=reviewers.models.ApprovalActivity.ActivityType.AWAITING_REVIEW, message=fake.paragraph(nb_sentences=1), ), + Verb.RESOLVED_ABUSE_REPORT: None, } fake_notifications = [ NotificationFactory.build( diff --git a/constants/activity.py b/constants/activity.py index 1da320ca..fa1e1cb0 100644 --- a/constants/activity.py +++ b/constants/activity.py @@ -5,15 +5,18 @@ class Verb: APPROVED = 'approved' COMMENTED = 'commented' + DISMISSED_ABUSE_REPORT = 'dismissed abuse report' RATED_EXTENSION = 'rated extension' REPORTED_EXTENSION = 'reported extension' REPORTED_RATING = 'reported rating' REQUESTED_CHANGES = 'requested changes' REQUESTED_REVIEW = 'requested review' + RESOLVED_ABUSE_REPORT = 'resolved abuse report' UPLOADED_NEW_VERSION = 'uploaded new version' class Flag: AUTHOR = 'author' MODERATOR = 'moderator' + REPORTER = 'reporter' REVIEWER = 'reviewer' diff --git a/emails/templates/emails/components/new_activity_action b/emails/templates/emails/components/new_activity_action index fd0263e1..a47c0fa6 100644 --- a/emails/templates/emails/components/new_activity_action +++ b/emails/templates/emails/components/new_activity_action @@ -4,6 +4,8 @@ {% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %} {% elif action.verb == Verb.COMMENTED %} {% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %} + {% elif verb == Verb.DISMISSED_ABUSE_REPORT %} + {% blocktrans %}{{ someone }} dismissed your {{ what }}{% endblocktrans %} {% elif verb == Verb.RATED_EXTENSION %} {% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %} {% elif verb == Verb.REPORTED_EXTENSION %} @@ -14,6 +16,8 @@ {% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %} {% elif verb == Verb.REQUESTED_REVIEW %} {% blocktrans %}{{ someone }} {{ verb }} of {{ what }}{% endblocktrans %} + {% elif verb == Verb.RESOLVED_ABUSE_REPORT %} + {% blocktrans %}{{ someone }} resolved your {{ what }}{% endblocktrans %} {% else %} {% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %} {% endif %} diff --git a/emails/templates/emails/new_activity_subject.txt b/emails/templates/emails/new_activity_subject.txt index 667a20a0..54c722b6 100644 --- a/emails/templates/emails/new_activity_subject.txt +++ b/emails/templates/emails/new_activity_subject.txt @@ -4,6 +4,8 @@ {% blocktrans %}{{ target_type }} approved: "{{ name }}"{% endblocktrans %} {% elif verb == Verb.COMMENTED %} {% blocktrans %}New comment on {{ what }}{% endblocktrans %} +{% elif verb == Verb.DISMISSED_ABUSE_REPORT %} + {% blocktrans %}Your {{ what }} was dismissed{% endblocktrans %} {% elif verb == Verb.RATED_EXTENSION %} {% blocktrans %}{{ target_type }} rated: "{{ name }}"{% endblocktrans %} {% elif verb == Verb.REPORTED_EXTENSION %} @@ -14,6 +16,8 @@ {% blocktrans %}{{ target_type }} changes requested: "{{ name }}"{% endblocktrans %} {% elif verb == Verb.REQUESTED_REVIEW %} {% blocktrans %}{{ target_type }} review requested: "{{ name }}"{% endblocktrans %} +{% elif verb == Verb.RESOLVED_ABUSE_REPORT %} + {% blocktrans %}Your {{ what }} was resolved{% endblocktrans %} {% else %} {% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %} {% endif %} diff --git a/notifications/signals.py b/notifications/signals.py index f6630f24..dbfb0180 100644 --- a/notifications/signals.py +++ b/notifications/signals.py @@ -13,11 +13,13 @@ logger = logging.getLogger(__name__) VERB2FLAGS = { Verb.APPROVED: [Flag.AUTHOR, Flag.REVIEWER], Verb.COMMENTED: [Flag.AUTHOR, Flag.REVIEWER], + Verb.DISMISSED_ABUSE_REPORT: [Flag.REPORTER], Verb.RATED_EXTENSION: [Flag.AUTHOR], Verb.REPORTED_EXTENSION: [Flag.MODERATOR], Verb.REPORTED_RATING: [Flag.MODERATOR], Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.REVIEWER], Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER], + Verb.RESOLVED_ABUSE_REPORT: [Flag.REPORTER], Verb.UPLOADED_NEW_VERSION: [], } -- 2.30.2 From 89fa06d805d2265b2f9b64731e69648056d5a456 Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 16:49:56 +0200 Subject: [PATCH 5/7] rename field --- abuse/admin.py | 4 ++-- abuse/forms.py | 2 +- abuse/migrations/0010_abusereport_moderator_note_and_more.py | 2 +- abuse/models.py | 2 +- abuse/templates/abuse/abusereport_detail.html | 4 ++-- abuse/templates/abuse/abusereport_list.html | 2 +- abuse/tests/test_abuse.py | 5 +++++ 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/abuse/admin.py b/abuse/admin.py index 3441dcb9..82a1779f 100644 --- a/abuse/admin.py +++ b/abuse/admin.py @@ -76,7 +76,7 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin): 'message', 'extension_version', 'version', - 'processed_by_moderator', + 'processed_by', 'moderator_note', ) fieldsets = ( @@ -89,7 +89,7 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin): 'date_modified', 'reporter', 'version', - 'processed_by_moderator', + 'processed_by', 'moderator_note', ) }, diff --git a/abuse/forms.py b/abuse/forms.py index b21807c3..0aef6b1f 100644 --- a/abuse/forms.py +++ b/abuse/forms.py @@ -59,7 +59,7 @@ class ResolveReportForm(forms.ModelForm): self.instance.status = self.instance.STATUSES.DISMISSED if 'resolve' in self.data: self.instance.status = self.instance.STATUSES.RESOLVED - self.instance.processed_by_moderator = self.request.user + self.instance.processed_by = self.request.user return self.cleaned_data def is_valid(self, *args, **kwargs) -> bool: diff --git a/abuse/migrations/0010_abusereport_moderator_note_and_more.py b/abuse/migrations/0010_abusereport_moderator_note_and_more.py index e9a597bb..2be46031 100644 --- a/abuse/migrations/0010_abusereport_moderator_note_and_more.py +++ b/abuse/migrations/0010_abusereport_moderator_note_and_more.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='abusereport', - name='processed_by_moderator', + name='processed_by', field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='abuse_reports_processed', to=settings.AUTH_USER_MODEL), ), migrations.AlterField( diff --git a/abuse/models.py b/abuse/models.py index 0114261a..8a777937 100644 --- a/abuse/models.py +++ b/abuse/models.py @@ -69,7 +69,7 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model): status = models.PositiveSmallIntegerField(default=STATUSES.UNTRIAGED, choices=STATUSES.choices) moderator_note = models.TextField(blank=True, null=True) - processed_by_moderator = models.ForeignKey( + processed_by = models.ForeignKey( User, null=True, related_name='abuse_reports_processed', diff --git a/abuse/templates/abuse/abusereport_detail.html b/abuse/templates/abuse/abusereport_detail.html index ff3702b9..fcd6be6b 100644 --- a/abuse/templates/abuse/abusereport_detail.html +++ b/abuse/templates/abuse/abusereport_detail.html @@ -98,10 +98,10 @@
Status
{% include "common/components/status.html" %}
- {% if object.processed_by_moderator %} + {% if object.processed_by %}
Processed by
-
{{ object.processed_by_moderator }}
+
{{ object.processed_by }}
{% endif %}
diff --git a/abuse/templates/abuse/abusereport_list.html b/abuse/templates/abuse/abusereport_list.html index c4110647..22e6750d 100644 --- a/abuse/templates/abuse/abusereport_list.html +++ b/abuse/templates/abuse/abusereport_list.html @@ -52,7 +52,7 @@ - {{ report.processed_by_moderator|default:"-" }} + {{ report.processed_by|default:"-" }} {% endfor %} diff --git a/abuse/tests/test_abuse.py b/abuse/tests/test_abuse.py index d7ec03a8..ab007e87 100644 --- a/abuse/tests/test_abuse.py +++ b/abuse/tests/test_abuse.py @@ -61,3 +61,8 @@ class ReportTest(TestCase): self.client.logout() self.client.force_login(account) self.assertEqual(self.client.get(report_url).status_code, 200) + + +class ResolveReportTest(TestCase): + def test_reporter_gets_notified(self): + pass -- 2.30.2 From 65b197b13841ee9b86896951301f99511688f063 Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 17:00:41 +0200 Subject: [PATCH 6/7] add test --- abuse/tests/test_abuse.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/abuse/tests/test_abuse.py b/abuse/tests/test_abuse.py index ab007e87..598ce4ac 100644 --- a/abuse/tests/test_abuse.py +++ b/abuse/tests/test_abuse.py @@ -1,8 +1,10 @@ from django.test import TestCase +from abuse.models import AbuseReport from common.tests.factories.abuse import AbuseReportFactory from common.tests.factories.extensions import create_approved_version from common.tests.factories.users import UserFactory, create_moderator +from notifications.models import Notification POST_DATA = { 'message': 'test message', @@ -65,4 +67,18 @@ class ReportTest(TestCase): class ResolveReportTest(TestCase): def test_reporter_gets_notified(self): - pass + report = AbuseReportFactory( + extension=create_approved_version().extension, + status=AbuseReport.STATUSES.UNTRIAGED, + ) + notification_nr = Notification.objects.filter(recipient=report.reporter).count() + moderator = create_moderator() + self.client.force_login(moderator) + response = self.client.post( + report.get_absolute_url(), {'moderator_note': 'lalala', 'resolve': ''} + ) + self.assertEqual(response.status_code, 302) + report.refresh_from_db() + self.assertEqual(report.status, AbuseReport.STATUSES.RESOLVED) + new_notification_nr = Notification.objects.filter(recipient=report.reporter).count() + self.assertEqual(new_notification_nr, notification_nr + 1) -- 2.30.2 From 5c6369070da73290a0711a3163db98eacabd179d Mon Sep 17 00:00:00 2001 From: Oleg Komarov Date: Fri, 7 Jun 2024 17:02:47 +0200 Subject: [PATCH 7/7] more comprehensive test --- abuse/tests/test_abuse.py | 1 + 1 file changed, 1 insertion(+) diff --git a/abuse/tests/test_abuse.py b/abuse/tests/test_abuse.py index 598ce4ac..9f130aa6 100644 --- a/abuse/tests/test_abuse.py +++ b/abuse/tests/test_abuse.py @@ -80,5 +80,6 @@ class ResolveReportTest(TestCase): self.assertEqual(response.status_code, 302) report.refresh_from_db() self.assertEqual(report.status, AbuseReport.STATUSES.RESOLVED) + self.assertEqual(report.processed_by, moderator) new_notification_nr = Notification.objects.filter(recipient=report.reporter).count() self.assertEqual(new_notification_nr, notification_nr + 1) -- 2.30.2