diff --git a/tailbone/templates/master/view.mako b/tailbone/templates/master/view.mako
index 2f340e2d..cfd1b925 100644
--- a/tailbone/templates/master/view.mako
+++ b/tailbone/templates/master/view.mako
@@ -50,6 +50,9 @@
% if master.cloneable and request.has_perm('{}.clone'.format(permission_prefix)):
${h.link_to("Clone this as new {}".format(model_title), url('{}.clone'.format(route_prefix), uuid=instance.uuid))}
% endif
+ % if master.touchable and request.has_perm('{}.touch'.format(permission_prefix)):
+ ${h.link_to("\"Touch\" this {}".format(model_title), url('{}.touch'.format(route_prefix), uuid=instance.uuid))}
+ % endif
% if master.has_rows and master.rows_downloadable_csv and request.has_perm('{}.row_results_csv'.format(permission_prefix)):
${h.link_to("Download row results as CSV", url('{}.row_results_csv'.format(route_prefix), uuid=instance.uuid))}
% endif
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index a11311ff..be0a9fc3 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -89,6 +89,7 @@ class MasterView(View):
mergeable = False
downloadable = False
cloneable = False
+ touchable = False
executable = False
execute_progress_template = None
execute_progress_initial_msg = None
@@ -1041,6 +1042,30 @@ class MasterView(View):
def clone_instance(self, instance):
raise NotImplementedError
+ def touch(self):
+ """
+ View for "touching" an object so as to trigger datasync logic for it.
+ Useful instead of actually "editing" the object, which is generally the
+ alternative.
+ """
+ obj = self.get_instance()
+ change = self.touch_instance(obj)
+ self.request.session.flash("{} has been touched: {}".format(
+ self.get_model_title(), self.get_instance_title(obj)))
+ return self.redirect(self.get_action_url('view', obj))
+
+ def touch_instance(self, obj):
+ """
+ Perform actual "touch" logic for the given object. Must return the
+ :class:`rattail:~rattail.db.model.Change` record involved.
+ """
+ change = model.Change()
+ change.class_name = obj.__class__.__name__
+ change.instance_uuid = obj.uuid
+ change = self.Session.merge(change)
+ change.deleted = False
+ return change
+
def versions(self):
"""
View to list version history for an object.
@@ -3429,6 +3454,14 @@ class MasterView(View):
config.add_view(cls, attr='clone', route_name='{}.clone'.format(route_prefix),
permission='{}.clone'.format(permission_prefix))
+ # touch
+ if cls.touchable:
+ config.add_tailbone_permission(permission_prefix, '{}.touch'.format(permission_prefix),
+ "\"Touch\" a {} to trigger datasync for it".format(model_title))
+ config.add_route('{}.touch'.format(route_prefix), '{}/{{{}}}/touch'.format(url_prefix, model_key))
+ config.add_view(cls, attr='touch', route_name='{}.touch'.format(route_prefix),
+ permission='{}.touch'.format(permission_prefix))
+
# download
if cls.downloadable:
config.add_route('{}.download'.format(route_prefix), '{}/{{{}}}/download'.format(url_prefix, model_key))