This commit is contained in:
Andy McKay 2010-11-03 15:49:17 -07:00
Родитель 7906ad514f
Коммит edb1ff2297
12 изменённых файлов: 209 добавлений и 3 удалений

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

@ -1,6 +1,7 @@
import re import re
from django import forms from django import forms
from django.conf import settings
import happyforms import happyforms
@ -91,3 +92,19 @@ class AddonForm(happyforms.ModelForm):
'get_satisfaction_product',) 'get_satisfaction_product',)
exclude = ('status', ) 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']

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

@ -158,3 +158,9 @@ def persona_preview(context, persona, size='large', linked=True, extra=None,
@jinja2.contextfunction @jinja2.contextfunction
def persona_grid(context, addons): def persona_grid(context, addons):
return new_context(**locals()) return new_context(**locals())
@register.inclusion_tag('addons/report_abuse.html')
@jinja2.contextfunction
def report_abuse(context, hide, addon):
return new_context(**locals())

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

@ -27,6 +27,7 @@
{# TODO(fwenzel): "add-on has been added to collection" notification #} {# TODO(fwenzel): "add-on has been added to collection" notification #}
<div id="addon" class="primary" role="main" data-id="{{ addon.id }}"> <div id="addon" class="primary" role="main" data-id="{{ addon.id }}">
{% include "messages.html" %}
<div class="featured"> <div class="featured">
<div class="featured-inner object-lead inverse"> <div class="featured-inner object-lead inverse">
@ -197,6 +198,10 @@
{{ version_detail(addon, version, src="addon-detail-version") }} {{ version_detail(addon, version, src="addon-detail-version") }}
{% endif %} {% endif %}
{% if abuse_form %}
{{ report_abuse(hide=True, addon=addon) }}
{% endif %}
</div>{# /primary #} </div>{# /primary #}
<div class="secondary" role="navigation"> <div class="secondary" role="navigation">
@ -325,4 +330,5 @@
{# /collections #} {# /collections #}
</div>{# /secondary #} </div>{# /secondary #}
{% endblock content %} {% endblock content %}

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

@ -116,6 +116,10 @@
{{ review_add_box(addon=addon) }} {{ review_add_box(addon=addon) }}
{% endif %} {% endif %}
{% if abuse_form %}
{{ report_abuse(hide=True, addon=addon) }}
{% endif %}
</div>{# /primary #} </div>{# /primary #}
<div id="persona-side" class="secondary" role="navigation"> <div id="persona-side" class="secondary" role="navigation">

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

@ -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>

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

@ -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 %}

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

@ -7,10 +7,12 @@ from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.utils import translation from django.utils import translation
from django.utils.encoding import iri_to_uri 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 import test_utils
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
from mock import patch
import amo import amo
from amo.helpers import absolutify from amo.helpers import absolutify
@ -28,6 +30,7 @@ def norm(s):
"""Normalize a string so that whitespace is uniform.""" """Normalize a string so that whitespace is uniform."""
return re.sub(r'[\s]+', ' ', str(s)).strip() return re.sub(r'[\s]+', ' ', str(s)).strip()
class TestHomepage(test_utils.TestCase): class TestHomepage(test_utils.TestCase):
fixtures = ['base/apps', fixtures = ['base/apps',
'base/users', 'base/users',
@ -801,3 +804,79 @@ class TestAddonSharing(test_utils.TestCase):
assert iri_to_uri(addon.name) in r['Location'] assert iri_to_uri(addon.name) in r['Location']
assert iri_to_uri(url) in r['Location'] assert iri_to_uri(url) in r['Location']
assert iri_to_uri(summary) 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)

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

@ -11,6 +11,7 @@ detail_patterns = patterns('',
url('^eula/(?P<file_id>\d+)?$', views.eula, name='addons.eula'), url('^eula/(?P<file_id>\d+)?$', views.eula, name='addons.eula'),
url('^license/(?P<version>[^/]+)?', views.license, name='addons.license'), url('^license/(?P<version>[^/]+)?', views.license, name='addons.license'),
url('^privacy/', views.privacy, name='addons.privacy'), url('^privacy/', views.privacy, name='addons.privacy'),
url('^abuse/', views.report_abuse, name='addons.abuse'),
url('^share$', views.share, name='addons.share'), url('^share$', views.share, name='addons.share'),
url('^developers$', views.developers, url('^developers$', views.developers,
{'page': 'developers'}, name='addons.meet'), {'page': 'developers'}, name='addons.meet'),

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

@ -10,11 +10,15 @@ from django.utils import http as urllib
import caching.base as caching import caching.base as caching
import jingo import jingo
import commonware.log
from tower import ugettext_lazy as _lazy from tower import ugettext_lazy as _lazy
from tower import ugettext as _ from tower import ugettext as _
import amo import amo
from amo import messages
from amo.utils import sorted_groupby, randslice from amo.utils import sorted_groupby, randslice
from amo.utils import send_mail
from amo.helpers import absolutify from amo.helpers import absolutify
from amo import urlresolvers from amo import urlresolvers
from amo.urlresolvers import reverse from amo.urlresolvers import reverse
@ -28,6 +32,9 @@ from translations.query import order_by_translation
from translations.helpers import truncate from translations.helpers import truncate
from versions.models import Version from versions.models import Version
from .models import Addon from .models import Addon
from .forms import AbuseForm
log = commonware.log.getLogger('z.addons')
def author_addon_clicked(f): def author_addon_clicked(f):
@ -132,6 +139,9 @@ def extension_detail(request, addon):
'collections': collections.order_by('-subscribers')[:3], 'collections': collections.order_by('-subscribers')[:3],
} }
if settings.REPORT_ABUSE:
data['abuse_form'] = AbuseForm(request=request)
return jingo.render(request, 'addons/details.html', data) 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, 'author_gallery': settings.PERSONAS_USER_ROOT % persona.author,
'search_cat': 'personas', 'search_cat': 'personas',
} }
if settings.REPORT_ABUSE:
data['abuse_form'] = AbuseForm(request=request)
return jingo.render(request, 'addons/personas_detail.html', data) 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): def license_redirect(request, version):
version = get_object_or_404(Version, pk=version) version = get_object_or_404(Version, pk=version)
return redirect(version.license_url(), permanent=True) 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]))

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

@ -1962,10 +1962,10 @@ form .error .note.error {
font-weight: bold; font-weight: bold;
} }
.abuse legend span { .abuse legend a {
padding-left: 25px; padding-left: 25px;
color: #05e; 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 { .html-rtl .abuse legend span {

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

@ -83,6 +83,18 @@ $(document).ready(function() {
var etiquette_box = $("#addons-display-review-etiquette").hide(); var etiquette_box = $("#addons-display-review-etiquette").hide();
$("#short-review").focus(function() { etiquette_box.show("fast"); } ); $("#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 */ /* get satisfaction initialization */

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

@ -653,3 +653,6 @@ ASYNC_SIGNALS = True
# Performance notes on add-ons # Performance notes on add-ons
PERFORMANCE_NOTES = False PERFORMANCE_NOTES = False
# flag to turn on or off Abuse reports
REPORT_ABUSE = True