backoffice: allow roles to manage their own custom views (#77194)
gitea/wcs/pipeline/head This commit looks good
Details
gitea/wcs/pipeline/head This commit looks good
Details
This commit is contained in:
parent
156e53a305
commit
7dc831b51a
|
@ -130,6 +130,8 @@ def test_export_import_dependencies(pub):
|
|||
role2.store()
|
||||
role3 = pub.role_class(name='Third role')
|
||||
role3.store()
|
||||
role4 = pub.role_class(name='Fourth role')
|
||||
role4.store()
|
||||
|
||||
wscall = NamedWsCall(name='Test')
|
||||
wscall.store()
|
||||
|
@ -179,6 +181,15 @@ def test_export_import_dependencies(pub):
|
|||
resp = get_app(pub).get(sign_uri(resp.json['data'][0]['urls']['dependencies']))
|
||||
assert not resp.json['data']
|
||||
|
||||
custom_view = pub.custom_view_class()
|
||||
custom_view.title = 'shared formdef custom view'
|
||||
custom_view.formdef = formdef
|
||||
custom_view.columns = {'list': [{'id': '1'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.visibility = 'role'
|
||||
custom_view.role_id = role4.id
|
||||
custom_view.store()
|
||||
|
||||
formdef.roles = ['logged-users']
|
||||
formdef.backoffice_submission_roles = [role2.id]
|
||||
formdef.workflow_roles = {'_receiver': role3.id}
|
||||
|
@ -323,6 +334,7 @@ def test_export_import_dependencies(pub):
|
|||
('test-quater', 'forms'),
|
||||
('second-role', 'roles'),
|
||||
('third-role', 'roles'),
|
||||
('fourth-role', 'roles'),
|
||||
}
|
||||
for dependency in resp.json['data']:
|
||||
get_app(pub).get(sign_uri(dependency['urls']['export']))
|
||||
|
|
|
@ -11,6 +11,7 @@ from wcs.categories import CardDefCategory
|
|||
from wcs.formdef import FormDef
|
||||
from wcs.qommon.http_request import HTTPRequest
|
||||
from wcs.qommon.ident.password_accounts import PasswordAccount
|
||||
from wcs.workflows import Workflow
|
||||
|
||||
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
|
||||
from .test_all import create_superuser, create_user
|
||||
|
@ -609,7 +610,10 @@ def test_backoffice_custom_view_visibility(pub):
|
|||
assert resp.text.count('<span>User Label</span>') == 0
|
||||
|
||||
resp.forms['save-custom-view']['title'] = 'custom test view'
|
||||
assert 'visibility' not in resp.forms['save-custom-view'].fields
|
||||
assert resp.forms['save-custom-view'].fields['visibility'][0].options == [
|
||||
('owner', True, None),
|
||||
('role', False, None),
|
||||
]
|
||||
resp = resp.forms['save-custom-view'].submit()
|
||||
assert resp.location.endswith('/user-custom-test-view/')
|
||||
resp = resp.follow()
|
||||
|
@ -655,6 +659,116 @@ def test_backoffice_custom_view_visibility(pub):
|
|||
}
|
||||
|
||||
|
||||
def test_backoffice_custom_view_role_visibility(pub):
|
||||
pub.user_class.wipe()
|
||||
pub.role_class.wipe()
|
||||
role1 = pub.role_class(name='foo')
|
||||
role1.allows_backoffice_access = True
|
||||
role1.store()
|
||||
role2 = pub.role_class(name='bar')
|
||||
role2.allows_backoffice_access = True
|
||||
role2.store()
|
||||
role3 = pub.role_class(name='baz')
|
||||
role3.allows_backoffice_access = True
|
||||
role3.store()
|
||||
|
||||
FormDef.wipe()
|
||||
pub.custom_view_class.wipe()
|
||||
|
||||
Workflow.wipe()
|
||||
workflow = Workflow(name='wf')
|
||||
workflow.roles = {'_foobar': 'Foobar', '_baz': 'Baz'}
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = []
|
||||
formdef.workflow_roles = {'_foobar': role1.id, '_baz': role3.id}
|
||||
formdef.store()
|
||||
|
||||
agent = pub.user_class(name='agent')
|
||||
agent.roles = [role1.id, role2.id]
|
||||
agent.store()
|
||||
|
||||
account = PasswordAccount(id='agent')
|
||||
account.set_password('agent')
|
||||
account.user_id = agent.id
|
||||
account.store()
|
||||
|
||||
app = login(get_app(pub), username='agent', password='agent')
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
|
||||
# columns
|
||||
resp.forms['listing-settings']['user-label'].checked = False
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
assert resp.text.count('<span>User Label</span>') == 0
|
||||
|
||||
resp.forms['save-custom-view']['title'] = 'custom test view'
|
||||
resp.forms['save-custom-view']['visibility'] = 'role'
|
||||
# only user roles listed in formdef functions are displayed
|
||||
# (role2 is not there as it's not in the formdef functions and
|
||||
# role3 is not there as the user is not a member)
|
||||
assert resp.forms['save-custom-view']['role'].options == [('None', True, '---'), (role1.id, False, 'foo')]
|
||||
resp.forms['save-custom-view']['role'] = role1.id
|
||||
resp = resp.forms['save-custom-view'].submit()
|
||||
assert resp.location.endswith('/custom-test-view/')
|
||||
resp = resp.follow()
|
||||
assert resp.text.count('<span>User Label</span>') == 0
|
||||
|
||||
# second agent
|
||||
agent2 = pub.user_class(name='agent2')
|
||||
agent2.roles = [role3.id]
|
||||
agent2.store()
|
||||
|
||||
account = PasswordAccount(id='agent2')
|
||||
account.set_password('agent2')
|
||||
account.user_id = agent2.id
|
||||
account.store()
|
||||
|
||||
app = login(get_app(pub), username='agent2', password='agent2')
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'custom test view' not in resp
|
||||
resp = app.get('/backoffice/management/form-title/custom-test-view/', status=404)
|
||||
|
||||
agent2.roles = [role1.id, role3.id]
|
||||
agent2.store()
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'custom test view' in resp.text
|
||||
resp = app.get('/backoffice/management/form-title/custom-test-view/', status=200)
|
||||
assert resp.forms['listing-settings']['user-label'].checked is False
|
||||
|
||||
# allow updating view
|
||||
resp.forms['listing-settings']['user-label'].checked = True
|
||||
resp.forms['listing-settings']['last_update_time'].checked = False
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
resp.forms['save-custom-view']['title'] = 'custom test view'
|
||||
resp.forms['save-custom-view']['visibility'] = 'role'
|
||||
resp.forms['save-custom-view']['role'] = role1.id
|
||||
resp.forms['save-custom-view']['update'].checked = True
|
||||
resp = resp.forms['save-custom-view'].submit()
|
||||
assert {(x.slug, x.visibility) for x in get_publisher().custom_view_class.select()} == {
|
||||
('custom-test-view', 'role')
|
||||
}
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
resp = resp.click('custom test view')
|
||||
assert resp.forms['listing-settings']['user-label'].checked is True
|
||||
assert resp.forms['listing-settings']['last_update_time'].checked is False
|
||||
|
||||
# do not allow duplicated slugs
|
||||
resp.forms['listing-settings']['user-label'].checked = False
|
||||
resp.forms['listing-settings']['last_update_time'].checked = False
|
||||
resp = resp.forms['listing-settings'].submit()
|
||||
resp.forms['save-custom-view']['title'] = 'custom test view'
|
||||
resp.forms['save-custom-view']['visibility'] = 'role'
|
||||
resp.forms['save-custom-view']['role'] = role1.id
|
||||
resp.forms['save-custom-view']['update'].checked = False
|
||||
resp = resp.forms['save-custom-view'].submit()
|
||||
assert {(x.slug, x.visibility) for x in get_publisher().custom_view_class.select()} == {
|
||||
('custom-test-view', 'role'),
|
||||
('custom-test-view-2', 'role'),
|
||||
}
|
||||
|
||||
|
||||
def test_backoffice_carddef_custom_view_visibility(pub):
|
||||
user = create_superuser(pub)
|
||||
|
||||
|
|
|
@ -786,6 +786,9 @@ def test_custom_views(pub):
|
|||
]
|
||||
formdef.store()
|
||||
|
||||
role = pub.role_class(name='Test')
|
||||
role.store()
|
||||
|
||||
# define also custom views
|
||||
pub.custom_view_class.wipe()
|
||||
|
||||
|
@ -804,10 +807,20 @@ def test_custom_views(pub):
|
|||
custom_view.columns = {'list': [{'id': 'id'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.visibility = 'owner'
|
||||
custom_view.usier_id = 42
|
||||
custom_view.user_id = '42'
|
||||
custom_view.order_by = 'id'
|
||||
custom_view.store()
|
||||
|
||||
custom_view = pub.custom_view_class()
|
||||
custom_view.title = 'shared form view on role'
|
||||
custom_view.formdef = formdef
|
||||
custom_view.columns = {'list': [{'id': 'id'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.order_by = 'id'
|
||||
custom_view.visibility = 'role'
|
||||
custom_view.role_id = role.id
|
||||
custom_view.store()
|
||||
|
||||
formdef_xml = formdef.export_to_xml()
|
||||
assert formdef_xml.tag == 'formdef'
|
||||
formdef.data_class().wipe()
|
||||
|
@ -818,7 +831,8 @@ def test_custom_views(pub):
|
|||
assert formdef2._custom_views
|
||||
|
||||
custom_views = formdef2._custom_views
|
||||
assert len(custom_views) == 1
|
||||
custom_views.sort(key=lambda x: x.slug)
|
||||
assert len(custom_views) == 2
|
||||
assert custom_views[0].title == 'shared form view'
|
||||
assert custom_views[0].slug == 'shared-form-view'
|
||||
assert custom_views[0].columns == {'list': [{'id': 'id'}, {'id': 'time'}, {'id': 'status'}]}
|
||||
|
@ -833,9 +847,19 @@ def test_custom_views(pub):
|
|||
assert custom_views[0].formdef_id is None
|
||||
assert custom_views[0].formdef_type is None
|
||||
|
||||
assert custom_views[1].title == 'shared form view on role'
|
||||
assert custom_views[1].slug == 'shared-form-view-on-role'
|
||||
assert custom_views[1].columns == {'list': [{'id': 'id'}]}
|
||||
assert custom_views[1].filters == {}
|
||||
assert custom_views[1].visibility == 'role'
|
||||
assert custom_views[1].role_id == role.id
|
||||
assert custom_views[1].order_by == 'id'
|
||||
assert custom_views[1].formdef_id is None
|
||||
assert custom_views[1].formdef_type is None
|
||||
|
||||
formdef2.store()
|
||||
custom_views = pub.custom_view_class.select()
|
||||
assert len(custom_views) == 1
|
||||
custom_views = pub.custom_view_class.select(order_by='slug')
|
||||
assert len(custom_views) == 2
|
||||
assert custom_views[0].title == 'shared form view'
|
||||
assert custom_views[0].slug == 'shared-form-view'
|
||||
assert custom_views[0].columns == {'list': [{'id': 'id'}, {'id': 'time'}, {'id': 'status'}]}
|
||||
|
@ -850,6 +874,67 @@ def test_custom_views(pub):
|
|||
assert custom_views[0].formdef_id == formdef2.id
|
||||
assert custom_views[0].formdef_type == 'formdef'
|
||||
|
||||
assert custom_views[1].title == 'shared form view on role'
|
||||
assert custom_views[1].slug == 'shared-form-view-on-role'
|
||||
assert custom_views[1].columns == {'list': [{'id': 'id'}]}
|
||||
assert custom_views[1].filters == {}
|
||||
assert custom_views[1].visibility == 'role'
|
||||
assert custom_views[1].role_id == role.id
|
||||
assert custom_views[1].order_by == 'id'
|
||||
assert custom_views[1].formdef_id == formdef2.id
|
||||
assert custom_views[1].formdef_type == 'formdef'
|
||||
|
||||
|
||||
def test_custom_views_include_id(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
fields.StringField(id='1', label='Foo', varname='foo'),
|
||||
fields.StringField(id='2', label='Bar', varname='bar'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
role1 = pub.role_class(name='Test1')
|
||||
role1.store()
|
||||
role2 = pub.role_class(name='Test2')
|
||||
role2.store()
|
||||
|
||||
pub.custom_view_class.wipe()
|
||||
|
||||
custom_view = pub.custom_view_class()
|
||||
custom_view.title = 'shared form view on role'
|
||||
custom_view.formdef = formdef
|
||||
custom_view.columns = {'list': [{'id': 'id'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.order_by = 'id'
|
||||
custom_view.visibility = 'role'
|
||||
custom_view.role_id = role1.id
|
||||
custom_view.store()
|
||||
|
||||
formdef_xml = formdef.export_to_xml(include_id=True)
|
||||
formdef.data_class().wipe()
|
||||
pub.custom_view_class.wipe()
|
||||
|
||||
# recreate role, it will get a different id
|
||||
role1.remove_self()
|
||||
role3 = pub.role_class(name='Test1')
|
||||
role3.store()
|
||||
role2.remove_self()
|
||||
|
||||
formdef2 = FormDef.import_from_xml(io.BytesIO(ET.tostring(formdef_xml)), include_id=False)
|
||||
formdef2.store()
|
||||
|
||||
custom_views = formdef2._custom_views
|
||||
assert custom_views[0].title == 'shared form view on role'
|
||||
assert custom_views[0].slug == 'shared-form-view-on-role'
|
||||
assert custom_views[0].columns == {'list': [{'id': 'id'}]}
|
||||
assert custom_views[0].filters == {}
|
||||
assert custom_views[0].visibility == 'role'
|
||||
assert custom_views[0].role_id == role3.id # will match on slug
|
||||
assert custom_views[0].order_by == 'id'
|
||||
assert custom_views[0].formdef_id == formdef2.id
|
||||
assert custom_views[0].formdef_type == 'formdef'
|
||||
|
||||
|
||||
def test_import_formdef_multiple_errors(pub):
|
||||
BlockDef.wipe()
|
||||
|
|
|
@ -43,7 +43,7 @@ from wcs.formdata import FormData, NoContentSnapshotAt
|
|||
from wcs.formdef import FormDef, UpdateDigestAfterJob
|
||||
from wcs.forms.backoffice import FormDefUI
|
||||
from wcs.forms.common import FormdefDirectoryBase, FormStatusPage
|
||||
from wcs.roles import logged_users_role
|
||||
from wcs.roles import get_user_roles, logged_users_role
|
||||
from wcs.sql_criterias import (
|
||||
And,
|
||||
Contains,
|
||||
|
@ -1508,12 +1508,15 @@ class FormPage(FormdefDirectoryBase):
|
|||
required=True,
|
||||
value=self.view.title if self.view else None,
|
||||
)
|
||||
can_update = False
|
||||
if self.formdef.has_admin_access(get_request().user):
|
||||
# admins can create views accessible to everyone
|
||||
# admins can create views accessible to roles or any users
|
||||
options = [
|
||||
('owner', _('to me only'), 'owner'),
|
||||
('role', _('to role'), 'role'),
|
||||
('any', _('to any users'), 'any'),
|
||||
]
|
||||
can_update = True
|
||||
|
||||
if isinstance(self.formdef, CardDef) and self.formdef.default_digest_template:
|
||||
options.append(('datasource', _('as data source'), 'datasource'))
|
||||
|
@ -1527,6 +1530,20 @@ class FormPage(FormdefDirectoryBase):
|
|||
attrs={'data-dynamic-display-parent': 'true'},
|
||||
extra_css_class='widget-inline-radio',
|
||||
)
|
||||
|
||||
role_options = [(None, '---', None)]
|
||||
role_options.extend(get_user_roles())
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'role',
|
||||
title=_('Role'),
|
||||
value=self.view.role_id if self.view else None,
|
||||
options=role_options,
|
||||
attrs={
|
||||
'data-dynamic-display-child-of': 'visibility',
|
||||
'data-dynamic-display-value-in': 'role',
|
||||
},
|
||||
)
|
||||
form.add(
|
||||
CheckboxWidget,
|
||||
'is_default',
|
||||
|
@ -1534,7 +1551,7 @@ class FormPage(FormdefDirectoryBase):
|
|||
value=self.view.is_default if self.view else False,
|
||||
attrs={
|
||||
'data-dynamic-display-child-of': 'visibility',
|
||||
'data-dynamic-display-value-in': 'owner|any',
|
||||
'data-dynamic-display-value-in': 'owner|role|any',
|
||||
},
|
||||
)
|
||||
if isinstance(self.formdef, CardDef):
|
||||
|
@ -1553,9 +1570,44 @@ class FormPage(FormdefDirectoryBase):
|
|||
'data-dynamic-display-value-in': 'datasource|any',
|
||||
},
|
||||
)
|
||||
if self.view and (
|
||||
self.view.user_id == get_request().user.id or self.formdef.has_admin_access(get_request().user)
|
||||
):
|
||||
else:
|
||||
user_roles = get_request().user.get_roles()
|
||||
static_function_role_ids = [x for x in self.formdef.workflow_roles.values() if x in user_roles]
|
||||
static_function_roles = get_publisher().role_class.select(
|
||||
[Contains('id', static_function_role_ids)]
|
||||
)
|
||||
if static_function_roles:
|
||||
# users can create custom views for their roles
|
||||
options = [
|
||||
('owner', _('to me only'), 'owner'),
|
||||
('role', _('to role'), 'role'),
|
||||
]
|
||||
can_update = True
|
||||
form.add(
|
||||
RadiobuttonsWidget,
|
||||
'visibility',
|
||||
title=_('Visibility'),
|
||||
value=self.view.visibility if self.view else 'owner',
|
||||
options=options,
|
||||
attrs={'data-dynamic-display-parent': 'true'},
|
||||
extra_css_class='widget-inline-radio',
|
||||
)
|
||||
|
||||
role_options = [(None, '---', None)]
|
||||
role_options.extend([(x.id, x.name, x.id) for x in static_function_roles])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'role',
|
||||
title=_('Role'),
|
||||
value=self.view.role_id if self.view else None,
|
||||
options=role_options,
|
||||
attrs={
|
||||
'data-dynamic-display-child-of': 'visibility',
|
||||
'data-dynamic-display-value-in': 'role',
|
||||
},
|
||||
)
|
||||
|
||||
if self.view and (self.view.user_id == get_request().user.id or can_update):
|
||||
form.add(CheckboxWidget, 'update', title=_('Update existing view settings'), value=True)
|
||||
form.add_submit('submit', _('Save View'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
@ -1585,6 +1637,12 @@ class FormPage(FormdefDirectoryBase):
|
|||
custom_view.visibility = form.get_widget('visibility').parse()
|
||||
if custom_view.visibility == 'datasource':
|
||||
custom_view.is_default = False
|
||||
if custom_view.visibility == 'role':
|
||||
custom_view.role_id = form.get_widget('role').parse()
|
||||
if not custom_view.role_id:
|
||||
custom_view.visibility = 'owner'
|
||||
else:
|
||||
custom_view.role_id = None
|
||||
custom_view.store()
|
||||
|
||||
if form.get_widget('digest_template') and custom_view.visibility != 'owner':
|
||||
|
@ -1617,7 +1675,11 @@ class FormPage(FormdefDirectoryBase):
|
|||
for view in self.get_custom_views():
|
||||
if view.id == custom_view.id:
|
||||
continue
|
||||
if custom_view.visibility == view.visibility and view.is_default:
|
||||
if (
|
||||
custom_view.visibility == view.visibility
|
||||
and view.is_default
|
||||
and view.role_id == custom_view.role_id
|
||||
):
|
||||
view.is_default = False
|
||||
view.store()
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ class CustomView(StorableObject):
|
|||
title = None
|
||||
slug = None
|
||||
user_id = None
|
||||
role_id = None
|
||||
visibility = 'owner'
|
||||
formdef_type = None
|
||||
formdef_id = None
|
||||
|
@ -78,7 +79,7 @@ class CustomView(StorableObject):
|
|||
formdef.store()
|
||||
super().remove_self()
|
||||
|
||||
def match(self, user, formdef):
|
||||
def match(self, user, formdef, for_export=False):
|
||||
if self.formdef_type != formdef.xml_root_node:
|
||||
return False
|
||||
if self.formdef_id != str(formdef.id):
|
||||
|
@ -87,6 +88,12 @@ class CustomView(StorableObject):
|
|||
user is None or not hasattr(user, 'id') or self.user_id != str(user.id)
|
||||
):
|
||||
return False
|
||||
if (
|
||||
self.visibility == 'role'
|
||||
and not for_export
|
||||
and (user is None or self.role_id not in user.get_roles())
|
||||
):
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_from_qs(self, qs):
|
||||
|
@ -210,7 +217,7 @@ class CustomView(StorableObject):
|
|||
|
||||
return criterias
|
||||
|
||||
def export_to_xml(self, charset=None):
|
||||
def export_to_xml(self, charset=None, include_id=False):
|
||||
root = ET.Element(self.xml_root_node)
|
||||
fields = [
|
||||
'title',
|
||||
|
@ -239,9 +246,21 @@ class CustomView(StorableObject):
|
|||
el.text = force_str(val, charset, errors='replace')
|
||||
else:
|
||||
el.text = str(val)
|
||||
|
||||
if self.visibility == 'role' and self.role_id:
|
||||
from wcs.workflows import get_role_name_and_slug
|
||||
|
||||
role_name, role_slug = get_role_name_and_slug(self.role_id)
|
||||
sub = ET.SubElement(root, 'role')
|
||||
if role_slug:
|
||||
sub.attrib['slug'] = role_slug
|
||||
if include_id:
|
||||
sub.attrib['role_id'] = str(self.role_id)
|
||||
sub.text = role_name
|
||||
|
||||
return root
|
||||
|
||||
def init_with_xml(self, elem, charset):
|
||||
def init_with_xml(self, elem, charset, include_id=False):
|
||||
fields = [
|
||||
'title',
|
||||
'slug',
|
||||
|
@ -266,3 +285,9 @@ class CustomView(StorableObject):
|
|||
setattr(self, attribute, {'list': v})
|
||||
else:
|
||||
setattr(self, attribute, xml_node_text(el))
|
||||
|
||||
self.role_id = get_publisher().role_class.get_role_by_node(elem.find('role'), include_id=include_id)
|
||||
|
||||
def get_dependencies(self):
|
||||
if self.visibility == 'role' and self.role_id:
|
||||
yield get_publisher().role_class.get(self.role_id, ignore_errors=True)
|
||||
|
|
|
@ -593,6 +593,9 @@ class FormDef(StorableObject):
|
|||
yield role_class.get(role_id, ignore_errors=True)
|
||||
for role_id in (self.workflow_roles or {}).values():
|
||||
yield role_class.get(role_id, ignore_errors=True)
|
||||
for view in get_publisher().custom_view_class.select():
|
||||
if view.match(user=None, formdef=self, for_export=True):
|
||||
yield from view.get_dependencies()
|
||||
|
||||
@property
|
||||
def keywords_list(self):
|
||||
|
@ -1273,10 +1276,10 @@ class FormDef(StorableObject):
|
|||
else:
|
||||
custom_views = []
|
||||
for view in get_publisher().custom_view_class.select():
|
||||
if view.match(user=None, formdef=self):
|
||||
if view.match(user=None, formdef=self, for_export=True):
|
||||
custom_views.append(view)
|
||||
for view in custom_views:
|
||||
custom_views_element.append(view.export_to_xml(charset=charset))
|
||||
custom_views_element.append(view.export_to_xml(charset=charset, include_id=include_id))
|
||||
|
||||
geolocations = ET.SubElement(root, 'geolocations')
|
||||
for geoloc_key, geoloc_label in (self.geolocations or {}).items():
|
||||
|
@ -1416,7 +1419,7 @@ class FormDef(StorableObject):
|
|||
formdef._custom_views = []
|
||||
for view in tree.findall('custom_views/%s' % get_publisher().custom_view_class.xml_root_node):
|
||||
view_o = get_publisher().custom_view_class()
|
||||
view_o.init_with_xml(view, charset)
|
||||
view_o.init_with_xml(view, charset, include_id=include_id)
|
||||
formdef._custom_views.append(view_o)
|
||||
|
||||
cls.category_class.object_category_xml_import(formdef, tree, include_id=include_id)
|
||||
|
@ -1440,24 +1443,6 @@ class FormDef(StorableObject):
|
|||
formdef.workflow_id = w.id
|
||||
break
|
||||
|
||||
def get_role_by_node(role_node):
|
||||
role_id = None
|
||||
value = xml_node_text(role_node)
|
||||
if value.startswith('_') or value == 'logged-users':
|
||||
return value
|
||||
|
||||
if include_id:
|
||||
role_id = role_node.attrib.get('role_id')
|
||||
if role_id and get_publisher().role_class.get(role_id, ignore_errors=True):
|
||||
return role_id
|
||||
|
||||
role_slug = role_node.attrib.get('slug')
|
||||
role = get_publisher().role_class.resolve(uuid=None, slug=role_slug, name=value)
|
||||
if role:
|
||||
return role.id
|
||||
|
||||
return None
|
||||
|
||||
roles_elements = [
|
||||
('roles', 'user-roles'),
|
||||
('backoffice_submission_roles', 'backoffice-submission-roles'),
|
||||
|
@ -1469,7 +1454,7 @@ class FormDef(StorableObject):
|
|||
roles = []
|
||||
setattr(formdef, attr_name, roles)
|
||||
for child in roles_node:
|
||||
role_id = get_role_by_node(child)
|
||||
role_id = get_publisher().role_class.get_role_by_node(child, include_id=include_id)
|
||||
if role_id:
|
||||
roles.append(role_id)
|
||||
|
||||
|
@ -1478,7 +1463,7 @@ class FormDef(StorableObject):
|
|||
formdef.workflow_roles = {}
|
||||
for child in roles_node:
|
||||
role_key = child.attrib['role_key']
|
||||
role_id = get_role_by_node(child)
|
||||
role_id = get_publisher().role_class.get_role_by_node(child, include_id=include_id)
|
||||
formdef.workflow_roles[role_key] = role_id
|
||||
|
||||
if tree.find('geolocations') is not None:
|
||||
|
|
20
wcs/roles.py
20
wcs/roles.py
|
@ -186,6 +186,26 @@ class Role(StorableObject):
|
|||
|
||||
return htmltext('<a href="%(url)s">%(name)s</a>') % {'url': url, 'name': self.name}
|
||||
|
||||
@classmethod
|
||||
def get_role_by_node(cls, role_node, include_id=False):
|
||||
if role_node is None:
|
||||
return None
|
||||
value = misc.xml_node_text(role_node)
|
||||
if value.startswith('_') or value == 'logged-users':
|
||||
return value
|
||||
|
||||
if include_id:
|
||||
role_id = role_node.attrib.get('role_id')
|
||||
if role_id and cls.get(role_id, ignore_errors=True):
|
||||
return role_id
|
||||
|
||||
role_slug = role_node.attrib.get('slug')
|
||||
role = cls.resolve(uuid=None, slug=role_slug, name=value)
|
||||
if role:
|
||||
return role.id
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def logged_users_role():
|
||||
volatile_role = Role.volatile()
|
||||
|
|
|
@ -1012,6 +1012,8 @@ def do_custom_views_table():
|
|||
# migrations
|
||||
if 'is_default' not in existing_fields:
|
||||
cur.execute('''ALTER TABLE %s ADD COLUMN is_default boolean DEFAULT FALSE''' % table_name)
|
||||
if 'role_id' not in existing_fields:
|
||||
cur.execute('''ALTER TABLE %s ADD COLUMN role_id VARCHAR''' % table_name)
|
||||
|
||||
# delete obsolete fields
|
||||
for field in existing_fields - needed_fields:
|
||||
|
@ -3423,6 +3425,7 @@ class CustomView(SqlMixin, wcs.custom_views.CustomView):
|
|||
('title', 'varchar'),
|
||||
('slug', 'varchar'),
|
||||
('user_id', 'varchar'),
|
||||
('role_id', 'varchar'),
|
||||
('visibility', 'varchar'),
|
||||
('formdef_type', 'varchar'),
|
||||
('formdef_id', 'varchar'),
|
||||
|
@ -3441,6 +3444,7 @@ class CustomView(SqlMixin, wcs.custom_views.CustomView):
|
|||
'title': self.title,
|
||||
'slug': self.slug,
|
||||
'user_id': self.user_id,
|
||||
'role_id': self.role_id,
|
||||
'visibility': self.visibility,
|
||||
'formdef_type': self.formdef_type,
|
||||
'formdef_id': self.formdef_id,
|
||||
|
@ -4969,7 +4973,7 @@ def get_period_total(
|
|||
# latest migration, number + description (description is not used
|
||||
# programmaticaly but will make sure git conflicts if two migrations are
|
||||
# separately added with the same number)
|
||||
SQL_LEVEL = (89, 'rerun creation of test results table')
|
||||
SQL_LEVEL = (90, 'add role_id to custom views')
|
||||
|
||||
|
||||
def migrate_global_views(conn, cur):
|
||||
|
@ -5129,10 +5133,11 @@ def migrate():
|
|||
if sql_level < 64:
|
||||
# 64: add transient data table
|
||||
do_transient_data_table()
|
||||
if sql_level < 66:
|
||||
if sql_level < 90:
|
||||
# 37: create custom_views table
|
||||
# 44: add is_default column to custom_views table
|
||||
# 66: index the formdef_id column
|
||||
# 90: add role_id to custom views
|
||||
do_custom_views_table()
|
||||
if sql_level < 67:
|
||||
# 57: store tokens in SQL
|
||||
|
|
Loading…
Reference in New Issue