Add basic import/export handler views, tool to run jobs
This commit is contained in:
parent
95da490f9a
commit
282185c5af
7 changed files with 744 additions and 77 deletions
|
@ -32,6 +32,7 @@ import datetime
|
|||
import tempfile
|
||||
import logging
|
||||
|
||||
import json
|
||||
import six
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
@ -65,6 +66,10 @@ from tailbone.config import global_help_url
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EverythingComplete(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MasterView(View):
|
||||
"""
|
||||
Base "master" view class. All model master views should derive from this.
|
||||
|
@ -1743,6 +1748,78 @@ class MasterView(View):
|
|||
def get_execute_success_url(self, obj, **kwargs):
|
||||
return self.get_action_url('view', obj, **kwargs)
|
||||
|
||||
def progress_thread(self, sock, success_url, progress):
|
||||
"""
|
||||
This method is meant to be used as a thread target. Its job is to read
|
||||
progress data from ``connection`` and update the session progress
|
||||
accordingly. When a final "process complete" indication is read, the
|
||||
socket will be closed and the thread will end.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
self.process_progress(sock, progress)
|
||||
except EverythingComplete:
|
||||
break
|
||||
|
||||
# close server socket
|
||||
sock.close()
|
||||
|
||||
# finalize session progress
|
||||
progress.session.load()
|
||||
progress.session['complete'] = True
|
||||
if callable(success_url):
|
||||
success_url = success_url()
|
||||
progress.session['success_url'] = success_url
|
||||
progress.session.save()
|
||||
|
||||
def process_progress(self, sock, progress):
|
||||
"""
|
||||
This method will accept a client connection on the given socket, and
|
||||
then update the given progress object according to data written by the
|
||||
client.
|
||||
"""
|
||||
connection, client_address = sock.accept()
|
||||
active_progress = None
|
||||
|
||||
# TODO: make this configurable?
|
||||
suffix = "\n\n.".encode('utf_8')
|
||||
data = b''
|
||||
|
||||
# listen for progress info, update session progress as needed
|
||||
while True:
|
||||
|
||||
# accumulate data bytestring until we see the suffix
|
||||
byte = connection.recv(1)
|
||||
data += byte
|
||||
if data.endswith(suffix):
|
||||
|
||||
# strip suffix, interpret data as JSON
|
||||
data = data[:-len(suffix)]
|
||||
if six.PY3:
|
||||
data = data.decode('utf_8')
|
||||
data = json.loads(data)
|
||||
|
||||
if data.get('everything_complete'):
|
||||
if active_progress:
|
||||
active_progress.finish()
|
||||
raise EverythingComplete
|
||||
|
||||
elif data.get('process_complete'):
|
||||
active_progress.finish()
|
||||
active_progress = None
|
||||
break
|
||||
|
||||
elif 'value' in data:
|
||||
if not active_progress:
|
||||
active_progress = progress(data['message'], data['maximum'])
|
||||
active_progress.update(data['value'])
|
||||
|
||||
# reset data buffer
|
||||
data = b''
|
||||
|
||||
# close client connection
|
||||
connection.close()
|
||||
|
||||
def get_merge_fields(self):
|
||||
if hasattr(self, 'merge_fields'):
|
||||
return self.merge_fields
|
||||
|
@ -2287,7 +2364,10 @@ class MasterView(View):
|
|||
try:
|
||||
mapper = orm.object_mapper(row)
|
||||
except orm.exc.UnmappedInstanceError:
|
||||
return {self.model_key: row[self.model_key]}
|
||||
try:
|
||||
return {self.model_key: row[self.model_key]}
|
||||
except TypeError:
|
||||
return {self.model_key: getattr(row, self.model_key)}
|
||||
else:
|
||||
pkeys = get_primary_keys(row)
|
||||
keys = list(pkeys)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue