Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/apps/reviews/views.py
blob: 7907c813d45d7d05ed4aa488160c599b924c8443 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
from django import http
from django.shortcuts import get_object_or_404, redirect

import commonware.log
import jingo
from tower import ugettext as _

from amo import messages
import amo.utils
from amo.decorators import post_required, json_view, login_required
from access import acl
from addons.models import Addon

from .models import Review, ReviewFlag, GroupedRating, Spam
from . import forms

log = commonware.log.getLogger('z.reviews')


def flag_context():
    return dict(ReviewFlag=ReviewFlag,
                flag_form=forms.ReviewFlagForm())


def review_list(request, addon_id, review_id=None, user_id=None):
    addon = get_object_or_404(Addon.objects.valid(), id=addon_id)
    q = (Review.objects.valid().filter(addon=addon)
         .order_by('-created'))

    ctx = {'addon': addon,
           'grouped_ratings': GroupedRating.get(addon_id)}
    ctx.update(flag_context())

    ctx['form'] = forms.ReviewForm(None)

    if review_id is not None:
        ctx['page'] = 'detail'
        # If this is a dev reply, find the first msg for context.
        review = get_object_or_404(Review.objects.all(), pk=review_id)
        if review.reply_to_id:
            review_id = review.reply_to_id
            ctx['reply'] = review
        q = q.filter(pk=review_id)
    elif user_id is not None:
        ctx['page'] = 'user'
        q = q.filter(user=user_id)
    else:
        ctx['page'] = 'list'
        q = q.filter(is_latest=True)

    ctx['reviews'] = reviews = amo.utils.paginate(request, q)
    if not reviews.object_list:
        raise http.Http404()

    ctx['replies'] = Review.get_replies(reviews.object_list)
    if request.user.is_authenticated():
        ctx['review_perms'] = {
            'is_admin': acl.action_allowed(request, 'Admin', 'EditAnyAddon'),
            'is_editor': acl.action_allowed(request, 'Editor', '%'),
            'is_author': acl.check_ownership(request, addon,
                                             require_owner=True),
            'can_delete': acl.action_allowed(request, 'Editors',
                                             'DeleteReview'),
        }
        ctx['flags'] = get_flags(request, reviews.object_list)
    else:
        ctx['review_perms'] = {}
    return jingo.render(request, 'reviews/review_list.html', ctx)


def get_flags(request, reviews):
    reviews = [r.id for r in reviews]
    qs = ReviewFlag.objects.filter(review__in=reviews, user=request.user.id)
    return dict((r.review_id, r) for r in qs)


@post_required
@login_required(redirect=False)
@json_view
def flag(request, addon_id, review_id):
    d = dict(review=review_id, user=request.user.id)
    try:
        instance = ReviewFlag.objects.get(**d)
    except ReviewFlag.DoesNotExist:
        instance = None
    data = dict(request.POST.items(), **d)
    form = forms.ReviewFlagForm(data, instance=instance)
    if form.is_valid():
        form.save()
        Review.objects.filter(id=review_id).update(editorreview=True)
        return {'msg': _('Thanks; this review has been flagged '
                         'for editor approval.')}
    else:
        return json_view.error(unicode(form.errors))


@post_required
@login_required(redirect=False)
def delete(request, addon_id, review_id):
    if not acl.action_allowed(request, 'Editors', 'DeleteReview'):
        return http.HttpResponseForbidden()
    review = get_object_or_404(Review.objects, pk=review_id, addon=addon_id)
    review.delete()
    log.info('DELETE: %s deleted %s by %s ("%s": "%s")' %
             (request.amo_user.name, review_id,
              review.user.name, review.title, review.body))
    return http.HttpResponse()


def _review_details(request, addon, form):
    version = addon.current_version and addon.current_version.id
    d = dict(addon_id=addon.id, user_id=request.user.id,
             version_id=version,
             ip_address=request.META.get('REMOTE_ADDR', ''))
    d.update(**form.cleaned_data)
    return d


@login_required
def reply(request, addon_id, review_id):
    addon = get_object_or_404(Addon.objects.valid(), id=addon_id)
    is_admin = acl.action_allowed(request, 'Admin', 'EditAnyAddon')
    is_author = acl.check_ownership(request, addon, require_owner=True)
    if not (is_admin or is_author):
        return http.HttpResponseForbidden()

    review = get_object_or_404(Review.objects, pk=review_id, addon=addon_id)
    form = forms.ReviewReplyForm(request.POST or None)
    if request.method == 'POST':
        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 key, val in _review_details(request, addon, form).items():
                setattr(reply, key, val)
            reply.save()
            action = 'New' if new else 'Edited'
            log.debug('%s reply to %s: %s' % (action, review_id, reply.id))
            return redirect('reviews.detail', addon_id, review_id)
    ctx = dict(review=review, form=form, addon=addon)
    ctx.update(flag_context())
    return jingo.render(request, 'reviews/reply.html', ctx)


@login_required
def add(request, addon_id):
    addon = get_object_or_404(Addon.objects.valid(), id=addon_id)
    form = forms.ReviewForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            details = _review_details(request, addon, form)
            review = Review.objects.create(**details)
            log.debug('New review: %s' % review.id)
            return redirect('reviews.list', addon_id)
    return jingo.render(request, 'reviews/add.html',
                        dict(addon=addon, form=form))


@login_required(redirect=False)
@post_required
def edit(request, addon_id, review_id):
    review = get_object_or_404(Review.objects, pk=review_id, addon=addon_id)
    is_admin = acl.action_allowed(request, 'Admin', 'EditAnyAddon')
    if not (request.user.id == review.user.id or is_admin):
        return http.HttpResponseForbidden()
    cls = forms.ReviewReplyForm if review.reply_to else forms.ReviewForm
    form = cls(request.POST)
    if form.is_valid():
        for field in form.fields:
            if field in form.cleaned_data:
                setattr(review, field, form.cleaned_data[field])
        review.save()
        return http.HttpResponse()
    else:
        return json_view.error(form.errors)


@login_required
def spam(request):
    if not acl.action_allowed(request, 'Admin', 'BattleSpam'):
        return http.HttpResponseForbidden()
    spam = Spam()

    if request.method == 'POST':
        review = Review.objects.get(pk=request.POST['review'])
        if 'del_review' in request.POST:
            log.info('SPAM: %s' % review.id)
            delete(request, request.POST['addon'], review.id)
            messages.success(request, 'Deleted that review.')
        elif 'del_user' in request.POST:
            user = review.user
            log.info('SPAMMER: %s deleted %s' %
                     (request.amo_user.username, user.username))
            if not user.is_developer:
                Review.objects.filter(user=user).delete()
                user.anonymize()
            messages.success(request, 'Deleted that dirty spammer.')

        for reason in spam.reasons():
            spam.redis.srem(reason, review.id)
        return redirect('reviews.spam')

    buckets = {}
    for reason in spam.reasons():
        ids = spam.redis.smembers(reason)
        key = reason.split(':')[-1]
        buckets[key] = (Review.objects.no_cache().filter(id__in=ids)
                        .select_related('addon'))
    return jingo.render(request, 'reviews/spam.html',
                        dict(buckets=buckets,
                             review_perms=dict(is_admin=True)))