Add Abuse reporting (#5975)
This commit is contained in:
Родитель
4f85865cc0
Коммит
04e09fe6f4
|
@ -0,0 +1,59 @@
|
|||
=============
|
||||
Abuse Reports
|
||||
=============
|
||||
|
||||
The following API endpoint covers abuse reporting
|
||||
|
||||
---------------------------------
|
||||
Submitting an add-on abuse report
|
||||
---------------------------------
|
||||
|
||||
.. _`addonabusereport-create`:
|
||||
|
||||
The following API endpoint allows an abuse report to be submitted for an Add-on,
|
||||
either listed on https://addons.mozilla.org or not.
|
||||
Authentication is not required, but is recommended so reports can be responded
|
||||
to if nessecary.
|
||||
|
||||
.. http:post:: /api/v3/abuse/report/addon/
|
||||
|
||||
.. _addonabusereport-create-request:
|
||||
|
||||
:<json string addon: The id, slug, or guid of the add-on to report for abuse (required).
|
||||
:<json string message: The body/content of the abuse report (required).
|
||||
:>json object|null reporter: The user who submitted the report, if authenticated.
|
||||
:>json int reporter.id: The id of the user who submitted the report.
|
||||
:>json string reporter.name: The name of the user who submitted the report.
|
||||
:>json string reporter.url: The link to the profile page for of the user who submitted the report.
|
||||
:>json object addon: The add-on reported for abuse.
|
||||
:>json string addon.guid: The add-on `extension identifier <https://developer.mozilla.org/en-US/Add-ons/Install_Manifests#id>`_.
|
||||
:>json int|null addon.id: The add-on id on AMO. If the guid submitted didn't match a known add-on on AMO, then null.
|
||||
:>json string|null addon.slug: The add-on slug. If the guid submitted didn't match a known add-on on AMO, then null.
|
||||
:>json string message: The body/content of the abuse report.
|
||||
|
||||
|
||||
------------------------------
|
||||
Submitting a user abuse report
|
||||
------------------------------
|
||||
|
||||
.. _`userabusereport-create`:
|
||||
|
||||
The following API endpoint allows an abuse report to be submitted for a user account
|
||||
on https://addons.mozilla.org. Authentication is not required, but is recommended
|
||||
so reports can be responded to if nessecary.
|
||||
|
||||
.. http:post:: /api/v3/abuse/report/user/
|
||||
|
||||
.. _userabusereport-create-request:
|
||||
|
||||
:<json string user: The id or username of the user to report for abuse (required).
|
||||
:<json string message: The body/content of the abuse report (required).
|
||||
:>json object|null reporter: The user who submitted the report, if authenticated.
|
||||
:>json int reporter.id: The id of the user who submitted the report.
|
||||
:>json string reporter.name: The name of the user who submitted the report.
|
||||
:>json string reporter.url: The link to the profile page for of the user who submitted the report.
|
||||
:>json object user: The user reported for abuse.
|
||||
:>json int user.id: The id of the user reported.
|
||||
:>json string user.name: The name of the user reported.
|
||||
:>json string user.url: The link to the profile page for of the user reported.
|
||||
:>json string message: The body/content of the abuse report.
|
|
@ -32,6 +32,7 @@ using the API.
|
|||
overview
|
||||
auth
|
||||
auth_internal
|
||||
abuse
|
||||
accounts
|
||||
activity
|
||||
addons
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from django.db.models import Q
|
||||
from .models import AbuseReport
|
||||
|
||||
|
||||
|
@ -32,14 +33,15 @@ class AbuseReportTypeFilter(admin.SimpleListFilter):
|
|||
if self.value() == 'user':
|
||||
return queryset.filter(user__isnull=False)
|
||||
elif self.value() == 'addon':
|
||||
return queryset.filter(addon__isnull=False)
|
||||
return queryset.filter(Q(addon__isnull=False) |
|
||||
Q(guid__isnull=False))
|
||||
return queryset
|
||||
|
||||
|
||||
class AbuseReportAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('addon', 'user', 'reporter')
|
||||
readonly_fields = ('ip_address', 'message', 'created', 'addon', 'user',
|
||||
'reporter')
|
||||
'guid', 'reporter')
|
||||
list_display = ('reporter', 'ip_address', 'type', 'target', 'message',
|
||||
'created')
|
||||
list_filter = (AbuseReportTypeFilter, )
|
||||
|
|
|
@ -14,9 +14,13 @@ class AbuseReport(ModelBase):
|
|||
reporter = models.ForeignKey(UserProfile, null=True,
|
||||
blank=True, related_name='abuse_reported')
|
||||
ip_address = models.CharField(max_length=255, default='0.0.0.0')
|
||||
# An abuse report can be for an addon or a user. Only one of these should
|
||||
# be null.
|
||||
# An abuse report can be for an addon or a user.
|
||||
# If user is non-null then both addon and guid should be null.
|
||||
# If user is null then addon should be non-null if guid was in our DB,
|
||||
# otherwise addon will be null also.
|
||||
# If both addon and user is null guid should be set.
|
||||
addon = models.ForeignKey(Addon, null=True, related_name='abuse_reports')
|
||||
guid = models.CharField(max_length=255, null=True)
|
||||
user = models.ForeignKey(UserProfile, null=True,
|
||||
related_name='abuse_reports')
|
||||
message = models.TextField()
|
||||
|
@ -30,11 +34,12 @@ class AbuseReport(ModelBase):
|
|||
else:
|
||||
user_name = 'An anonymous coward'
|
||||
|
||||
msg = u'%s reported abuse for %s (%s%s).\n\n%s' % (
|
||||
user_name, self.target.name, settings.SITE_URL,
|
||||
self.target.get_url_path(), self.message)
|
||||
send_mail(unicode(self), msg,
|
||||
recipient_list=(settings.ABUSE_EMAIL,))
|
||||
target_url = ('%s%s' % (settings.SITE_URL, self.target.get_url_path())
|
||||
if self.target else 'GUID not in database')
|
||||
name = self.target.name if self.target else self.guid
|
||||
msg = u'%s reported abuse for %s (%s).\n\n%s' % (
|
||||
user_name, name, target_url, self.message)
|
||||
send_mail(unicode(self), msg, recipient_list=(settings.ABUSE_EMAIL,))
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
|
@ -44,14 +49,16 @@ class AbuseReport(ModelBase):
|
|||
def type(self):
|
||||
with no_translation():
|
||||
type_ = (ugettext(amo.ADDON_TYPE[self.addon.type])
|
||||
if self.addon else 'User')
|
||||
if self.addon else 'User' if self.user else 'Addon')
|
||||
return type_
|
||||
|
||||
def __unicode__(self):
|
||||
return u'[%s] Abuse Report for %s' % (self.type, self.target.name)
|
||||
name = self.target.name if self.target else self.guid
|
||||
return u'[%s] Abuse Report for %s' % (self.type, name)
|
||||
|
||||
|
||||
def send_abuse_report(request, obj, message):
|
||||
# Only used by legacy frontend
|
||||
report = AbuseReport(ip_address=request.META.get('REMOTE_ADDR'),
|
||||
message=message)
|
||||
if request.user.is_authenticated():
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from olympia.abuse.models import AbuseReport
|
||||
from olympia.users.serializers import BaseUserSerializer
|
||||
|
||||
|
||||
class AddonAbuseReportSerializer(serializers.ModelSerializer):
|
||||
addon = serializers.SerializerMethodField()
|
||||
reporter = BaseUserSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = AbuseReport
|
||||
fields = ('reporter', 'addon', 'message')
|
||||
|
||||
def get_addon(self, obj):
|
||||
addon = obj.addon
|
||||
if not addon and not obj.guid:
|
||||
return None
|
||||
return {
|
||||
'guid': addon.guid if addon else obj.guid,
|
||||
'id': addon.id if addon else None,
|
||||
'slug': addon.slug if addon else None,
|
||||
}
|
||||
|
||||
|
||||
class UserAbuseReportSerializer(serializers.ModelSerializer):
|
||||
reporter = BaseUserSerializer(read_only=True)
|
||||
user = BaseUserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = AbuseReport
|
||||
fields = ('reporter', 'user', 'message')
|
|
@ -21,6 +21,8 @@ class TestAbuse(TestCase):
|
|||
AbuseReport.objects.create(
|
||||
addon=addon, ip_address='1.2.3.4', reporter=user_factory(),
|
||||
message='Bar')
|
||||
# This is a report for an addon not in the database
|
||||
AbuseReport.objects.create(guid='@guid', message='Foo')
|
||||
AbuseReport.objects.create(user=user_factory(), message='Eheheheh')
|
||||
|
||||
url = reverse('admin:abuse_abusereport_changelist')
|
||||
|
@ -29,12 +31,12 @@ class TestAbuse(TestCase):
|
|||
response = self.client.get(url)
|
||||
assert response.status_code == 200
|
||||
doc = pq(response.content)
|
||||
assert doc('#result_list tbody tr').length == 3
|
||||
assert doc('#result_list tbody tr').length == 4
|
||||
|
||||
response = self.client.get(url, {'type': 'addon'})
|
||||
assert response.status_code == 200
|
||||
doc = pq(response.content)
|
||||
assert doc('#result_list tbody tr').length == 2
|
||||
assert doc('#result_list tbody tr').length == 3
|
||||
|
||||
response = self.client.get(url, {'type': 'user'})
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -18,6 +18,7 @@ class TestAbuse(TestCase):
|
|||
assert (
|
||||
mail.outbox[0].subject ==
|
||||
u'[User] Abuse Report for regularuser التطب')
|
||||
assert 'user/regularuser' in mail.outbox[0].body
|
||||
|
||||
assert mail.outbox[0].to == [settings.ABUSE_EMAIL]
|
||||
|
||||
|
@ -30,6 +31,7 @@ class TestAbuse(TestCase):
|
|||
assert (
|
||||
mail.outbox[0].subject ==
|
||||
u'[Extension] Abuse Report for Delicious Bookmarks')
|
||||
assert 'addon/a3615' in mail.outbox[0].body
|
||||
|
||||
def test_addon_fr(self):
|
||||
with self.activate(locale='fr'):
|
||||
|
@ -41,3 +43,14 @@ class TestAbuse(TestCase):
|
|||
assert (
|
||||
mail.outbox[0].subject ==
|
||||
u'[Extension] Abuse Report for Delicious Bookmarks')
|
||||
|
||||
def test_guid(self):
|
||||
report = AbuseReport(guid='foo@bar.org')
|
||||
report.send()
|
||||
assert (
|
||||
unicode(report) ==
|
||||
u'[Addon] Abuse Report for foo@bar.org')
|
||||
assert (
|
||||
mail.outbox[0].subject ==
|
||||
u'[Addon] Abuse Report for foo@bar.org')
|
||||
assert 'GUID not in database' in mail.outbox[0].body
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
from olympia.abuse.models import AbuseReport
|
||||
from olympia.abuse.serializers import (
|
||||
AddonAbuseReportSerializer, UserAbuseReportSerializer)
|
||||
from olympia.amo.tests import (
|
||||
addon_factory, BaseTestCase, user_factory)
|
||||
from olympia.users.serializers import BaseUserSerializer
|
||||
|
||||
|
||||
class TestAddonAbuseReportSerializer(BaseTestCase):
|
||||
|
||||
def serialize(self, report, **extra_context):
|
||||
return AddonAbuseReportSerializer(report, context=extra_context).data
|
||||
|
||||
def test_addon_report(self):
|
||||
addon = addon_factory(guid='@guid')
|
||||
report = AbuseReport(addon=addon, message='bad stuff')
|
||||
serial = self.serialize(report)
|
||||
assert serial == {'reporter': None,
|
||||
'addon': {'guid': addon.guid,
|
||||
'id': addon.id,
|
||||
'slug': addon.slug},
|
||||
'message': 'bad stuff'}
|
||||
|
||||
def test_guid_report(self):
|
||||
report = AbuseReport(guid='@guid', message='bad stuff')
|
||||
serial = self.serialize(report)
|
||||
assert serial == {'reporter': None,
|
||||
'addon': {'guid': '@guid',
|
||||
'id': None,
|
||||
'slug': None},
|
||||
'message': 'bad stuff'}
|
||||
|
||||
|
||||
class TestUserAbuseReportSerializer(BaseTestCase):
|
||||
|
||||
def serialize(self, report, **extra_context):
|
||||
return UserAbuseReportSerializer(report, context=extra_context).data
|
||||
|
||||
def test_user_report(self):
|
||||
user = user_factory()
|
||||
report = AbuseReport(user=user, message='bad stuff')
|
||||
serial = self.serialize(report)
|
||||
user_serial = BaseUserSerializer(user).data
|
||||
assert serial == {'reporter': None,
|
||||
'user': user_serial,
|
||||
'message': 'bad stuff'}
|
|
@ -0,0 +1,217 @@
|
|||
import json
|
||||
|
||||
from django.core import mail
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from olympia import amo
|
||||
from olympia.abuse.models import AbuseReport
|
||||
from olympia.amo.tests import (
|
||||
addon_factory, APITestClient, TestCase, user_factory)
|
||||
|
||||
|
||||
class AddonAbuseReviewSetTestBase(object):
|
||||
client_class = APITestClient
|
||||
|
||||
def setUp(self):
|
||||
self.url = reverse('abusereportaddon-list')
|
||||
|
||||
def check_reporter(self, report):
|
||||
raise NotImplementedError
|
||||
|
||||
def check_report(self, report, text):
|
||||
assert unicode(report) == text
|
||||
assert report.ip_address == '123.45.67.89'
|
||||
assert mail.outbox[0].subject == text
|
||||
self.check_reporter(report)
|
||||
|
||||
def test_report_addon_by_id(self):
|
||||
addon = addon_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': unicode(addon.id), 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(addon_id=addon.id).exists()
|
||||
report = AbuseReport.objects.get(addon_id=addon.id)
|
||||
self.check_report(report,
|
||||
u'[Extension] Abuse Report for %s' % addon.name)
|
||||
|
||||
def test_report_addon_by_slug(self):
|
||||
addon = addon_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': addon.slug, 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(addon_id=addon.id).exists()
|
||||
report = AbuseReport.objects.get(addon_id=addon.id)
|
||||
self.check_report(report,
|
||||
u'[Extension] Abuse Report for %s' % addon.name)
|
||||
|
||||
def test_report_addon_by_guid(self):
|
||||
addon = addon_factory(guid='@badman')
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': addon.guid, 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(addon_id=addon.id).exists()
|
||||
report = AbuseReport.objects.get(addon_id=addon.id)
|
||||
self.check_report(report,
|
||||
u'[Extension] Abuse Report for %s' % addon.name)
|
||||
|
||||
def test_report_addon_guid_not_on_amo(self):
|
||||
guid = '@mysteryman'
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': guid, 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(guid=guid).exists()
|
||||
report = AbuseReport.objects.get(guid=guid)
|
||||
self.check_report(report,
|
||||
u'[Addon] Abuse Report for %s' % guid)
|
||||
|
||||
def test_report_addon_invalid_identifier(self):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': 'randomnotguid', 'message': 'abuse!'})
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_addon_not_public(self):
|
||||
addon = addon_factory(status=amo.STATUS_NULL)
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': unicode(addon.id), 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(addon_id=addon.id).exists()
|
||||
report = AbuseReport.objects.get(addon_id=addon.id)
|
||||
self.check_report(report,
|
||||
u'[Extension] Abuse Report for %s' % addon.name)
|
||||
|
||||
def test_no_addon_fails(self):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'message': 'abuse!'})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Need an addon parameter'}
|
||||
|
||||
def test_message_required(self):
|
||||
addon = addon_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': unicode(addon.id),
|
||||
'message': ''})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Abuse reports need a message'}
|
||||
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'addon': unicode(addon.id)})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Abuse reports need a message'}
|
||||
|
||||
|
||||
class TestAddonAbuseReviewSetLoggedOut(AddonAbuseReviewSetTestBase, TestCase):
|
||||
def check_reporter(self, report):
|
||||
assert not report.reporter
|
||||
|
||||
|
||||
class TestAddonAbuseReviewSetLoggedIn(AddonAbuseReviewSetTestBase, TestCase):
|
||||
def setUp(self):
|
||||
super(TestAddonAbuseReviewSetLoggedIn, self).setUp()
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
|
||||
def check_reporter(self, report):
|
||||
assert report.reporter == self.user
|
||||
|
||||
|
||||
class UserAbuseReviewSetTestBase(object):
|
||||
client_class = APITestClient
|
||||
|
||||
def setUp(self):
|
||||
self.url = reverse('abusereportuser-list')
|
||||
|
||||
def check_reporter(self, report):
|
||||
raise NotImplementedError
|
||||
|
||||
def check_report(self, report, text):
|
||||
assert unicode(report) == text
|
||||
assert report.ip_address == '123.45.67.89'
|
||||
assert mail.outbox[0].subject == text
|
||||
self.check_reporter(report)
|
||||
|
||||
def test_report_user_id(self):
|
||||
user = user_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'user': unicode(user.id), 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(user_id=user.id).exists()
|
||||
report = AbuseReport.objects.get(user_id=user.id)
|
||||
self.check_report(report,
|
||||
u'[User] Abuse Report for %s' % user.name)
|
||||
|
||||
def test_report_user_username(self):
|
||||
user = user_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'user': unicode(user.username), 'message': 'abuse!'},
|
||||
REMOTE_ADDR='123.45.67.89')
|
||||
assert response.status_code == 201
|
||||
|
||||
assert AbuseReport.objects.filter(user_id=user.id).exists()
|
||||
report = AbuseReport.objects.get(user_id=user.id)
|
||||
self.check_report(report,
|
||||
u'[User] Abuse Report for %s' % user.name)
|
||||
|
||||
def test_no_user_fails(self):
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'message': 'abuse!'})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Need a user parameter'}
|
||||
|
||||
def test_message_required(self):
|
||||
user = user_factory()
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'user': unicode(user.username), 'message': ''})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Abuse reports need a message'}
|
||||
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
data={'user': unicode(user.username)})
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.content) == {
|
||||
'detail': 'Abuse reports need a message'}
|
||||
|
||||
|
||||
class TestUserAbuseReviewSetLoggedOut(UserAbuseReviewSetTestBase, TestCase):
|
||||
def check_reporter(self, report):
|
||||
assert not report.reporter
|
||||
|
||||
|
||||
class TestUserAbuseReviewSetLoggedIn(UserAbuseReviewSetTestBase, TestCase):
|
||||
def setUp(self):
|
||||
super(TestUserAbuseReviewSetLoggedIn, self).setUp()
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
|
||||
def check_reporter(self, report):
|
||||
assert report.reporter == self.user
|
|
@ -0,0 +1,16 @@
|
|||
from django.conf.urls import include, url
|
||||
|
||||
from rest_framework.routers import SimpleRouter
|
||||
|
||||
from views import AddonAbuseViewSet, UserAbuseViewSet
|
||||
|
||||
|
||||
reporting = SimpleRouter()
|
||||
reporting.register(r'addon', AddonAbuseViewSet,
|
||||
base_name='abusereportaddon')
|
||||
reporting.register(r'user', UserAbuseViewSet,
|
||||
base_name='abusereportuser')
|
||||
|
||||
urlpatterns = [
|
||||
url(r'report/', include(reporting.urls)),
|
||||
]
|
|
@ -0,0 +1,117 @@
|
|||
from django.http import Http404
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework.mixins import CreateModelMixin
|
||||
|
||||
from olympia.accounts.views import AccountViewSet
|
||||
from olympia.abuse.models import AbuseReport
|
||||
from olympia.abuse.serializers import (
|
||||
AddonAbuseReportSerializer, UserAbuseReportSerializer)
|
||||
from olympia.addons.views import AddonViewSet
|
||||
|
||||
|
||||
class AddonAbuseViewSet(CreateModelMixin, GenericViewSet):
|
||||
permission_classes = []
|
||||
serializer_class = AddonAbuseReportSerializer
|
||||
|
||||
def get_addon_viewset(self):
|
||||
if hasattr(self, 'addon_viewset'):
|
||||
return self.addon_viewset
|
||||
|
||||
if 'addon_pk' not in self.kwargs:
|
||||
self.kwargs['addon_pk'] = (
|
||||
self.request.data.get('addon') or
|
||||
self.request.GET.get('addon'))
|
||||
self.addon_viewset = AddonViewSet(
|
||||
request=self.request, permission_classes=[],
|
||||
kwargs={'pk': self.kwargs['addon_pk']})
|
||||
return self.addon_viewset
|
||||
|
||||
def get_addon_object(self):
|
||||
if hasattr(self, 'addon_object'):
|
||||
return self.addon_object
|
||||
|
||||
self.addon_object = self.get_addon_viewset().get_object()
|
||||
return self.addon_object
|
||||
|
||||
def get_guid(self):
|
||||
# See if the addon input is guid-like, if so set guid.
|
||||
if self.get_addon_viewset().get_lookup_field(
|
||||
self.kwargs['addon_pk']) == 'guid':
|
||||
guid = self.kwargs['addon_pk']
|
||||
try:
|
||||
# But see if it's also in our database.
|
||||
self.get_addon_object()
|
||||
except Http404:
|
||||
# If it isn't, that's okay, we have a guid. Setting
|
||||
# addon_object=None here means get_addon_object won't raise 404
|
||||
self.addon_object = None
|
||||
return guid
|
||||
return None
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
addon_id = self.request.data.get('addon')
|
||||
if not addon_id:
|
||||
raise ParseError('Need an addon parameter')
|
||||
|
||||
message = self.request.data.get('message')
|
||||
if not message:
|
||||
raise ParseError('Abuse reports need a message')
|
||||
|
||||
abuse_kwargs = {
|
||||
'ip_address': request.META.get('REMOTE_ADDR'),
|
||||
'message': message,
|
||||
# get_guid() must be called first or addons not in our DB will 404.
|
||||
'guid': self.get_guid(),
|
||||
'addon': self.get_addon_object()}
|
||||
if request.user.is_authenticated():
|
||||
abuse_kwargs['reporter'] = request.user
|
||||
|
||||
report = AbuseReport.objects.create(**abuse_kwargs)
|
||||
report.send()
|
||||
|
||||
serializer = self.get_serializer(report)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
|
||||
class UserAbuseViewSet(CreateModelMixin, GenericViewSet):
|
||||
permission_classes = []
|
||||
serializer_class = UserAbuseReportSerializer
|
||||
|
||||
def get_user_object(self, user_id):
|
||||
if hasattr(self, 'user_object'):
|
||||
return self.user_object
|
||||
|
||||
if 'user_pk' not in self.kwargs:
|
||||
self.kwargs['user_pk'] = (
|
||||
self.request.data.get('user') or
|
||||
self.request.GET.get('user'))
|
||||
|
||||
return AccountViewSet(
|
||||
request=self.request, permission_classes=[],
|
||||
kwargs={'pk': self.kwargs['user_pk']}).get_object()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
user_id = self.request.data.get('user')
|
||||
if not user_id:
|
||||
raise ParseError('Need a user parameter')
|
||||
|
||||
message = self.request.data.get('message')
|
||||
if not message:
|
||||
raise ParseError('Abuse reports need a message')
|
||||
|
||||
abuse_kwargs = {
|
||||
'ip_address': request.META.get('REMOTE_ADDR'),
|
||||
'message': message,
|
||||
'user': self.get_user_object(user_id)}
|
||||
if request.user.is_authenticated():
|
||||
abuse_kwargs['reporter'] = request.user
|
||||
|
||||
report = AbuseReport.objects.create(**abuse_kwargs)
|
||||
report.send()
|
||||
|
||||
serializer = self.get_serializer(report)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
@ -626,7 +626,7 @@ class AddonViewSet(RetrieveModelMixin, GenericViewSet):
|
|||
|
||||
|
||||
class AddonChildMixin(object):
|
||||
"""Mixin containing method to retrive the parent add-on object."""
|
||||
"""Mixin containing method to retrieve the parent add-on object."""
|
||||
|
||||
def get_addon_object(self, permission_classes=None, lookup='addon_pk'):
|
||||
"""Return the parent Addon object using the URL parameter passed
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.conf.urls import include, url
|
|||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^v3/abuse/', include('olympia.abuse.urls')),
|
||||
url(r'^v3/accounts/', include('olympia.accounts.urls')),
|
||||
url(r'^v3/addons/', include('olympia.addons.api_urls')),
|
||||
url(r'^v3/', include('olympia.discovery.api_urls')),
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE `abuse_reports`
|
||||
ADD COLUMN `guid` CHAR(255) NULL;
|
Загрузка…
Ссылка в новой задаче