wscall: import/export (#46310)

This commit is contained in:
Lauréline Guérin 2020-09-03 14:18:09 +02:00
parent 682665288b
commit 049b485be0
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
4 changed files with 126 additions and 2 deletions

View File

@ -1,6 +1,11 @@
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
from django.utils.six import StringIO
import pytest
from webtest import Upload
from wcs.qommon.http_request import HTTPRequest
from wcs.wscalls import NamedWsCall
@ -127,3 +132,56 @@ def test_wscalls_delete(pub, wscall):
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/'
assert NamedWsCall.count() == 0
def test_wscalls_export(pub, wscall):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/xxx/')
resp = resp.click(href='export')
xml_export = resp.text
ds = StringIO(xml_export)
wscall2 = NamedWsCall.import_from_xml(ds)
assert wscall2.name == 'xxx'
def test_wscalls_import(pub, wscall):
create_superuser(pub)
wscall.slug = 'foobar'
wscall.store()
wscall_xml = ET.tostring(wscall.export_to_xml(include_id=True))
NamedWsCall.wipe()
assert NamedWsCall.count() == 0
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('wscall.wcs', wscall_xml)
resp = resp.forms[0].submit()
assert NamedWsCall.count() == 1
assert set([wc.slug for wc in NamedWsCall.select()]) == set(['foobar'])
# check slug
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('wscall.wcs', wscall_xml)
resp = resp.forms[0].submit()
assert NamedWsCall.count() == 2
assert set([wc.slug for wc in NamedWsCall.select()]) == set(['foobar', 'xxx'])
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('wscall.wcs', wscall_xml)
resp = resp.forms[0].submit()
assert NamedWsCall.count() == 3
assert set([wc.slug for wc in NamedWsCall.select()]) == set(['foobar', 'xxx', 'xxx_1'])
# import an invalid file
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click(href='import')
resp.form['file'] = Upload('wscall.wcs', b'garbage')
resp = resp.form.submit()
assert 'Invalid File' in resp.text

View File

@ -14,11 +14,14 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import xml.etree.ElementTree as ET
from quixote import redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
from wcs.qommon import _, errors, template
from wcs.qommon import misc
from wcs.qommon.form import *
from wcs.qommon.backoffice.menu import html_top
from wcs.wscalls import NamedWsCall, WsCallRequestWidget
@ -80,7 +83,7 @@ class NamedWsCallUI(object):
class NamedWsCallPage(Directory):
_q_exports = ['', 'edit', 'delete']
_q_exports = ['', 'edit', 'delete', 'export']
def __init__(self, component):
try:
@ -138,9 +141,19 @@ class NamedWsCallPage(Directory):
self.wscall.remove_self()
return redirect('..')
def export(self):
x = self.wscall.export_to_xml(include_id=True)
misc.indent_xml(x)
response = get_response()
response.set_content_type('application/x-wcs-wscall')
response.set_header(
'content-disposition',
'attachment; filename=wscall-%s.wcs' % self.wscall.slug)
return '<?xml version="1.0"?>\n' + force_str(ET.tostring(x))
class NamedWsCallsDirectory(Directory):
_q_exports = ['', 'new']
_q_exports = ['', 'new', ('import', 'p_import')]
def _q_traverse(self, path):
get_response().breadcrumb.append( ('wscalls/', _('Webservice Calls')) )
@ -175,3 +188,54 @@ class NamedWsCallsDirectory(Directory):
def _q_lookup(self, component):
return NamedWsCallPage(component)
def p_import(self):
form = Form(enctype='multipart/form-data')
import_title = _('Import webservice call')
form.add(FileWidget, 'file', title=_('File'), required=True)
form.add_submit('submit', import_title)
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
try:
return self.import_submit(form)
except ValueError:
pass
get_response().breadcrumb.append(('import', _('Import')))
html_top('wscalls', title=import_title)
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % import_title
r += htmltext('<p>%s</p>') % _(
'You can install a new webservice call by uploading a file.')
r += form.render()
return r.getvalue()
def import_submit(self, form):
fp = form.get_widget('file').parse().fp
error = False
try:
wscall = NamedWsCall.import_from_xml(fp)
get_session().message = (
'info', _('This webservice call has been successfully imported.'))
except ValueError:
error = True
if error:
form.set_error('file', _('Invalid File'))
raise ValueError()
try:
# check slug unicity
NamedWsCall.get(wscall.slug, ignore_migration=True)
except KeyError:
pass
else:
wscall.slug = None # a new one will be set in .store()
wscall.store()
return redirect('%s/' % wscall.id)

View File

@ -5,6 +5,7 @@
<h2>{% trans "Webservice Call" %} - {{ wscall.name }}</h2>
{% if not wscall.is_readonly %}
<span class="actions">
<a href="export">{% trans "Export" %}</a>
<a href="delete" rel="popup">{% trans "Delete" %}</a>
<a href="edit">{% trans "Edit" %}</a>
</span>

View File

@ -4,6 +4,7 @@
{% block appbar-title %}{% trans "Webservice Calls" %}{% endblock %}
{% block appbar-actions %}
<a rel="popup" href="import">{% trans "Import" %}</a>
<a rel="popup" href="new">{% trans "New webservice call" %}</a>
{% endblock %}