def test_get_total(self): user2 = UserProfile.objects.get(email="*****@*****.**") self._give_points() self._give_points(status=amo.STATUS_LITE) self._give_points(user=user2, status=amo.STATUS_NOMINATED) eq_( ReviewerScore.get_total(self.user), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL] + amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_PRELIM], ) eq_(ReviewerScore.get_total(user2), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL])
def test_get_total(self): user2 = UserProfile.objects.get(email='*****@*****.**') self._give_points() self._give_points(status=amo.STATUS_LITE) self._give_points(user=user2, status=amo.STATUS_NOMINATED) eq_(ReviewerScore.get_total(self.user), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL] + amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_PRELIM]) eq_(ReviewerScore.get_total(user2), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL])
def test_get_total(self): waffle.models.Switch.objects.create(name='reviewer-incentive-points', active=True) user2 = UserProfile.objects.get(email='*****@*****.**') self._give_points() self._give_points(event=amo.REVIEWED_ADDON_PRELIM) self._give_points(user=user2) eq_(ReviewerScore.get_total(self.user), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL] + amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_PRELIM]) eq_(ReviewerScore.get_total(user2), amo.REVIEWED_SCORES[amo.REVIEWED_ADDON_FULL])
def themes_commit(request): reviewer = request.user.get_profile() ThemeReviewFormset = formset_factory(forms.ThemeReviewForm) formset = ThemeReviewFormset(request.POST) scores = [] for form in formset: try: lock = ThemeLock.objects.filter(theme_id=form.data[form.prefix + '-theme'], reviewer=reviewer) except MultiValueDictKeyError: # Address off-by-one error caused by management form. continue if lock and form.is_valid(): scores.append(form.save()) # Success message. points = sum(scores) success = ngettext( # L10n: {0} is the number of reviews. {1} is the points just earned. # L10n: {2} is the total number of points the reviewer has overall. '{0} theme review successfully processed (+{1} points, {2} total).', '{0} theme reviews successfully processed (+{1} points, {2} total).', len(scores)).format(len(scores), points, ReviewerScore.get_total(request.amo_user)) amo.messages.success(request, success) if 'theme_redirect_url' in request.session: return redirect(request.session['theme_redirect_url']) else: return redirect(reverse('reviewers.themes.queue_themes'))
def performance(request, user_id=False): user = request.amo_user editors = _recent_editors() is_admin = acl.action_allowed(request, "Admin", "%") if is_admin and user_id: try: user = UserProfile.objects.get(pk=user_id) except UserProfile.DoesNotExist: pass # Use request.amo_user from above. monthly_data = _performance_by_month(user.id) performance_total = _performance_total(monthly_data) point_total = ReviewerScore.get_total(user) point_breakdown = ReviewerScore.get_breakdown(user) data = context( monthly_data=json.dumps(monthly_data), performance_month=performance_total["month"], performance_year=performance_total["year"], point_breakdown=point_breakdown, point_total=point_total, editors=editors, current_user=user, is_admin=is_admin, is_user=(request.amo_user.id == user.id), ) return jingo.render(request, "editors/performance.html", data)
def themes_commit(request): reviewer = request.user.get_profile() ThemeReviewFormset = formset_factory(forms.ThemeReviewForm) formset = ThemeReviewFormset(request.POST) scores = [] for form in formset: try: lock = ThemeLock.objects.filter( theme_id=form.data[form.prefix + '-theme'], reviewer=reviewer) except MultiValueDictKeyError: # Address off-by-one error caused by management form. continue if lock and form.is_valid(): scores.append(form.save()) # Success message. points = sum(scores) success = ngettext( # L10n: {0} is the number of reviews. {1} is the points just earned. # L10n: {2} is the total number of points the reviewer has overall. '{0} theme review successfully processed (+{1} points, {2} total).', '{0} theme reviews successfully processed (+{1} points, {2} total).', len(scores)).format(len(scores), points, ReviewerScore.get_total(request.amo_user)) amo.messages.success(request, success) if 'theme_redirect_url' in request.session: return redirect(request.session['theme_redirect_url']) else: return redirect(reverse('editors.themes.queue_themes'))
def reviewers_score_bar(context): user = context.get('amo_user') return new_context(dict( amo=amo, points=ReviewerScore.get_recent(user), total=ReviewerScore.get_total(user), **ReviewerScore.get_leaderboards(user)))
def performance(request, user_id=False): user = request.amo_user editors = _recent_editors() is_admin = (acl.action_allowed(request, 'Admin', '%') or acl.action_allowed(request, 'ReviewerAdminTools', 'View')) if is_admin and user_id: try: user = UserProfile.objects.get(pk=user_id) except UserProfile.DoesNotExist: pass # Use request.amo_user from above. monthly_data = _performance_by_month(user.id) performance_total = _performance_total(monthly_data) # Incentive point breakdown. today = date.today() month_ago = today - timedelta(days=30) year_ago = today - timedelta(days=365) point_total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { 'month': { 'addons': _sum(months, amo.GROUP_TYPE_ADDON), 'apps': _sum(months, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(months, amo.GROUP_TYPE_THEME), }, 'year': { 'addons': _sum(years, amo.GROUP_TYPE_ADDON), 'apps': _sum(years, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(years, amo.GROUP_TYPE_THEME), }, 'total': { 'addons': _sum(totals, amo.GROUP_TYPE_ADDON), 'apps': _sum(totals, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(totals, amo.GROUP_TYPE_THEME), } } data = context(monthly_data=json.dumps(monthly_data), performance_month=performance_total['month'], performance_year=performance_total['year'], breakdown=breakdown, point_total=point_total, editors=editors, current_user=user, is_admin=is_admin, is_user=(request.amo_user.id == user.id)) return jingo.render(request, 'editors/performance.html', data)
def reviewers_score_bar(context, types=None): user = context.get('amo_user') return new_context(dict( request=context.get('request'), amo=amo, settings=settings, points=ReviewerScore.get_recent(user), total=ReviewerScore.get_total(user), **ReviewerScore.get_leaderboards(user, types=types)))
def reviewers_score_bar(context, types=None): user = context.get('amo_user') return new_context( dict(request=context.get('request'), amo=amo, settings=settings, points=ReviewerScore.get_recent(user), total=ReviewerScore.get_total(user), **ReviewerScore.get_leaderboards(user, types=types)))
def performance(request, user_id=False): user = request.amo_user editors = _recent_editors() is_admin = (acl.action_allowed(request, 'Admin', '%') or acl.action_allowed(request, 'ReviewerAdminTools', 'View')) if is_admin and user_id: try: user = UserProfile.objects.get(pk=user_id) except UserProfile.DoesNotExist: pass # Use request.amo_user from above. monthly_data = _performance_by_month(user.id) performance_total = _performance_total(monthly_data) # Incentive point breakdown. today = date.today() month_ago = today - timedelta(days=30) year_ago = today - timedelta(days=365) point_total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { 'month': { 'addons': _sum(months, amo.GROUP_TYPE_ADDON), 'apps': _sum(months, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(months, amo.GROUP_TYPE_THEME), }, 'year': { 'addons': _sum(years, amo.GROUP_TYPE_ADDON), 'apps': _sum(years, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(years, amo.GROUP_TYPE_THEME), }, 'total': { 'addons': _sum(totals, amo.GROUP_TYPE_ADDON), 'apps': _sum(totals, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(totals, amo.GROUP_TYPE_THEME), } } data = context(monthly_data=json.dumps(monthly_data), performance_month=performance_total['month'], performance_year=performance_total['year'], breakdown=breakdown, point_total=point_total, editors=editors, current_user=user, is_admin=is_admin, is_user=(request.amo_user.id == user.id)) return render(request, 'editors/performance.html', data)
def test_caching(self): waffle.models.Switch.objects.create(name='reviewer-incentive-points', active=True) self._give_points() with self.assertNumQueries(1): ReviewerScore.get_total(self.user) with self.assertNumQueries(0): ReviewerScore.get_total(self.user) with self.assertNumQueries(1): ReviewerScore.get_recent(self.user) with self.assertNumQueries(0): ReviewerScore.get_recent(self.user) with self.assertNumQueries(2): ReviewerScore.get_leaderboards(self.user) with self.assertNumQueries(0): ReviewerScore.get_leaderboards(self.user) # New points invalidates all caches. self._give_points() with self.assertNumQueries(1): ReviewerScore.get_total(self.user) with self.assertNumQueries(1): ReviewerScore.get_recent(self.user) with self.assertNumQueries(2): ReviewerScore.get_leaderboards(self.user)
def test_caching(self): self._give_points() with self.assertNumQueries(1): ReviewerScore.get_total(self.user) with self.assertNumQueries(0): ReviewerScore.get_total(self.user) with self.assertNumQueries(1): ReviewerScore.get_recent(self.user) with self.assertNumQueries(0): ReviewerScore.get_recent(self.user) with self.assertNumQueries(1): ReviewerScore.get_leaderboards(self.user) with self.assertNumQueries(0): ReviewerScore.get_leaderboards(self.user) with self.assertNumQueries(1): ReviewerScore.get_breakdown(self.user) with self.assertNumQueries(0): ReviewerScore.get_breakdown(self.user) # New points invalidates all caches. self._give_points() with self.assertNumQueries(1): ReviewerScore.get_total(self.user) with self.assertNumQueries(1): ReviewerScore.get_recent(self.user) with self.assertNumQueries(1): ReviewerScore.get_leaderboards(self.user) with self.assertNumQueries(1): ReviewerScore.get_breakdown(self.user)
def performance(request, username=None): is_admin = acl.action_allowed(request, 'Admin', '%') if username: if username == request.amo_user.username: user = request.amo_user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.amo_user today = datetime.date.today() month_ago = today - datetime.timedelta(days=30) year_ago = today - datetime.timedelta(days=365) total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { 'month': { 'addons': _sum(months, amo.GROUP_TYPE_ADDON), 'apps': _sum(months, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(months, amo.GROUP_TYPE_THEME), }, 'year': { 'addons': _sum(years, amo.GROUP_TYPE_ADDON), 'apps': _sum(years, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(years, amo.GROUP_TYPE_THEME), }, 'total': { 'addons': _sum(totals, amo.GROUP_TYPE_ADDON), 'apps': _sum(totals, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(totals, amo.GROUP_TYPE_THEME), } } ctx = context( request, **{ 'profile': user, 'total': total, 'breakdown': breakdown, }) return jingo.render(request, 'reviewers/performance.html', ctx)
def reviewers_score_bar(context, types=None, addon_type=None): user = context.get("amo_user") return new_context( dict( request=context.get("request"), amo=amo, settings=settings, points=ReviewerScore.get_recent(user, addon_type=addon_type), total=ReviewerScore.get_total(user), **ReviewerScore.get_leaderboards(user, types=types, addon_type=addon_type) ) )
def performance(request, username=None): is_admin = acl.action_allowed(request, 'Admin', '%') if username: if username == request.amo_user.username: user = request.amo_user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.amo_user today = datetime.date.today() month_ago = today - datetime.timedelta(days=30) year_ago = today - datetime.timedelta(days=365) total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { 'month': { 'addons': _sum(months, amo.GROUP_TYPE_ADDON), 'apps': _sum(months, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(months, amo.GROUP_TYPE_THEME), }, 'year': { 'addons': _sum(years, amo.GROUP_TYPE_ADDON), 'apps': _sum(years, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(years, amo.GROUP_TYPE_THEME), }, 'total': { 'addons': _sum(totals, amo.GROUP_TYPE_ADDON), 'apps': _sum(totals, amo.GROUP_TYPE_WEBAPP), 'themes': _sum(totals, amo.GROUP_TYPE_THEME), } } ctx = context(request, **{ 'profile': user, 'total': total, 'breakdown': breakdown, }) return jingo.render(request, 'reviewers/performance.html', ctx)
def performance(request, username=None): is_admin = acl.action_allowed(request, "Admin", "%") if username: if username == request.amo_user.username: user = request.amo_user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.amo_user today = datetime.date.today() month_ago = today - datetime.timedelta(days=30) year_ago = today - datetime.timedelta(days=365) total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { "month": { "addons": _sum(months, amo.GROUP_TYPE_ADDON), "apps": _sum(months, amo.GROUP_TYPE_WEBAPP), "themes": _sum(months, amo.GROUP_TYPE_THEME), }, "year": { "addons": _sum(years, amo.GROUP_TYPE_ADDON), "apps": _sum(years, amo.GROUP_TYPE_WEBAPP), "themes": _sum(years, amo.GROUP_TYPE_THEME), }, "total": { "addons": _sum(totals, amo.GROUP_TYPE_ADDON), "apps": _sum(totals, amo.GROUP_TYPE_WEBAPP), "themes": _sum(totals, amo.GROUP_TYPE_THEME), }, } ctx = context(request, **{"profile": user, "total": total, "breakdown": breakdown}) return jingo.render(request, "reviewers/performance.html", ctx)
def performance(request, user_id=False): user = request.amo_user editors = _recent_editors() is_admin = acl.action_allowed(request, "Admin", "%") or acl.action_allowed(request, "ReviewerAdminTools", "View") if is_admin and user_id: try: user = UserProfile.objects.get(pk=user_id) except UserProfile.DoesNotExist: pass # Use request.amo_user from above. monthly_data = _performance_by_month(user.id) performance_total = _performance_total(monthly_data) # Incentive point breakdown. today = date.today() month_ago = today - timedelta(days=30) year_ago = today - timedelta(days=365) point_total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types): return sum(s.total for s in iter if s.atype in types) breakdown = { "month": {"addons": _sum(months, amo.GROUP_TYPE_ADDON), "themes": _sum(months, amo.GROUP_TYPE_THEME)}, "year": {"addons": _sum(years, amo.GROUP_TYPE_ADDON), "themes": _sum(years, amo.GROUP_TYPE_THEME)}, "total": {"addons": _sum(totals, amo.GROUP_TYPE_ADDON), "themes": _sum(totals, amo.GROUP_TYPE_THEME)}, } data = context( monthly_data=json.dumps(monthly_data), performance_month=performance_total["month"], performance_year=performance_total["year"], breakdown=breakdown, point_total=point_total, editors=editors, current_user=user, is_admin=is_admin, is_user=(request.amo_user.id == user.id), ) return render(request, "editors/performance.html", data)
def performance(request, username=None): is_admin = acl.action_allowed(request, "Admin", "%") if username: if username == request.amo_user.username: user = request.amo_user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.amo_user total = ReviewerScore.get_total(user) breakdown = ReviewerScore.get_breakdown(user) ctx = context(**{"profile": user, "total": total, "breakdown": breakdown}) return jingo.render(request, "reviewers/performance.html", ctx)
def performance(request, username=None): is_admin = acl.action_allowed(request, 'Admin', '%') if username: if username == request.amo_user.username: user = request.amo_user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.amo_user total = ReviewerScore.get_total(user) breakdown = ReviewerScore.get_breakdown(user) ctx = context(**{ 'profile': user, 'total': total, 'breakdown': breakdown, }) return jingo.render(request, 'reviewers/performance.html', ctx)
def performance(request, user_id=False): user = request.user editors = _recent_editors() is_admin = (acl.action_allowed(request, 'Admin', '%') or acl.action_allowed(request, 'ReviewerAdminTools', 'View')) if is_admin and user_id: try: user = UserProfile.objects.get(pk=user_id) except UserProfile.DoesNotExist: pass # Use request.user from above. motd_editable = acl.action_allowed(request, 'AddonReviewerMOTD', 'Edit') monthly_data = _performance_by_month(user.id) performance_total = _performance_total(monthly_data) # Incentive point breakdown. today = date.today() month_ago = today - timedelta(days=30) year_ago = today - timedelta(days=365) point_total = ReviewerScore.get_total(user) totals = ReviewerScore.get_breakdown(user) months = ReviewerScore.get_breakdown_since(user, month_ago) years = ReviewerScore.get_breakdown_since(user, year_ago) def _sum(iter, types, exclude=False): """Sum the `total` property for items in `iter` that have an `atype` that is included in `types` when `exclude` is False (default) or not in `types` when `exclude` is True.""" return sum(s.total for s in iter if (s.atype in types) == (not exclude)) breakdown = { 'month': { 'addons': _sum(months, amo.GROUP_TYPE_ADDON), 'themes': _sum(months, amo.GROUP_TYPE_THEME), 'other': _sum(months, amo.GROUP_TYPE_ADDON + amo.GROUP_TYPE_THEME, exclude=True) }, 'year': { 'addons': _sum(years, amo.GROUP_TYPE_ADDON), 'themes': _sum(years, amo.GROUP_TYPE_THEME), 'other': _sum(years, amo.GROUP_TYPE_ADDON + amo.GROUP_TYPE_THEME, exclude=True) }, 'total': { 'addons': _sum(totals, amo.GROUP_TYPE_ADDON), 'themes': _sum(totals, amo.GROUP_TYPE_THEME), 'other': _sum(totals, amo.GROUP_TYPE_ADDON + amo.GROUP_TYPE_THEME, exclude=True) } } data = context(request, monthly_data=json.dumps(monthly_data), performance_month=performance_total['month'], performance_year=performance_total['year'], breakdown=breakdown, point_total=point_total, editors=editors, current_user=user, is_admin=is_admin, is_user=(request.user.id == user.id), motd_editable=motd_editable) return render(request, 'editors/performance.html', data)
def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.amo_user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = CommAttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset] if version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Addons', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) old_features = set(features_list) new_features = set(unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get('action') == 'public': if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _(u'Device(s) changed by ' 'reviewer: {0}').format(', '.join( [_(u'Added {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices] + [_(u'Removed {0}').format( unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices])) amo.log(amo.LOG.REVIEW_DEVICE_OVERRIDE, addon, addon.current_version, details={'comments': msg}) if old_features != new_features: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) amo.log(amo.LOG.REVIEW_FEATURES_OVERRIDE, addon, addon.current_version, details={'comments': msg}) score = form.helper.process() if form.cleaned_data.get('notify'): EditorSubscription.objects.get_or_create(user=request.amo_user, addon=addon) # Success message. if score: score = ReviewerScore.objects.filter(user=request.amo_user)[0] # L10N: {0} is the type of review. {1} is the points they earned. # {2} is the points they now have total. success = _( u'"{0}" successfully processed (+{1} points, {2} total).' .format(unicode(amo.REVIEWED_CHOICES[score.note_key]), score.score, ReviewerScore.get_total(request.amo_user))) else: success = _('Review successfully processed.') messages.success(request, success) return redirect(redirect_url) canned = AppCannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id) .filter(files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC) .latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter(addon=addon) .order_by('-created') .transform(Version.transformer_activity) .transform(Version.transformer)) product_attrs = { 'product': json.dumps( product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, flags=Review.objects.filter(addon=addon, flag=True), form=form, canned=canned, is_admin=is_admin, status_types=amo.MKT_STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form) if features_list is not None: ctx['feature_list'] = features_list return render(request, 'reviewers/review.html', ctx)
def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.amo_user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = CommAttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset] if version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Addons', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) old_features = set(features_list) new_features = set( unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get('action') == 'public': if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _( u'Device(s) changed by ' 'reviewer: {0}' ).format(', '.join([ _(u'Added {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices ] + [ _(u'Removed {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices ])) amo.log(amo.LOG.REVIEW_DEVICE_OVERRIDE, addon, addon.current_version, details={'comments': msg}) if old_features != new_features: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) amo.log(amo.LOG.REVIEW_FEATURES_OVERRIDE, addon, addon.current_version, details={'comments': msg}) score = form.helper.process() if form.cleaned_data.get('notify'): EditorSubscription.objects.get_or_create(user=request.amo_user, addon=addon) # Success message. if score: score = ReviewerScore.objects.filter(user=request.amo_user)[0] rev_str = amo.REVIEWED_CHOICES[score.note_key] try: rev_str = str(unicode(rev_str)) except UnicodeEncodeError: pass # L10N: {0} is the type of review. {1} is the points they earned. # {2} is the points they now have total. success = _( '"{0}" successfully processed (+{1} points, {2} total).'. format(rev_str, score.score, ReviewerScore.get_total(request.amo_user))) else: success = _('Review successfully processed.') messages.success(request, success) return redirect(redirect_url) canned = AppCannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id).filter( files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC).latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter( addon=addon).order_by('-created').transform( Version.transformer_activity).transform(Version.transformer)) product_attrs = { 'product': json.dumps(product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, flags=Review.objects.filter(addon=addon, flag=True), form=form, canned=canned, is_admin=is_admin, status_types=amo.MKT_STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form) if features_list is not None: ctx['feature_list'] = features_list return jingo.render(request, 'reviewers/review.html', ctx)