Skip to content

Commit

Permalink
add abuse report (bug 546830)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy McKay committed Nov 4, 2010
1 parent 7906ad5 commit edb1ff2
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 3 deletions.
17 changes: 17 additions & 0 deletions apps/addons/forms.py
@@ -1,6 +1,7 @@
import re

from django import forms
from django.conf import settings

import happyforms

Expand Down Expand Up @@ -91,3 +92,19 @@ class Meta:
'get_satisfaction_product',)

exclude = ('status', )

import captcha.fields

class AbuseForm(happyforms.Form):
recaptcha = captcha.fields.ReCaptchaField(label='')
text = forms.CharField(required=True,
label=_('Please report abuse in the form below.'),
widget=forms.Textarea())

def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(AbuseForm, self).__init__(*args, **kwargs)

if (not self.request.user.is_anonymous() or
not settings.RECAPTCHA_PRIVATE_KEY):
del self.fields['recaptcha']
6 changes: 6 additions & 0 deletions apps/addons/helpers.py
Expand Up @@ -158,3 +158,9 @@ def persona_preview(context, persona, size='large', linked=True, extra=None,
@jinja2.contextfunction
def persona_grid(context, addons):
return new_context(**locals())


@register.inclusion_tag('addons/report_abuse.html')
@jinja2.contextfunction
def report_abuse(context, hide, addon):
return new_context(**locals())
6 changes: 6 additions & 0 deletions apps/addons/templates/addons/details.html
Expand Up @@ -27,6 +27,7 @@ <h4 class="author">{{ _('by') }} {{ users_list(addon.listed_authors) }}</h4>
{# TODO(fwenzel): "add-on has been added to collection" notification #}

<div id="addon" class="primary" role="main" data-id="{{ addon.id }}">
{% include "messages.html" %}
<div class="featured">
<div class="featured-inner object-lead inverse">

Expand Down Expand Up @@ -197,6 +198,10 @@ <h3 id="releasenotes">{{ _('Release Notes', 'addons_display_release_notes') }}</
{{ version_detail(addon, version, src="addon-detail-version") }}
{% endif %}

{% if abuse_form %}
{{ report_abuse(hide=True, addon=addon) }}
{% endif %}

</div>{# /primary #}

<div class="secondary" role="navigation">
Expand Down Expand Up @@ -325,4 +330,5 @@ <h3 class="compact-bottom">{{ _('Related Collections') }}</h3>
{# /collections #}

</div>{# /secondary #}

{% endblock content %}
4 changes: 4 additions & 0 deletions apps/addons/templates/addons/personas_detail.html
Expand Up @@ -116,6 +116,10 @@ <h3>{{ _('More by this Artist') }}</h3>
{{ review_add_box(addon=addon) }}
{% endif %}

{% if abuse_form %}
{{ report_abuse(hide=True, addon=addon) }}
{% endif %}

</div>{# /primary #}

<div id="persona-side" class="secondary" role="navigation">
Expand Down
19 changes: 19 additions & 0 deletions apps/addons/templates/addons/report_abuse.html
@@ -0,0 +1,19 @@
<div id="addon" class="primary">
<form method="post" action="{{ url('addons.abuse', addon.pk) }}">
<fieldset class="abuse">
{% if hide %}<legend><a href="#">{{ _('Report Abuse') }}</a></legend>{% endif %}
<ol>
<li>
{{ csrf() }}
{{ abuse_form.as_p()|safe }}
</li>
<li>
<button type="submit">{{ _('Send Report') }}</button>
{% if hide %}
or <button type="reset" class="link">{{ _('Cancel') }}</button>
{% endif %}
</li>
</ol>
</fieldset>
</form>
</div>
18 changes: 18 additions & 0 deletions 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 %}

<header>
{{ breadcrumbs([(addon.type_url(), amo.ADDON_TYPES[addon.type]),
(addon.get_url_path(), addon.name),
(None, _('Add Abuse'))]) }}
<h2>{{ title }}</h2>
</header>

{{ report_abuse(hide=False, addon=addon) }}

{% endblock %}
81 changes: 80 additions & 1 deletion apps/addons/tests/test_views.py
Expand Up @@ -7,10 +7,12 @@
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
Expand All @@ -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',
Expand Down Expand Up @@ -801,3 +804,79 @@ def test_redirect_sharing(self):
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)
1 change: 1 addition & 0 deletions apps/addons/urls.py
Expand Up @@ -11,6 +11,7 @@
url('^eula/(?P<file_id>\d+)?$', views.eula, name='addons.eula'),
url('^license/(?P<version>[^/]+)?', 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'),
Expand Down
41 changes: 41 additions & 0 deletions apps/addons/views.py
Expand Up @@ -10,11 +10,15 @@

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
Expand All @@ -28,6 +32,9 @@
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):
Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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]))
4 changes: 2 additions & 2 deletions media/css/zamboni/zamboni.css
Expand Up @@ -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 {
Expand Down
12 changes: 12 additions & 0 deletions media/js/zamboni/addon_details.js
Expand Up @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions settings.py
Expand Up @@ -653,3 +653,6 @@ def read_only_mode(env):

# Performance notes on add-ons
PERFORMANCE_NOTES = False

# flag to turn on or off Abuse reports
REPORT_ABUSE = True

0 comments on commit edb1ff2

Please sign in to comment.