pass message from celery up to the front end (bug #652566)
This commit is contained in:
Родитель
9ad3e2df41
Коммит
2fab97fc64
|
@ -5,6 +5,7 @@ import os
|
|||
|
||||
from django.conf import settings
|
||||
from django.core import mail
|
||||
from django.core.cache import cache
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.utils import encoding
|
||||
|
||||
|
@ -17,7 +18,7 @@ import test_utils
|
|||
|
||||
import amo
|
||||
from amo import urlresolvers, utils, helpers
|
||||
from amo.utils import ImageCheck, Token
|
||||
from amo.utils import ImageCheck, Message, Token
|
||||
from versions.models import License
|
||||
|
||||
|
||||
|
@ -407,6 +408,32 @@ class TestToken(test_utils.TestCase):
|
|||
assert not new.well_formed()
|
||||
|
||||
|
||||
class TestMessage(test_utils.TestCase):
|
||||
|
||||
def test_message_save(self):
|
||||
new = Message('abc')
|
||||
new.save('123')
|
||||
|
||||
new = Message('abc')
|
||||
eq_(new.get(), '123')
|
||||
|
||||
def test_message_expires(self):
|
||||
new = Message('abc')
|
||||
new.save('123')
|
||||
cache.clear()
|
||||
|
||||
new = Message('abc')
|
||||
eq_(new.get(), None)
|
||||
|
||||
def test_message_get_delete(self):
|
||||
new = Message('abc')
|
||||
new.save('123')
|
||||
|
||||
new = Message('abc')
|
||||
eq_(new.get(delete=True), '123')
|
||||
eq_(new.get(delete=True), None)
|
||||
|
||||
|
||||
def test_site_nav():
|
||||
r = Mock()
|
||||
r.APP = amo.FIREFOX
|
||||
|
|
|
@ -449,7 +449,34 @@ def memoize(prefix, time=60):
|
|||
return decorator
|
||||
|
||||
|
||||
class Message:
|
||||
"""
|
||||
A simple message class for when you don't have a session, but wish
|
||||
to pass a message through memcache. For example, memcache up to the
|
||||
user.
|
||||
"""
|
||||
def __init__(self, key):
|
||||
self.key = '%s:message:%s' % (settings.CACHE_PREFIX, key)
|
||||
|
||||
def delete(self):
|
||||
cache.delete(self.key)
|
||||
|
||||
def save(self, message, time=60 * 5):
|
||||
cache.set(self.key, message, time)
|
||||
|
||||
def get(self, delete=False):
|
||||
res = cache.get(self.key)
|
||||
cache.delete(self.key)
|
||||
return res
|
||||
|
||||
|
||||
class Token:
|
||||
"""
|
||||
A simple token, useful for security. It can have an expiry
|
||||
or be grabbed and deleted. It will check that the key is valid and
|
||||
and well formed before checking. If you don't have a key, it will
|
||||
generate a randomish one for you.
|
||||
"""
|
||||
_well_formed = re.compile('^[a-z0-9-]+$')
|
||||
|
||||
def __init__(self, token=None, data=True):
|
||||
|
|
|
@ -41,12 +41,12 @@ def file_tree(files, selected):
|
|||
t = env.get_template('files/node.html')
|
||||
for k, v in files.items():
|
||||
if v['depth'] > depth:
|
||||
output.append('<ul class="hidden">')
|
||||
output.append('<ul class="js-hidden">')
|
||||
elif v['depth'] < depth:
|
||||
output.extend(['</ul>' for x in range(v['depth'], depth) ])
|
||||
output.extend(['</ul>' for x in range(v['depth'], depth)])
|
||||
output.append(t.render(value=v, selected=selected))
|
||||
depth = v['depth']
|
||||
output.extend(['</ul>' for x in range(depth, -1, -1) ])
|
||||
output.extend(['</ul>' for x in range(depth, -1, -1)])
|
||||
return jinja2.Markup('\n'.join(output))
|
||||
|
||||
|
||||
|
@ -71,10 +71,12 @@ class FileViewer:
|
|||
os.makedirs(os.path.dirname(self.dest))
|
||||
except OSError, err:
|
||||
pass
|
||||
|
||||
try:
|
||||
extract_xpi(self.src, self.dest, expand=True)
|
||||
except Exception, err:
|
||||
task_log.error('Error (%s) extracting %s' % (err, self.src))
|
||||
raise
|
||||
|
||||
def cleanup(self):
|
||||
if os.path.exists(self.dest):
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
from django.conf import settings
|
||||
|
||||
from celeryutils import task
|
||||
import commonware.log
|
||||
from tower import ugettext as _
|
||||
|
||||
from amo.utils import Message
|
||||
|
||||
task_log = commonware.log.getLogger('z.task')
|
||||
|
||||
|
||||
@task
|
||||
def extract_file(viewer, **kw):
|
||||
msg = Message('file-viewer:%s' % viewer)
|
||||
msg.delete()
|
||||
task_log.info('[1@%s] Unzipping %s for file viewer.' % (
|
||||
extract_file.rate_limit, viewer))
|
||||
|
||||
try:
|
||||
viewer.extract()
|
||||
except ValueError, msg:
|
||||
except Exception, err:
|
||||
if settings.DEBUG:
|
||||
msg.save(_('There was an error accessing file %s. %s.') %
|
||||
(viewer, err))
|
||||
else:
|
||||
msg.save(_('There was an error accessing file %s.') % viewer)
|
||||
task_log.error('[1@%s] Error unzipping: %s' %
|
||||
(extract_file.rate_limit, msg))
|
||||
(extract_file.rate_limit, err))
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<p class="waiting" id="extracting" data-url="{{ poll_url }}">
|
||||
{{ _('Add-on file being processed, please wait.') }}
|
||||
</p>
|
||||
<div class="notification-box error js-hidden"></div>
|
||||
{% endif %}
|
||||
<div id="files">
|
||||
{% if files %}
|
||||
|
@ -36,7 +37,7 @@
|
|||
<p>{{ _('No files in the uploaded file.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="thinking" class="hidden">
|
||||
<div id="thinking" class="js-hidden">
|
||||
<p class="waiting">
|
||||
{{ _('Fetching file.') }}
|
||||
</p>
|
||||
|
@ -65,9 +66,9 @@
|
|||
</p>
|
||||
{% endif %}
|
||||
{% if text_one and text_two %}
|
||||
<pre id="diff" class="wrapped hidden"></pre>
|
||||
<pre class="left hidden">{{ text_one }}</pre>
|
||||
<pre class="right hidden">{{ text_two }}</pre>
|
||||
<pre id="diff" class="wrapped js-hidden"></pre>
|
||||
<pre class="left js-hidden">{{ text_one }}</pre>
|
||||
<pre class="right js-hidden">{{ text_two }}</pre>
|
||||
{% endif %}
|
||||
{% if selected and not selected['directory']%}
|
||||
{% if diff.one %}
|
||||
|
|
|
@ -13,6 +13,7 @@ from nose.tools import eq_
|
|||
from pyquery import PyQuery as pq
|
||||
import test_utils
|
||||
|
||||
from amo.utils import Message
|
||||
from amo.urlresolvers import reverse
|
||||
from addons.models import Addon
|
||||
from files.helpers import FileViewer, DiffHelper
|
||||
|
@ -319,6 +320,15 @@ class TestFileViewer(FilesBase, test_utils.TestCase):
|
|||
doc = pq(res.content)
|
||||
assert doc('p.notification-box').text().startswith('File size is')
|
||||
|
||||
def test_poll_failed(self):
|
||||
msg = Message('file-viewer:%s' % self.file_viewer)
|
||||
msg.save('I like cheese.')
|
||||
res = self.client.get(self.poll_url())
|
||||
eq_(res.status_code, 200)
|
||||
data = json.loads(res.content)
|
||||
eq_(data['status'], False)
|
||||
eq_(data['msg'], ['I like cheese.'])
|
||||
|
||||
|
||||
class TestDiffViewer(FilesBase, test_utils.TestCase):
|
||||
fixtures = ['base/addon_3615', 'base/users']
|
||||
|
|
|
@ -11,7 +11,7 @@ import jingo
|
|||
from access import acl
|
||||
from amo.decorators import json_view
|
||||
from amo.urlresolvers import reverse
|
||||
from amo.utils import HttpResponseSendFile, Token
|
||||
from amo.utils import HttpResponseSendFile, Message, Token
|
||||
from files.decorators import file_view, compare_file_view, file_view_token
|
||||
from files.tasks import extract_file
|
||||
|
||||
|
@ -43,7 +43,8 @@ def setup_viewer(request, file_obj):
|
|||
@json_view
|
||||
@file_view
|
||||
def files_poll(request, viewer):
|
||||
return {'status': viewer.is_extracted}
|
||||
return {'status': viewer.is_extracted,
|
||||
'msg': [Message('file-viewer:%s' % viewer).get(delete=True)]}
|
||||
|
||||
|
||||
@file_view
|
||||
|
@ -79,7 +80,12 @@ def files_list(request, viewer, key='install.rdf'):
|
|||
@compare_file_view
|
||||
@json_view
|
||||
def files_compare_poll(request, diff):
|
||||
return {'status': diff.is_extracted}
|
||||
msgs = []
|
||||
for f in (diff.file_one, diff.file_two):
|
||||
m = Message('file-viewer:%s' % f).get(delete=True)
|
||||
if m:
|
||||
msgs.append(m)
|
||||
return {'status': diff.is_extracted, 'msg': msgs}
|
||||
|
||||
|
||||
@compare_file_view
|
||||
|
@ -109,7 +115,8 @@ def files_compare(request, diff, key='install.rdf'):
|
|||
data['msg'] = omsg or tmsg
|
||||
|
||||
else:
|
||||
extract_file.delay(diff)
|
||||
extract_file.delay(diff.file_one)
|
||||
extract_file.delay(diff.file_two)
|
||||
|
||||
response = jingo.render(request, 'files/viewer.html', data)
|
||||
if not settings.DEBUG:
|
||||
|
|
|
@ -37,7 +37,7 @@ span.number {
|
|||
}
|
||||
|
||||
pre {
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre.wrapped {
|
||||
|
|
|
@ -62,7 +62,7 @@ function bind_viewer(nodes) {
|
|||
'<span class="code"> {1}</span></div>', k+1, text));
|
||||
}
|
||||
}
|
||||
$content.html(html.join('')).removeClass('hidden').show();
|
||||
$content.html(html.join('')).show();
|
||||
}
|
||||
|
||||
if ($diff.length) {
|
||||
|
@ -71,7 +71,7 @@ function bind_viewer(nodes) {
|
|||
var a = dmp.diff_linesToChars_($diff.siblings('.left').text(), $diff.siblings('.right').text());
|
||||
var diffs = dmp.diff_main(a[0], a[1], false);
|
||||
dmp.diff_charsToLines_(diffs, a[2]);
|
||||
$diff.html(dmp.diff_prettyHtml(diffs)).removeClass('hidden').show();
|
||||
$diff.html(dmp.diff_prettyHtml(diffs)).show();
|
||||
}
|
||||
|
||||
if (window.location.hash) {
|
||||
|
@ -93,13 +93,11 @@ function bind_viewer(nodes) {
|
|||
this.show_leaf = function($leaf) {
|
||||
/* Exposes the leaves for a given set of node. */
|
||||
$leaf.removeClass('closed').addClass('open')
|
||||
.closest('li').next('ul')
|
||||
.removeClass('hidden').show();
|
||||
.closest('li').next('ul').show();
|
||||
};
|
||||
this.selected = function($link) {
|
||||
/* Exposes all the leaves to an element */
|
||||
$link.parentsUntil('ul.root').filter('ul')
|
||||
.removeClass('hidden').show()
|
||||
$link.parentsUntil('ul.root').filter('ul').show()
|
||||
.each(function() {
|
||||
$(this).prev('li').find('a:first')
|
||||
.removeClass('closed').addClass('open');
|
||||
|
@ -113,7 +111,7 @@ function bind_viewer(nodes) {
|
|||
var self = this,
|
||||
$old_wrapper = $('#content-wrapper');
|
||||
$old_wrapper.hide();
|
||||
this.nodes.$thinking.removeClass('hidden').show();
|
||||
this.nodes.$thinking.show();
|
||||
if (history.pushState !== undefined) {
|
||||
history.pushState({ path: $link.text() }, '', $link.attr('href'));
|
||||
}
|
||||
|
@ -172,11 +170,17 @@ function bind_viewer(nodes) {
|
|||
}));
|
||||
|
||||
$('#files-prev').click(_pd(function() {
|
||||
viewer.select(viewer.nodes.$files.find('a.file').eq(viewer.get_selected() - 1));
|
||||
var prev = viewer.get_selected() - 1
|
||||
if (prev >= 0) {
|
||||
viewer.select(viewer.nodes.$files.find('a.file').eq(prev));
|
||||
}
|
||||
}));
|
||||
|
||||
$('#files-next').click(_pd(function() {
|
||||
viewer.select(viewer.nodes.$files.find('a.file').eq(viewer.get_selected() + 1));
|
||||
var next = viewer.nodes.$files.find('a.file').eq(viewer.get_selected() + 1);
|
||||
if (next.length) {
|
||||
viewer.select(next);
|
||||
}
|
||||
}));
|
||||
|
||||
$('#files-wrap').click(_pd(function() {
|
||||
|
@ -231,6 +235,13 @@ $(document).ready(function() {
|
|||
viewer.selected(viewer.nodes.$files.find('a.selected'));
|
||||
viewer.compute($('#content-wrapper'));
|
||||
});
|
||||
} else if (json && json.msg) {
|
||||
$('#extracting').hide();
|
||||
$.each(json.msg, function(k) {
|
||||
$('<p>').text(json.msg[k])
|
||||
.appendTo($('#file-viewer div.error'));
|
||||
});
|
||||
$('#file-viewer div.error').show();
|
||||
} else {
|
||||
setTimeout(poll_file_extraction, 2000);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче