settings: make site export async (#34915)

This commit is contained in:
Frédéric Péters 2019-07-16 20:41:33 +02:00
parent bef5381961
commit c26cfd1734
2 changed files with 92 additions and 27 deletions

View File

@ -9,6 +9,7 @@ import re
import shutil
import StringIO
import tarfile
import urlparse
import time
import xml.etree.ElementTree as ET
import zipfile
@ -3942,11 +3943,20 @@ def test_settings_export_import(pub):
resp = resp.form.submit('cancel')
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
assert 'completed' in resp.body
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert len(filelist) == 0
# check afterjob ajax call
status_resp = app.get('/afterjobs/' + job_id)
assert status_resp.body == 'completed|completed'
formdef = FormDef()
formdef.name = 'foo'
formdef.store()
@ -3971,6 +3981,10 @@ def test_settings_export_import(pub):
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
@ -4006,6 +4020,10 @@ def test_settings_export_import(pub):
pub.write_cfg()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()

View File

@ -41,6 +41,7 @@ from qommon import template
from qommon.form import *
from qommon.sms import SMS
from qommon.afterjobs import AfterJob
from qommon.backoffice.menu import html_top
from qommon.admin.menu import error_page
from qommon.admin.cfg import cfg_submit
@ -840,6 +841,9 @@ class SettingsDirectory(QommonSettingsDirectory):
return redirect('.')
def export(self):
if get_request().form.get('job') or get_request().form.get('download'):
return self.export_pending()
form = Form(enctype="multipart/form-data")
form.add(CheckboxWidget, 'formdefs', title = _('Forms'), value = True)
form.add(CheckboxWidget, 'workflows', title = _('Workflows'), value = True)
@ -861,10 +865,37 @@ class SettingsDirectory(QommonSettingsDirectory):
r += htmltext('<h2>%s</h2>') % _('Export')
r += form.render()
return r.getvalue()
else:
return self.export_submit(form)
def export_submit(self, form):
class Exporter(object):
def __init__(self, dirs, settings):
self.app_dir = get_publisher().app_dir
self.dirs = dirs
self.settings = settings
def export(self, job):
c = StringIO()
z = zipfile.ZipFile(c, 'w')
for d in self.dirs:
path = os.path.join(self.app_dir, d)
if not os.path.exists(path):
continue
for f in os.listdir(path):
if f == '.indexes':
continue
z.write(os.path.join(path, f), os.path.join(d, f))
if self.settings:
z.write(os.path.join(self.app_dir, 'config.pck'), 'config.pck')
for f in os.listdir(self.app_dir):
if f.startswith('idp-') and os.path.splitext(f)[-1] in ('.pem', '.xml'):
z.write(os.path.join(self.app_dir, f), f)
if os.path.exists(os.path.join(self.app_dir, 'config')):
for f in os.listdir(os.path.join(self.app_dir, 'config')):
z.write(os.path.join(self.app_dir, 'config', f), os.path.join('config', f))
z.close()
job.file_content = c.getvalue()
job.store()
dirs = []
for w in ('formdefs', 'workflows', 'roles', 'categories',
'datasources', 'wscalls'):
@ -875,32 +906,48 @@ class SettingsDirectory(QommonSettingsDirectory):
if not dirs and not form.get_widget('settings').parse():
return redirect('.')
c = StringIO()
z = zipfile.ZipFile(c, 'w')
app_dir = get_publisher().app_dir
for d in dirs:
path = os.path.join(app_dir, d)
if not os.path.exists(path):
continue
for f in os.listdir(path):
if f == '.indexes':
continue
z.write(os.path.join(path, f), os.path.join(d, f))
if form.get_widget('settings').parse():
z.write(os.path.join(app_dir, 'config.pck'), 'config.pck')
for f in os.listdir(app_dir):
if f.startswith('idp-') and os.path.splitext(f)[-1] in ('.pem', '.xml'):
z.write(os.path.join(app_dir, f), f)
if os.path.exists(os.path.join(app_dir, 'config')):
for f in os.listdir(os.path.join(app_dir, 'config')):
z.write(os.path.join(app_dir, 'config', f), os.path.join('config', f))
exporter = Exporter(dirs, settings=form.get_widget('settings').parse())
z.close()
job = get_response().add_after_job(
N_('Exporting site settings'),
exporter.export)
job.store()
return redirect('export?job=%s' % job.id)
response = get_response()
response.set_content_type('application/x-wcs')
response.set_header('content-disposition', 'attachment; filename=export.wcs')
return c.getvalue()
def export_pending(self):
job_id = get_request().form.get('job') or get_request().form.get('download')
try:
job = AfterJob.get(job_id)
except KeyError:
return redirect('.')
if get_request().form.get('download'):
response = get_response()
response.set_content_type('application/x-wcs')
response.set_header('content-disposition', 'attachment; filename=export.wcs')
return job.file_content
html_top('settings', title=_('Exporting'))
r = TemplateIO(html=True)
get_response().add_javascript(['jquery.js', 'afterjob.js'])
r += htmltext('<h2>%s</h2>') % _('Export')
r += htmltext('<div class="section"><dl class="job-status">')
r += htmltext('<dt>')
r += _(job.label)
r += htmltext('</dt>')
r += htmltext('<dd>')
r += htmltext('<span class="afterjob" id="%s">') % job.id
r += _(job.status)
r += htmltext('</span>')
r += htmltext('</dd>')
r += htmltext('</dl>')
r += htmltext('<div class="done">')
r += htmltext('<a download="export.wcs" href="export?download=%s">%s</a>') % (
job.id, _('Download Export'))
r += htmltext('</div>')
r += htmltext('</div>')
return r.getvalue()
def p_import(self):
form = Form(enctype='multipart/form-data')