addons-server/mkt/ratings/views.py

252 строки
9.9 KiB
Python

from django import http
from django.shortcuts import get_object_or_404, redirect
import commonware.log
import jingo
from tower import ugettext as _
from access import acl
import amo
import amo.log
from amo.urlresolvers import reverse
from addons.decorators import addon_view_factory, has_purchased_or_refunded
from addons.models import Addon
from amo.decorators import (json_view, login_required, post_required,
restricted_content)
from reviews.forms import ReviewReplyForm
from reviews.models import Review, ReviewFlag
from reviews.tasks import addon_review_aggregates
from reviews.views import get_flags
from stats.models import ClientData, Contribution
from mkt.site import messages
from mkt.ratings.forms import ReviewForm
from mkt.webapps.models import Installed
log = commonware.log.getLogger('mkt.ratings')
addon_view = addon_view_factory(qs=Addon.objects.valid)
def _review_details(request, addon, form):
d = dict(addon_id=addon.id, user_id=request.user.id,
ip_address=request.META.get('REMOTE_ADDR', ''))
d.update(**form.cleaned_data)
return d
@addon_view
def review_list(request, addon, review_id=None, user_id=None, rating=None):
qs = Review.objects.valid().filter(addon=addon).order_by('-created')
ctx = {'product': addon, 'score': rating, 'review_perms': {}}
if review_id is not None:
qs = qs.filter(pk=review_id)
ctx['page'] = 'detail'
# If this is a dev reply, find the first msg for context.
review = get_object_or_404(Review, pk=review_id)
if review.reply_to_id:
review_id = review.reply_to_id
ctx['reply'] = review
elif user_id is not None:
qs = qs.filter(user=user_id)
ctx['page'] = 'user'
if not qs:
raise http.Http404()
else:
ctx['page'] = 'list'
qs = qs.filter(is_latest=True)
ctx['ratings'] = ratings = amo.utils.paginate(request, qs, 20)
if not ctx.get('reply'):
ctx['replies'] = Review.get_replies(ratings.object_list)
if request.user.is_authenticated():
ctx['review_perms'] = {
'is_admin': acl.action_allowed(request, 'Addons', 'Edit'),
'is_editor': acl.check_reviewer(request),
'is_author': acl.check_addon_ownership(request, addon, viewer=True,
dev=True, support=True),
}
ctx['flags'] = get_flags(request, ratings.object_list)
ctx['has_review'] = addon.reviews.filter(user=request.user.id).exists()
return jingo.render(request, 'ratings/listing.html', ctx)
@addon_view
@json_view
@login_required(redirect=False)
@post_required
def edit(request, addon, review_id):
return http.HttpResponse()
@addon_view
@login_required
@post_required
def reply(request, addon, review_id):
is_admin = acl.action_allowed(request, 'Addons', 'Edit')
is_author = acl.check_addon_ownership(request, addon, dev=True)
if not (is_admin or is_author):
return http.HttpResponseForbidden()
review = get_object_or_404(Review.objects, pk=review_id, addon=addon)
form = ReviewReplyForm(request.POST or None)
if form.is_valid():
d = dict(reply_to=review, addon=addon,
defaults=dict(user=request.amo_user))
reply, new = Review.objects.get_or_create(**d)
for k, v in _review_details(request, addon, form).items():
setattr(reply, k, v)
reply.save()
action = 'New' if new else 'Edited'
if new:
amo.log(amo.LOG.ADD_REVIEW, addon, reply)
else:
amo.log(amo.LOG.EDIT_REVIEW, addon, reply)
log.debug('%s reply to %s: %s' % (action, review_id, reply.id))
messages.success(request,
_('Your reply was successfully added.') if new else
_('Your reply was successfully updated.'))
return http.HttpResponse()
@addon_view
@login_required
@restricted_content
@has_purchased_or_refunded
def add(request, addon):
if addon.has_author(request.user):
# Don't let app owners review their own apps.
return http.HttpResponseForbidden()
# Get user agent of user submitting review. If there is an install with
# logged user agent that matches the current user agent, hook up that
# install's client data with the rating. If there aren't any install that
# match, use the most recent install. This implies that user must have an
# install to submit a review, but not sure if that logic is worked in, so
# default client_data to None.
client_data = None
user_agent = request.META.get('HTTP_USER_AGENT', '')
install = (Installed.objects.filter(user=request.user, addon=addon)
.order_by('-created'))
install_w_user_agent = (install.filter(client_data__user_agent=user_agent)
.order_by('-created'))
has_review = False
try:
if install_w_user_agent:
client_data = install_w_user_agent[0].client_data
elif install:
client_data = install[0].client_data
except ClientData.DoesNotExist:
client_data = None
data = request.POST or None
# Try to get an existing review of the app by this user if we can.
try:
existing_review = Review.objects.valid().filter(addon=addon,
user=request.user)[0]
except IndexError:
# If one doesn't exist, set it to None.
existing_review = None
# If the user is posting back, try to process the submission.
if data:
form = ReviewForm(data)
if form.is_valid():
cleaned = form.cleaned_data
if existing_review:
# If there's a review to overwrite, overwrite it.
if (cleaned['body'] != existing_review.body or
cleaned['rating'] != existing_review.rating):
existing_review.body = cleaned['body']
existing_review.rating = cleaned['rating']
ip = request.META.get('REMOTE_ADDR', '')
existing_review.ip_address = ip
if 'flag' in cleaned and cleaned['flag']:
existing_review.flag = True
existing_review.editorreview = True
rf = ReviewFlag(review=existing_review,
user_id=request.user.id,
flag=ReviewFlag.OTHER,
note='URLs')
rf.save()
existing_review.save()
# Update ratings and review counts.
addon_review_aggregates.delay(addon.id,
using='default')
amo.log(amo.LOG.EDIT_REVIEW, addon, existing_review)
log.debug('[Review:%s] Edited by %s' % (existing_review.id,
request.user.id))
messages.success(request,
_('Your review was updated successfully!'))
# If there is a developer reply to the review, delete it. We do
# this per bug 777059.
try:
reply = existing_review.replies.all()[0]
except IndexError:
pass
else:
log.debug('[Review:%s] Deleted reply to %s' %
(reply.id, existing_review.id))
reply.delete()
else:
# If there isn't a review to overwrite, create a new review.
review = Review.objects.create(client_data=client_data,
**_review_details(request, addon, form))
if 'flag' in cleaned and cleaned['flag']:
rf = ReviewFlag(review=review,
user_id=request.user.id,
flag=ReviewFlag.OTHER,
note='URLs')
rf.save()
amo.log(amo.LOG.ADD_REVIEW, addon, review)
log.debug('[Review:%s] Created by user %s ' %
(review.id, request.user.id))
messages.success(request,
_('Your review was successfully added!'))
Addon.objects.invalidate(*[addon])
return redirect(addon.get_ratings_url('list'))
# If the form isn't valid, we've set `form` so that it can be used when
# the template is rendered below.
elif existing_review:
# If the user isn't posting back but has an existing review, populate
# the form with their existing review and rating.
form = ReviewForm({'rating': existing_review.rating or 1,
'body': existing_review.body})
has_review = True
else:
# If the user isn't posting back and doesn't have an existing review,
# just show a blank version of the form.
form = ReviewForm()
# Get app's support url, either from support flow if contribution exists or
# author's support url.
support_email = str(addon.support_email) if addon.support_email else None
try:
contrib_id = (Contribution.objects
.filter(user=request.user, addon=addon,
type__in=(amo.CONTRIB_PURCHASE,
amo.CONTRIB_INAPP,
amo.CONTRIB_REFUND))
.order_by('-created')[0].id)
support_url = reverse('support', args=[contrib_id])
except IndexError:
support_url = addon.support_url
return jingo.render(request, 'ratings/add.html',
{'product': addon, 'form': form,
'support_url': support_url,
'has_review': has_review,
'support_email': support_email})