Abuse reports: moderator form for resolving/dismissing + notification #173
@ -19,8 +19,7 @@ class AbuseReportTypeFilter(admin.SimpleListFilter):
|
|||||||
parameter_name = 'type'
|
parameter_name = 'type'
|
||||||
|
|
||||||
def lookups(self, request, model_admin):
|
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
|
tuple is the coded value for the option that will
|
||||||
appear in the URL query. The second element is the
|
appear in the URL query. The second element is the
|
||||||
human-readable name for the option that will appear
|
human-readable name for the option that will appear
|
||||||
@ -32,8 +31,7 @@ class AbuseReportTypeFilter(admin.SimpleListFilter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
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
|
provided in the query string and retrievable via
|
||||||
`self.value()`.
|
`self.value()`.
|
||||||
"""
|
"""
|
||||||
@ -78,6 +76,8 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin):
|
|||||||
'message',
|
'message',
|
||||||
'extension_version',
|
'extension_version',
|
||||||
'version',
|
'version',
|
||||||
|
'processed_by',
|
||||||
|
'moderator_note',
|
||||||
)
|
)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Abuse Report Core Information', {'fields': ('status', 'reason', 'message')}),
|
('Abuse Report Core Information', {'fields': ('status', 'reason', 'message')}),
|
||||||
@ -89,6 +89,8 @@ class AbuseReportAdmin(CommaSearchInAdminMixin, admin.ModelAdmin):
|
|||||||
'date_modified',
|
'date_modified',
|
||||||
'reporter',
|
'reporter',
|
||||||
'version',
|
'version',
|
||||||
|
'processed_by',
|
||||||
|
'moderator_note',
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -41,3 +41,28 @@ class ReportRatingForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = abuse.models.AbuseReport
|
model = abuse.models.AbuseReport
|
||||||
fields = ('reason', 'message')
|
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)
|
||||||
|
self.fields['moderator_note'].required = True
|
||||||
|
|
||||||
|
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 = self.request.user
|
||||||
|
return self.cleaned_data
|
||||||
|
|
||||||
|
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)
|
||||||
|
31
abuse/migrations/0010_abusereport_moderator_note_and_more.py
Normal file
31
abuse/migrations/0010_abusereport_moderator_note_and_more.py
Normal file
@ -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',
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
]
|
@ -29,7 +29,7 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
|||||||
|
|
||||||
STATUSES = Choices(
|
STATUSES = Choices(
|
||||||
('UNTRIAGED', 1, 'Untriaged'),
|
('UNTRIAGED', 1, 'Untriaged'),
|
||||||
('CONFIRMED', 2, 'Confirmed'),
|
('DISMISSED', 2, 'Dismissed'),
|
||||||
('RESOLVED', 3, 'Resolved'),
|
('RESOLVED', 3, 'Resolved'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,6 +68,13 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
status = models.PositiveSmallIntegerField(default=STATUSES.UNTRIAGED, choices=STATUSES.choices)
|
status = models.PositiveSmallIntegerField(default=STATUSES.UNTRIAGED, choices=STATUSES.choices)
|
||||||
|
moderator_note = models.TextField(blank=True, null=True)
|
||||||
|
processed_by = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
null=True,
|
||||||
|
related_name='abuse_reports_processed',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def lookup_country_code_from_ip(cls, ip):
|
def lookup_country_code_from_ip(cls, ip):
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from actstream import action
|
from actstream import action
|
||||||
|
from actstream.actions import follow
|
||||||
from django.db.models.signals import post_save, pre_delete
|
from django.db.models.signals import post_save, pre_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from abuse.models import AbuseReport
|
from abuse.models import AbuseReport
|
||||||
from constants.activity import Verb
|
from constants.activity import Flag, Verb
|
||||||
from constants.base import (
|
from constants.base import (
|
||||||
ABUSE_TYPE_EXTENSION,
|
ABUSE_TYPE_EXTENSION,
|
||||||
ABUSE_TYPE_RATING,
|
ABUSE_TYPE_RATING,
|
||||||
@ -45,6 +46,8 @@ def _create_action_from_report(
|
|||||||
target=instance.extension,
|
target=instance.extension,
|
||||||
action_object=instance,
|
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)
|
@receiver(pre_delete, sender=AbuseReport)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<div class="hero extension-detail">
|
<div class="hero extension-detail">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
|
{% if user_is_moderator %}
|
||||||
{% block hero_breadcrumbs %}
|
{% block hero_breadcrumbs %}
|
||||||
<div class="hero-breadcrumbs">
|
<div class="hero-breadcrumbs">
|
||||||
<a href="{% url 'abuse:report-list' %}">
|
<a href="{% url 'abuse:report-list' %}">
|
||||||
@ -17,6 +18,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock hero_breadcrumbs %}
|
{% endblock hero_breadcrumbs %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h1>{{ object.get_type_display }} Report</h1>
|
<h1>{{ object.get_type_display }} Report</h1>
|
||||||
|
|
||||||
@ -73,12 +75,12 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<h2>Reason</h2>
|
|
||||||
<p>"{{ object.get_reason_display }}"</p>
|
|
||||||
{% if object.rating %}
|
{% if object.rating %}
|
||||||
{% include "ratings/components/rating.html" with rating=object.rating classes="mb-3" %}
|
{% include "ratings/components/rating.html" with rating=object.rating classes="mb-3" %}
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h2>Reason</h2>
|
||||||
|
<p>"{{ object.get_reason_display }}"</p>
|
||||||
<h2 class="mt-4 mb-3">Message</h2>
|
<h2 class="mt-4 mb-3">Message</h2>
|
||||||
<div class="card p-3 mx-1 mb-3">
|
<div class="card p-3 mx-1 mb-3">
|
||||||
{% if object.message %}
|
{% if object.message %}
|
||||||
@ -96,30 +98,25 @@
|
|||||||
<dt>Status</dt>
|
<dt>Status</dt>
|
||||||
<dd>{% include "common/components/status.html" %}</dd>
|
<dd>{% include "common/components/status.html" %}</dd>
|
||||||
</div>
|
</div>
|
||||||
|
{% if object.processed_by %}
|
||||||
|
<div class="dl-col">
|
||||||
|
<dt>Processed by</dt>
|
||||||
|
<dd>{{ object.processed_by }}</dd>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if extension %}
|
||||||
<div class="dl-row">
|
<div class="dl-row">
|
||||||
<div class="dl-col">
|
<div class="dl-col">
|
||||||
{% if extension %}
|
|
||||||
<dt>{{ extension.get_type_display }}</dt>
|
<dt>{{ extension.get_type_display }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<a href="{{ extension.get_absolute_url }}">
|
<a href="{{ extension.get_absolute_url }}">
|
||||||
{{ extension.name }}
|
{{ extension.name }}
|
||||||
</a>
|
</a>
|
||||||
</dd>
|
</dd>
|
||||||
{% else %}
|
|
||||||
<dt>Reported user</dt>
|
|
||||||
<dd>{{ object.name }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dl-row">
|
|
||||||
<div class="dl-col">
|
|
||||||
<dt>Compatibility</dt>
|
|
||||||
<dd>
|
|
||||||
{% if object.version %}Blender {{ object.version }}{% else %}Other{% endif %}
|
|
||||||
</dd>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="dl-row">
|
<div class="dl-row">
|
||||||
<div class="dl-col">
|
<div class="dl-col">
|
||||||
<dt>Submitted</dt>
|
<dt>Submitted</dt>
|
||||||
@ -145,4 +142,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if user_is_moderator %}
|
||||||
|
<div class="col-md-8">
|
||||||
|
<form method="post" enctype="multipart/form-data" class="mt-3">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% with form=form|add_form_classes %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
{% include "common/components/field.html" with field=form.moderator_note placeholder="Add a note..." %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
<button type="submit" class="btn btn-primary" name="resolve"><i class="i-check"></i> Resolve</button>
|
||||||
|
<button type="submit" class="btn btn-secondary" name="dismiss"><i class="i-trash"></i> Dismiss</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% elif object.moderator_note %}
|
||||||
|
<h2>Moderator note</h2>
|
||||||
|
<p>{{ object.moderator_note }}</p>
|
||||||
|
{% endif %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{% extends "common/base.html" %}
|
{% extends "common/base.html" %}
|
||||||
{% load i18n humanize filters %}
|
{% load common i18n humanize filters %}
|
||||||
|
|
||||||
{% block page_title %}Approval queue{% endblock page_title %}
|
{% block page_title %}Approval queue{% endblock page_title %}
|
||||||
|
|
||||||
@ -25,6 +25,7 @@
|
|||||||
<th>{% trans "Reporter" %}</th>
|
<th>{% trans "Reporter" %}</th>
|
||||||
<th>{% trans "Submitted" %}</th>
|
<th>{% trans "Submitted" %}</th>
|
||||||
<th>{% trans "Status" %}</th>
|
<th>{% trans "Status" %}</th>
|
||||||
|
<th>{% trans "Process by" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -50,6 +51,9 @@
|
|||||||
{% include "common/components/status.html" with object=report classes="d-block" %}
|
{% include "common/components/status.html" with object=report classes="d-block" %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ report.processed_by|default:"-" }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -58,4 +62,5 @@
|
|||||||
<p>{% trans "No extensions to review." %}</p>
|
<p>{% trans "No extensions to review." %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
|
{{ page_obj|paginator }}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from abuse.models import AbuseReport
|
||||||
from common.tests.factories.abuse import AbuseReportFactory
|
from common.tests.factories.abuse import AbuseReportFactory
|
||||||
from common.tests.factories.extensions import create_approved_version
|
from common.tests.factories.extensions import create_approved_version
|
||||||
from common.tests.factories.users import UserFactory, create_moderator
|
from common.tests.factories.users import UserFactory, create_moderator
|
||||||
|
from notifications.models import Notification
|
||||||
|
|
||||||
POST_DATA = {
|
POST_DATA = {
|
||||||
'message': 'test message',
|
'message': 'test message',
|
||||||
@ -61,3 +63,23 @@ class ReportTest(TestCase):
|
|||||||
self.client.logout()
|
self.client.logout()
|
||||||
self.client.force_login(account)
|
self.client.force_login(account)
|
||||||
self.assertEqual(self.client.get(report_url).status_code, 200)
|
self.assertEqual(self.client.get(report_url).status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class ResolveReportTest(TestCase):
|
||||||
|
def test_reporter_gets_notified(self):
|
||||||
|
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)
|
||||||
|
self.assertEqual(report.processed_by, moderator)
|
||||||
|
new_notification_nr = Notification.objects.filter(recipient=report.reporter).count()
|
||||||
|
self.assertEqual(new_notification_nr, notification_nr + 1)
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from actstream import action
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
||||||
from django.http import Http404
|
from django.db import transaction
|
||||||
from django.views.generic import DetailView
|
from django.http import Http404, HttpResponseForbidden
|
||||||
from django.views.generic.list import ListView
|
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 django.shortcuts import get_object_or_404, redirect
|
||||||
|
|
||||||
from .forms import ReportExtensionForm, ReportRatingForm
|
from .forms import ReportExtensionForm, ReportRatingForm, ResolveReportForm
|
||||||
|
from constants.activity import Verb
|
||||||
from constants.base import ABUSE_TYPE_EXTENSION, ABUSE_TYPE_RATING
|
from constants.base import ABUSE_TYPE_EXTENSION, ABUSE_TYPE_RATING
|
||||||
from abuse.models import AbuseReport
|
from abuse.models import AbuseReport
|
||||||
from ratings.models import Rating
|
from ratings.models import Rating
|
||||||
@ -29,7 +31,7 @@ class ReportList(
|
|||||||
return self.request.user.is_moderator
|
return self.request.user.is_moderator
|
||||||
|
|
||||||
def get_queryset(self):
|
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'
|
template_name = 'abuse/abusereport_list.html'
|
||||||
|
|
||||||
@ -123,8 +125,9 @@ class ReportRatingView(
|
|||||||
return self.object.get_absolute_url()
|
return self.object.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
class ReportView(LoginRequiredMixin, DetailView):
|
class ReportView(LoginRequiredMixin, UpdateView):
|
||||||
model = AbuseReport
|
model = AbuseReport
|
||||||
|
template_name = 'abuse/abusereport_detail.html'
|
||||||
|
|
||||||
def get_object(self, *args, **kwargs):
|
def get_object(self, *args, **kwargs):
|
||||||
obj = super().get_object(*args, **kwargs)
|
obj = super().get_object(*args, **kwargs)
|
||||||
@ -133,3 +136,25 @@ class ReportView(LoginRequiredMixin, DetailView):
|
|||||||
):
|
):
|
||||||
return obj
|
return obj
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
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()
|
||||||
|
return super().post(*args, **kwargs)
|
||||||
|
@ -56,6 +56,7 @@ def construct_fake_notifications() -> list['NotificationFactory']:
|
|||||||
type=reviewers.models.ApprovalActivity.ActivityType.COMMENT,
|
type=reviewers.models.ApprovalActivity.ActivityType.COMMENT,
|
||||||
message=fake.paragraph(nb_sentences=1),
|
message=fake.paragraph(nb_sentences=1),
|
||||||
),
|
),
|
||||||
|
Verb.DISMISSED_ABUSE_REPORT: None,
|
||||||
Verb.RATED_EXTENSION: RatingFactory.build(
|
Verb.RATED_EXTENSION: RatingFactory.build(
|
||||||
text=fake.paragraph(nb_sentences=2),
|
text=fake.paragraph(nb_sentences=2),
|
||||||
),
|
),
|
||||||
@ -71,6 +72,7 @@ def construct_fake_notifications() -> list['NotificationFactory']:
|
|||||||
type=reviewers.models.ApprovalActivity.ActivityType.AWAITING_REVIEW,
|
type=reviewers.models.ApprovalActivity.ActivityType.AWAITING_REVIEW,
|
||||||
message=fake.paragraph(nb_sentences=1),
|
message=fake.paragraph(nb_sentences=1),
|
||||||
),
|
),
|
||||||
|
Verb.RESOLVED_ABUSE_REPORT: None,
|
||||||
}
|
}
|
||||||
fake_notifications = [
|
fake_notifications = [
|
||||||
NotificationFactory.build(
|
NotificationFactory.build(
|
||||||
|
@ -5,15 +5,18 @@ class Verb:
|
|||||||
|
|
||||||
APPROVED = 'approved'
|
APPROVED = 'approved'
|
||||||
COMMENTED = 'commented'
|
COMMENTED = 'commented'
|
||||||
|
DISMISSED_ABUSE_REPORT = 'dismissed abuse report'
|
||||||
RATED_EXTENSION = 'rated extension'
|
RATED_EXTENSION = 'rated extension'
|
||||||
REPORTED_EXTENSION = 'reported extension'
|
REPORTED_EXTENSION = 'reported extension'
|
||||||
REPORTED_RATING = 'reported rating'
|
REPORTED_RATING = 'reported rating'
|
||||||
REQUESTED_CHANGES = 'requested changes'
|
REQUESTED_CHANGES = 'requested changes'
|
||||||
REQUESTED_REVIEW = 'requested review'
|
REQUESTED_REVIEW = 'requested review'
|
||||||
|
RESOLVED_ABUSE_REPORT = 'resolved abuse report'
|
||||||
UPLOADED_NEW_VERSION = 'uploaded new version'
|
UPLOADED_NEW_VERSION = 'uploaded new version'
|
||||||
|
|
||||||
|
|
||||||
class Flag:
|
class Flag:
|
||||||
AUTHOR = 'author'
|
AUTHOR = 'author'
|
||||||
MODERATOR = 'moderator'
|
MODERATOR = 'moderator'
|
||||||
|
REPORTER = 'reporter'
|
||||||
REVIEWER = 'reviewer'
|
REVIEWER = 'reviewer'
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
||||||
{% elif action.verb == Verb.COMMENTED %}
|
{% elif action.verb == Verb.COMMENTED %}
|
||||||
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
||||||
|
{% elif verb == Verb.DISMISSED_ABUSE_REPORT %}
|
||||||
|
{% blocktrans %}{{ someone }} dismissed your {{ what }}{% endblocktrans %}
|
||||||
{% elif verb == Verb.RATED_EXTENSION %}
|
{% elif verb == Verb.RATED_EXTENSION %}
|
||||||
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
||||||
{% elif verb == Verb.REPORTED_EXTENSION %}
|
{% elif verb == Verb.REPORTED_EXTENSION %}
|
||||||
@ -14,6 +16,8 @@
|
|||||||
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
||||||
{% elif verb == Verb.REQUESTED_REVIEW %}
|
{% elif verb == Verb.REQUESTED_REVIEW %}
|
||||||
{% blocktrans %}{{ someone }} {{ verb }} of {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} of {{ what }}{% endblocktrans %}
|
||||||
|
{% elif verb == Verb.RESOLVED_ABUSE_REPORT %}
|
||||||
|
{% blocktrans %}{{ someone }} resolved your {{ what }}{% endblocktrans %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} {{ what }}{% endblocktrans %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
{% blocktrans %}{{ target_type }} approved: "{{ name }}"{% endblocktrans %}
|
{% blocktrans %}{{ target_type }} approved: "{{ name }}"{% endblocktrans %}
|
||||||
{% elif verb == Verb.COMMENTED %}
|
{% elif verb == Verb.COMMENTED %}
|
||||||
{% blocktrans %}New comment on {{ what }}{% endblocktrans %}
|
{% blocktrans %}New comment on {{ what }}{% endblocktrans %}
|
||||||
|
{% elif verb == Verb.DISMISSED_ABUSE_REPORT %}
|
||||||
|
{% blocktrans %}Your {{ what }} was dismissed{% endblocktrans %}
|
||||||
{% elif verb == Verb.RATED_EXTENSION %}
|
{% elif verb == Verb.RATED_EXTENSION %}
|
||||||
{% blocktrans %}{{ target_type }} rated: "{{ name }}"{% endblocktrans %}
|
{% blocktrans %}{{ target_type }} rated: "{{ name }}"{% endblocktrans %}
|
||||||
{% elif verb == Verb.REPORTED_EXTENSION %}
|
{% elif verb == Verb.REPORTED_EXTENSION %}
|
||||||
@ -14,6 +16,8 @@
|
|||||||
{% blocktrans %}{{ target_type }} changes requested: "{{ name }}"{% endblocktrans %}
|
{% blocktrans %}{{ target_type }} changes requested: "{{ name }}"{% endblocktrans %}
|
||||||
{% elif verb == Verb.REQUESTED_REVIEW %}
|
{% elif verb == Verb.REQUESTED_REVIEW %}
|
||||||
{% blocktrans %}{{ target_type }} review requested: "{{ name }}"{% endblocktrans %}
|
{% blocktrans %}{{ target_type }} review requested: "{{ name }}"{% endblocktrans %}
|
||||||
|
{% elif verb == Verb.RESOLVED_ABUSE_REPORT %}
|
||||||
|
{% blocktrans %}Your {{ what }} was resolved{% endblocktrans %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
{% blocktrans %}{{ someone }} {{ verb }} on {{ what }}{% endblocktrans %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -13,11 +13,13 @@ logger = logging.getLogger(__name__)
|
|||||||
VERB2FLAGS = {
|
VERB2FLAGS = {
|
||||||
Verb.APPROVED: [Flag.AUTHOR, Flag.REVIEWER],
|
Verb.APPROVED: [Flag.AUTHOR, Flag.REVIEWER],
|
||||||
Verb.COMMENTED: [Flag.AUTHOR, Flag.REVIEWER],
|
Verb.COMMENTED: [Flag.AUTHOR, Flag.REVIEWER],
|
||||||
|
Verb.DISMISSED_ABUSE_REPORT: [Flag.REPORTER],
|
||||||
Verb.RATED_EXTENSION: [Flag.AUTHOR],
|
Verb.RATED_EXTENSION: [Flag.AUTHOR],
|
||||||
Verb.REPORTED_EXTENSION: [Flag.MODERATOR],
|
Verb.REPORTED_EXTENSION: [Flag.MODERATOR],
|
||||||
Verb.REPORTED_RATING: [Flag.MODERATOR],
|
Verb.REPORTED_RATING: [Flag.MODERATOR],
|
||||||
Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.REVIEWER],
|
Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.REVIEWER],
|
||||||
Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER],
|
Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER],
|
||||||
|
Verb.RESOLVED_ABUSE_REPORT: [Flag.REPORTER],
|
||||||
Verb.UPLOADED_NEW_VERSION: [],
|
Verb.UPLOADED_NEW_VERSION: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user