Skip to content
This repository was archived by the owner on Mar 15, 2018. It is now read-only.

Commit 6f754d3

Browse files
author
Rob Hudson
committed
Added backend for device specific queue (bug 862474)
1 parent 892d0ea commit 6f754d3

7 files changed

Lines changed: 145 additions & 39 deletions

File tree

apps/amo/tests/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ def __getattr__(self, name):
190190

191191

192192
ES_patchers = [mock.patch('amo.search.get_es', spec=True),
193-
mock.patch('elasticutils.contrib.django', spec=True)]
193+
mock.patch('elasticutils.contrib.django', spec=True),
194+
mock.patch('mkt.webapps.models.WebappIndexer.get_es',
195+
spec=True)]
194196

195197

196198
def start_es_mock():

mkt/reviewers/helpers.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from django.core.exceptions import ObjectDoesNotExist
66

77
import jinja2
8+
import waffle
89
from jingo import register
910
from tower import ugettext as _, ugettext_lazy as _lazy
10-
import waffle
1111

1212

1313
from access import acl
@@ -16,7 +16,7 @@
1616

1717
from mkt.developers.helpers import mkt_page_title
1818
from mkt.reviewers.utils import (AppsReviewing, clean_sort_param,
19-
create_sort_link)
19+
create_sort_link, device_queue_search)
2020

2121

2222
@register.function
@@ -38,6 +38,7 @@ def reviewers_breadcrumbs(context, queue=None, items=None):
3838
'rereview': _('Re-reviews'),
3939
'updates': _('Updates'),
4040
'escalated': _('Escalations'),
41+
'device': _('Device'),
4142
'moderated': _('Moderated Reviews'),
4243
'reviewing': _('Reviewing'),
4344
'themes': _('Themes')}
@@ -73,11 +74,12 @@ def queue_tabnav(context):
7374
7475
Each tuple contains three elements: (named_url. tab_code, tab_text)
7576
"""
77+
request = context['request']
7678
counts = context['queue_counts']
77-
apps_reviewing = AppsReviewing(context['request']).get_apps()
79+
apps_reviewing = AppsReviewing(request).get_apps()
7880

7981
# Apps.
80-
if acl.action_allowed(context['request'], 'Apps', 'Review'):
82+
if acl.action_allowed(request, 'Apps', 'Review'):
8183
rv = [
8284
('reviewers.apps.queue_pending', 'pending',
8385
_('Apps ({0})', counts['pending']).format(counts['pending'])),
@@ -89,7 +91,7 @@ def queue_tabnav(context):
8991
('reviewers.apps.queue_updates', 'updates',
9092
_('Updates ({0})', counts['updates']).format(counts['updates'])),
9193
]
92-
if acl.action_allowed(context['request'], 'Apps', 'ReviewEscalated'):
94+
if acl.action_allowed(request, 'Apps', 'ReviewEscalated'):
9395
rv.append(('reviewers.apps.queue_escalated', 'escalated',
9496
_('Escalations ({0})', counts['escalated']).format(
9597
counts['escalated'])))
@@ -105,10 +107,16 @@ def queue_tabnav(context):
105107
rv = []
106108

107109
# Themes.
108-
if (acl.action_allowed(context['request'], 'Personas', 'Review') and
110+
if (acl.action_allowed(request, 'Personas', 'Review') and
109111
waffle.switch_is_active('mkt-themes')):
110112
rv.append(('reviewers.themes.list', 'themes',
111113
_('Themes ({0})').format(counts['themes']),))
114+
115+
if waffle.switch_is_active('buchets') and 'pro' in request.GET:
116+
device_srch = device_queue_search(request)
117+
rv.append(('reviewers.apps.queue_device', 'device',
118+
_('Device ({0})').format(device_srch.count()),))
119+
112120
return rv
113121

114122

mkt/reviewers/tests/test_views.py

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# -*- coding: utf-8 -*-
22
import datetime
33
import json
4+
import os.path
45
import time
56
from itertools import cycle
6-
import os.path
77

88
from django.conf import settings
99
from django.core import mail
@@ -13,13 +13,14 @@
1313
from django.utils import translation
1414

1515
import mock
16+
import requests
1617
from nose import SkipTest
1718
from nose.tools import eq_, ok_
1819
from pyquery import PyQuery as pq
19-
import requests
2020

2121
import amo
2222
import amo.tests
23+
import reviews
2324
from abuse.models import AbuseReport
2425
from access.models import GroupUser
2526
from addons.models import AddonDeviceType
@@ -35,16 +36,17 @@
3536
from files.models import File
3637
from lib.crypto import packaged
3738
from lib.crypto.tests import mock_sign
39+
from reviews.models import Review, ReviewFlag
40+
from users.models import UserProfile
41+
from versions.models import Version
42+
from zadmin.models import get_config, set_config
43+
44+
from mkt.constants.features import FeatureProfile
3845
from mkt.reviewers.views import _do_sort, _queue_to_apps
3946
from mkt.site.fixtures import fixture
4047
from mkt.submit.tests.test_views import BasePackagedAppTest
4148
from mkt.webapps.models import Webapp
4249
from mkt.webapps.tests.test_models import PackagedFilesMixin
43-
import reviews
44-
from reviews.models import Review, ReviewFlag
45-
from users.models import UserProfile
46-
from versions.models import Version
47-
from zadmin.models import get_config, set_config
4850

4951

5052
class AttachmentManagementMixin(object):
@@ -660,6 +662,50 @@ def test_deleted_version_not_in_queue(self, _mock):
660662
ok_(self.apps[1] in apps)
661663

662664

665+
class TestDeviceQueue(AppReviewerTest, AccessMixin):
666+
fixtures = fixture('group_editor.json', 'user_editor.json',
667+
'user_editor_group.json', 'user_999.json')
668+
669+
def setUp(self):
670+
self.create_switch('buchets')
671+
self.create_switch('search-api-es')
672+
673+
self.app1 = app_factory(name='XXX',
674+
version_kw={'version': '1.0',
675+
'created': self.days_ago(2),
676+
'nomination': self.days_ago(2)})
677+
self.app1.versions.latest().features.update(has_sms=True)
678+
679+
self.app2 = app_factory(name='YYY',
680+
version_kw={'version': '1.0',
681+
'created': self.days_ago(2),
682+
'nomination': self.days_ago(2)})
683+
self.app2.versions.latest().features.update(has_mp3=True)
684+
685+
self.app1.update(status=amo.STATUS_PENDING)
686+
self.app2.update(status=amo.STATUS_PENDING)
687+
688+
self.apps = list(Webapp.objects.order_by('id'))
689+
self.login_as_editor()
690+
self.url = reverse('reviewers.apps.queue_device')
691+
692+
def test_no_queue_if_no_pro(self):
693+
res = self.client.get(self.url)
694+
eq_(res.status_code, 200)
695+
ok_('queue_device' not in res.context['queue_counts'])
696+
eq_(res.context['addons'], [])
697+
698+
def test_queue_filters(self):
699+
"Test queue filters out apps we don't support."
700+
pro = FeatureProfile(sms=True).to_signature()
701+
res = self.client.get(self.url, {'pro': pro})
702+
eq_(res.status_code, 200)
703+
eq_(res.context['queue_counts']['device'], 1)
704+
apps = [a.app for a in res.context['addons']]
705+
ok_(self.app1 in apps)
706+
ok_(self.app2 not in apps)
707+
708+
663709
class TestEscalationQueue(AppReviewerTest, AccessMixin, FlagsMixin,
664710
SearchMixin, XSSMixin):
665711
fixtures = ['base/users']

mkt/reviewers/urls.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
name='reviewers.apps.queue_updates'),
2323
url(r'^apps/queue/escalated/$', views.queue_escalated,
2424
name='reviewers.apps.queue_escalated'),
25-
url(r'^apps/queue/moderated$', views.queue_moderated,
25+
url(r'^apps/queue/moderated/$', views.queue_moderated,
2626
name='reviewers.apps.queue_moderated'),
27+
url(r'^apps/queue/device/$', views.queue_device,
28+
name='reviewers.apps.queue_device'),
2729
url(r'^apps/review/%s$' % amo.APP_SLUG, views.app_review,
2830
name='reviewers.apps.review'),
2931
url(r'^apps/review/%s/manifest$' % amo.APP_SLUG, views.app_view_manifest,

mkt/reviewers/utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from editors.models import EscalationQueue, RereviewQueue, ReviewerScore
1919
from files.models import File
2020

21+
from mkt.constants.features import FeatureProfile
2122
from mkt.site.helpers import product_as_dict
2223
from mkt.webapps.models import Webapp
2324

@@ -533,3 +534,23 @@ def add(self, addon_id):
533534
apps.append(addon_id)
534535
cache.set(self.key, ','.join(map(str, set(apps))),
535536
amo.EDITOR_VIEWING_INTERVAL * 2)
537+
538+
539+
def device_queue_search(request):
540+
"""
541+
Returns a queryset that can be used as a base for searching the device
542+
specific queue.
543+
"""
544+
filters = {
545+
'type': amo.ADDON_WEBAPP,
546+
'status': amo.STATUS_PENDING,
547+
'disabled_by_user': False,
548+
}
549+
sig = request.GET.get('pro')
550+
if sig:
551+
profile = FeatureProfile.from_signature(sig)
552+
filters.update(dict(
553+
**profile.to_kwargs(prefix='_current_version__features__has_')
554+
))
555+
return Webapp.version_and_file_transformer(
556+
Webapp.objects.filter(**filters))

mkt/reviewers/views.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
from users.models import UserProfile
4545
from zadmin.models import set_config, unmemoized_get_config
4646

47-
from mkt.reviewers.utils import AppsReviewing, clean_sort_param
47+
from mkt.reviewers.utils import (AppsReviewing, clean_sort_param,
48+
device_queue_search)
4849
from mkt.search.forms import ApiSearchForm
4950
from mkt.site.helpers import product_as_dict
5051
from mkt.submit.forms import AppFeaturesForm
@@ -67,6 +68,7 @@ def home(request):
6768
progress, percentage = _progress()
6869

6970
data = context(
71+
request,
7072
reviews_total=ActivityLog.objects.total_reviews(webapp=True)[:5],
7173
reviews_monthly=ActivityLog.objects.monthly_reviews(webapp=True)[:5],
7274
#new_editors=EventLog.new_editors(), # Bug 747035
@@ -78,7 +80,7 @@ def home(request):
7880
return jingo.render(request, 'reviewers/home.html', data)
7981

8082

81-
def queue_counts():
83+
def queue_counts(request):
8284
excluded_ids = EscalationQueue.uncached.values_list('addon', flat=True)
8385

8486
counts = {
@@ -114,6 +116,10 @@ def queue_counts():
114116
.filter(addon__status=amo.STATUS_PENDING)
115117
.count(),
116118
}
119+
120+
if waffle.switch_is_active('buchets') and 'pro' in request.GET:
121+
counts.update({'device': device_queue_search(request).count()})
122+
117123
rv = {}
118124
if isinstance(type, basestring):
119125
return counts[type]
@@ -154,10 +160,10 @@ def _progress():
154160
return (progress, percentage)
155161

156162

157-
def context(**kw):
163+
def context(request, **kw):
158164
statuses = dict((k, unicode(v)) for k, v in amo.STATUS_CHOICES.items())
159165
ctx = dict(motd=unmemoized_get_config('mkt_reviewers_motd'),
160-
queue_counts=queue_counts(),
166+
queue_counts=queue_counts(request),
161167
search_url=reverse('api_dispatch_list', kwargs={
162168
'api_name': 'apps', 'resource_name': 'search'}),
163169
statuses=statuses, point_types=amo.REVIEWED_MARKETPLACE)
@@ -299,7 +305,7 @@ def _review(request, addon, version):
299305
num_pages = pager.paginator.num_pages
300306
count = pager.paginator.count
301307

302-
ctx = context(version=version, product=addon, pager=pager,
308+
ctx = context(request, version=version, product=addon, pager=pager,
303309
num_pages=num_pages, count=count,
304310
flags=Review.objects.filter(addon=addon, flag=True),
305311
form=form, canned=canned, is_admin=is_admin,
@@ -352,7 +358,7 @@ def _queue(request, apps, tab, pager_processor=None):
352358
per_page = request.GET.get('per_page', QUEUE_PER_PAGE)
353359
pager = paginate(request, apps, per_page)
354360

355-
return jingo.render(request, 'reviewers/queue.html', context(**{
361+
return jingo.render(request, 'reviewers/queue.html', context(request, **{
356362
'addons': pager.object_list,
357363
'pager': pager,
358364
'tab': tab,
@@ -443,6 +449,21 @@ def queue_updates(request):
443449
return _queue(request, apps, 'updates')
444450

445451

452+
@permission_required('Apps', 'Review')
453+
def queue_device(request):
454+
"""
455+
A device specific queue matching apps which require features that our
456+
device support based on the `profile` query string.
457+
"""
458+
if waffle.switch_is_active('buchets') and 'pro' in request.GET:
459+
apps = [QueuedApp(app, app.all_versions[0].nomination)
460+
for app in device_queue_search(request)]
461+
else:
462+
apps = []
463+
464+
return _queue(request, apps, 'device')
465+
466+
446467
@permission_required('Apps', 'Review')
447468
def queue_moderated(request):
448469
"""Queue for reviewing app reviews."""
@@ -463,7 +484,7 @@ def queue_moderated(request):
463484
return redirect(reverse('reviewers.apps.queue_moderated'))
464485

465486
return jingo.render(request, 'reviewers/queue.html',
466-
context(reviews_formset=reviews_formset,
487+
context(request, reviews_formset=reviews_formset,
467488
tab='moderated', page=page, flags=flags))
468489

469490

@@ -524,7 +545,7 @@ def logs(request):
524545
Q(user__username__icontains=term)).distinct()
525546

526547
pager = paginate(request, approvals, 50)
527-
data = context(form=form, pager=pager, ACTION_DICT=amo.LOG_BY_ID,
548+
data = context(request, form=form, pager=pager, ACTION_DICT=amo.LOG_BY_ID,
528549
tab='apps')
529550
return jingo.render(request, 'reviewers/logs.html', data)
530551

@@ -538,7 +559,7 @@ def motd(request):
538559
if form and request.method == 'POST' and form.is_valid():
539560
set_config(u'mkt_reviewers_motd', form.cleaned_data['motd'])
540561
return redirect(reverse('reviewers.apps.motd'))
541-
data = context(form=form)
562+
data = context(request, form=form)
542563
return jingo.render(request, 'reviewers/motd.html', data)
543564

544565

@@ -656,7 +677,8 @@ def app_abuse(request, addon):
656677
total = reports.count()
657678
reports = paginate(request, reports, count=total)
658679
return jingo.render(request, 'reviewers/abuse.html',
659-
context(addon=addon, reports=reports, total=total))
680+
context(request, addon=addon, reports=reports,
681+
total=total))
660682

661683

662684
@permission_required('Apps', 'Review')
@@ -718,7 +740,7 @@ def _sum(iter, types):
718740
}
719741
}
720742

721-
ctx = context(**{
743+
ctx = context(request, **{
722744
'profile': user,
723745
'total': total,
724746
'breakdown': breakdown,
@@ -730,18 +752,18 @@ def _sum(iter, types):
730752
@permission_required('Apps', 'Review')
731753
def leaderboard(request):
732754

733-
return jingo.render(request, 'reviewers/leaderboard.html', context(**{
734-
'scores': ReviewerScore.all_users_by_score(),
735-
}))
755+
return jingo.render(request, 'reviewers/leaderboard.html', context(request,
756+
**{'scores': ReviewerScore.all_users_by_score()}))
736757

737758

738759
@permission_required('Apps', 'Review')
739760
@json_view
740761
def apps_reviewing(request):
741762

742-
return jingo.render(request, 'reviewers/apps_reviewing.html', context(**{
743-
'apps': AppsReviewing(request).get_apps(),
744-
'tab': 'reviewing'}))
763+
return jingo.render(request, 'reviewers/apps_reviewing.html',
764+
context(request, **{
765+
'apps': AppsReviewing(request).get_apps(),
766+
'tab': 'reviewing'}))
745767

746768

747769
@permission_required('Apps', 'Review')

0 commit comments

Comments
 (0)