allow user reviews for apps (bug 691623)

This commit is contained in:
Chris Van 2011-10-28 15:24:36 -07:00
Родитель eb97e0cc18
Коммит c3ffe47bb1
34 изменённых файлов: 182 добавлений и 128 удалений

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

@ -25,7 +25,7 @@ import amo.models
import sharing.utils as sharing
from amo.decorators import use_master
from amo.fields import DecimalCharField
from amo.helpers import absolutify
from amo.helpers import absolutify, shared_url
from amo.utils import (send_mail, urlparams, sorted_groupby, JSONEncoder,
slugify, to_language)
from amo.urlresolvers import get_outgoing_url, reverse
@ -408,7 +408,7 @@ class Addon(amo.models.OnChangeMixin, amo.models.ModelBase):
@property
def reviews_url(self):
return reverse('reviews.list', args=[self.slug])
return shared_url('reviews.list', self)
def type_url(self):
"""The url for this add-on's AddonType."""

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

@ -10,8 +10,8 @@
data-name="{{ addon.name }}"
{{ b.attrs()|xmlattr }}
{% if waffle.switch('marketplace') and addon.can_be_purchased() %}
data-purchase="{{ addon_url('addons.purchase', addon) }}?"
data-start-purchase="{{ addon_url('addons.purchase.start', addon) }}"
data-purchase="{{ shared_url('addons.purchase', addon) }}?"
data-start-purchase="{{ shared_url('addons.purchase.start', addon) }}"
data-cost="{{ addon.premium.get_price() }}"
data-login-url="{{ url('users.login_modal') }}"
{% endif %}
@ -63,7 +63,7 @@
href="{{ b.addon.get_url_path() }}"
data-realurl="{{ link.url }}"
{% elif waffle.switch('marketplace') and addon.can_be_purchased() %}
href="{{ addon_url('addons.purchase', addon) }}"
href="{{ shared_url('addons.purchase', addon) }}"
{% if not addon.is_webapp() %}
data-realurl="{{ link.url }}"
{% endif %}

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

@ -16,7 +16,7 @@
{% include "reviews/grouped_ratings.html" %}
{% if addon.can_review(amo_user) %}
<div>
<a class="button" id="add-review" href="{{ url('reviews.add', addon.slug) }}">{{ _('Write a review') }}</a>
<a class="button" id="add-review" href="{{ shared_url('reviews.add', addon) }}">{{ _('Write a review') }}</a>
</div>
{% endif %}
<a id="report-abuse" href="{{ url('devhub.docs', 'policies', 'contact') }}"

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

@ -13,7 +13,7 @@
</p>
{% endif %}
<form disabled method="post" action="{{ url('reviews.add', addon.slug) }}">
<form disabled method="post" action="{{ shared_url('reviews.add', addon) }}">
{% set attrs = {} if user.is_authenticated() else {'disabled': 'disabled'} %}
{{ csrf() }}
{{ field(review_form.body, _('Review:'), **attrs) }}
@ -39,7 +39,7 @@
{% endif %}
<p><a href="{{ remora_url('/pages/review_guide') }}" target="_blank">{{ _('Review Guidelines') }}</a></p>
<p>
<a href="{{ url('reviews.add', addon.slug) }}">
<a href="{{ shared_url('reviews.add', addon) }}">
{{ _('Detailed Review') }}</a>
</p>
</div>

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

@ -42,7 +42,7 @@
{{ _('This add-on has not yet been reviewed.') }}
{% endif %}
{% if addon.can_review(amo_user) %}
<a id="add-first-review" href="{{ url('reviews.add', addon.slug) }}">
<a id="add-first-review" href="{{ shared_url('reviews.add', addon) }}">
{{ _('Be the first!') }}
</a>
{% endif %}

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

@ -23,9 +23,9 @@
{% else %}
<h4>{{ _('Payment completed') }}</h4>
{% if addon.is_premium() %}
<a href="{{ addon_url('addons.purchase.thanks', addon)|urlparams(realurl=realurl) }}"
<a href="{{ shared_url('addons.purchase.thanks', addon)|urlparams(realurl=realurl) }}"
id="paypal-thanks">{{ _('Thank you for purchasing the add-on') }}</a>
{% endif %}
{% endif %}
<p><a id="paypal-result" target="_top" href="{{ addon_url('addons.detail', addon) }}">{{ _('Return to the addon.') }}</a></p>
<p><a id="paypal-result" target="_top" href="{{ shared_url('addons.detail', addon) }}">{{ _('Return to the addon.') }}</a></p>
{% endblock %}

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

@ -41,7 +41,7 @@
{% endtrans %}
</div>
<button class="button prominent paypal"
href="{{ addon_url('addons.purchase', addon) }}?"
href="{{ shared_url('addons.purchase', addon) }}?"
data-realurl="{{ download }}">
{# The <small> makes it smaller, <em> makes it darker. Don't localize "PayPal". #}
{{ _('Pay <small>with</small> Pay<em>Pal</em>') }}
@ -49,7 +49,7 @@
<p>{{ _('Complete your purchase with PayPal. No account necessary.') }}</p>
{% else %}
<div class="paypal-user login">
{% with is_ajax=False, action="%s?realurl=%s" % (addon_url('addons.purchase.start', addon), download) %}
{% with is_ajax=False, action="%s?realurl=%s" % (shared_url('addons.purchase.start', addon), download) %}
{% include "users/login_form.html" %}
{% endwith %}
</div>

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

@ -39,7 +39,7 @@
addon.created|datetime(dt)) }}
</p>
{% if addon.total_reviews %}
<a href="{{ url('reviews.list', addon.slug) }}">
<a href="{{ shared_url('reviews.list', addon) }}">
{{ addon.average_rating|float|stars }}
{{ addon.total_reviews }}</a>
{% else %}

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

@ -84,7 +84,7 @@
</div>
{# Building a url with a fake addon that's replaced with a js placeholder? Sketchy. #}
<p class="older-versions">{% trans href=remora_url('/addons/versions/xxx')|replace('xxx', '{addon}') %}
{# <p class="older-versions">{% trans href=url('reviews.list', 000)|replace(000, '{addon}') %} #}
{# <p class="older-versions">{% trans href=url('addons.reviews.list', 000)|replace(000, '{addon}') %} #}
or view <a href="{{ href }}">older versions of this add-on</a>.
{% endtrans %}</p>
</div>

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

@ -1,4 +1,4 @@
<form method="post" action="{{ addon_url('addons.abuse', addon) }}">
<form method="post" action="{{ shared_url('addons.abuse', addon) }}">
<fieldset class="abuse">
{% if hide %}
<legend><a href="{{ url('devhub.docs', 'policies', 'contact') }}"

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

@ -11,7 +11,7 @@
</p>
{% endif %}
<form disabled method="post" action="{{ url('reviews.add', addon.slug) }}">
<form disabled method="post" action="{{ shared_url('reviews.add', addon) }}">
{% set attrs = {} if user.is_authenticated() else {'disabled': 'disabled'} %}
{{ csrf() }}
{{ field(review_form.body, _('Review:'), **attrs) }}
@ -37,7 +37,7 @@
{% endif %}
<p><a href="{{ remora_url('/pages/review_guide') }}" target="_blank">{{ _('Review Guidelines') }}</a></p>
<p>
<a href="{{ url('reviews.add', addon.slug) }}">
<a href="{{ shared_url('reviews.add', addon) }}">
{{ _('Detailed Review') }}</a>
</p>
</div>

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

@ -23,7 +23,7 @@
{% endfor %}
{% if addon %}
<p>
<a class="more-info" href="{{ url('reviews.list', addon.slug) }}">
<a class="more-info" href="{{ shared_url('reviews.list', addon) }}">
{% trans num=addon.total_reviews, cnt=addon.total_reviews|numberfmt %}
See all reviews of this add-on
{% pluralize %}

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

@ -21,7 +21,7 @@ import waffle
import amo
import amo.tests
from amo.helpers import absolutify, numberfmt, urlparams, addon_url
from amo.helpers import absolutify, numberfmt, urlparams, shared_url
from amo.tests import addon_factory
from amo.tests.test_helpers import get_image_path
from amo.urlresolvers import reverse
@ -450,7 +450,7 @@ class TestPaypalStart(amo.tests.TestCase):
self.data = {'username': 'jbalogh@mozilla.com',
'password': 'foo'}
self.addon = Addon.objects.all()[0]
self.url = addon_url('addons.purchase.start', self.addon)
self.url = shared_url('addons.purchase.start', self.addon)
self.addon, self.price = setup_premium(self.addon)
def test_loggedout_purchased(self):
@ -919,7 +919,8 @@ class TestDetailPage(amo.tests.TestCase):
r = self.client.get(reverse('addons.detail', args=['a3615']))
doc = pq(r.content)
href = doc('#review-box a[href*="reviews/add"]').attr('href')
assert href.endswith(reverse('reviews.add', args=['a3615'])), href
assert href.endswith(reverse('addons.reviews.add', args=['a3615'])), (
href)
def test_no_listed_authors(self):
r = self.client.get(reverse('addons.detail', args=['a59']))
@ -1520,8 +1521,8 @@ class TestReportAbuse(amo.tests.TestCase):
assert AbuseReport.objects.get(addon=addon)
def test_abuse_persona(self):
addon_url = reverse('addons.detail', args=['a15663'])
r = self.client.get(addon_url)
shared_url = reverse('addons.detail', args=['a15663'])
r = self.client.get(shared_url)
doc = pq(r.content)
assert doc("fieldset.abuse")
@ -1529,7 +1530,7 @@ class TestReportAbuse(amo.tests.TestCase):
self.client.login(username='regular@mozilla.com', password='password')
r = self.client.post(reverse('addons.abuse', args=['a15663']),
{'text': 'spammy'})
self.assertRedirects(r, addon_url)
self.assertRedirects(r, shared_url)
eq_(len(mail.outbox), 1)
assert 'spammy' in mail.outbox[0].body
assert AbuseReport.objects.get(addon=15663)

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

@ -2,6 +2,7 @@ from django.conf.urls.defaults import patterns, url, include
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import redirect
from reviews.urls import review_patterns
from . import views
ADDON_ID = r"""(?P<addon_id>[^/<>"']+)"""
@ -41,7 +42,7 @@ detail_patterns = patterns('',
addon_id, permanent=True),
name='addons.about'),
('^reviews/', include('reviews.urls')),
('^reviews/', include(review_patterns('addons'))),
('^statistics/', include('stats.urls')),
('^versions/', include('versions.urls')),
)

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

@ -89,19 +89,31 @@ def url(viewname, *args, **kwargs):
@register.function
def addon_url(viewname, addon, *args, **kwargs):
def shared_url(viewname, addon, *args, **kwargs):
"""
Helper specifically for addons or apps to get urls. Requires
the viewname, addon (or app). It's assumed that we'll pass the
slug into the args and we'll look up the right slug (addon or app)
for you.
Viewname should be a normal view eg: addons.details or apps.details,
this will flip the first part for you. eg: addons.details > apps.details.
Viewname should be a normal view eg: `addons.details` or `apps.details`.
`addons.details` becomes `apps.details`, if we've passed an app, etc.
A viewname such as `details` becomes `addons.details` or `apps.details`,
depending on the add-on type.
"""
slug = addon.app_slug if addon.is_webapp() else addon.slug
prefix = 'apps' if addon.is_webapp() else 'addons'
viewname = '%s.%s' % (prefix, viewname.split('.', 1)[-1])
namespace, dot, latter = viewname.partition('.')
# If `viewname` is prefixed with `addons.` but we're linking to a
# webapp, the `viewname` magically gets prefixed with `apps.`.
if namespace in ('addons', 'apps'):
viewname = latter
# Otherwise, we just slap the appropriate prefix in front of `viewname`.
viewname = '.'.join([prefix, viewname])
return url(viewname, *([slug] + list(args)), **kwargs)

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

@ -207,7 +207,7 @@ def test_urlparams_unicode():
utils.urlparams(url)
class TestAddonURL(amo.tests.TestCase):
class TestSharedURL(amo.tests.TestCase):
def setUp(self):
self.webapp = Mock()
@ -220,16 +220,26 @@ class TestAddonURL(amo.tests.TestCase):
self.addon.is_webapp.return_value = False
def test_appurl(self):
eq_(helpers.addon_url('addons.detail', self.webapp),
'/en-US/apps/app/webapp/')
eq_(helpers.addon_url('apps.detail', self.webapp),
'/en-US/apps/app/webapp/')
expected = '/en-US/apps/app/webapp/'
eq_(helpers.shared_url('addons.detail', self.webapp), expected)
eq_(helpers.shared_url('apps.detail', self.webapp), expected)
eq_(helpers.shared_url('detail', self.webapp), expected)
eq_(helpers.shared_url('detail', self.webapp, add_prefix=False),
'/apps/app/webapp/')
eq_(helpers.shared_url('reviews.detail', self.webapp, 1,
add_prefix=False),
'/apps/app/webapp/reviews/1/')
def test_addonurl(self):
eq_(helpers.addon_url('addons.detail', self.addon),
'/en-US/firefox/addon/addon/')
eq_(helpers.addon_url('apps.detail', self.addon),
'/en-US/firefox/addon/addon/')
expected = '/en-US/firefox/addon/addon/'
eq_(helpers.shared_url('addons.detail', self.addon), expected)
eq_(helpers.shared_url('apps.detail', self.addon), expected)
eq_(helpers.shared_url('detail', self.addon), expected)
eq_(helpers.shared_url('detail', self.addon, add_prefix=False),
'/addon/addon/')
eq_(helpers.shared_url('reviews.detail', self.addon, 1,
add_prefix=False),
'/addon/addon/reviews/1/')
def test_isotime():

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

@ -825,7 +825,7 @@ class TestModeratedQueue(QueueTest):
def setUp(self):
self.url = reverse('editors.queue_moderated')
url_flag = reverse('reviews.flag', args=['a1865', 218468])
url_flag = reverse('addons.reviews.flag', args=['a1865', 218468])
self.login_as_editor()
response = self.client.post(url_flag, {'flag': ReviewFlag.SPAM})

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

@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404
from tower import ugettext as _
from amo.urlresolvers import reverse
from amo.helpers import absolutify, url
from amo.helpers import absolutify, shared_url, url
from addons.models import Addon, Review
@ -40,8 +40,7 @@ class ReviewsRss(Feed):
def item_link(self, review):
"""Link for a particular review (<item><link>)"""
return absolutify(reverse('reviews.detail', args=[self.addon.slug,
review.id]))
return absolutify(shared_url('reviews.detail', self.addon, review.id))
def item_title(self, review):
"""Title for particular review (<item><title>)"""
@ -60,7 +59,7 @@ class ReviewsRss(Feed):
def item_guid(self, review):
"""Guid for a particuar review (<item><guid>)"""
guid_url = absolutify(reverse('reviews.list', args=[self.addon.slug]))
guid_url = absolutify(shared_url('reviews.list', self.addon))
return guid_url + urllib.quote(str(review.id))
def item_author_name(self, review):

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

@ -9,6 +9,7 @@ from celeryutils import task
from tower import ugettext_lazy as _
import amo.models
from amo.helpers import shared_url
from amo.urlresolvers import reverse
from translations.fields import TranslatedField
from users.models import UserProfile
@ -57,7 +58,7 @@ class Review(amo.models.ModelBase):
ordering = ('-created',)
def get_url_path(self):
return reverse('reviews.detail', args=[self.addon_id, self.id])
return shared_url('reviews.detail', self.addon, self.id)
def flush_urls(self):
urls = ['*/addon/%d/' % self.addon_id,

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

@ -1,4 +1,4 @@
{% extends "impala/base.html" %}
{% extends "impala/base_shared.html" %}
{% from 'includes/forms.html' import pretty_field, required_note %}
{% set title = _('Add a review for {0}')|f(addon.name) %}
@ -76,7 +76,7 @@
{% endif %}
</fieldset>
<form method="post" class="review-form" id="review-form"
action="{{ url('reviews.add', addon.slug) }}">
action="{{ shared_url('reviews.add', addon) }}">
{{ csrf() }}
<fieldset>
<ul>

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

@ -1,4 +1,4 @@
{% set base = url('addons.detail', addon.slug)|urlparams('reviews') %}
{% set base = addon.get_url_path()|urlparams('reviews') %}
{% if collection_uuid %}
{% set base = base|urlparams(collection_uuid=collection_uuid) %}
{% endif %}

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

@ -2,12 +2,12 @@
{% if not amo_user %}
<h2 id="add-review">{{ _('Add a Review') }}</h2>
<section class="copy">
<a href="{{ url('reviews.add', addon.slug) }}" class="login-button button">{{ _('Log in to add a review') }}</a>
<a href="{{ shared_url('reviews.add', addon) }}" class="login-button button">{{ _('Log in to add a review') }}</a>
</section>
{% elif addon.can_review(amo_user) %}
<h2 id="add-review">{{ _('Add a Review') }}</h2>
<form method="post" class="form-mobile review-form" id="review-form"
action="{{ url('reviews.add', addon.slug) }}">
action="{{ shared_url('reviews.add', addon) }}">
{{ csrf() }}
<p>
<label for="id_title">{{ _('Title:') }} <span class="optional">{{ _('(optional)') }}</span></label>

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

@ -1,6 +1,6 @@
{% set amo_user = request.amo_user if request and request.user.is_authenticated() else None %}
{% if addon.total_reviews %}
<a class="listview" href="{{ url('reviews.list', addon.slug) }}">
<a class="listview" href="{{ shared_url('reviews.list', addon) }}">
<div class="icon">
{{ addon.average_rating|stars }}
</div>
@ -11,6 +11,6 @@
{% endtrans %}
</a>
{% elif addon.can_review(amo_user) %}
<a class="listview" id="add-review" href="{{ url('reviews.add', addon.slug) }}">
<a class="listview" id="add-review" href="{{ shared_url('reviews.add', addon) }}">
{{ _('Be the first to write a review.') }}</a>
{% endif %}

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

@ -1,4 +1,4 @@
{% extends "impala/base.html" %}
{% extends "impala/base_shared.html" %}
{% from 'includes/forms.html' import pretty_field, required_note %}
{% set title = _('Reply to review by {0}')|f(review.user.name) %}
@ -22,7 +22,7 @@
<div class="primary island hero" id="reviews">
{% include "reviews/review.html" %}
<form method="post" class="prettyform c"
action="{{ url('reviews.reply', addon.slug, review.id) }}">
action="{{ shared_url('reviews.reply', addon, review.id) }}">
{{ csrf() }}
<fieldset>
<h2>{{ _('Write a Reply') }}</h2>

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

@ -36,7 +36,7 @@
<span>[{{ review.ip_address }}]</span>
{% endif %}
<a class="permalink"
href="{{ url('reviews.detail', addon.slug, review.id) }}">#</a>
href="{{ shared_url('reviews.detail', addon, review.id) }}">#</a>
</p>
<p class="description">{{ review.body|nl2br }}</p>
{% if outdated and not is_reply %}
@ -45,7 +45,7 @@
{% endif %}
{% if page != 'user' and review.previous_count %}
<span class="item-note">
{% with user_review_url = url('reviews.user', addon.slug, review.user.id) %}
{% with user_review_url = shared_url('reviews.user', addon, review.user.id) %}
{% if review.is_latest %}
{% trans num=review.previous_count, cnt=review.previous_count|numberfmt %}
This user has a <a href="{{ user_review_url }}">previous review</a> of this add-on.
@ -66,13 +66,13 @@
<li class="flagged">{{ _('Flagged for review') }}</li>
{% elif review.user_id != request.user.id %}
<li>
<a class="flag-review" href="{{ url('reviews.flag', addon.slug, review.id) }}">
<a class="flag-review" href="{{ shared_url('reviews.flag', addon, review.id) }}">
{{ _('Report this review') }}</a>
</li>
{% endif %}
{% if not (is_reply or has_reply) and (perms.is_author or perms.is_admin) %}
<li>
<a class="review-delete" href="{{ url('reviews.reply', addon.slug, review.id) }}">
<a class="review-delete" href="{{ shared_url('reviews.reply', addon, review.id) }}">
{{ _('Reply to review') }}</a>
</li>
{% endif %}
@ -84,7 +84,7 @@
{% endif %}
{% if perms.can_delete %}
<li>
<a class="delete-review" href="{{ url('reviews.delete', addon.slug, review.id) }}">
<a class="delete-review" href="{{ shared_url('reviews.delete', addon, review.id) }}">
{{ _('Delete review') }}</a>
</li>
{% endif %}

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

@ -1,4 +1,4 @@
{% extends "impala/base.html" %}
{% extends "impala/base_shared.html" %}
{% set amo_user = request.amo_user if request.user.is_authenticated() else None %}
{# L10n: {0} is an add-on name. #}
@ -73,7 +73,7 @@
</section>
<section>
{% if amo_user and addon.can_review(amo_user) %}
<a class="button" id="add-review" href="{{ url('reviews.add', addon.slug) }}">
<a class="button" id="add-review" href="{{ shared_url('reviews.add', addon) }}">
{{ _('Write a New Review') }}</a>
{% endif %}
</section>
@ -82,7 +82,7 @@
{% block review_list %}
{% if not reviews.object_list %}
{% if addon.can_review(amo_user) %}
<p id="add-first-review"><a href="{{ url('reviews.add', addon.slug) }}">
<p id="add-first-review"><a href="{{ shared_url('reviews.add', addon) }}">
{{ _('Be the first to write a review.') }}</a><p>
{% else %}
<p id="no-add-first-review">

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

@ -1,7 +1,7 @@
{% if link_to_list %}
{% set base = url('reviews.list', addon.slug) %}
{% set base = shared_url('reviews.list', addon) %}
{% else %}
{% set base = url('addons.detail', addon.slug)|urlparams('reviews') %}
{% set base = addon.get_url_path()|urlparams('reviews') %}
{% if collection_uuid %}
{% set base = base|urlparams(collection_uuid=collection_uuid) %}
{% endif %}

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

@ -54,7 +54,7 @@ def test_reviews_link():
eq_(pq(s)('strong').text(), 'Not yet rated')
# with link
u = reverse('reviews.list', args=['xx'])
u = reverse('addons.reviews.list', args=['xx'])
s = render('{{ reviews_link(myaddon, link_to_list=True) }}',
{'myaddon': a})
eq_(pq(s)('a').attr('href'), u)
@ -66,9 +66,9 @@ def test_mobile_reviews_link():
a = Addon(total_reviews=0, id=1, type=1, slug='xx')
doc = s(a)
eq_(doc('a').attr('href'), reverse('reviews.add', args=['xx']))
eq_(doc('a').attr('href'), reverse('addons.reviews.add', args=['xx']))
u = reverse('reviews.list', args=['xx'])
u = reverse('addons.reviews.list', args=['xx'])
a = Addon(average_rating=4, total_reviews=37, id=1, type=1, slug='xx')
doc = s(a)

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

@ -5,6 +5,7 @@ from pyquery import PyQuery as pq
import amo.tests
from amo.urlresolvers import reverse
from amo.helpers import shared_url
from access.models import GroupUser
from addons.models import Addon
from devhub.models import ActivityLog
@ -15,6 +16,9 @@ from users.models import UserProfile
class ReviewTest(amo.tests.TestCase):
fixtures = ['base/apps', 'reviews/dev-reply.json', 'base/admin']
def setUp(self):
self.addon = Addon.objects.get(id=1865)
def login_dev(self):
self.client.login(username='trev@adblockplus.org', password='password')
@ -30,34 +34,35 @@ class ReviewTest(amo.tests.TestCase):
class TestViews(ReviewTest):
def test_dev_reply(self):
url = reverse('reviews.detail', args=['a1865', 218468])
url = shared_url('reviews.detail', self.addon, 218468)
r = self.client.get(url)
eq_(r.status_code, 200)
def test_404_user_page(self):
url = reverse('reviews.user', args=['a1865', 233452342])
url = shared_url('reviews.user', self.addon, 233452342)
r = self.client.get(url)
eq_(r.status_code, 404)
def test_feed(self):
url = reverse('reviews.list.rss', args=['a1865'])
url = shared_url('reviews.list.rss', self.addon)
r = self.client.get(url)
eq_(r.status_code, 200)
def test_abuse_form(self):
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
self.assertTemplateUsed(r, 'reviews/report_review.html')
r = self.client.get(reverse('reviews.detail', args=['a1865', 218468]))
r = self.client.get(shared_url('reviews.detail', self.addon,
218468))
self.assertTemplateUsed(r, 'reviews/report_review.html')
def test_edit_review_form(self):
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
self.assertTemplateUsed(r, 'reviews/edit_review.html')
r = self.client.get(reverse('reviews.detail', args=['a1865', 218468]))
r = self.client.get(shared_url('reviews.detail', self.addon, 218468))
self.assertTemplateUsed(r, 'reviews/edit_review.html')
def test_list(self):
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
eq_(r.status_code, 200)
doc = pq(r.content)
reviews = doc('#reviews .item')
@ -84,7 +89,7 @@ class TestViews(ReviewTest):
def test_empty_list(self):
Review.objects.all().delete()
eq_(Review.objects.count(), 0)
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
eq_(r.status_code, 200)
doc = pq(r.content)
eq_(doc('#reviews .item').length, 0)
@ -95,7 +100,7 @@ class TestViews(ReviewTest):
def test_list_item_actions(self):
self.login_admin()
self.make_it_my_review()
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
reviews = pq(r.content)('#reviews .item')
r = Review.objects.get(id=218207)
@ -116,7 +121,8 @@ class TestViews(ReviewTest):
class TestFlag(ReviewTest):
def setUp(self):
self.url = reverse('reviews.flag', args=['a1865', 218468])
super(TestFlag, self).setUp()
self.url = shared_url('reviews.flag', self.addon, 218468)
self.login_admin()
def test_no_login(self):
@ -168,7 +174,8 @@ class TestFlag(ReviewTest):
class TestDelete(ReviewTest):
def setUp(self):
self.url = reverse('reviews.delete', args=['a1865', 218207])
super(TestDelete, self).setUp()
self.url = shared_url('reviews.delete', self.addon, 218207)
self.login_admin()
def test_no_login(self):
@ -182,7 +189,7 @@ class TestDelete(ReviewTest):
eq_(response.status_code, 403)
def test_404(self):
url = reverse('reviews.delete', args=['a1865', 0])
url = shared_url('reviews.delete', self.addon, 0)
response = self.client.post(url)
eq_(response.status_code, 404)
@ -204,14 +211,14 @@ class TestDelete(ReviewTest):
class TestCreate(ReviewTest):
def setUp(self):
self.addon = Addon.objects.get(slug='a1865')
self.add = reverse('reviews.add', args=[self.addon.slug])
super(TestCreate, self).setUp()
self.add = shared_url('reviews.add', self.addon)
self.client.login(username='root_x@ukr.net', password='password')
self.user = UserProfile.objects.get(email='root_x@ukr.net')
self.qs = Review.objects.filter(addon=1865)
self.log_count = ActivityLog.objects.count
self.more = reverse('addons.detail_more', args=['a1865'])
self.list = reverse('reviews.list', args=['a1865'])
self.more = self.addon.get_url_path(more=True)
self.list = shared_url('reviews.list', self.addon)
def test_add_logged(self):
r = self.client.get(self.add)
@ -242,7 +249,7 @@ class TestCreate(ReviewTest):
old_cnt = self.qs.count()
log_count = self.log_count()
r = self.client.post(self.add, {'body': 'xx', 'rating': 3})
self.assertRedirects(r, reverse('reviews.list', args=['a1865']),
self.assertRedirects(r, shared_url('reviews.list', self.addon),
status_code=302)
eq_(self.qs.count(), old_cnt + 1)
# We should have an ADD_REVIEW entry now.
@ -256,10 +263,10 @@ class TestCreate(ReviewTest):
def test_new_reply(self):
self.login_dev()
Review.objects.filter(reply_to__isnull=False).delete()
url = reverse('reviews.reply', args=['a1865', 218207])
url = shared_url('reviews.reply', self.addon, 218207)
r = self.client.post(url, {'body': 'unst unst'})
self.assertRedirects(r,
reverse('reviews.detail', args=['a1865', 218207]))
shared_url('reviews.detail', self.addon, 218207))
eq_(self.qs.filter(reply_to=218207).count(), 1)
eq_(len(mail.outbox), 1)
@ -267,10 +274,10 @@ class TestCreate(ReviewTest):
def test_double_reply(self):
self.login_dev()
url = reverse('reviews.reply', args=['a1865', 218207])
url = shared_url('reviews.reply', self.addon, 218207)
r = self.client.post(url, {'body': 'unst unst'})
self.assertRedirects(r,
reverse('reviews.detail', args=['a1865', 218207]))
shared_url('reviews.detail', self.addon, 218207))
eq_(self.qs.filter(reply_to=218207).count(), 1)
review = Review.objects.get(id=218468)
eq_('%s' % review.body, 'unst unst')
@ -296,7 +303,7 @@ class TestCreate(ReviewTest):
self.client.logout()
r = self.client.get_ajax(self.more)
eq_(pq(r.content)('#add-review').length, 1)
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
doc = pq(r.content)
eq_(doc('#add-review').length, 0)
eq_(doc('#add-first-review').length, 0)
@ -315,7 +322,7 @@ class TestCreate(ReviewTest):
self.login_dev()
r = self.client.get_ajax(self.more)
eq_(pq(r.content)('#add-review').length, 0)
r = self.client.get(reverse('reviews.list', args=['a1865']))
r = self.client.get(shared_url('reviews.list', self.addon))
doc = pq(r.content)
eq_(doc('#add-review').length, 0)
eq_(doc('#add-first-review').length, 0)
@ -421,24 +428,25 @@ class TestCreate(ReviewTest):
class TestEdit(ReviewTest):
def setUp(self):
super(TestEdit, self).setUp()
self.client.login(username='root_x@ukr.net', password='password')
def test_edit(self):
url = reverse('reviews.edit', args=['a1865', 218207])
url = shared_url('reviews.edit', self.addon, 218207)
r = self.client.post(url, {'rating': 2, 'body': 'woo woo'},
X_REQUESTED_WITH='XMLHttpRequest')
eq_(r.status_code, 200)
eq_('%s' % Review.objects.get(id=218207).body, 'woo woo')
def test_edit_not_owner(self):
url = reverse('reviews.edit', args=['a1865', 218468])
url = shared_url('reviews.edit', self.addon, 218468)
r = self.client.post(url, {'rating': 2, 'body': 'woo woo'},
X_REQUESTED_WITH='XMLHttpRequest')
eq_(r.status_code, 403)
def test_edit_reply(self):
self.login_dev()
url = reverse('reviews.edit', args=['a1865', 218468])
url = shared_url('reviews.edit', self.addon, 218468)
r = self.client.post(url, {'title': 'fo', 'body': 'shizzle'},
X_REQUESTED_WITH='XMLHttpRequest')
eq_(r.status_code, 200)
@ -452,12 +460,11 @@ class TestMobileReviews(amo.tests.MobileTest, amo.tests.TestCase):
'base/users']
def setUp(self):
super(TestMobileReviews, self).setUp()
self.addon = Addon.objects.get(id=1865)
self.user = UserProfile.objects.get(email='regular@mozilla.com')
self.login_regular()
self.add = reverse('reviews.add', args=['a1865'])
self.list = reverse('reviews.list', args=['a1865'])
self.add = shared_url('reviews.add', self.addon)
self.list = shared_url('reviews.list', self.addon)
def login_regular(self):
self.client.login(username='regular@mozilla.com', password='password')
@ -544,5 +551,5 @@ class TestMobileReviews(amo.tests.MobileTest, amo.tests.TestCase):
def test_add_logged_out(self):
self.client.logout()
self.mobile_init()
r = self.client.get(reverse('reviews.add', args=['a1865']))
r = self.client.get(shared_url('reviews.add', self.addon))
eq_(r.status_code, 302)

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

@ -3,19 +3,23 @@ from reviews.feeds import ReviewsRss
from . import views
# These all start with /addon/:id/reviews/:review_id/.
detail_patterns = patterns('',
url('^$', views.review_list, name='reviews.detail'),
url('^reply$', views.reply, name='reviews.reply'),
url('^flag$', views.flag, name='reviews.flag'),
url('^delete$', views.delete, name='reviews.delete'),
url('^edit$', views.edit, name='reviews.edit'),
)
def review_detail_patterns(prefix):
# These all start with /addon/:id/reviews/:review_id/.
return patterns('',
url('^$', views.review_list, name='%s.reviews.detail' % prefix),
url('^reply$', views.reply, name='%s.reviews.reply' % prefix),
url('^flag$', views.flag, name='%s.reviews.flag' % prefix),
url('^delete$', views.delete, name='%s.reviews.delete' % prefix),
url('^edit$', views.edit, name='%s.reviews.edit' % prefix),
)
urlpatterns = patterns('',
url('^$', views.review_list, name='reviews.list'),
url('^add$', views.add, name='reviews.add'),
url('^(?P<review_id>\d+)/', include(detail_patterns)),
url('^format:rss$', ReviewsRss(), name='reviews.list.rss'),
url('^user:(?P<user_id>\d+)$', views.review_list, name='reviews.user'),
)
def review_patterns(prefix):
return patterns('',
url('^$', views.review_list, name='%s.reviews.list' % prefix),
url('^add$', views.add, name='%s.reviews.add' % prefix),
url('^(?P<review_id>\d+)/', include(review_detail_patterns(prefix))),
url('^format:rss$', ReviewsRss(), name='%s.reviews.list.rss' % prefix),
url('^user:(?P<user_id>\d+)$', views.review_list,
name='%s.reviews.user' % prefix),
)

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

@ -7,9 +7,10 @@ import jingo
from tower import ugettext as _
from mobility.decorators import mobile_template
import amo
from amo import messages
from amo.decorators import json_view, login_required, post_required
from amo.helpers import absolutify
from amo.helpers import absolutify, shared_url
from amo.urlresolvers import reverse
import amo.utils
from access import acl
@ -150,18 +151,18 @@ def reply(request, addon, review_id):
log.debug('%s reply to %s: %s' % (action, review_id, reply.id))
if new:
reply_url = shared_url('reviews.detail', addon, review.id,
add_prefix=False)
data = {'name': addon.name,
'reply_title': reply.title,
'reply': reply.body,
'reply_url': absolutify(reverse('reviews.detail',
args=[addon.slug, review.id],
add_prefix=False))}
'reply_url': absolutify(reply_url)}
emails = [review.user.email]
sub = u'Mozilla Add-on Developer Reply: %s' % addon.name
send_mail('reviews/emails/reply_review.ltxt',
sub, emails, Context(data), 'reply')
return redirect('reviews.detail', addon.slug, review_id)
return redirect(shared_url('reviews.detail', addon, review_id))
ctx = dict(review=review, form=form, addon=addon)
return jingo.render(request, 'reviews/reply.html', ctx)
@ -180,18 +181,19 @@ def add(request, addon, template=None):
amo.log(amo.LOG.ADD_REVIEW, addon, review)
log.debug('New review: %s' % review.id)
reply_url = shared_url('reviews.reply', addon, review.id,
add_prefix=False)
data = {'name': addon.name,
'rating': '%s out of 5 stars' % details['rating'],
'review': details['body'],
'reply_url': absolutify(reverse('reviews.reply',
args=[addon.slug, review.id], add_prefix=False))}
'reply_url': absolutify(reply_url)}
emails = [a.email for a in addon.authors.all()]
send_mail('reviews/emails/add_review.ltxt',
u'Mozilla Add-on User Review: %s' % addon.name,
emails, Context(data), 'new_review')
return redirect('reviews.list', addon.slug)
return redirect(shared_url('reviews.list', addon))
return jingo.render(request, template, dict(addon=addon, form=form))
@ -239,7 +241,7 @@ def spam(request):
for reason in spam.reasons():
spam.redis.srem(reason, review.id)
return redirect('reviews.spam')
return redirect(request.path)
buckets = {}
for reason in spam.reasons():

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

@ -130,9 +130,18 @@ class TestDetail(WebappTest):
eq_(doc('#addon h1').text(), 'woo')
eq_(doc('h2:first').text(), 'About this App')
def test_reviews(self):
eq_(self.get_more_pq()('#reviews h3').remove('a').text(),
def test_add_review_link_aside(self):
r = self.client.get(self.url)
eq_(pq(r.content)('#reviews-link').attr('href'),
reverse('apps.reviews.list', args=[self.webapp.app_slug]))
def test_add_review_link_more(self):
doc = self.get_more_pq()
add_url = reverse('apps.reviews.add', args=[self.webapp.app_slug])
eq_(doc.find('#reviews #add-first-review').attr('href'), add_url)
eq_(doc.find('#reviews h3').remove('a').text(),
'This app has not yet been reviewed.')
eq_(doc.find('#add-review').attr('href'), add_url)
def test_other_apps(self):
"""Ensure listed apps by the same author show up."""

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

@ -1,7 +1,9 @@
from django.conf.urls.defaults import include, patterns, url
from django.shortcuts import redirect
from . import views
from addons import views as addons_views
from reviews.urls import review_patterns
APP_SLUG = r"""(?P<app_slug>[^/<>"']+)"""
@ -22,12 +24,18 @@ detail_patterns = patterns('',
name='apps.purchase.thanks'),
url('^purchase/(?P<status>cancel|complete)$',
addons_views.purchase_complete, name='apps.purchase.finished'),
('^reviews/', include(review_patterns('apps'))),
)
urlpatterns = patterns('',
url('^$', views.app_home, name='apps.home'),
url('^search/$', 'search.views.app_search', name='apps.search'),
# Review spam.
url('^reviews/spam/$', 'reviews.views.spam', name='apps.reviews.spam'),
url('^(?P<category>[^/]+)?$', views.app_list, name='apps.list'),
# URLs for a single app.

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

@ -90,7 +90,7 @@ urlpatterns = patterns('',
('^compatibility/', include('compat.urls')),
# Review spam.
url('^reviews/spam/$', 'reviews.views.spam', name='reviews.spam'),
url('^reviews/spam/$', 'reviews.views.spam', name='addons.reviews.spam'),
# marketplace
('^market/', include('market.urls')),
@ -100,10 +100,10 @@ urlpatterns = patterns('',
lambda r: redirect('browse.extensions', 'bookmarks', permanent=True)),
('^reviews/display/(\d+)',
lambda r, id: redirect('reviews.list', id, permanent=True)),
lambda r, id: redirect('addons.reviews.list', id, permanent=True)),
('^reviews/add/(\d+)',
lambda r, id: redirect('reviews.add', id, permanent=True)),
lambda r, id: redirect('addons.reviews.add', id, permanent=True)),
('^users/info/(\d+)',
lambda r, id: redirect('users.profile', id, permanent=True)),
@ -136,7 +136,7 @@ urlpatterns = patterns('',
'versions.views.update_info_redirect'),
('^addons/reviews/(\d+)/format:rss$',
lambda r, id: redirect('reviews.list.rss', id, permanent=True)),
lambda r, id: redirect('addons.reviews.list.rss', id, permanent=True)),
('^search-engines.*$',
lambda r: redirect('browse.search-tools', permanent=True)),