@live-change/access-control-service 0.2.39 → 0.2.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/access.js CHANGED
@@ -1,38 +1,318 @@
1
+ const { parents, parentsSources } = require('./accessControlParents.js')
2
+ const App = require('@live-change/framework')
3
+ const app = App.app()
1
4
 
2
5
  module.exports = (definition) => {
3
6
 
4
- const Access = definition.foreignModel('access-control', 'Access')
5
- const PublicAccess = definition.foreignModel('access-control', 'PublicAccess')
7
+ const Access = definition.foreignModel('accessControl', 'Access')
8
+ const PublicAccess = definition.foreignModel('accessControl', 'PublicAccess')
6
9
 
7
- function clientHasAnyAccess(client, { objectType, object }) {
8
- /// TODO: access control
9
- return true
10
+ const config = definition?.config?.access ?? {}
11
+
12
+ const {
13
+ hasAny = (roles, client, { objectType, object }) => roles.length > 0,
14
+ isAdmin = (roles, client, { objectType, object }) => roles.includes('administrator'),
15
+ canInvite = (roles, client, { objectType, object }) => roles.length > 0,
16
+ canRequest = (roles, client, { objectType, object }) => false
17
+ } = config
18
+
19
+ function testRoles(requiredRoles, clientRoles) {
20
+ for(const requiredRolesOption of requiredRoles) {
21
+ if(
22
+ (Array.isArray(requiredRolesOption) ? requiredRolesOption : [requiredRolesOption])
23
+ .every(role => clientRoles.includes(role))
24
+ ) return true
25
+ }
26
+ return false
27
+ }
28
+
29
+ async function clientHasAnyAccess(client, { objectType, object, objects }) {
30
+ return checkRoles(client, { objectType, object, objects }, hasAny)
31
+ }
32
+
33
+ function clientHasAdminAccess(client, { objectType, object, objects }) {
34
+ return checkRoles(client, { objectType, object, objects }, isAdmin)
35
+ }
36
+
37
+ function clientCanInvite(client, { objectType, object, objects }) {
38
+ return checkRoles(client, { objectType, object, objects }, canInvite, true)
39
+ }
40
+
41
+ function clientCanRequest(client, { objectType, object, objects }) {
42
+ return checkRoles(client, { objectType, object, objects }, canRequest)
43
+ }
44
+
45
+ function clientHasAccessRole(client, { objectType, object, objects }, role) {
46
+ return checkRoles(client, { objectType, object, objects }, (roles) => roles.includes(role) )
47
+ }
48
+
49
+ function clientHasAccessRoles(client, { objectType, object, objects }, roles) {
50
+ return checkRoles(client, { objectType, object, objects },
51
+ (clientRoles) => testRoles(requiredRoles, roles)
52
+ )
53
+ }
54
+
55
+ async function getUnitClientRoles(client, { objectType, object }, ignorePublic) {
56
+ const [ sessionOrUserType, sessionOrUser ] = client.user ? ['user_User', client.user] : ['session_Session']
57
+ const [
58
+ publicAccessData,
59
+ sessionAccess,
60
+ userAccess,
61
+ ] = await Promise.all([
62
+ ignorePublic ? null : PublicAccess.get(App.encodeIdentifier([ objectType, object ])),
63
+ Access.get(App.encodeIdentifier([ 'session_Session', client.session, objectType, object ])),
64
+ client.user
65
+ ? Access.get(App.encodeIdentifier([ 'user_User', client.user, objectType, object ]))
66
+ : Promise.resolve(null)
67
+ ])
68
+ let roles = []
69
+ if(publicAccessData) {
70
+ roles.push(...publicAccessData.sessionRoles)
71
+ if(client.user) roles.push(...publicAccessData.userRoles)
72
+ }
73
+ if(sessionAccess) roles.push(...sessionAccess.roles)
74
+ if(userAccess) roles.push(...userAccess.roles)
75
+ return Array.from(new Set(roles))
76
+ }
77
+
78
+ async function getClientObjectRoles(client, { objectType, object }, ignorePublic) {
79
+ const unitRolesPromise = getUnitClientRoles(client, { objectType, object}, ignorePublic)
80
+ const accessParentsPromise = parents[objectType]
81
+ ? parents[objectType]({ objectType, object })
82
+ : Promise.resolve([])
83
+ const parentRolesPromise = accessParentsPromise.then(accessParents => Promise.all(
84
+ accessParents.map(
85
+ ({ objectType, object }) =>
86
+ getClientObjectRoles(client, { objectType, object }, ignorePublic)
87
+ )
88
+ ).then(rolesArrays => rolesArrays.flat()))
89
+ const [ unitRoles, parentRoles ] = await Promise.all([ unitRolesPromise, parentRolesPromise ])
90
+ return Array.from(new Set([ ...client.roles, ...unitRoles, ...parentRoles]))
10
91
  }
11
92
 
12
- function clientHasAdminAccess(client, { objectType, object }) {
13
- /// TODO: access control
14
- return true
93
+ async function getClientObjectsRoles(client, objects, ignorePublic) {
94
+ const objectsRoles = await Promise.all(objects.map(obj => getClientObjectRoles(client, obj, ignorePublic)))
95
+ const firstObjectRoles = objectsRoles.shift()
96
+ let roles = firstObjectRoles
97
+ for(const objectRoles of objectsRoles) {
98
+ roles = roles.filter(role => objectRoles.includes(role))
99
+ }
100
+ return roles
15
101
  }
16
102
 
17
- function clientCanInvite(client, { roles, objectType, object }) {
18
- /// TODO: access control
19
- return true
103
+ async function checkRoles(client, { objectType, object, objects }, callback, ignorePublic) {
104
+ const allObjects = ((objectType && object) ? [{ objectType, object }] : []).concat(objects || [])
105
+ const roles = await getClientObjectsRoles(client, allObjects, ignorePublic)
106
+ return await callback(roles, client, { objectType, object })
20
107
  }
21
108
 
22
- function clientCanRequest(client, { roles, objectType, object }) {
23
- /// TODO: access control
24
- return true
109
+ /// QUERIES:
110
+
111
+ function dbAccessFunctions({
112
+ input, publicAccessTable, accessTable, updateRoles, isLoaded,
113
+ client, parentsSourcesMap, output
114
+ }) {
115
+ async function treeNode(objectType, object) {
116
+ const node = {
117
+ objectType, object,
118
+ data: null,
119
+ parents: [],
120
+ publicSessionRoles: [],
121
+ publicUserRoles: [],
122
+ sessionRoles: [],
123
+ userRoles: []
124
+ }
125
+ let objectObserver, publicAccessObserver, sessionAccessObserver, userAccessObserver
126
+
127
+ const publicAccessObject = publicAccessTable.object(`${JSON.stringify(objectType)}:${JSON.stringify(object)}`)
128
+ publicAccessObserver = publicAccessObject.onChange((accessData, oldAccessData) => {
129
+ node.publicSessionRoles = accessData?.sessionRoles ?? []
130
+ node.publicUserRoles = (client.user && accessData?.userRoles) ?? []
131
+ if(isLoaded()) updateRoles()
132
+ })
133
+
134
+ const sessionAccessObject = accessTable.object(
135
+ `"session_Session":${JSON.stringify(client.session)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
136
+ )
137
+ sessionAccessObserver = sessionAccessObject && sessionAccessObject.onChange((accessData, oldAccessData) => {
138
+ node.sessionRoles = accessData?.roles ?? []
139
+ if(isLoaded()) updateRoles()
140
+ })
141
+
142
+ const userAccessObject = client.user && accessTable.object(
143
+ `"user_User":${JSON.stringify(client.user)}:${JSON.stringify(objectType)}:${JSON.stringify(object)}`
144
+ )
145
+ userAccessObserver = userAccessObject && userAccessObject.onChange((accessData, oldAccessData) => {
146
+ node.userRoles = accessData?.roles ?? []
147
+ if(isLoaded()) updateRoles()
148
+ })
149
+
150
+ async function disposeParents() {
151
+ const oldParents = node.parents
152
+ return Promise.all(oldParents.map(parent => parent.dispose()))
153
+ }
154
+ const parentsSources = parentsSourcesMap[objectType]
155
+ if(parentsSources) {
156
+ const objectTable = input.table(objectType)
157
+ const objectTableObject = objectTable.object(object)
158
+ objectObserver = objectTableObject.onChange(async (objectData, oldObjectData) => {
159
+ await disposeParents()
160
+ node.parents = objectData ? await Promise.all(parentsSources.map(parentSource => {
161
+ const parentType = parentSource.type || objectData[parentSource.property + 'Type']
162
+ const parent = objectData[parentSource.property]
163
+ return treeNode(parentType, parent)
164
+ })) : []
165
+ })
166
+ }
167
+ node.dispose = async function() {
168
+ const disposePromises = []
169
+ if(objectObserver) disposePromises.push(objectObserver.then(obs => obs.dispose()))
170
+ if(publicAccessObserver) disposePromises.push(publicAccessObserver.then(obs => obs.dispose()))
171
+ if(sessionAccessObserver) disposePromises.push(sessionAccessObserver.then(obs => obs.dispose()))
172
+ if(userAccessObserver) disposePromises.push(userAccessObserver.then(obs => obs.dispose()))
173
+ disposePromises.push(disposeParents())
174
+ return Promise.all(disposePromises)
175
+ }
176
+ await Promise.all([ objectObserver, publicAccessObserver, sessionAccessObserver, userAccessObserver ])
177
+ return node
178
+ }
179
+ function computeNodeRoles(node) {
180
+ const parentsRoles = node.parents.map(parent => computeNodeRoles(parent)).flat()
181
+ return Array.from(new Set([
182
+ ...parentsRoles,
183
+ ...node.publicUserRoles,
184
+ ...node.publicSessionRoles,
185
+ ...node.userRoles,
186
+ ...node.sessionRoles
187
+ ]))
188
+ }
189
+ return { treeNode, computeNodeRoles }
190
+ }
191
+
192
+ function accessPath(client, objects) {
193
+ return ['database', 'queryObject', app.databaseName, `(${
194
+ async (input, output, {
195
+ objects, parentsSourcesMap, client,
196
+ accessTableName, publicAccessTableName, dbAccessFunctions
197
+ }) => {
198
+ const accessTable = input.table(accessTableName)
199
+ const publicAccessTable = input.table(publicAccessTableName)
200
+ let loaded = false
201
+
202
+ const { treeNode, computeNodeRoles } =
203
+ eval(dbAccessFunctions)({
204
+ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded,
205
+ client, parentsSourcesMap, output
206
+ })
207
+
208
+ let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object, client))
209
+
210
+ const outputObjectId = `${JSON.stringify(client.session)}:${JSON.stringify(client.user)}:` +
211
+ objects.map( obj => `${JSON.stringify(objectType)}:${JSON.stringify(object)}`)
212
+ .join(':')
213
+ let oldOutputObject = null
214
+ async function updateRoles() {
215
+ const roots = await Promise.all(rolesTreesRoots)
216
+ const accesses = roots.map(root => computeNodeRoles(root))
217
+ const firstAccess = accesses.shift()
218
+ let roles = firstAccess.roles
219
+ for(const access of accesses) {
220
+ roles = roles.filter(role => access.roles.includes(role))
221
+ }
222
+ const accessControlRoles = computeNodeRoles()
223
+ const outputObject = {
224
+ id: outputObjectId,
225
+ roles: Array.from(new Set([...accessControlRoles, ...client.roles]))
226
+ }
227
+ output.change(outputObject, oldOutputObject)
228
+ oldOutputObject = outputObject
229
+ }
230
+ await Promise.all(rolesTreesRoots)
231
+ loaded = true
232
+ await updateRoles()
233
+ }
234
+ })`, {
235
+ objectType, object, parentsSourcesMap: parentsSources, client,
236
+ accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
237
+ dbAccessFunctions: `(${dbAccessFunctions})`
238
+ }]
239
+ }
240
+
241
+ function accessesPath(client, objects) {
242
+ return ['database', 'query', app.databaseName, `(${
243
+ async (input, output, {
244
+ objects, parentsSourcesMap, client,
245
+ accessTableName, publicAccessTableName, dbAccessFunctions
246
+ }) => {
247
+ const accessTable = input.table(accessTableName)
248
+ const publicAccessTable = input.table(publicAccessTableName)
249
+ let loaded = false
250
+
251
+ const { treeNode, computeNodeRoles } =
252
+ eval(dbAccessFunctions)({
253
+ input, publicAccessTable, accessTable, updateRoles, isLoaded: () => loaded,
254
+ client, parentsSourcesMap, output,
255
+ })
256
+
257
+ let rolesTreesRoots = objects.map(({ object, objectType }) => treeNode(objectType, object, client))
258
+ const accesses = []
259
+ async function updateRoles() {
260
+ const roots = await Promise.all(rolesTreesRoots)
261
+ for(let root of roots) {
262
+ const outputObjectId = `${JSON.stringify(client.session)}:${JSON.stringify(client.user)}` +
263
+ `:${JSON.stringify(root.objectType)}:${JSON.stringify(root.object)}`
264
+ const nodeRoles = computeNodeRoles(root)
265
+ const outputObject = {
266
+ id: outputObjectId,
267
+ roles: Array.from(new Set([...nodeRoles, ...client.roles]))
268
+ }
269
+ const existingAccessIndex = accesses.findIndex(acc => acc.id == outputObjectId)
270
+ if(existingAccessIndex != -1) {
271
+ if(JSON.stringify(outputObject) != JSON.stringify(accesses[existingAccessIndex])) {
272
+ output.change(outputObject, accesses[existingAccessIndex])
273
+ accesses[existingAccessIndex] = outputObject
274
+ } /// else ignore
275
+ } else {
276
+ output.change(outputObject, null)
277
+ accesses.push(outputObject)
278
+ }
279
+ }
280
+ }
281
+ await Promise.all(rolesTreesRoots)
282
+ loaded = true
283
+ await updateRoles()
284
+ }
285
+ })`, {
286
+ objects, parentsSourcesMap: parentsSources, client,
287
+ accessTableName: Access.tableName, publicAccessTableName: PublicAccess.tableName,
288
+ dbAccessFunctions: `(${dbAccessFunctions})`
289
+ }]
290
+ }
291
+
292
+ function accessLimitedGet(client, objects, requiredRoles, path) {
293
+ const roles = getClientObjectsRoles(client, objects)
294
+ for(const requiredRole of requiredRoles) {
295
+
296
+ }
25
297
  }
26
298
 
27
- function clientHasAccessRole(client, { objectType, object }, role) {
28
- return true
299
+ function accessLimitedObservable(client, objects, path) {
300
+ if(path[0] != 'database') throw new Error("non database path "+ JSON.stringify(path))
301
+ const isObject = path[1] == 'queryObject' || path[1] == ''
29
302
  }
30
303
 
31
304
  return {
305
+ testRoles,
32
306
  clientHasAnyAccess, clientHasAdminAccess,
33
307
  clientCanInvite,
34
308
  clientCanRequest,
35
- clientHasAccessRole
309
+ clientHasAccessRole,
310
+ clientHasAccessRoles,
311
+ getClientObjectRoles,
312
+ getClientObjectsRoles,
313
+ checkRoles,
314
+ accessPath,
315
+ accessesPath
36
316
  }
37
317
 
38
318
  }
@@ -0,0 +1,110 @@
1
+ const definition = require('./definition.js')
2
+ const App = require("@live-change/framework")
3
+ const { ObservableValue, ObservableList, ObservableProxy } = require("@live-change/dao")
4
+ const app = App.app()
5
+ const access = require('./access.js')(definition)
6
+
7
+ definition.processor({
8
+ priority: -1,
9
+ process(service, app) {
10
+
11
+ for(const actionName in service.actions) {
12
+ const action = service.actions[actionName]
13
+ if(!action.accessControl) continue
14
+ const config = action.accessControl
15
+
16
+ console.log("ACCESS CONTROL", service.name, "ACTION", action.name)
17
+
18
+ const oldExec = action.execute
19
+ action.execute = async (...args) => {
20
+ const [ properties, context, emit ] = args
21
+ const { client } = context
22
+
23
+ const objects = [].concat(
24
+ config.objects ? config.objects(properties) : [],
25
+ (objectType && object) ? [{ objectType, object }] : []
26
+ )
27
+ if(objects.length == 0) {
28
+ throw new Error('no objects for access control to work')
29
+ }
30
+ const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
31
+ if(!accessible) throw 'notAuthorized'
32
+
33
+ return oldExec.apply(action, args)
34
+ }
35
+ }
36
+
37
+ for(const viewName in service.views) {
38
+ const view = service.views[viewName]
39
+ if(!view.accessControl) continue
40
+ const config = view.accessControl
41
+
42
+ console.log("ACCESS CONTROL", service.name, "VIEW", view.name)
43
+
44
+ const oldGet = view.get
45
+ const oldObservable = view.observable
46
+ view.get = async (...args) => {
47
+ const [ properties, context ] = args
48
+ const { client } = context
49
+ const { objectType, object } = properties
50
+ const objects = [].concat(
51
+ config.objects ? config.objects(properties) : [],
52
+ (objectType && object) ? [{ objectType, object }] : []
53
+ )
54
+ if(objects.length == 0) {
55
+ throw new Error('no objects for access control to work')
56
+ }
57
+ const accessible = access.clientHasAccessRoles(client, { objects }, config.roles)
58
+ if(!accessible) throw 'notAuthorized'
59
+ return oldGet.apply(view, args)
60
+ }
61
+ view.observable = (...args) => {
62
+ const [ properties, context ] = args
63
+ const { client } = context
64
+ const { objectType, object } = properties
65
+ const objects = [].concat(
66
+ config.objects ? config.objects(properties) : [],
67
+ (objectType && object) ? [{ objectType, object }] : []
68
+ )
69
+ if(objects.length == 0) {
70
+ throw new Error('no objects for access control to work')
71
+ }
72
+
73
+ const rolesPath = access.accessPath(client, objects)
74
+
75
+ const errorObservable = new ObservableValue()
76
+ errorObservable.handleError('notAuthorized')
77
+
78
+ const observableProxy = new ObservableProxy(null)
79
+
80
+ let valueObservable
81
+
82
+ let accessible
83
+ const rolesObservable = app.dao.observable(rolesPath)
84
+ const rolesObserver = (signal, value) => {
85
+ const accessObject = rolesObservable.getValue()
86
+ const newAccessible = access.testRoles(config.roles, accessObject.roles)
87
+ if(newAccessible !== accessible) {
88
+ if(newAccessible === true /*&& !valueObservable*/) {
89
+ valueObservable = oldObservable.apply(view, args)
90
+ }
91
+ observableProxy.setTarget(accessible ? valueObservable : errorObservable)
92
+ }
93
+ }
94
+ rolesObservable.observe(rolesObserver)
95
+
96
+ const oldDispose = observableProxy.dispose
97
+ const oldRespawn = observableProxy.respawn
98
+ observableProxy.dispose = () => {
99
+ rolesObservable.unobserve(rolesObserver)
100
+ oldDispose.apply(observableProxy)
101
+ }
102
+ observableProxy.respawn = () => {
103
+ rolesObservable.observe(rolesObserver)
104
+ oldRespawn.apply(observableProxy)
105
+ }
106
+ }
107
+ }
108
+
109
+ }
110
+ })
@@ -0,0 +1,22 @@
1
+ const definition = require("./definition.js")
2
+
3
+ const parents = { }
4
+ const parentsSources = { }
5
+
6
+ definition.processor(function(service, app) {
7
+
8
+ for(let modelName in service.models) {
9
+ const model = service.models[modelName]
10
+ if(!model.accessControlParents) continue
11
+ parents[service.name + '_' + modelName] = model.accessControlParents
12
+ }
13
+
14
+ for(let modelName in service.models) {
15
+ const model = service.models[modelName]
16
+ if(!model.accessControlParentsSource) continue
17
+ parentsSources[service.name + '_' + modelName] = model.accessControlParentsSource
18
+ }
19
+
20
+ })
21
+
22
+ module.exports = { parents, parentsSources }
package/index.js CHANGED
@@ -5,5 +5,7 @@ const definition = require('./definition.js')
5
5
  require('./model.js')
6
6
  require('./invite.js')
7
7
  require('./request.js')
8
+ require('./view.js')
9
+ require('./accessControl.js')
8
10
 
9
11
  module.exports = definition
package/invite.js CHANGED
@@ -221,6 +221,14 @@ for(const contactType of config.contactTypes) {
221
221
  access: (params, { client, context, visibilityTest }) =>
222
222
  visibilityTest || access.clientCanInvite(client, params),
223
223
  async execute(params, { client, service }, emit) {
224
+ const { roles } = params
225
+ const myRoles = await access.getClientObjectRoles(client, { objectType, object }, true)
226
+ if(!myRoles.includes('administrator')) {
227
+ for(const requestedRole of roles) {
228
+ if(!myRoles.includes(requestedRole)) throw 'notAuthorized'
229
+ }
230
+ }
231
+
224
232
  const [ fromType, from ] = client.user ? ['user_User', client.user] : ['session_Session', client.session]
225
233
  const { [contactTypeName]: contact } = params
226
234
  const { objectType, object } = params
package/model.js CHANGED
@@ -39,7 +39,7 @@ const PublicAccess = definition.model({
39
39
  to: 'object',
40
40
  readAccess: (params, { client, context, visibilityTest }) =>
41
41
  visibilityTest || access.clientHasAnyAccess(client, params),
42
- writeAccess: (params, { client, context, visibilityTest }) =>
42
+ writeAccess: async (params, { client, context, visibilityTest }) =>
43
43
  visibilityTest || access.clientHasAdminAccess(client, params)
44
44
  },
45
45
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/access-control-service",
3
- "version": "0.2.39",
3
+ "version": "0.2.42",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "url": "https://www.viamage.com/"
22
22
  },
23
23
  "dependencies": {
24
- "@live-change/framework": "0.6.5"
24
+ "@live-change/framework": "0.6.9"
25
25
  },
26
- "gitHead": "09bd3c0c5e1991360c8f13c30b29ccca8f3158ea"
26
+ "gitHead": "ad7e746f87b5c7be7d040885ca228aab2ec2f23e"
27
27
  }
package/request.js CHANGED
@@ -43,6 +43,12 @@ definition.action({
43
43
  access: (params, { client, context, visibilityTest }) =>
44
44
  visibilityTest || access.clientCanInvite(client, params),
45
45
  async execute({ objectType, object, sessionOrUserType, sessionOrUser, roles }, { client, service }, emit) {
46
+ const myRoles = await access.getClientObjectRoles(client, { objectType, object }, true)
47
+ if(!myRoles.includes('administrator')) {
48
+ for(const requestedRole of roles) {
49
+ if(!myRoles.includes(requestedRole)) throw 'notAuthorized'
50
+ }
51
+ }
46
52
  const request = App.encodeIdentifier([ sessionOrUserType, sessionOrUser, objectType, object ])
47
53
  const requestData = await AccessRequest.get(request)
48
54
  if(!requestData) throw 'not_found'
package/view.js ADDED
@@ -0,0 +1,72 @@
1
+ const definition = require("./definition.js")
2
+ const App = require("@live-change/framework")
3
+ const app = App.app()
4
+
5
+ const access = require('./access.js')(definition)
6
+
7
+ definition.view({
8
+ name: "myAccessTo",
9
+ properties: {
10
+ objectType: {
11
+ type: String
12
+ },
13
+ object: {
14
+ type: String
15
+ },
16
+ objects: {
17
+ type: Array,
18
+ of: {
19
+ type: Object,
20
+ properties: {
21
+ objectType: {
22
+ type: String
23
+ },
24
+ object: {
25
+ type: String
26
+ },
27
+ }
28
+ }
29
+ }
30
+ },
31
+ returns: {
32
+ type: Array,
33
+ of: {
34
+ type: String
35
+ }
36
+ },
37
+ async daoPath({ objectType, object, objects }, { client, service }, method) {
38
+ const allObjects = ((objectType && object) ? [{ objectType, object }] : []).concat(objects || [])
39
+ if(allObjects.length == 0) throw 'empty_objects_list'
40
+ return access.accessPath(client, allObjects)
41
+ }
42
+ })
43
+
44
+ definition.view({
45
+ name: "myAccessesTo",
46
+ properties: {
47
+ objects: {
48
+ type: Array,
49
+ of: {
50
+ type: Object,
51
+ properties: {
52
+ objectType: {
53
+ type: String
54
+ },
55
+ object: {
56
+ type: String
57
+ }
58
+ }
59
+ }
60
+ }
61
+ },
62
+ returns: {
63
+ type: Array,
64
+ of: {
65
+ type: String
66
+ }
67
+ },
68
+ async daoPath({ objects }, { client, service }, method) {
69
+ if(objects.length == 0) throw 'empty_objects_list'
70
+ return access.accessesPath(client, objects)
71
+ }
72
+ })