@@ -197,6 +198,10 @@
{{ version_detail(addon, version, src="addon-detail-version") }}
{% endif %}
+ {% if abuse_form %}
+ {{ report_abuse(hide=True, addon=addon) }}
+ {% endif %}
+
{# /primary #}
@@ -325,4 +330,5 @@
{# /collections #}
{# /secondary #}
+
{% endblock content %}
diff --git a/apps/addons/templates/addons/personas_detail.html b/apps/addons/templates/addons/personas_detail.html
index 3184d4a9d1..e566f3855f 100644
--- a/apps/addons/templates/addons/personas_detail.html
+++ b/apps/addons/templates/addons/personas_detail.html
@@ -116,6 +116,10 @@
{{ review_add_box(addon=addon) }}
{% endif %}
+ {% if abuse_form %}
+ {{ report_abuse(hide=True, addon=addon) }}
+ {% endif %}
+
diff --git a/apps/addons/templates/addons/report_abuse.html b/apps/addons/templates/addons/report_abuse.html
new file mode 100644
index 0000000000..48b3909a81
--- /dev/null
+++ b/apps/addons/templates/addons/report_abuse.html
@@ -0,0 +1,19 @@
+
+ {{ breadcrumbs([(addon.type_url(), amo.ADDON_TYPES[addon.type]),
+ (addon.get_url_path(), addon.name),
+ (None, _('Add Abuse'))]) }}
+
+
+{{ report_abuse(hide=False, addon=addon) }}
+
+{% endblock %}
diff --git a/apps/addons/tests/test_views.py b/apps/addons/tests/test_views.py
index d314fefb28..836fabe660 100644
--- a/apps/addons/tests/test_views.py
+++ b/apps/addons/tests/test_views.py
@@ -7,10 +7,12 @@ from django.conf import settings
from django.core.cache import cache
from django.utils import translation
from django.utils.encoding import iri_to_uri
+from django.core import mail
-from nose.tools import eq_, set_trace
+from nose.tools import eq_
import test_utils
from pyquery import PyQuery as pq
+from mock import patch
import amo
from amo.helpers import absolutify
@@ -28,6 +30,7 @@ def norm(s):
"""Normalize a string so that whitespace is uniform."""
return re.sub(r'[\s]+', ' ', str(s)).strip()
+
class TestHomepage(test_utils.TestCase):
fixtures = ['base/apps',
'base/users',
@@ -801,3 +804,79 @@ class TestAddonSharing(test_utils.TestCase):
assert iri_to_uri(addon.name) in r['Location']
assert iri_to_uri(url) in r['Location']
assert iri_to_uri(summary) in r['Location']
+
+
+class TestReportAbuse(test_utils.TestCase):
+ fixtures = ['addons/persona',
+ 'base/apps',
+ 'base/addon_3615',
+ 'base/users']
+
+ @patch('captcha.fields.ReCaptchaField.clean')
+ def test_abuse_anonymous(self, clean):
+ clean.return_value = ""
+ self.client.post(reverse('addons.abuse', args=[3615]),
+ {'text': 'spammy'})
+ eq_(len(mail.outbox), 1)
+ assert 'spammy' in mail.outbox[0].body
+
+ def test_abuse_anonymous_fails(self):
+ r = self.client.post(reverse('addons.abuse', args=[3615]),
+ {'text': 'spammy'})
+ assert 'recaptcha' in r.context['abuse_form'].errors
+
+ def test_abuse_logged_in(self):
+ self.client.login(username='regular@mozilla.com', password='password')
+ self.client.post(reverse('addons.abuse', args=[3615]),
+ {'text': 'spammy'})
+ eq_(len(mail.outbox), 1)
+ assert 'spammy' in mail.outbox[0].body
+
+ def test_abuse_persona(self):
+ r = self.client.get(reverse('addons.detail', args=[15663]))
+ doc = pq(r.content)
+ assert doc("fieldset.abuse")
+
+ # and now just test it works
+ self.client.login(username='regular@mozilla.com', password='password')
+ self.client.post(reverse('addons.abuse', args=[15663]),
+ {'text': 'spammy'})
+ eq_(len(mail.outbox), 1)
+ assert 'spammy' in mail.outbox[0].body
+
+
+class TestReportAbuseDisabled(test_utils.TestCase):
+ fixtures = ['addons/persona',
+ 'base/apps',
+ 'base/addon_3615',
+ 'base/users']
+
+ def setUp(self):
+ settings.REPORT_ABUSE = False
+
+ def tearDown(self):
+ settings.REPORT_ABUSE = True
+
+ def test_abuse_persona(self):
+ r = self.client.get(reverse('addons.detail', args=[15663]))
+ doc = pq(r.content)
+ assert not doc("fieldset.abuse")
+
+ def test_abuse_fails_anonymous(self):
+ r = self.client.get(reverse('addons.detail', args=[3615]))
+ doc = pq(r.content)
+ assert not doc("fieldset.abuse")
+
+ res = self.client.post(reverse('addons.abuse', args=[3615]),
+ {'text': 'spammy'})
+ eq_(res.status_code, 404)
+
+ def test_abuse_fails_logged_in(self):
+ self.client.login(username='regular@mozilla.com', password='password')
+ r = self.client.get(reverse('addons.detail', args=[3615]))
+ doc = pq(r.content)
+ assert not doc("fieldset.abuse")
+
+ res = self.client.post(reverse('addons.abuse', args=[3615]),
+ {'text': 'spammy'})
+ eq_(res.status_code, 404)
diff --git a/apps/addons/urls.py b/apps/addons/urls.py
index 5a65abf1f9..2521369046 100644
--- a/apps/addons/urls.py
+++ b/apps/addons/urls.py
@@ -11,6 +11,7 @@ detail_patterns = patterns('',
url('^eula/(?P\d+)?$', views.eula, name='addons.eula'),
url('^license/(?P[^/]+)?', views.license, name='addons.license'),
url('^privacy/', views.privacy, name='addons.privacy'),
+ url('^abuse/', views.report_abuse, name='addons.abuse'),
url('^share$', views.share, name='addons.share'),
url('^developers$', views.developers,
{'page': 'developers'}, name='addons.meet'),
diff --git a/apps/addons/views.py b/apps/addons/views.py
index 794ffdfbca..28ceab6bb8 100644
--- a/apps/addons/views.py
+++ b/apps/addons/views.py
@@ -10,11 +10,15 @@ from django.utils import http as urllib
import caching.base as caching
import jingo
+import commonware.log
+
from tower import ugettext_lazy as _lazy
from tower import ugettext as _
import amo
+from amo import messages
from amo.utils import sorted_groupby, randslice
+from amo.utils import send_mail
from amo.helpers import absolutify
from amo import urlresolvers
from amo.urlresolvers import reverse
@@ -28,6 +32,9 @@ from translations.query import order_by_translation
from translations.helpers import truncate
from versions.models import Version
from .models import Addon
+from .forms import AbuseForm
+
+log = commonware.log.getLogger('z.addons')
def author_addon_clicked(f):
@@ -132,6 +139,9 @@ def extension_detail(request, addon):
'collections': collections.order_by('-subscribers')[:3],
}
+ if settings.REPORT_ABUSE:
+ data['abuse_form'] = AbuseForm(request=request)
+
return jingo.render(request, 'addons/details.html', data)
@@ -177,6 +187,8 @@ def persona_detail(request, addon):
'author_gallery': settings.PERSONAS_USER_ROOT % persona.author,
'search_cat': 'personas',
}
+ if settings.REPORT_ABUSE:
+ data['abuse_form'] = AbuseForm(request=request)
return jingo.render(request, 'addons/personas_detail.html', data)
@@ -478,3 +490,32 @@ def license(request, addon_id, version=None):
def license_redirect(request, version):
version = get_object_or_404(Version, pk=version)
return redirect(version.license_url(), permanent=True)
+
+
+def report_abuse(request, addon_id):
+ if not settings.REPORT_ABUSE:
+ raise http.Http404()
+
+ addon = get_object_or_404(Addon, pk=addon_id)
+ form = AbuseForm(request.POST or None, request=request)
+ if request.method == "POST" and form.is_valid():
+ if request.user.is_anonymous():
+ user_name = 'An anonymous user'
+ else:
+ user_name = '%s (%s)' % (request.amo_user.name,
+ request.amo_user.email)
+
+ subject = 'Abuse Report for %s' % addon.name
+ msg = u'%s reported abuse for %s (%s%s).\n\n%s'
+ msg = msg % (user_name, addon.name, settings.SITE_URL,
+ reverse('addons.detail', args=[addon.pk]),
+ form.cleaned_data['text'])
+
+ messages.success(request, _('Abuse reported.'))
+ log.debug('Abuse reported by %s for %s.' % (user_name, addon_id))
+ send_mail(subject, msg, recipient_list=(settings.FLIGTAR,))
+
+ else:
+ return jingo.render(request, 'addons/report_abuse_full.html',
+ {'addon': addon, 'abuse_form': form, })
+ return redirect(reverse('addons.detail', args=[addon.pk]))
diff --git a/media/css/zamboni/zamboni.css b/media/css/zamboni/zamboni.css
index bc0cb723ab..098eca98f7 100644
--- a/media/css/zamboni/zamboni.css
+++ b/media/css/zamboni/zamboni.css
@@ -1962,10 +1962,10 @@ form .error .note.error {
font-weight: bold;
}
-.abuse legend span {
+.abuse legend a {
padding-left: 25px;
color: #05e;
- background: transparent url("../../img/amo2009/icons/icons.png") 0 -1700px no-repeat;
+ background: transparent url("../../img/zamboni/notifications.png") 0 -305px no-repeat;
}
.html-rtl .abuse legend span {
diff --git a/media/js/zamboni/addon_details.js b/media/js/zamboni/addon_details.js
index d8b9ec6b72..a20842fca8 100644
--- a/media/js/zamboni/addon_details.js
+++ b/media/js/zamboni/addon_details.js
@@ -83,6 +83,18 @@ $(document).ready(function() {
var etiquette_box = $("#addons-display-review-etiquette").hide();
$("#short-review").focus(function() { etiquette_box.show("fast"); } );
+
+ var abuse = $("fieldset.abuse");
+ if (abuse.find("legend a").length) {
+ abuse.find("ol").hide();
+ abuse.find("legend a").click(function() {
+ abuse.find("ol").slideToggle("fast");
+ return false;
+ });
+ abuse.find("button[type=reset]").click(function() {
+ abuse.find("ol").slideToggle("fast");
+ });
+ }
});
/* get satisfaction initialization */
diff --git a/settings.py b/settings.py
index 0064df3c22..fd7c251725 100644
--- a/settings.py
+++ b/settings.py
@@ -653,3 +653,6 @@ ASYNC_SIGNALS = True
# Performance notes on add-ons
PERFORMANCE_NOTES = False
+
+# flag to turn on or off Abuse reports
+REPORT_ABUSE = True
+
+
diff --git a/apps/addons/templates/addons/report_abuse_full.html b/apps/addons/templates/addons/report_abuse_full.html
new file mode 100644
index 0000000000..0b471cf329
--- /dev/null
+++ b/apps/addons/templates/addons/report_abuse_full.html
@@ -0,0 +1,18 @@
+{% extends "base_side_categories.html" %}
+
+{% set title = _('Report abuse for {0}')|f(addon.name) %}
+
+{% block title %}{{ page_title(title) }}{% endblock %}
+
+{% block content %}
+
+