Filter Editor Review Queue by search terms (Bug 531910)
This commit is contained in:
Родитель
7d424845b6
Коммит
828ea06408
|
@ -377,7 +377,7 @@ def log(action, *args, **kw):
|
|||
e.g. amo.log(amo.LOG.CREATE_ADDON, []),
|
||||
amo.log(amo.LOG.ADD_FILE_TO_VERSION, file, version)
|
||||
"""
|
||||
from devhub.models import ActivityLog, AddonLog, UserLog
|
||||
from devhub.models import ActivityLog, AddonLog, UserLog, CommentLog
|
||||
from addons.models import Addon
|
||||
from users.models import UserProfile
|
||||
from amo import get_user, logger_log
|
||||
|
@ -394,6 +394,9 @@ def log(action, *args, **kw):
|
|||
al.details = kw['details']
|
||||
al.save()
|
||||
|
||||
if 'details' in kw and 'comments' in al.details:
|
||||
CommentLog(comments=al.details['comments'], activity_log=al).save()
|
||||
|
||||
# TODO(davedash): post-remora this may not be necessary.
|
||||
if 'created' in kw:
|
||||
al.created = kw['created']
|
||||
|
@ -406,6 +409,7 @@ def log(action, *args, **kw):
|
|||
AddonLog(addon_id=arg[1], activity_log=al).save()
|
||||
elif arg[0] == UserProfile:
|
||||
UserLog(user_id=arg[1], activity_log=al).save()
|
||||
|
||||
if isinstance(arg, Addon):
|
||||
AddonLog(addon=arg, activity_log=al).save()
|
||||
elif isinstance(arg, UserProfile):
|
||||
|
|
|
@ -84,6 +84,19 @@ class AddonLog(amo.models.ModelBase):
|
|||
ordering = ('-created',)
|
||||
|
||||
|
||||
class CommentLog(amo.models.ModelBase):
|
||||
"""
|
||||
This table is for indexing the activity log by user.
|
||||
Note: This includes activity performed unto the user.
|
||||
"""
|
||||
activity_log = models.ForeignKey('ActivityLog')
|
||||
comments = models.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
db_table = 'log_activity_comment'
|
||||
ordering = ('-created',)
|
||||
|
||||
|
||||
class UserLog(amo.models.ModelBase):
|
||||
"""
|
||||
This table is for indexing the activity log by user.
|
||||
|
|
|
@ -52,6 +52,24 @@ class ReviewLogForm(happyforms.Form):
|
|||
label=_lazy(u'View entries between'))
|
||||
end = forms.DateField(required=False,
|
||||
label=_lazy(u'and'))
|
||||
search = forms.CharField(required=False,
|
||||
label=_lazy(u'containing'))
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super(ReviewLogForm, self).__init__(*args, **kw)
|
||||
|
||||
|
||||
# L10n: start, as in "start date"
|
||||
self.fields['start'].widget.attrs = {'placeholder': _('start'),
|
||||
'size': 10}
|
||||
|
||||
# L10n: end, as in "end date"
|
||||
self.fields['end'].widget.attrs = {'size': 10, 'placeholder': _('end')}
|
||||
|
||||
# L10n: Description of what can be searched for
|
||||
search_ph = _('add-on, editor or comment')
|
||||
self.fields['search'].widget.attrs = {'placeholder': search_ph,
|
||||
'size': 30}
|
||||
|
||||
def clean(self):
|
||||
data = self.cleaned_data
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
|
||||
from addons.models import Addon
|
||||
from amo.utils import chunked
|
||||
from devhub.models import ActivityLog
|
||||
from editors.tasks import add_commentlog
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Add a CommentLog entry for all ActivityLog items'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
pks = ActivityLog.objects.review_queue().values_list('pk', flat=True).order_by('id')
|
||||
|
||||
for chunk in chunked(pks, 100):
|
||||
add_commentlog.delay(chunk)
|
|
@ -0,0 +1,30 @@
|
|||
from django.conf import settings
|
||||
|
||||
import commonware.log
|
||||
import celery.task
|
||||
from celeryutils import task
|
||||
from hera.contrib.django_utils import flush_urls
|
||||
|
||||
from devhub.models import ActivityLog, CommentLog
|
||||
|
||||
log = commonware.log.getLogger('z.task')
|
||||
|
||||
|
||||
# We use celery.task.ping in /monitor, so we need it to return results.
|
||||
celery.task.PingTask.ignore_result = False
|
||||
|
||||
|
||||
@task
|
||||
def add_commentlog(items, **kw):
|
||||
log.info('[%s@%s] Adding CommentLog starting with ActivityLog: %s' %
|
||||
(len(items), add_commentlog.rate_limit, items[0]))
|
||||
|
||||
|
||||
for al in ActivityLog.objects.filter(pk__in=items):
|
||||
import pdb; pdb.set_trace()
|
||||
# Delete existing entries:
|
||||
CommentLog.objects.filter(activity_log=al).delete()
|
||||
|
||||
# Create a new entry:
|
||||
if 'comments' in al.details:
|
||||
CommentLog(comments=al.details['comments'], activity_log=al).save()
|
|
@ -5,24 +5,28 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="log-filter" class="log-filter-outside">
|
||||
<form action="{{ url('editors.reviewlog') }}" method="get">
|
||||
<div class="date_range">
|
||||
{{ form.start.label_tag() }}
|
||||
{{ form.start }}
|
||||
{{ form.end.label_tag() }}
|
||||
{{ form.end }}
|
||||
{{ form.search.label_tag() }}
|
||||
{{ form.search }}
|
||||
|
||||
{# L10n: "Filter" is a button label (verb) #}
|
||||
<button type="submit">
|
||||
{{ _('Filter', 'editorcp_reviewlog_page_heading') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div><!-- #log-filter -->
|
||||
|
||||
<h2>{{ _('Add-on Review Log', 'editorcp_reviewlog_page_heading') }}</h2>
|
||||
|
||||
<div class="listing results"><div class="results-inner controls">
|
||||
<div id="log-filter">
|
||||
<form action="{{ url('editors.reviewlog') }}" method="get">
|
||||
<div class="date_range">
|
||||
{{ form.start.label_tag() }}
|
||||
{{ form.start }}
|
||||
{{ form.end.label_tag() }}
|
||||
{{ form.end }}
|
||||
|
||||
{# L10n: "Filter" is a button label (verb) #}
|
||||
<button type="submit">
|
||||
{{ _('Filter', 'editorcp_reviewlog_page_heading') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div><!-- #log-filter -->
|
||||
{% if pager.object_list %}
|
||||
<table id="log-listing" class="data-grid">
|
||||
<thead>
|
||||
|
|
|
@ -124,18 +124,26 @@ class TestReviewLog(EditorTest):
|
|||
amo.log(amo.LOG.REJECT_VERSION, a, v, user=u,
|
||||
details={'comments': 'youwin'})
|
||||
|
||||
def make_an_approval(self, action):
|
||||
u = UserProfile.objects.filter()[0]
|
||||
a = Addon.objects.create(type=amo.ADDON_EXTENSION)
|
||||
def make_an_approval(self, action, **kw):
|
||||
comment = kw.pop('comment', 'youwin')
|
||||
username = kw.pop('username', False)
|
||||
addon_name = kw.pop('addon_name', None)
|
||||
|
||||
user_filter = {}
|
||||
if username:
|
||||
user_filter['username'] = username
|
||||
|
||||
u = UserProfile.objects.filter(**user_filter)[0]
|
||||
a = Addon.objects.create(type=amo.ADDON_EXTENSION, name=addon_name)
|
||||
v = Version.objects.create(addon=a)
|
||||
amo.log(action, a, v, user=u, details={'comments': 'youwin'})
|
||||
amo.log(action, a, v, user=u, details={'comments': comment})
|
||||
|
||||
def test_basic(self):
|
||||
self.make_approvals()
|
||||
r = self.client.get(reverse('editors.reviewlog'))
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
assert doc('.listing button'), 'No filters.'
|
||||
assert doc('#log-filter button'), 'No filters.'
|
||||
# Should have 6 showing.
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 6)
|
||||
eq_(doc('tbody tr.hide').eq(0).text(), 'youwin')
|
||||
|
@ -186,6 +194,88 @@ class TestReviewLog(EditorTest):
|
|||
doc = pq(r.content)
|
||||
eq_(doc('#log-listing tr:not(.hide)').length, 7)
|
||||
|
||||
def test_search_comment_exists(self):
|
||||
"""
|
||||
Search by comment.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, comment='hello')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=hello')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 1)
|
||||
eq_(doc('tbody tr.hide').eq(0).text(), 'hello')
|
||||
|
||||
def test_search_comment_doesnt_exist(self):
|
||||
"""
|
||||
Search by comment, with no results.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, comment='hello')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=bye')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 0)
|
||||
|
||||
def test_search_author_exists(self):
|
||||
"""
|
||||
Search by author.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, username='editor',
|
||||
comment='hi')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=editor')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 1)
|
||||
eq_(doc('tbody tr.hide').eq(0).text(), 'hi')
|
||||
|
||||
def test_search_author_doesnt_exist(self):
|
||||
"""
|
||||
Search by author, with no results.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, user_name='editor')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=wrong')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 0)
|
||||
|
||||
def test_search_addon_exists(self):
|
||||
"""
|
||||
Search by add-on name.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, addon_name='abcd',
|
||||
comment='ab')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=ab')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 1)
|
||||
eq_(doc('tbody tr.hide').eq(0).text(), 'ab')
|
||||
|
||||
def test_search_addon_doesnt_exist(self):
|
||||
"""
|
||||
Search by add-on name, with no results.
|
||||
"""
|
||||
self.make_approvals()
|
||||
self.make_an_approval(amo.LOG.REQUEST_SUPER_REVIEW, addon_name='abcd',
|
||||
comment='ab')
|
||||
|
||||
r = self.client.get(reverse('editors.reviewlog') + '?search=by')
|
||||
eq_(r.status_code, 200)
|
||||
doc = pq(r.content)
|
||||
|
||||
eq_(len(doc('tbody tr').not_('.hide')), 0)
|
||||
|
||||
def test_breadcrumbs(self):
|
||||
r = self.client.get(reverse('editors.reviewlog'))
|
||||
doc = pq(r.content)
|
||||
|
|
|
@ -6,6 +6,7 @@ import time
|
|||
from django import http
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.utils.datastructures import SortedDict
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
@ -504,6 +505,13 @@ def reviewlog(request):
|
|||
approvals = approvals.filter(created__gte=data['start'])
|
||||
if data['end']:
|
||||
approvals = approvals.filter(created__lt=data['end'])
|
||||
if data['search']:
|
||||
term = data['search']
|
||||
approvals = approvals.filter(
|
||||
Q(commentlog__comments__contains=term) |
|
||||
Q(addonlog__addon__name__localized_string__contains=term) |
|
||||
Q(user__display_name__contains=term) |
|
||||
Q(user__username__contains=term)).distinct()
|
||||
|
||||
pager = amo.utils.paginate(request, approvals, 50)
|
||||
ad = {
|
||||
|
|
|
@ -423,6 +423,24 @@ div.editor-stats-table > div.editor-stats-dark {
|
|||
#log-filter form {
|
||||
margin: 0;
|
||||
}
|
||||
.log-filter-outside {
|
||||
float: right;
|
||||
}
|
||||
.log-filter-outside label {
|
||||
font-weight: normal;
|
||||
}
|
||||
.log-filter-outside input::-webkit-input-placeholder {
|
||||
color: #BBB;
|
||||
}
|
||||
|
||||
.log-filter-outside input:-moz-placeholder {
|
||||
color: #BBB;
|
||||
}
|
||||
|
||||
.log-filter-outside div.date_range {
|
||||
padding: 0.5em 0 0;
|
||||
}
|
||||
|
||||
.queue-outer #queue-search table {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -672,3 +690,4 @@ span.currently_viewing_warning {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
DROP TABLE IF EXISTS log_activity_comment;
|
||||
|
||||
CREATE TABLE `log_activity_comment` (
|
||||
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
`created` datetime NOT NULL,
|
||||
`modified` datetime NOT NULL,
|
||||
`activity_log_id` integer NOT NULL,
|
||||
`comments` longtext NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
;
|
||||
|
||||
ALTER TABLE `log_activity_comment` ADD CONSTRAINT `activity_log_id_refs_id_4f8d99d4` FOREIGN KEY (`activity_log_id`) REFERENCES `log_activity` (`id`);
|
||||
CREATE INDEX `log_activity_comment_3bf68f54` ON `log_activity_comment` (`activity_log_id`);
|
Загрузка…
Ссылка в новой задаче