backoffice: add possibility to open snapshots (#4960)
This commit is contained in:
parent
c5f3c1a1f8
commit
a804ac37fe
|
@ -468,19 +468,19 @@ def test_form_workflow_link(pub):
|
|||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/forms/%s/' % formdef.id)
|
||||
assert '../workflows/_default/' in resp.text
|
||||
assert '/backoffice/workflows/_default/' in resp.text
|
||||
|
||||
formdef.workflow = workflow
|
||||
formdef.store()
|
||||
|
||||
resp = app.get('/backoffice/forms/%s/' % formdef.id)
|
||||
assert '../workflows/%s/' % workflow.id in resp.text
|
||||
assert '/backoffice/workflows/%s/' % workflow.id in resp.text
|
||||
|
||||
# check workflow link is not displayed if user has no access right
|
||||
pub.cfg['admin-permissions'] = {'workflows': ['x']} # block access
|
||||
pub.write_cfg()
|
||||
resp = app.get('/backoffice/forms/%s/' % formdef.id)
|
||||
assert '../workflows/%s/' % workflow.id not in resp.text
|
||||
assert '/backoffice/workflows/%s/' % workflow.id not in resp.text
|
||||
|
||||
|
||||
def test_form_workflow_remapping(pub):
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import pytest
|
||||
|
||||
from wcs.blocks import BlockDef
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.data_sources import NamedDataSource
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.workflows import Workflow
|
||||
from wcs.wscalls import NamedWsCall
|
||||
|
||||
from utilities import get_app, login, create_temporary_pub, clean_temporary_pub
|
||||
from test_admin_pages import create_superuser, create_role
|
||||
|
@ -31,6 +34,7 @@ def formdef_with_history(pub):
|
|||
|
||||
for i in range(5):
|
||||
formdef.name = 'testform %s' % i
|
||||
formdef.description = 'this is a description (%s)' % i
|
||||
formdef.store()
|
||||
|
||||
return formdef
|
||||
|
@ -207,3 +211,109 @@ def test_form_snapshot_restore(pub, formdef_with_history):
|
|||
formdef = FormDef.get(resp.location.split('/')[-2])
|
||||
assert formdef.id == formdef_with_history.id
|
||||
assert formdef.url_name == formdef_with_history.url_name
|
||||
|
||||
|
||||
def test_block_snapshot_browse(pub, blocks_feature):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
BlockDef.wipe()
|
||||
blockdef = BlockDef()
|
||||
blockdef.name = 'testblock'
|
||||
blockdef.fields = []
|
||||
blockdef.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/forms/blocks/%s/history/' % blockdef.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(blockdef)[0]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This block of fields is readonly.' in resp
|
||||
|
||||
|
||||
def test_card_snapshot_browse(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
CardDef.wipe()
|
||||
carddef = CardDef()
|
||||
carddef.name = 'testcard'
|
||||
carddef.fields = []
|
||||
carddef.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/cards/%s/history/' % carddef.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(carddef)[0]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This card model is readonly' in resp
|
||||
resp = resp.click('Geolocation')
|
||||
assert [x[0].name for x in resp.form.fields.values() if x[0].tag == 'button'] == ['cancel']
|
||||
|
||||
|
||||
def test_datasource_snapshot_browse(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
NamedDataSource.wipe()
|
||||
datasource = NamedDataSource(name='test')
|
||||
datasource.data_source = {'type': 'formula',
|
||||
'value': repr([('1', 'un'), ('2', 'deux')])}
|
||||
datasource.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/forms/data-sources/%s/history/' % datasource.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(datasource)[0]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This data source is readonly' in resp
|
||||
with pytest.raises(IndexError):
|
||||
resp = resp.click('Edit')
|
||||
|
||||
|
||||
def test_form_snapshot_browse(pub, formdef_with_history):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/forms/%s/history/' % formdef_with_history.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(formdef_with_history)[2]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This form is readonly' in resp
|
||||
resp = resp.click('Description')
|
||||
assert resp.form['description'].value == 'this is a description (2)'
|
||||
assert [x[0].name for x in resp.form.fields.values() if x[0].tag == 'button'] == ['cancel']
|
||||
|
||||
|
||||
def test_workflow_snapshot_browse(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
Workflow.wipe()
|
||||
workflow = Workflow(name='test')
|
||||
workflow.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/workflows/%s/history/' % workflow.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(workflow)[0]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This workflow is readonly' in resp
|
||||
|
||||
|
||||
def test_wscall_snapshot_browse(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
NamedWsCall.wipe()
|
||||
wscall = NamedWsCall(name='test')
|
||||
wscall.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
resp = app.get('/backoffice/settings/wscalls/%s/history/' % wscall.id)
|
||||
snapshot = pub.snapshot_class.select_object_history(wscall)[0]
|
||||
resp = resp.click(href='%s/view/' % snapshot.id)
|
||||
assert 'This webservice call is readonly' in resp
|
||||
with pytest.raises(IndexError):
|
||||
resp = resp.click('Edit')
|
||||
|
|
|
@ -160,9 +160,9 @@ class NamedDataSourcePage(Directory):
|
|||
('history', 'snapshots_dir'),]
|
||||
do_not_call_in_templates = True
|
||||
|
||||
def __init__(self, component):
|
||||
def __init__(self, component=None, instance=None):
|
||||
try:
|
||||
self.datasource = NamedDataSource.get(component)
|
||||
self.datasource = instance or NamedDataSource.get(component)
|
||||
except KeyError:
|
||||
raise errors.TraversalError()
|
||||
self.datasource_ui = NamedDataSourceUI(self.datasource)
|
||||
|
|
|
@ -384,9 +384,9 @@ class FormDefPage(Directory):
|
|||
'The form has been successfully overwritten. '
|
||||
'Do note it kept its existing address and role and workflow parameters.')
|
||||
|
||||
def __init__(self, component):
|
||||
def __init__(self, component, instance=None):
|
||||
try:
|
||||
self.formdef = self.formdef_class.get(component)
|
||||
self.formdef = instance or self.formdef_class.get(component)
|
||||
except KeyError:
|
||||
raise TraversalError()
|
||||
self.formdefui = self.formdef_ui_class(self.formdef)
|
||||
|
@ -458,12 +458,12 @@ class FormDefPage(Directory):
|
|||
'<span class="label">%(label)s</span> '
|
||||
'<span class="value offset">%(current_value)s</span>'
|
||||
'</a>'
|
||||
'<a class="extra-link" title="%(title)s" href="../../workflows/%(workflow_id)s/">↗</a>'
|
||||
'<a class="extra-link" title="%(title)s" href="%(workflow_url)s">↗</a>'
|
||||
'</li>' % {
|
||||
'link': 'workflow',
|
||||
'label': _('Workflow'),
|
||||
'title': _('Open workflow page'),
|
||||
'workflow_id': self.formdef.workflow.id,
|
||||
'workflow_url': self.formdef.workflow.get_admin_url(),
|
||||
'current_value': self.formdef.workflow.name or '-'})
|
||||
else:
|
||||
r += add_option_line('workflow', _('Workflow'),
|
||||
|
|
|
@ -1373,26 +1373,30 @@ class WorkflowPage(Directory):
|
|||
('history', 'snapshots_dir'),
|
||||
]
|
||||
|
||||
def __init__(self, component, html_top):
|
||||
if component == '_carddef_default':
|
||||
def __init__(self, component, instance=None):
|
||||
if instance:
|
||||
self.workflow = instance
|
||||
elif component == '_carddef_default':
|
||||
self.workflow = CardDef.get_default_workflow()
|
||||
else:
|
||||
try:
|
||||
self.workflow = Workflow.get(component)
|
||||
except KeyError:
|
||||
raise errors.TraversalError()
|
||||
self.html_top = html_top
|
||||
self.workflow_ui = WorkflowUI(self.workflow)
|
||||
self.status_dir = WorkflowStatusDirectory(self.workflow, html_top)
|
||||
self.status_dir = WorkflowStatusDirectory(self.workflow, self.html_top)
|
||||
self.variables_dir = VariablesDirectory(self.workflow)
|
||||
self.backoffice_fields_dir = BackofficeFieldsDirectory(self.workflow)
|
||||
self.functions_dir = FunctionsDirectory(self.workflow)
|
||||
self.global_actions_dir = GlobalActionsDirectory(self.workflow, html_top)
|
||||
self.global_actions_dir = GlobalActionsDirectory(self.workflow, self.html_top)
|
||||
self.criticality_levels_dir = CriticalityLevelsDirectory(self.workflow)
|
||||
self.logged_errors_dir = LoggedErrorsDirectory(parent_dir=self, workflow_id=self.workflow.id)
|
||||
self.snapshots_dir = SnapshotsDirectory(self.workflow)
|
||||
get_response().breadcrumb.append((component + '/', self.workflow.name))
|
||||
|
||||
def html_top(self, title):
|
||||
return html_top('workflows', title)
|
||||
|
||||
def _q_index(self):
|
||||
self.html_top(title = _('Workflow - %s') % self.workflow.name)
|
||||
r = TemplateIO(html=True)
|
||||
|
@ -1919,7 +1923,7 @@ class WorkflowsDirectory(Directory):
|
|||
return r.getvalue()
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return WorkflowPage(component, html_top=self.html_top)
|
||||
return WorkflowPage(component)
|
||||
|
||||
def p_import(self):
|
||||
form = Form(enctype = 'multipart/form-data')
|
||||
|
|
|
@ -99,9 +99,9 @@ class NamedWsCallPage(Directory):
|
|||
_q_exports = ['', 'edit', 'delete', 'export',
|
||||
('history', 'snapshots_dir'),]
|
||||
|
||||
def __init__(self, component):
|
||||
def __init__(self, component, instance=None):
|
||||
try:
|
||||
self.wscall = NamedWsCall.get(component)
|
||||
self.wscall = instance or NamedWsCall.get(component)
|
||||
except KeyError:
|
||||
raise errors.TraversalError()
|
||||
self.wscall_ui = NamedWsCallUI(self.wscall)
|
||||
|
|
|
@ -97,12 +97,12 @@ class CardDefPage(FormDefPage):
|
|||
'<span class="label">%(label)s</span> '
|
||||
'<span class="value offset">%(current_value)s</span>'
|
||||
'</a>'
|
||||
'<a class="extra-link" title="%(title)s" href="../../workflows/%(workflow_id)s/">↗</a>'
|
||||
'<a class="extra-link" title="%(title)s" href="%(workflow_url)s">↗</a>'
|
||||
'</li>' % {
|
||||
'link': 'workflow',
|
||||
'label': _('Workflow'),
|
||||
'title': _('Open workflow page'),
|
||||
'workflow_id': self.formdef.workflow.id,
|
||||
'workflow_url': self.formdef.workflow.get_admin_url(),
|
||||
'current_value': self.formdef.workflow.name or '-'})
|
||||
else:
|
||||
r += add_option_line('workflow', _('Workflow'),
|
||||
|
|
|
@ -66,7 +66,7 @@ class SnapshotsDirectory(Directory):
|
|||
|
||||
|
||||
class SnapshotDirectory(Directory):
|
||||
_q_exports = ['', 'export', 'restore']
|
||||
_q_exports = ['', 'export', 'restore', 'view']
|
||||
|
||||
def __init__(self, instance, snapshot):
|
||||
self.obj = instance
|
||||
|
@ -80,7 +80,7 @@ class SnapshotDirectory(Directory):
|
|||
return super()._q_traverse(path)
|
||||
|
||||
def _q_index(self):
|
||||
return ''
|
||||
return redirect('view/')
|
||||
|
||||
def export(self):
|
||||
response = get_response()
|
||||
|
@ -114,3 +114,34 @@ class SnapshotDirectory(Directory):
|
|||
r += htmltext('<h2>%s</h2>') % _('Restore snapshot')
|
||||
r += form.render()
|
||||
return r.getvalue()
|
||||
|
||||
@property
|
||||
def view(self):
|
||||
from wcs.blocks import BlockDef
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.data_sources import NamedDataSource
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.workflows import Workflow
|
||||
from wcs.wscalls import NamedWsCall
|
||||
klass = self.snapshot.get_object_class()
|
||||
if klass is BlockDef:
|
||||
from wcs.admin.blocks import BlockDirectory
|
||||
return BlockDirectory(section='forms', objectdef=self.snapshot.instance)
|
||||
if klass is FormDef:
|
||||
from wcs.admin.forms import FormDefPage
|
||||
return FormDefPage(component='view', instance=self.snapshot.instance)
|
||||
if klass is CardDef:
|
||||
from wcs.backoffice.cards import CardDefPage
|
||||
return CardDefPage(component='view', instance=self.snapshot.instance)
|
||||
if klass is Workflow:
|
||||
from wcs.admin.workflows import WorkflowPage
|
||||
return WorkflowPage(component='view',
|
||||
instance=self.snapshot.instance)
|
||||
if klass is NamedDataSource:
|
||||
from wcs.admin.data_sources import NamedDataSourcePage
|
||||
return NamedDataSourcePage(component='view',
|
||||
instance=self.snapshot.instance)
|
||||
if klass is NamedWsCall:
|
||||
from wcs.admin.wscalls import NamedWsCallPage
|
||||
return NamedWsCallPage(component='view',
|
||||
instance=self.snapshot.instance)
|
||||
|
|
|
@ -74,6 +74,7 @@ class Snapshot:
|
|||
if self._instance is None:
|
||||
tree = ET.fromstring(self.serialization)
|
||||
self._instance = self.get_object_class().import_from_xml_tree(tree, include_id=True)
|
||||
self._instance.readonly = True
|
||||
return self._instance
|
||||
|
||||
@property
|
||||
|
@ -101,6 +102,7 @@ class Snapshot:
|
|||
if hasattr(current_object, attr):
|
||||
setattr(instance, attr, getattr(current_object, attr))
|
||||
|
||||
delattr(instance, 'readonly')
|
||||
instance.store(comment=_('Restored snapshot %(id)s (%(timestamp)s)') % {
|
||||
'id': self.id,
|
||||
'timestamp': misc.localstrftime(self.timestamp)})
|
||||
|
|
Loading…
Reference in New Issue