Hide empty reviews, apart from admins and your own (#5227)
This commit is contained in:
Родитель
87eff8b801
Коммит
b098079c45
|
@ -44,6 +44,10 @@ user has already posted a review for the current version of an add-on.
|
||||||
can change that with the ``filter=with_deleted`` query parameter, which
|
can change that with the ``filter=with_deleted`` query parameter, which
|
||||||
requires the Addons:Edit permission.
|
requires the Addons:Edit permission.
|
||||||
|
|
||||||
|
Only non-empty reviews (reviews with both a rating and text body) are returned,
|
||||||
|
unless a) the reviews were created by the user making the API request or
|
||||||
|
b) the user has the Addons:Edit permission.
|
||||||
|
|
||||||
------
|
------
|
||||||
Detail
|
Detail
|
||||||
------
|
------
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import json
|
import json
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import test
|
from django import test
|
||||||
|
@ -17,7 +18,7 @@ from waffle.testutils import override_switch
|
||||||
from olympia import amo
|
from olympia import amo
|
||||||
from olympia.amo.tests import APITestClient, ESTestCase, TestCase
|
from olympia.amo.tests import APITestClient, ESTestCase, TestCase
|
||||||
from olympia.amo.helpers import numberfmt, urlparams
|
from olympia.amo.helpers import numberfmt, urlparams
|
||||||
from olympia.amo.tests import addon_factory, version_factory
|
from olympia.amo.tests import addon_factory, user_factory, version_factory
|
||||||
from olympia.amo.urlresolvers import reverse
|
from olympia.amo.urlresolvers import reverse
|
||||||
from olympia.addons.utils import generate_addon_guid
|
from olympia.addons.utils import generate_addon_guid
|
||||||
from olympia.abuse.models import AbuseReport
|
from olympia.abuse.models import AbuseReport
|
||||||
|
@ -28,6 +29,7 @@ from olympia.bandwagon.models import Collection
|
||||||
from olympia.constants.categories import CATEGORIES
|
from olympia.constants.categories import CATEGORIES
|
||||||
from olympia.files.models import WebextPermission, WebextPermissionDescription
|
from olympia.files.models import WebextPermission, WebextPermissionDescription
|
||||||
from olympia.paypal.tests.test import other_error
|
from olympia.paypal.tests.test import other_error
|
||||||
|
from olympia.reviews.models import Review
|
||||||
from olympia.stats.models import Contribution
|
from olympia.stats.models import Contribution
|
||||||
from olympia.users.helpers import users_list
|
from olympia.users.helpers import users_list
|
||||||
from olympia.users.models import UserProfile
|
from olympia.users.models import UserProfile
|
||||||
|
@ -1075,6 +1077,29 @@ class TestDetailPage(TestCase):
|
||||||
assert pq(content)('.manage-button a').eq(2).attr('href') == (
|
assert pq(content)('.manage-button a').eq(2).attr('href') == (
|
||||||
reverse('zadmin.addon_manage', args=[self.addon.slug]))
|
reverse('zadmin.addon_manage', args=[self.addon.slug]))
|
||||||
|
|
||||||
|
def test_reviews(self):
|
||||||
|
def create_review(body='review text'):
|
||||||
|
return Review.objects.create(
|
||||||
|
addon=self.addon, user=user_factory(),
|
||||||
|
rating=random.randrange(0, 6),
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
url = reverse('addons.detail', args=['a3615'])
|
||||||
|
|
||||||
|
create_review()
|
||||||
|
response = self.client.get(url, follow=True)
|
||||||
|
assert len(response.context['reviews']) == 1
|
||||||
|
|
||||||
|
# Add a new review but with no body - shouldn't be shown on detail page
|
||||||
|
create_review(body=None)
|
||||||
|
response = self.client.get(url, follow=True)
|
||||||
|
assert len(response.context['reviews']) == 1
|
||||||
|
|
||||||
|
# Test one last time in case caching
|
||||||
|
create_review()
|
||||||
|
response = self.client.get(url, follow=True)
|
||||||
|
assert len(response.context['reviews']) == 2
|
||||||
|
|
||||||
def get_pq(self):
|
def get_pq(self):
|
||||||
return pq(self.client.get(self.url).content)
|
return pq(self.client.get(self.url).content)
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ def extension_detail(request, addon):
|
||||||
'grouped_ratings': GroupedRating.get(addon.id),
|
'grouped_ratings': GroupedRating.get(addon.id),
|
||||||
'review_form': ReviewForm(),
|
'review_form': ReviewForm(),
|
||||||
'reviews': Review.without_replies.all().filter(
|
'reviews': Review.without_replies.all().filter(
|
||||||
addon=addon, is_latest=True),
|
addon=addon, is_latest=True).exclude(body=None),
|
||||||
'get_replies': Review.get_replies,
|
'get_replies': Review.get_replies,
|
||||||
'collections': collections.order_by('-subscribers')[:3],
|
'collections': collections.order_by('-subscribers')[:3],
|
||||||
'abuse_form': AbuseForm(request=request),
|
'abuse_form': AbuseForm(request=request),
|
||||||
|
|
|
@ -105,6 +105,31 @@ class TestViews(ReviewTest):
|
||||||
assert r.rating is None
|
assert r.rating is None
|
||||||
assert item.attr('data-rating') == ''
|
assert item.attr('data-rating') == ''
|
||||||
|
|
||||||
|
def test_empty_reviews_in_list(self):
|
||||||
|
def create_review(body='review text', user=None):
|
||||||
|
return Review.objects.create(
|
||||||
|
addon=self.addon, user=user or user_factory(),
|
||||||
|
rating=3, body=body)
|
||||||
|
|
||||||
|
url = helpers.url('addons.reviews.list', self.addon.slug)
|
||||||
|
|
||||||
|
create_review()
|
||||||
|
create_review(body=None)
|
||||||
|
create_review(
|
||||||
|
body=None,
|
||||||
|
user=UserProfile.objects.get(email='trev@adblockplus.org'))
|
||||||
|
|
||||||
|
# Don't show the reviews with no body.
|
||||||
|
assert len(self.client.get(url).context['reviews']) == 2
|
||||||
|
|
||||||
|
self.login_dev()
|
||||||
|
# Except if it's your review
|
||||||
|
assert len(self.client.get(url).context['reviews']) == 3
|
||||||
|
|
||||||
|
# Or you're an admin
|
||||||
|
self.login_admin()
|
||||||
|
assert len(self.client.get(url).context['reviews']) == 4
|
||||||
|
|
||||||
def test_list_rss(self):
|
def test_list_rss(self):
|
||||||
r = self.client.get(helpers.url('addons.reviews.list',
|
r = self.client.get(helpers.url('addons.reviews.list',
|
||||||
self.addon.slug))
|
self.addon.slug))
|
||||||
|
@ -926,6 +951,36 @@ class TestReviewViewSetGet(TestCase):
|
||||||
def test_list_addon_slug(self):
|
def test_list_addon_slug(self):
|
||||||
self.test_list_addon(addon_pk=self.addon.slug)
|
self.test_list_addon(addon_pk=self.addon.slug)
|
||||||
|
|
||||||
|
def test_list_with_empty_reviews(self):
|
||||||
|
def create_review(body='review text', user=None):
|
||||||
|
return Review.objects.create(
|
||||||
|
addon=self.addon, user=user or user_factory(),
|
||||||
|
rating=3, body=body)
|
||||||
|
|
||||||
|
self.user = user_factory()
|
||||||
|
|
||||||
|
create_review()
|
||||||
|
create_review()
|
||||||
|
create_review(body=None)
|
||||||
|
create_review(body=None, user=self.user)
|
||||||
|
|
||||||
|
# Don't show the reviews with no body.
|
||||||
|
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||||
|
data = json.loads(response.content)
|
||||||
|
assert data['count'] == 2 == len(data['results'])
|
||||||
|
|
||||||
|
# Except if it's your review
|
||||||
|
self.client.login_api(self.user)
|
||||||
|
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||||
|
data = json.loads(response.content)
|
||||||
|
assert data['count'] == 3 == len(data['results'])
|
||||||
|
|
||||||
|
# Or you're an admin
|
||||||
|
self.grant_permission(self.user, 'Addons:Edit')
|
||||||
|
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||||
|
data = json.loads(response.content)
|
||||||
|
assert data['count'] == 4 == len(data['results'])
|
||||||
|
|
||||||
def test_list_user(self, **kwargs):
|
def test_list_user(self, **kwargs):
|
||||||
self.user = user_factory()
|
self.user = user_factory()
|
||||||
review1 = Review.objects.create(
|
review1 = Review.objects.create(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django import http
|
from django import http
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db.models import Prefetch
|
from django.db.models import Q, Prefetch
|
||||||
from django.db.transaction import non_atomic_requests
|
from django.db.transaction import non_atomic_requests
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
@ -49,6 +49,7 @@ def review_list(request, addon, review_id=None, user_id=None, template=None):
|
||||||
'grouped_ratings': GroupedRating.get(addon.id)}
|
'grouped_ratings': GroupedRating.get(addon.id)}
|
||||||
|
|
||||||
ctx['form'] = forms.ReviewForm(None)
|
ctx['form'] = forms.ReviewForm(None)
|
||||||
|
is_admin = acl.action_allowed(request, amo.permissions.ADDONS_EDIT)
|
||||||
|
|
||||||
if review_id is not None:
|
if review_id is not None:
|
||||||
ctx['page'] = 'detail'
|
ctx['page'] = 'detail'
|
||||||
|
@ -66,13 +67,18 @@ def review_list(request, addon, review_id=None, user_id=None, template=None):
|
||||||
else:
|
else:
|
||||||
ctx['page'] = 'list'
|
ctx['page'] = 'list'
|
||||||
qs = qs.filter(is_latest=True)
|
qs = qs.filter(is_latest=True)
|
||||||
|
# Don't filter out empty reviews for admins.
|
||||||
|
if not is_admin:
|
||||||
|
# But otherwise, filter out everyone elses empty reviews.
|
||||||
|
user_filter = (Q(user=request.user.pk)
|
||||||
|
if request.user.is_authenticated() else Q())
|
||||||
|
qs = qs.filter(~Q(body=None) | user_filter)
|
||||||
|
|
||||||
ctx['reviews'] = reviews = paginate(request, qs)
|
ctx['reviews'] = reviews = paginate(request, qs)
|
||||||
ctx['replies'] = Review.get_replies(reviews.object_list)
|
ctx['replies'] = Review.get_replies(reviews.object_list)
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
ctx['review_perms'] = {
|
ctx['review_perms'] = {
|
||||||
'is_admin': acl.action_allowed(request,
|
'is_admin': is_admin,
|
||||||
amo.permissions.ADDONS_EDIT),
|
|
||||||
'is_editor': acl.is_editor(request, addon),
|
'is_editor': acl.is_editor(request, addon),
|
||||||
'is_author': acl.check_addon_ownership(request, addon, viewer=True,
|
'is_author': acl.check_addon_ownership(request, addon, viewer=True,
|
||||||
dev=True, support=True),
|
dev=True, support=True),
|
||||||
|
@ -359,6 +365,8 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
requested = self.request.GET.get('filter')
|
requested = self.request.GET.get('filter')
|
||||||
|
has_addons_edit = acl.action_allowed(self.request,
|
||||||
|
amo.permissions.ADDONS_EDIT)
|
||||||
|
|
||||||
# Add this as a property of the view, because we need to pass down the
|
# Add this as a property of the view, because we need to pass down the
|
||||||
# information to the serializer to show/hide delete replies.
|
# information to the serializer to show/hide delete replies.
|
||||||
|
@ -366,7 +374,7 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
||||||
self.should_access_deleted_reviews = (
|
self.should_access_deleted_reviews = (
|
||||||
(requested == 'with_deleted' or self.action != 'list') and
|
(requested == 'with_deleted' or self.action != 'list') and
|
||||||
self.request.user.is_authenticated() and
|
self.request.user.is_authenticated() and
|
||||||
acl.action_allowed(self.request, amo.permissions.ADDONS_EDIT))
|
has_addons_edit)
|
||||||
|
|
||||||
should_access_only_top_level_reviews = (
|
should_access_only_top_level_reviews = (
|
||||||
self.action == 'list' and self.get_addon_object())
|
self.action == 'list' and self.get_addon_object())
|
||||||
|
@ -387,6 +395,12 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
||||||
# reviews instead.
|
# reviews instead.
|
||||||
self.queryset = Review.without_replies.all()
|
self.queryset = Review.without_replies.all()
|
||||||
|
|
||||||
|
# Filter out (other user's) empty reviews for non-admins.
|
||||||
|
if self.action == 'list' and not has_addons_edit:
|
||||||
|
user_filter = (Q(user=self.request.user.pk)
|
||||||
|
if self.request.user.is_authenticated() else Q())
|
||||||
|
self.queryset = self.queryset.filter(~Q(body=None) | user_filter)
|
||||||
|
|
||||||
qs = super(ReviewViewSet, self).get_queryset()
|
qs = super(ReviewViewSet, self).get_queryset()
|
||||||
# The serializer needs reply, version (only the "version" field) and
|
# The serializer needs reply, version (only the "version" field) and
|
||||||
# user. We don't need much for version and user, so we can make joins
|
# user. We don't need much for version and user, so we can make joins
|
||||||
|
|
Загрузка…
Ссылка в новой задаче