Add "populatable" for master views (populating new objects with progress)

This commit is contained in:
Lance Edgar 2017-09-23 16:27:22 -05:00
parent 8a945f8baf
commit 47ce0fd448

View file

@ -71,6 +71,7 @@ class MasterView(View):
editable = True
deletable = True
bulk_deletable = False
populatable = False
mergeable = False
downloadable = False
cloneable = False
@ -279,8 +280,74 @@ class MasterView(View):
form.save()
def redirect_after_create(self, instance, mobile=False):
if self.populatable and self.should_populate(instance):
return self.redirect(self.get_action_url('populate', instance, mobile=mobile))
return self.redirect(self.get_action_url('view', instance, mobile=mobile))
def should_populate(self, obj):
return True
def populate(self):
"""
View for populating a new object. What exactly this means / does will
depend on the logic in :meth:`populate_object()`.
"""
obj = self.get_instance()
route_prefix = self.get_route_prefix()
permission_prefix = self.get_permission_prefix()
# showing progress requires a separate thread; start that first
key = '{}.populate'.format(route_prefix)
progress = SessionProgress(self.request, key)
thread = Thread(target=self.populate_thread, args=(obj.uuid, progress)) # TODO: uuid?
thread.start()
# Send user to progress page.
kwargs = {
'cancel_url': self.get_action_url('view', obj),
'cancel_msg': "{} population was canceled.".format(self.get_model_title()),
}
return self.render_progress(progress, kwargs)
def populate_thread(self, uuid, progress): # TODO: uuid?
"""
Thread target for populating new object with progress indicator.
"""
# mustn't use tailbone web session here
session = RattailSession()
obj = session.query(self.model_class).get(uuid)
try:
self.populate_object(session, obj, progress=progress)
except Exception as error:
session.rollback()
msg = "{} population failed".format(self.get_model_title())
log.warning("{}: {}".format(msg, obj), exc_info=True)
session.close()
if progress:
progress.session.load()
progress.session['error'] = True
progress.session['error_msg'] = "{}: {} {}".format(msg, error.__class__.__name__, error)
progress.session.save()
return
session.commit()
session.refresh(obj)
session.close()
# finalize progress
if progress:
progress.session.load()
progress.session['complete'] = True
progress.session['success_url'] = self.get_action_url('view', obj)
progress.session.save()
def populate_object(self, session, obj, progress=None):
"""
You must define this if new objects require population.
"""
raise NotImplementedError
def view(self, instance=None):
"""
View for viewing details of an existing model record.
@ -1862,6 +1929,12 @@ class MasterView(View):
config.add_view(cls, attr='mobile_create', route_name='mobile.{}.create'.format(route_prefix),
permission='{}.create'.format(permission_prefix))
# populate new object
if cls.populatable:
config.add_route('{}.populate'.format(route_prefix), '{}/{{uuid}}/populate'.format(url_prefix))
config.add_view(cls, attr='populate', route_name='{}.populate'.format(route_prefix),
permission='{}.create'.format(permission_prefix))
# bulk delete
if cls.bulk_deletable:
config.add_route('{}.bulk_delete'.format(route_prefix), '{}/bulk-delete'.format(url_prefix))