add new fields to AbuseReport model to support DSA/Feedback flow (#21260)

* add new fields to AbuseReport model to support DSA/Feedback flow

* drop extra line that makes black sad in CI

* create CinderReport model

* change abuse report fk to 1to1 field
This commit is contained in:
Andrew Williamson 2023-10-04 00:02:37 +01:00 коммит произвёл GitHub
Родитель 33765b0ee4
Коммит 15edba7187
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 161 добавлений и 2 удалений

Просмотреть файл

@ -0,0 +1,52 @@
# Generated by Django 4.2.5 on 2023-10-03 08:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('abuse', '0008_alter_abusereport_report_entry_point'),
]
operations = [
migrations.AddField(
model_name='abusereport',
name='reporter_email',
field=models.CharField(default=None, max_length=255, null=True),
),
migrations.AddField(
model_name='abusereport',
name='reporter_name',
field=models.CharField(default=None, max_length=255, null=True),
),
migrations.AlterField(
model_name='abusereport',
name='reason',
field=models.PositiveSmallIntegerField(
blank=True,
choices=[
(None, 'None'),
(1, 'Damages computer and/or data'),
(2, 'Creates spam or advertising'),
(
3,
'Changes search / homepage / new tab page without informing user',
),
(5, 'Doesnt work, breaks websites, or slows Firefox down'),
(6, 'Hateful, violent, or illegal content'),
(7, 'Pretends to be something its not'),
(9, "Wasn't wanted / impossible to get rid of"),
(11, 'DSA: Contains hate speech'),
(12, 'DSA: Contains child sexual abuse material'),
(
20,
'Feedback: Doesnt work, breaks websites, or slows Firefox down',
),
(21, "Feedback: Wasn't wanted or can't be uninstalled"),
(127, 'Other'),
],
default=None,
null=True,
),
),
]

Просмотреть файл

@ -0,0 +1,63 @@
# Generated by Django 4.2.5 on 2023-10-03 20:33
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import olympia.amo.models
class Migration(migrations.Migration):
dependencies = [
('abuse', '0009_abusereport_reporter_email_name_reasons'),
]
operations = [
migrations.CreateModel(
name='CinderReport',
fields=[
(
'created',
models.DateTimeField(
blank=True, default=django.utils.timezone.now, editable=False
),
),
('modified', models.DateTimeField(auto_now=True)),
('job_id', models.CharField(max_length=36)),
(
'abuse_report',
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
primary_key=True,
serialize=False,
to='abuse.abusereport',
),
),
(
'decision_action',
models.PositiveSmallIntegerField(
choices=[
(0, 'No decision'),
(1, 'User ban'),
(2, 'Add-on disable'),
(3, 'Escalate add-on to reviewers'),
(4, 'Escalate add-on to reviewers'),
(5, 'Rating delete'),
(6, 'Collection delete'),
(7, 'Approved (no action)'),
],
default=0,
),
),
(
'decision_id',
models.CharField(default=None, max_length=36, null=True),
),
],
options={
'get_latest_by': 'created',
'abstract': False,
'base_manager_name': 'objects',
},
bases=(olympia.amo.models.SaveUpdateMixin, models.Model),
),
]

Просмотреть файл

@ -4,7 +4,7 @@ from extended_choices import Choices
from olympia import amo from olympia import amo
from olympia.amo.models import BaseQuerySet, ManagerBase, ModelBase from olympia.amo.models import BaseQuerySet, ManagerBase, ModelBase
from olympia.api.utils import APIChoicesWithNone from olympia.api.utils import APIChoices, APIChoicesWithNone
from olympia.users.models import UserProfile from olympia.users.models import UserProfile
@ -58,6 +58,7 @@ class AbuseReport(ModelBase):
('PRIVILEGED', 12, 'Privileged'), ('PRIVILEGED', 12, 'Privileged'),
) )
REASONS = APIChoicesWithNone( REASONS = APIChoicesWithNone(
# Reporting reasons used in Firefox
('DAMAGE', 1, 'Damages computer and/or data'), ('DAMAGE', 1, 'Damages computer and/or data'),
('SPAM', 2, 'Creates spam or advertising'), ('SPAM', 2, 'Creates spam or advertising'),
( (
@ -74,6 +75,16 @@ class AbuseReport(ModelBase):
# previous one. We avoid re-using the value. # previous one. We avoid re-using the value.
('UNWANTED', 9, "Wasn't wanted / impossible to get rid of"), ('UNWANTED', 9, "Wasn't wanted / impossible to get rid of"),
# `10` was previously "Other". We avoid re-using the value. # `10` was previously "Other". We avoid re-using the value.
# Reporting reasons used in AMO Feedback flow - DSA categories
('HATE_SPEECH', 11, 'DSA: Contains hate speech'),
('CSAM', 12, 'DSA: Contains child sexual abuse material'),
# Reporting reasons used in AMO Feedback flow - Feedback (non-DSA) categories
(
'DOES_NOT_WORK',
20,
'Feedback: Doesnt work, breaks websites, or slows Firefox down',
),
('NOT_WANTED', 21, "Feedback: Wasn't wanted or can't be uninstalled"),
('OTHER', 127, 'Other'), ('OTHER', 127, 'Other'),
) )
@ -150,7 +161,7 @@ class AbuseReport(ModelBase):
('DELETED', 4, 'Deleted'), ('DELETED', 4, 'Deleted'),
) )
# NULL if the reporter is anonymous. # NULL if the reporter was not authenticated.
reporter = models.ForeignKey( reporter = models.ForeignKey(
UserProfile, UserProfile,
null=True, null=True,
@ -158,6 +169,9 @@ class AbuseReport(ModelBase):
related_name='abuse_reported', related_name='abuse_reported',
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
) )
# name and/or email can be provided instead for unauthenticated reporters
reporter_email = models.CharField(max_length=255, default=None, null=True)
reporter_name = models.CharField(max_length=255, default=None, null=True)
country_code = models.CharField(max_length=2, default=None, null=True) country_code = models.CharField(max_length=2, default=None, null=True)
# An abuse report can be for an addon or a user. # An abuse report can be for an addon or a user.
# If user is set then guid should be null. # If user is set then guid should be null.
@ -279,3 +293,25 @@ class AbuseReport(ModelBase):
def __str__(self): def __str__(self):
name = self.guid if self.guid else self.user name = self.guid if self.guid else self.user
return f'Abuse Report for {self.type} {name}' return f'Abuse Report for {self.type} {name}'
class CinderReport(ModelBase):
DECISION_ACTIONS = APIChoices(
('NO_DECISION', 0, 'No decision'),
('AMO_BAN_USER', 1, 'User ban'),
('AMO_DISABLE_ADDON', 2, 'Add-on disable'),
('AMO_ESCALATE_ADDON', 3, 'Escalate add-on to reviewers'),
('AMO_ESCALATE_USER', 4, 'Escalate add-on to reviewers'),
('AMO_DELETE_RATING', 5, 'Rating delete'),
('AMO_DELETE_COLLECTION', 6, 'Collection delete'),
('AMO_APPROVE', 7, 'Approved (no action)'),
)
job_id = models.CharField(max_length=36)
abuse_report = models.OneToOneField(
AbuseReport, on_delete=models.CASCADE, primary_key=True
)
decision_action = models.PositiveSmallIntegerField(
default=DECISION_ACTIONS.NO_DECISION, choices=DECISION_ACTIONS.choices
)
decision_id = models.CharField(max_length=36, default=None, null=True)

Просмотреть файл

@ -46,6 +46,10 @@ class TestAbuse(TestCase):
(6, 'Hateful, violent, or illegal content'), (6, 'Hateful, violent, or illegal content'),
(7, 'Pretends to be something its not'), (7, 'Pretends to be something its not'),
(9, "Wasn't wanted / impossible to get rid of"), (9, "Wasn't wanted / impossible to get rid of"),
(11, 'DSA: Contains hate speech'),
(12, 'DSA: Contains child sexual abuse material'),
(20, 'Feedback: Doesnt work, breaks websites, or slows Firefox down'),
(21, "Feedback: Wasn't wanted or can't be uninstalled"),
(127, 'Other'), (127, 'Other'),
) )
assert AbuseReport.REASONS.api_choices == ( assert AbuseReport.REASONS.api_choices == (
@ -57,6 +61,10 @@ class TestAbuse(TestCase):
(6, 'policy'), (6, 'policy'),
(7, 'deceptive'), (7, 'deceptive'),
(9, 'unwanted'), (9, 'unwanted'),
(11, 'hate_speech'),
(12, 'csam'),
(20, 'does_not_work'),
(21, 'not_wanted'),
(127, 'other'), (127, 'other'),
) )