14 |
14 |
# You should have received a copy of the GNU General Public License
|
15 |
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
16 |
16 |
|
|
17 |
import xml.etree.ElementTree as ET
|
|
18 |
|
17 |
19 |
from quixote import redirect
|
18 |
20 |
from quixote.directory import Directory
|
19 |
21 |
from quixote.html import TemplateIO, htmltext
|
20 |
22 |
|
21 |
|
from wcs.qommon import _
|
|
23 |
from wcs.qommon import _, force_str
|
22 |
24 |
from wcs.qommon import errors, template
|
23 |
25 |
from wcs.qommon.form import *
|
24 |
|
from wcs.qommon.misc import json_response
|
|
26 |
from wcs.qommon.form import FileWidget
|
|
27 |
from wcs.qommon.form import Form
|
|
28 |
from wcs.qommon.form import UrlWidget
|
|
29 |
from wcs.qommon.form import get_response
|
|
30 |
from wcs.qommon.form import get_session
|
|
31 |
from wcs.qommon import misc
|
25 |
32 |
from wcs.qommon.backoffice.menu import html_top
|
26 |
33 |
from wcs.data_sources import (NamedDataSource, DataSourceSelectionWidget,
|
27 |
34 |
get_structured_items)
|
... | ... | |
123 |
130 |
|
124 |
131 |
|
125 |
132 |
class NamedDataSourcePage(Directory):
|
126 |
|
_q_exports = ['', 'edit', 'delete']
|
|
133 |
_q_exports = ['', 'edit', 'delete', 'export']
|
127 |
134 |
do_not_call_in_templates = True
|
128 |
135 |
|
129 |
136 |
def __init__(self, component):
|
... | ... | |
222 |
229 |
self.datasource.remove_self()
|
223 |
230 |
return redirect('..')
|
224 |
231 |
|
|
232 |
def export(self):
|
|
233 |
x = self.datasource.export_to_xml(include_id=True)
|
|
234 |
misc.indent_xml(x)
|
|
235 |
response = get_response()
|
|
236 |
response.set_content_type('application/x-wcs-datasource')
|
|
237 |
response.set_header(
|
|
238 |
'content-disposition',
|
|
239 |
'attachment; filename=datasource-%s.wcs' % self.datasource.slug)
|
|
240 |
return '<?xml version="1.0"?>\n' + force_str(ET.tostring(x))
|
|
241 |
|
225 |
242 |
|
226 |
243 |
class NamedDataSourcesDirectory(Directory):
|
227 |
|
_q_exports = ['', 'new']
|
|
244 |
_q_exports = ['', 'new', ('import', 'p_import')]
|
228 |
245 |
|
229 |
246 |
def _q_traverse(self, path):
|
230 |
247 |
get_response().breadcrumb.append( ('data-sources/', _('Data Sources')) )
|
... | ... | |
239 |
256 |
r += htmltext('<div id="appbar">')
|
240 |
257 |
r += htmltext('<h2>%s</h2>') % _('Data Sources')
|
241 |
258 |
r += htmltext('<span class="actions">')
|
|
259 |
r += htmltext('<a href="import" rel="popup">%s</a>') % _('Import')
|
242 |
260 |
r += htmltext('<a class="new-item" href="new">%s</a>') % _('New Data Source')
|
243 |
261 |
r += htmltext('</span>')
|
244 |
262 |
r += htmltext('</div>')
|
... | ... | |
275 |
293 |
|
276 |
294 |
def _q_lookup(self, component):
|
277 |
295 |
return NamedDataSourcePage(component)
|
|
296 |
|
|
297 |
def p_import(self):
|
|
298 |
form = Form(enctype='multipart/form-data')
|
|
299 |
import_title = _('Import Data Source')
|
|
300 |
|
|
301 |
form.add(FileWidget, 'file', title=_('File'), required=False)
|
|
302 |
form.add(UrlWidget, 'url', title=_('Address'), required=False, size=50)
|
|
303 |
form.add_submit('submit', import_title)
|
|
304 |
form.add_submit('cancel', _('Cancel'))
|
|
305 |
|
|
306 |
if form.get_submit() == 'cancel':
|
|
307 |
return redirect('.')
|
|
308 |
|
|
309 |
if form.is_submitted() and not form.has_errors():
|
|
310 |
try:
|
|
311 |
return self.import_submit(form)
|
|
312 |
except ValueError:
|
|
313 |
pass
|
|
314 |
|
|
315 |
get_response().breadcrumb.append(('import', _('Import')))
|
|
316 |
html_top('datasources', title=import_title)
|
|
317 |
r = TemplateIO(html=True)
|
|
318 |
r += htmltext('<h2>%s</h2>') % import_title
|
|
319 |
r += htmltext('<p>%s</p>') % _(
|
|
320 |
'You can install a new data source by uploading a file '
|
|
321 |
'or by pointing to the data source URL.')
|
|
322 |
r += form.render()
|
|
323 |
return r.getvalue()
|
|
324 |
|
|
325 |
def import_submit(self, form):
|
|
326 |
self.imported_datasource = None
|
|
327 |
if form.get_widget('file').parse():
|
|
328 |
fp = form.get_widget('file').parse().fp
|
|
329 |
elif form.get_widget('url').parse():
|
|
330 |
url = form.get_widget('url').parse()
|
|
331 |
try:
|
|
332 |
fp = misc.urlopen(url)
|
|
333 |
except misc.ConnectionError as e:
|
|
334 |
form.set_error('url', _('Error loading datasource (%s).') % str(e))
|
|
335 |
raise ValueError()
|
|
336 |
else:
|
|
337 |
form.set_error('file', _('You have to enter a file or a URL.'))
|
|
338 |
raise ValueError()
|
|
339 |
|
|
340 |
error = False
|
|
341 |
try:
|
|
342 |
datasource = NamedDataSource.import_from_xml(fp)
|
|
343 |
get_session().message = (
|
|
344 |
'info', _('This datasource has been successfully imported.'))
|
|
345 |
except ValueError:
|
|
346 |
error = True
|
|
347 |
|
|
348 |
if error:
|
|
349 |
msg = _('Invalid File')
|
|
350 |
if form.get_widget('url').parse():
|
|
351 |
form.set_error('url', msg)
|
|
352 |
else:
|
|
353 |
form.set_error('file', msg)
|
|
354 |
raise ValueError()
|
|
355 |
|
|
356 |
self.imported_datasource = datasource
|
|
357 |
datasource.slug = None # a new one will be set in .store()
|
|
358 |
datasource.store()
|
|
359 |
return redirect('%s/' % datasource.id)
|