@xen-orchestra/rest-api 0.29.0 → 0.30.0
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/README.md +108 -1
- package/dist/abstract-classes/base-controller.mjs +18 -3
- package/dist/abstract-classes/listener.mjs +116 -12
- package/dist/acl-privileges/acl-privilege.controller.mjs +172 -0
- package/dist/acl-roles/acl-role.controller.mjs +384 -0
- package/dist/alarms/alarm.controller.mjs +22 -9
- package/dist/alarms/alarm.service.mjs +8 -0
- package/dist/backup-archives/backup-archive.controller.mjs +30 -21
- package/dist/backup-archives/backup-archive.service.mjs +21 -0
- package/dist/backup-jobs/backup-job.controller.mjs +59 -15
- package/dist/backup-jobs/backup-job.service.mjs +7 -0
- package/dist/backup-logs/backup-log.controller.mjs +25 -11
- package/dist/backup-logs/backup-log.service.mjs +19 -0
- package/dist/backup-repositories/backup-repositories.controller.mjs +21 -3
- package/dist/events/event.class.mjs +24 -9
- package/dist/events/event.controller.mjs +3 -0
- package/dist/events/event.service.mjs +2 -1
- package/dist/groups/group.controller.mjs +90 -6
- package/dist/hosts/host.controller.mjs +78 -7
- package/dist/ioc/ioc.mjs +13 -4
- package/dist/messages/message.controller.mjs +29 -8
- package/dist/middlewares/acl.middleware.mjs +202 -0
- package/dist/middlewares/authentication.middleware.mjs +15 -6
- package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
- package/dist/networks/network.controller.mjs +60 -9
- package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
- package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
- package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
- package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
- package/dist/open-api/routes/routes.js +676 -132
- package/dist/pbds/pbd.controller.mjs +17 -3
- package/dist/pcis/pci.controller.mjs +16 -3
- package/dist/pgpus/pgpu.controller.mjs +16 -3
- package/dist/pifs/pif.controller.mjs +44 -8
- package/dist/pools/pool.controller.mjs +154 -9
- package/dist/proxies/proxy.controller.mjs +22 -4
- package/dist/restore-logs/restore-log.controller.mjs +36 -19
- package/dist/schedules/schedule.controller.mjs +33 -3
- package/dist/servers/server.controller.mjs +65 -5
- package/dist/sms/sm.controller.mjs +14 -2
- package/dist/srs/sr.controller.mjs +62 -10
- package/dist/tasks/task.controller.mjs +71 -11
- package/dist/users/user.controller.mjs +115 -16
- package/dist/vbds/vbd.controller.mjs +65 -31
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +36 -6
- package/dist/vdis/vdi.controller.mjs +69 -8
- package/dist/vifs/vif.controller.mjs +43 -7
- package/dist/vm-controller/vm-controller.controller.mjs +62 -9
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +70 -8
- package/dist/vm-templates/vm-template.controller.mjs +71 -8
- package/dist/vms/vm.controller.mjs +164 -12
- package/open-api/spec/swagger.json +10907 -3265
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -60,7 +60,114 @@ class Foo extends Controller {
|
|
|
60
60
|
|
|
61
61
|
### Examples
|
|
62
62
|
|
|
63
|
-
In order not to pollute important decorators, all example structures should be in a separate file. `src/open-api/examples/<resource>.example.mts`
|
|
63
|
+
In order not to pollute important decorators, all example structures should be in a separate file. `src/open-api/oa-examples/<resource>.oa-example.mts`
|
|
64
|
+
|
|
65
|
+
### ACLs
|
|
66
|
+
|
|
67
|
+
To define an ACL for an endpoint, simply add the `acl` middleware and pass the required ACL(s).
|
|
68
|
+
|
|
69
|
+
If an endpoint does not have a middleware ACL, it will be accessible **ONLY** to administrators.
|
|
70
|
+
|
|
71
|
+
It is sometimes necessary to check ACLs based on the body of the request sent by the user (for example, for a PATCH endpoint). For this, you can use `actions` (which allows you to pass multiple actions) and `actionsFromBody` (a function exported from `acl.middleware.mts`).
|
|
72
|
+
|
|
73
|
+
`actionsFromBody(['update:name_label', 'update:name_description'])` checks if `name_label` is present in the request body, and then applies the ACL check. The same applies to `name_description`.
|
|
74
|
+
|
|
75
|
+
`actionIfNotSelfUser('read')` returns the given action only if the current user is **not** the target user. If the current user is the target (self), no action is returned and the ACL check is skipped entirely.
|
|
76
|
+
|
|
77
|
+
#### Guidelines
|
|
78
|
+
|
|
79
|
+
- **JSDoc Documentation**: Always document the required privileges in the JSDoc annotation so users know which permissions are needed. Use the format: `Required privilege: - ...`
|
|
80
|
+
- **Error Handling**: If you define an ACL for an endpoint, you **must** add a `@Response(403)` decorator.
|
|
81
|
+
- **Non XAPI objects**: When dealing with non XAPI XO Record, you must define the `getObject` function.
|
|
82
|
+
|
|
83
|
+
##### Example: ACL on an existing resource
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
/**
|
|
87
|
+
* Start a VM
|
|
88
|
+
*
|
|
89
|
+
* Required privilege:
|
|
90
|
+
* - resource: vm, action: start
|
|
91
|
+
*/
|
|
92
|
+
@Post('{id}/actions/start')
|
|
93
|
+
@Middlewares(acl({resource: 'vm', action: 'start', objectId: 'params.id'}))
|
|
94
|
+
@Response(403)
|
|
95
|
+
getVm(@Path() id: string) {
|
|
96
|
+
const action = async () => {
|
|
97
|
+
const vm = await this.getObject(id)
|
|
98
|
+
// ...
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
##### Example: Resource creation
|
|
104
|
+
|
|
105
|
+
When creating a resource (which doesn't exist yet), pass the object being created as the target:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
/**
|
|
109
|
+
* Create a new VDI
|
|
110
|
+
*
|
|
111
|
+
* Required privilege:
|
|
112
|
+
* - resource: vdi, action: create
|
|
113
|
+
*/
|
|
114
|
+
@Post('/')
|
|
115
|
+
@Middlewares(acl({resource: 'vdi', action: 'create', object: ({req}) => {
|
|
116
|
+
const {srId,...rest} = req.body
|
|
117
|
+
return {$SR: srId, ...rest}
|
|
118
|
+
}}))
|
|
119
|
+
@Response(403)
|
|
120
|
+
createVdi(@Body() body: VdiConfig) {
|
|
121
|
+
const {srId, ...rest}
|
|
122
|
+
const bodyParam = {$SR: srId, ...rest}
|
|
123
|
+
await VDI_create(bodyParam)
|
|
124
|
+
// ...
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
##### Example: Resource update
|
|
129
|
+
|
|
130
|
+
When creating a resource (which doesn't exist yet), pass the object being created as the target:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
/**
|
|
134
|
+
* Update a VM
|
|
135
|
+
*
|
|
136
|
+
* Required privileges:
|
|
137
|
+
* - resource: vm, action: update (grants all fields)
|
|
138
|
+
* - resource: vm, action: update:name_label (if name_label is passed)
|
|
139
|
+
* - resource: vm, action: update:name_description (if name_description is passed)
|
|
140
|
+
*/
|
|
141
|
+
@Patch('{id}')
|
|
142
|
+
@Middlewares(acl({resource: 'vm', actions: actionsFromBody(['update:name_label', 'update:name_description']), objectId: 'params.id'}))
|
|
143
|
+
@Response(403)
|
|
144
|
+
createVdi(@Path() id: string, @Body() body: patchBody) {
|
|
145
|
+
updateVm(id, body)
|
|
146
|
+
// ...
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
##### Example: Self-bypass ACL
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
/**
|
|
154
|
+
* Get a user
|
|
155
|
+
*
|
|
156
|
+
* Required privilege:
|
|
157
|
+
* - resource: user, action: read (if not self)
|
|
158
|
+
*/
|
|
159
|
+
@Get('{id}')
|
|
160
|
+
@Middlewares(acl({
|
|
161
|
+
resource: 'user',
|
|
162
|
+
actions: actionsIfNotSelfUser(['read']),
|
|
163
|
+
objectId: 'params.id',
|
|
164
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
165
|
+
}))
|
|
166
|
+
@Response(403)
|
|
167
|
+
getUser(@Path() id: string) { ... }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If you need to use a privilege that doesn't exist yet (e.g., `resource: 'vm', action: 'foo'`), you must register it in ACL Definition: here `@xen-orchestra/acl/src/actions/vm.mts`, add: `foo: true`.
|
|
64
171
|
|
|
65
172
|
## Contributions
|
|
66
173
|
|
|
@@ -2,6 +2,7 @@ import { Controller } from 'tsoa';
|
|
|
2
2
|
import { createGzip } from 'node:zlib';
|
|
3
3
|
import { pipeline } from 'node:stream/promises';
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
|
+
import { hasPrivilegeOn, } from '@xen-orchestra/acl';
|
|
5
6
|
import { BASE_URL } from '../index.mjs';
|
|
6
7
|
import { makeMarkdownTable } from '../helpers/markdown.helper.mjs';
|
|
7
8
|
import { makeNdJsonStream } from '../helpers/stream.helper.mjs';
|
|
@@ -17,9 +18,23 @@ export class BaseController extends Controller {
|
|
|
17
18
|
this.type = type;
|
|
18
19
|
this.restApi = restApi;
|
|
19
20
|
}
|
|
20
|
-
sendObjects(objects, req,
|
|
21
|
-
const mapper = makeObjectMapper(req, path);
|
|
22
|
-
const mappedObjects =
|
|
21
|
+
async sendObjects(objects, req, opts) {
|
|
22
|
+
const mapper = makeObjectMapper(req, opts?.path);
|
|
23
|
+
const mappedObjects = [];
|
|
24
|
+
const user = this.restApi.getCurrentUser();
|
|
25
|
+
const userPrivileges = (opts?.privilege !== undefined ? await this.restApi.xoApp.getAclV2UserPrivileges(user.id) : []);
|
|
26
|
+
let limit = opts?.limit ?? Infinity;
|
|
27
|
+
for (const object of objects) {
|
|
28
|
+
if (limit === 0) {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
if (opts?.privilege !== undefined &&
|
|
32
|
+
!hasPrivilegeOn({ user, userPrivileges, objects: object, ...opts.privilege })) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
mappedObjects.push(mapper(object));
|
|
36
|
+
limit--;
|
|
37
|
+
}
|
|
23
38
|
if (req.query.ndjson === 'true' && req.query.markdown === 'true') {
|
|
24
39
|
throw invalidParameters('Cannot use both ndjson and markdown output formats simultaneously');
|
|
25
40
|
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
import { createLogger } from '@xen-orchestra/log';
|
|
2
|
+
import { hasPrivilegeOn } from '@xen-orchestra/acl';
|
|
3
|
+
import { iocContainer } from '../ioc/ioc.mjs';
|
|
4
|
+
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
5
|
+
import { XAPI_TYPE_BY_ACL_RESOURCE } from '../middlewares/acl.middleware.mjs';
|
|
6
|
+
const log = createLogger('xo:rest-api:listener');
|
|
1
7
|
export class Listener {
|
|
2
8
|
#subscribers = new Map();
|
|
3
9
|
#eventEmitter;
|
|
4
10
|
#eventCallbacks = new Map();
|
|
5
11
|
#watchedEvent;
|
|
6
|
-
|
|
12
|
+
#type;
|
|
13
|
+
constructor(eventEmitter, watchedEvent, type) {
|
|
7
14
|
this.#eventEmitter = eventEmitter;
|
|
8
15
|
this.#watchedEvent = watchedEvent;
|
|
16
|
+
// cast needed because Type !== Type | undefined (even if Type extends undefined...)
|
|
17
|
+
this.#type = type;
|
|
9
18
|
}
|
|
10
19
|
get subscribers() {
|
|
11
20
|
return this.#subscribers;
|
|
@@ -13,6 +22,9 @@ export class Listener {
|
|
|
13
22
|
get eventEmitter() {
|
|
14
23
|
return this.#eventEmitter;
|
|
15
24
|
}
|
|
25
|
+
get type() {
|
|
26
|
+
return this.#type;
|
|
27
|
+
}
|
|
16
28
|
addSubscriber(subscriber, fields = '*') {
|
|
17
29
|
const unregisterOnClear = subscriber.onClear(() => this.removeSubscriber(subscriber.id));
|
|
18
30
|
this.#subscribers.set(subscriber.id, { fields, subscriber, unregisterOnClear });
|
|
@@ -45,20 +57,112 @@ export class Listener {
|
|
|
45
57
|
if (this.#eventCallbacks.has(event)) {
|
|
46
58
|
return;
|
|
47
59
|
}
|
|
48
|
-
const broadcastAllSubscriber = (...args) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
const broadcastAllSubscriber = async (...args) => {
|
|
61
|
+
try {
|
|
62
|
+
await Promise.all([...this.#subscribers.values()].map(async (conf) => {
|
|
63
|
+
if (!conf.subscriber.isAlive) {
|
|
64
|
+
this.removeSubscriber(conf.subscriber.id);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let data;
|
|
68
|
+
try {
|
|
69
|
+
data = await this.handleData({ ...conf, event }, ...args);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
log.error(`cannot handle data for ${this.type} listener on subscriber: ${conf.subscriber.id} (user: ${conf.subscriber.userId}). Removing it from the subscriber list.`, { error });
|
|
73
|
+
this.removeSubscriber(conf.subscriber.id);
|
|
74
|
+
conf.subscriber.clear();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (data === undefined) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const { event: overridenEvent, ...dataToBroadcast } = data;
|
|
81
|
+
conf.subscriber.broadcast(overridenEvent ?? event, dataToBroadcast);
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
log.warn('unexpected error broadcasting to subscribers', { error });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
this.#eventCallbacks.set(event, broadcastAllSubscriber);
|
|
89
|
+
this.#eventEmitter.on(event, broadcastAllSubscriber);
|
|
90
|
+
}
|
|
91
|
+
async getAclEvent({ event, object, previousObject, userId, }) {
|
|
92
|
+
if (this.type === undefined || (object === undefined && previousObject === undefined)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const restApi = iocContainer.get(RestApi);
|
|
96
|
+
const user = await restApi.xoApp.getUser(userId);
|
|
97
|
+
if (user.permission === 'admin') {
|
|
98
|
+
return event;
|
|
99
|
+
}
|
|
100
|
+
const userPrivileges = (await restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
101
|
+
let resource;
|
|
102
|
+
// alarm and task are not real `XAPI` type
|
|
103
|
+
if (this.type === 'alarm' || this.type === 'task') {
|
|
104
|
+
resource = this.type;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const resourceXapiType = Object.entries(XAPI_TYPE_BY_ACL_RESOURCE).find(([, xapiType]) => xapiType === this.type);
|
|
108
|
+
if (resourceXapiType === undefined) {
|
|
109
|
+
throw new Error(`No resource found for ${this.type} listener type`);
|
|
110
|
+
}
|
|
111
|
+
// cast is necessary because `Object.entries` loses inference on the key (it transforms it into a simple string).
|
|
112
|
+
;
|
|
113
|
+
[resource] = resourceXapiType;
|
|
114
|
+
}
|
|
115
|
+
switch (event) {
|
|
116
|
+
case 'add':
|
|
117
|
+
if (object === undefined) {
|
|
52
118
|
return;
|
|
53
119
|
}
|
|
54
|
-
|
|
55
|
-
if (data === undefined) {
|
|
120
|
+
if (!hasPrivilegeOn({ user, userPrivileges, action: 'read', objects: object, resource })) {
|
|
56
121
|
return;
|
|
57
122
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
123
|
+
return 'add';
|
|
124
|
+
case 'update': {
|
|
125
|
+
const canSeeObject = object !== undefined &&
|
|
126
|
+
hasPrivilegeOn({
|
|
127
|
+
user,
|
|
128
|
+
userPrivileges,
|
|
129
|
+
action: 'read',
|
|
130
|
+
objects: object,
|
|
131
|
+
resource,
|
|
132
|
+
});
|
|
133
|
+
const canSeePreviousObject = previousObject !== undefined &&
|
|
134
|
+
hasPrivilegeOn({
|
|
135
|
+
user,
|
|
136
|
+
userPrivileges,
|
|
137
|
+
action: 'read',
|
|
138
|
+
objects: previousObject,
|
|
139
|
+
resource,
|
|
140
|
+
});
|
|
141
|
+
if (canSeeObject && canSeePreviousObject) {
|
|
142
|
+
return 'update';
|
|
143
|
+
}
|
|
144
|
+
if (canSeeObject) {
|
|
145
|
+
return 'add';
|
|
146
|
+
}
|
|
147
|
+
if (canSeePreviousObject) {
|
|
148
|
+
return 'remove';
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
case 'remove':
|
|
153
|
+
if (!hasPrivilegeOn({
|
|
154
|
+
user,
|
|
155
|
+
userPrivileges,
|
|
156
|
+
action: 'read',
|
|
157
|
+
objects: object ?? previousObject,
|
|
158
|
+
resource,
|
|
159
|
+
})) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
return 'remove';
|
|
163
|
+
default:
|
|
164
|
+
// Not supposed to be here
|
|
165
|
+
throw new Error(`${event} event unhandled on ${this.type} listener`);
|
|
166
|
+
}
|
|
63
167
|
}
|
|
64
168
|
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Body, Delete, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
|
|
11
|
+
import { provide } from 'inversify-binding-decorators';
|
|
12
|
+
import { json } from 'express';
|
|
13
|
+
import { acl, actionsFromBody } from '../middlewares/acl.middleware.mjs';
|
|
14
|
+
import { aclPrivilege, aclPrivilegeIds, partialAclPrivileges, } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
|
|
15
|
+
import { badRequestResp, createdResp, forbiddenOperationResp, invalidParameters, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
16
|
+
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
17
|
+
import { entityId } from '../open-api/oa-examples/common.oa-example.mjs';
|
|
18
|
+
import { inject } from 'inversify';
|
|
19
|
+
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
20
|
+
let AclPrivilegeController = class AclPrivilegeController extends XoController {
|
|
21
|
+
constructor(restApi) {
|
|
22
|
+
super('acl-privilege', restApi);
|
|
23
|
+
}
|
|
24
|
+
getAllCollectionObjects() {
|
|
25
|
+
return this.restApi.xoApp.getAclV2Privileges();
|
|
26
|
+
}
|
|
27
|
+
getCollectionObject(id) {
|
|
28
|
+
return this.restApi.xoApp.getAclV2Privilege(id);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns all ACL privileges that match the following privilege:
|
|
32
|
+
* - resource: acl-privilege, action: read
|
|
33
|
+
*
|
|
34
|
+
* @example fields "id,action,resource"
|
|
35
|
+
* @example filter "action:create"
|
|
36
|
+
* @example limit 42
|
|
37
|
+
*/
|
|
38
|
+
async getAclV2Privileges(req, fields, ndjson, filter, limit) {
|
|
39
|
+
return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
|
|
40
|
+
limit,
|
|
41
|
+
privilege: { action: 'read', resource: 'acl-privilege' },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Required privilege:
|
|
46
|
+
* - resource: acl-privilege, action: create
|
|
47
|
+
*
|
|
48
|
+
* @example privilege {
|
|
49
|
+
* "action": "read",
|
|
50
|
+
* "resource": "alarm",
|
|
51
|
+
* "roleId": "784bd959-08de-4b26-b575-92ded5aef872",
|
|
52
|
+
* "effect": "allow",
|
|
53
|
+
* "selector": "id:784bd959-08de-4b26-b575-92ded5aef872"
|
|
54
|
+
* }
|
|
55
|
+
*/
|
|
56
|
+
async createAclV2Privilege(privilege) {
|
|
57
|
+
const newPrivilege = await this.restApi.xoApp.createAclV2Privilege(privilege);
|
|
58
|
+
return { id: newPrivilege.id };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Required privilege:
|
|
62
|
+
* - resource: acl-privilege, action: read
|
|
63
|
+
*
|
|
64
|
+
* @example id "c5d89d1a-df1e-4b72-98a0-c40adfdf49c1"
|
|
65
|
+
*/
|
|
66
|
+
getAclV2Privilege(id) {
|
|
67
|
+
return this.getObject(id);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Required privilege:
|
|
71
|
+
* - resource: acl-privilege, action: delete
|
|
72
|
+
*
|
|
73
|
+
* @example id "784bd959-08de-4b26-b575-92ded5aef872"
|
|
74
|
+
*/
|
|
75
|
+
async deleteAclV2Privilege(id) {
|
|
76
|
+
await this.restApi.xoApp.deleteAclV2Privilege(id);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Required privileges:
|
|
80
|
+
* - resource: acl-privilege, action: update (grants all fields)
|
|
81
|
+
* - resource: acl-privilege, action: update:action (if action is passed)
|
|
82
|
+
* - resource: acl-privilege, action: update:resource (if resource is passed)
|
|
83
|
+
* - resource: acl-privilege, action: update:effect (if effect is passed)
|
|
84
|
+
* - resource: acl-privilege, action: update:selector (if selector is passed)
|
|
85
|
+
*
|
|
86
|
+
* @example id "784bd959-08de-4b26-b575-92ded5aef872"
|
|
87
|
+
* @example privilege {
|
|
88
|
+
* "action": "read",
|
|
89
|
+
* "resource": "alarm",
|
|
90
|
+
* "effect": "allow",
|
|
91
|
+
* "selector": "id:784bd959-08de-4b26-b575-92ded5aef872"
|
|
92
|
+
* }
|
|
93
|
+
*/
|
|
94
|
+
async updateAclV2Privilege(id, privilege) {
|
|
95
|
+
await this.restApi.xoApp.updateAclV2Privilege(id, privilege);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
__decorate([
|
|
99
|
+
Example(aclPrivilegeIds),
|
|
100
|
+
Example(partialAclPrivileges),
|
|
101
|
+
Get(''),
|
|
102
|
+
Security('*', ['acl']),
|
|
103
|
+
__param(0, Request()),
|
|
104
|
+
__param(1, Query()),
|
|
105
|
+
__param(2, Query()),
|
|
106
|
+
__param(3, Query()),
|
|
107
|
+
__param(4, Query())
|
|
108
|
+
], AclPrivilegeController.prototype, "getAclV2Privileges", null);
|
|
109
|
+
__decorate([
|
|
110
|
+
Example(entityId),
|
|
111
|
+
Post(''),
|
|
112
|
+
Middlewares([json(), acl({ resource: 'acl-privilege', action: 'create', object: ({ req }) => req.body })]),
|
|
113
|
+
SuccessResponse(createdResp.status, createdResp.description),
|
|
114
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
115
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
116
|
+
Response(invalidParameters.status, invalidParameters.description),
|
|
117
|
+
__param(0, Body())
|
|
118
|
+
], AclPrivilegeController.prototype, "createAclV2Privilege", null);
|
|
119
|
+
__decorate([
|
|
120
|
+
Example(aclPrivilege),
|
|
121
|
+
Get('{id}'),
|
|
122
|
+
Middlewares(acl({
|
|
123
|
+
resource: 'acl-privilege',
|
|
124
|
+
action: 'read',
|
|
125
|
+
objectId: 'params.id',
|
|
126
|
+
getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
|
|
127
|
+
})),
|
|
128
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
129
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
130
|
+
__param(0, Path())
|
|
131
|
+
], AclPrivilegeController.prototype, "getAclV2Privilege", null);
|
|
132
|
+
__decorate([
|
|
133
|
+
Delete('{id}'),
|
|
134
|
+
Middlewares(acl({
|
|
135
|
+
resource: 'acl-privilege',
|
|
136
|
+
action: 'delete',
|
|
137
|
+
objectId: 'params.id',
|
|
138
|
+
getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
|
|
139
|
+
})),
|
|
140
|
+
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
141
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
142
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
143
|
+
__param(0, Path())
|
|
144
|
+
], AclPrivilegeController.prototype, "deleteAclV2Privilege", null);
|
|
145
|
+
__decorate([
|
|
146
|
+
Patch('{id}'),
|
|
147
|
+
Middlewares([
|
|
148
|
+
json(),
|
|
149
|
+
acl({
|
|
150
|
+
resource: 'acl-privilege',
|
|
151
|
+
actions: actionsFromBody(['update:action', 'update:resource', 'update:effect', 'update:selector']),
|
|
152
|
+
objectId: 'params.id',
|
|
153
|
+
getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
|
|
154
|
+
}),
|
|
155
|
+
]),
|
|
156
|
+
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
157
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
158
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
159
|
+
Response(invalidParameters.status, invalidParameters.description),
|
|
160
|
+
__param(0, Path()),
|
|
161
|
+
__param(1, Body())
|
|
162
|
+
], AclPrivilegeController.prototype, "updateAclV2Privilege", null);
|
|
163
|
+
AclPrivilegeController = __decorate([
|
|
164
|
+
Route('acl-privileges'),
|
|
165
|
+
Security('*'),
|
|
166
|
+
Response(badRequestResp.status, badRequestResp.description),
|
|
167
|
+
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
168
|
+
Tags('acls'),
|
|
169
|
+
provide(AclPrivilegeController),
|
|
170
|
+
__param(0, inject(RestApi))
|
|
171
|
+
], AclPrivilegeController);
|
|
172
|
+
export { AclPrivilegeController };
|