backoffice: add link to tag/save snapshot (#4960)

This commit is contained in:
Frédéric Péters 2020-08-17 17:23:53 +02:00
parent a804ac37fe
commit f7c1315323
9 changed files with 55 additions and 6 deletions

View File

@ -317,3 +317,25 @@ def test_wscall_snapshot_browse(pub):
assert 'This webservice call is readonly' in resp
with pytest.raises(IndexError):
resp = resp.click('Edit')
def test_form_snapshot_save(pub, formdef_with_history):
create_superuser(pub)
create_role()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_with_history.id)
resp = resp.click('Save snapshot')
resp.form['label'] = 'test snapshot'
resp = resp.form.submit('submit')
# add more snapshots
formdef = FormDef.get(id=formdef_with_history.id)
for i in range(10, 15):
formdef.description = 'this is a description (%s)' % i
formdef.store()
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
assert [x.attrib['class'] for x in resp.pyquery.find('ul.snapshots-list li')] == [
'new-day', 'collapsed', 'collapsed', 'collapsed', 'collapsed', 'has-label',
'collapsed', 'collapsed', 'collapsed', 'collapsed', 'collapsed', 'collapsed']

View File

@ -90,6 +90,7 @@ class BlockDirectory(FieldsDirectory):
r += htmltext('<li><a href="delete" rel="popup">%s</a></li>') % _('Delete')
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('<li><a href="settings" rel="popup">%s</a></li>') % _('Settings')
r += htmltext('</ul>')

View File

@ -178,6 +178,7 @@ class NamedDataSourcePage(Directory):
r += htmltext('<li><a href="delete" rel="popup">%s</a></li>') % _('Delete')
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('</ul>')
return r.getvalue()

View File

@ -623,6 +623,7 @@ class FormDefPage(Directory):
'Overwrite with new import')
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('<li><a href="anonymise">%s</a></li>') % _('Anonymise forms')
if not get_publisher().is_using_postgresql():

View File

@ -1581,6 +1581,7 @@ class WorkflowPage(Directory):
r += htmltext('<li><a href="duplicate">%s</a></li>') % _('Duplicate')
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('</ul>')
if not self.workflow.is_readonly():

View File

@ -117,6 +117,7 @@ class NamedWsCallPage(Directory):
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
r += htmltext('<li><a href="delete" rel="popup">%s</a></li>') % _('Delete')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('</ul>')
return r.getvalue()

View File

@ -184,6 +184,7 @@ class CardDefPage(FormDefPage):
'Overwrite with new import')
r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
if get_publisher().snapshot_class:
r += htmltext('<li><a rel="popup" href="history/save">%s</a></li>') % _('Save snapshot')
r += htmltext('<li><a href="history/">%s</a></li>') % _('History')
r += htmltext('</ul>')

View File

@ -20,12 +20,12 @@ from quixote.html import TemplateIO, htmltext
from wcs.qommon import _, errors, misc, template
from wcs.qommon.backoffice.menu import html_top
from wcs.qommon.form import Form, RadiobuttonsWidget
from wcs.qommon.form import Form, RadiobuttonsWidget, StringWidget
from wcs.qommon.storage import Equal
class SnapshotsDirectory(Directory):
_q_exports = ['']
_q_exports = ['', 'save']
do_not_call_in_templates = True
def __init__(self, instance):
@ -43,9 +43,28 @@ class SnapshotsDirectory(Directory):
templates=['wcs/backoffice/snapshots.html'],
context={'view': self})
def save(self):
form = Form(enctype='multipart/form-data')
label = form.add(StringWidget, 'label', title=_('Label'), required=True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('../')
if form.is_submitted() and not form.has_errors():
get_publisher().snapshot_class.snap(instance=self.obj, label=label.parse())
return redirect('../')
html_top('', _('History'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Save snapshot')
r += form.render()
return r.getvalue()
def snapshots(self):
current_date = None
snapshots = get_publisher().snapshot_class.select_object_history(self.obj)[1:]
snapshots = get_publisher().snapshot_class.select_object_history(self.obj)
day_snapshot = None
for i, snapshot in enumerate(snapshots):
if snapshot.timestamp.date() != current_date:

View File

@ -43,7 +43,7 @@ class Snapshot:
_user = None
@classmethod
def snap(cls, instance, comment):
def snap(cls, instance, comment=None, label=None):
obj = cls()
obj.object_type = instance.xml_root_node
obj.object_id = instance.id
@ -52,9 +52,11 @@ class Snapshot:
obj.user_id = get_session().user
obj.serialization = ET.tostring(instance.export_to_xml(include_id=True)).decode('utf-8')
obj.comment = comment
obj.label = label
latest = cls.get_latest(obj.object_type, obj.object_id)
if latest is None or obj.serialization != latest.serialization:
# save snapshot if there are changes
if label is not None or latest is None or obj.serialization != latest.serialization:
# save snapshot if there are changes or an explicit label was
# given.
obj.store()
def get_object_class(self):