@xen-orchestra/rest-api 0.28.2 → 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 +28 -3
- package/dist/abstract-classes/listener.mjs +124 -15
- 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 +25 -11
- package/dist/alarms/alarm.service.mjs +8 -0
- package/dist/backup-archives/backup-archive.controller.mjs +33 -23
- package/dist/backup-archives/backup-archive.service.mjs +21 -0
- package/dist/backup-jobs/backup-job.controller.mjs +74 -25
- package/dist/backup-jobs/backup-job.service.mjs +7 -0
- package/dist/backup-logs/backup-log.controller.mjs +28 -13
- package/dist/backup-logs/backup-log.service.mjs +19 -0
- package/dist/backup-repositories/backup-repositories.controller.mjs +24 -5
- package/dist/events/event.class.mjs +36 -18
- package/dist/events/event.controller.mjs +3 -0
- package/dist/events/event.service.mjs +4 -4
- package/dist/groups/group.controller.mjs +99 -12
- package/dist/helpers/markdown.helper.mjs +20 -0
- package/dist/helpers/object-wrapper.helper.mjs +3 -3
- package/dist/hosts/host.controller.mjs +90 -15
- package/dist/ioc/ioc.mjs +13 -4
- package/dist/messages/message.controller.mjs +32 -10
- 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 +72 -17
- 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 +856 -172
- package/dist/pbds/pbd.controller.mjs +20 -5
- package/dist/pcis/pci.controller.mjs +19 -5
- package/dist/pgpus/pgpu.controller.mjs +19 -5
- package/dist/pifs/pif.controller.mjs +56 -16
- package/dist/pools/pool.controller.mjs +166 -17
- package/dist/proxies/proxy.controller.mjs +25 -6
- package/dist/restore-logs/restore-log.controller.mjs +42 -23
- package/dist/schedules/schedule.controller.mjs +36 -5
- package/dist/servers/server.controller.mjs +71 -9
- package/dist/sms/sm.controller.mjs +17 -4
- package/dist/srs/sr.controller.mjs +74 -18
- package/dist/tasks/task.controller.mjs +74 -13
- package/dist/users/user.controller.mjs +124 -22
- package/dist/vbds/vbd.controller.mjs +76 -38
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +48 -14
- package/dist/vdis/vdi.controller.mjs +81 -16
- package/dist/vifs/vif.controller.mjs +118 -16
- package/dist/vm-controller/vm-controller.controller.mjs +77 -19
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +85 -18
- package/dist/vm-templates/vm-template.controller.mjs +86 -18
- package/dist/vms/vm.controller.mjs +182 -24
- package/open-api/spec/swagger.json +12112 -3537
- package/package.json +12 -11
|
@@ -8,8 +8,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
10
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
11
|
-
import { Get, Path, Query, Request, Route, Security, Tags, Response, Example, Delete, Post, SuccessResponse, } from 'tsoa';
|
|
12
|
-
import {
|
|
11
|
+
import { Get, Path, Query, Request, Route, Security, Tags, Response, Example, Delete, Post, SuccessResponse, Middlewares, } from 'tsoa';
|
|
12
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
13
|
+
import { asynchronousActionResp, badRequestResp, forbiddenOperationResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
13
14
|
import { inject } from 'inversify';
|
|
14
15
|
import { provide } from 'inversify-binding-decorators';
|
|
15
16
|
import { partialTasks, task, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
@@ -19,6 +20,7 @@ import { Transform } from 'node:stream';
|
|
|
19
20
|
import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs';
|
|
20
21
|
import { safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
21
22
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
23
|
+
import { hasPrivilegeOn } from '@xen-orchestra/acl';
|
|
22
24
|
let TaskController = class TaskController extends XoController {
|
|
23
25
|
constructor(restApi) {
|
|
24
26
|
super('task', restApi);
|
|
@@ -34,6 +36,8 @@ let TaskController = class TaskController extends XoController {
|
|
|
34
36
|
return this.restApi.tasks.get(id);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
39
|
+
* Returns all tasks that match the following privilege:
|
|
40
|
+
* - resource: task, action: read
|
|
37
41
|
*
|
|
38
42
|
* If watch is true, ndjson must also be true
|
|
39
43
|
*
|
|
@@ -41,7 +45,7 @@ let TaskController = class TaskController extends XoController {
|
|
|
41
45
|
* @example filter "status:failure"
|
|
42
46
|
* @example limit 42
|
|
43
47
|
*/
|
|
44
|
-
async getTasks(req, fields, ndjson, watch, filter, limit) {
|
|
48
|
+
async getTasks(req, fields, ndjson, markdown, watch, filter, limit) {
|
|
45
49
|
if (watch) {
|
|
46
50
|
if (!ndjson) {
|
|
47
51
|
throw new ApiError('watch=true requires ndjson=true', 400);
|
|
@@ -63,21 +67,36 @@ let TaskController = class TaskController extends XoController {
|
|
|
63
67
|
process.on('SIGTERM', () => {
|
|
64
68
|
req.destroy();
|
|
65
69
|
});
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const userId = this.restApi.getCurrentUser().id;
|
|
71
|
+
const update = async (task) => {
|
|
72
|
+
const user = await this.restApi.xoApp.getUser(userId);
|
|
73
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
74
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
75
|
+
(userFilter === undefined || userFilter(task))) {
|
|
68
76
|
stream.write(['update', task]);
|
|
69
77
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
};
|
|
79
|
+
const remove = async (task) => {
|
|
80
|
+
const user = await this.restApi.xoApp.getUser(userId);
|
|
81
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
82
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
83
|
+
(userFilter === undefined || userFilter(task))) {
|
|
84
|
+
stream.write(['remove', { id: task.id }]);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
74
87
|
this.restApi.tasks.on('update', update).on('remove', remove);
|
|
75
88
|
return stream;
|
|
76
89
|
}
|
|
77
|
-
const tasks = Object.values(await this.getObjects({ filter
|
|
78
|
-
return this.sendObjects(tasks, req
|
|
90
|
+
const tasks = Object.values(await this.getObjects({ filter }));
|
|
91
|
+
return this.sendObjects(tasks, req, {
|
|
92
|
+
limit,
|
|
93
|
+
privilege: { action: 'read', resource: 'task' },
|
|
94
|
+
});
|
|
79
95
|
}
|
|
80
96
|
/**
|
|
97
|
+
* Required privilege:
|
|
98
|
+
* - resource: task, action: read
|
|
99
|
+
*
|
|
81
100
|
* @example id "0mdd1basu"
|
|
82
101
|
*/
|
|
83
102
|
async getTask(req, id, wait) {
|
|
@@ -95,10 +114,25 @@ let TaskController = class TaskController extends XoController {
|
|
|
95
114
|
}
|
|
96
115
|
return this.getObject(taskId);
|
|
97
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Deletes all tasks the current user has the following privilege on:
|
|
119
|
+
* - resource: task, action: delete
|
|
120
|
+
*/
|
|
98
121
|
async deleteTasks() {
|
|
99
|
-
|
|
122
|
+
const user = this.restApi.getCurrentUser();
|
|
123
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
124
|
+
const deletePromises = [];
|
|
125
|
+
for await (const task of this.restApi.tasks.list()) {
|
|
126
|
+
if (hasPrivilegeOn({ user, userPrivileges, resource: 'task', action: 'delete', objects: task })) {
|
|
127
|
+
deletePromises.push(this.restApi.tasks.deleteLog(task.id));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(deletePromises);
|
|
100
131
|
}
|
|
101
132
|
/**
|
|
133
|
+
* Required privilege:
|
|
134
|
+
* - resource: task, action: delete
|
|
135
|
+
*
|
|
102
136
|
* @example id "0mdd1basu"
|
|
103
137
|
*/
|
|
104
138
|
async deleteTask(id) {
|
|
@@ -106,6 +140,9 @@ let TaskController = class TaskController extends XoController {
|
|
|
106
140
|
await this.restApi.tasks.deleteLog(task.id);
|
|
107
141
|
}
|
|
108
142
|
/**
|
|
143
|
+
* Required privilege:
|
|
144
|
+
* - resource: task, action: abort
|
|
145
|
+
*
|
|
109
146
|
* @example id "0mdd1basu"
|
|
110
147
|
*/
|
|
111
148
|
async abortTask(id, sync) {
|
|
@@ -127,17 +164,26 @@ __decorate([
|
|
|
127
164
|
Example(taskIds),
|
|
128
165
|
Example(partialTasks),
|
|
129
166
|
Get(''),
|
|
167
|
+
Security('*', ['acl']),
|
|
130
168
|
Response(badRequestResp.status, badRequestResp.description),
|
|
131
169
|
__param(0, Request()),
|
|
132
170
|
__param(1, Query()),
|
|
133
171
|
__param(2, Query()),
|
|
134
172
|
__param(3, Query()),
|
|
135
173
|
__param(4, Query()),
|
|
136
|
-
__param(5, Query())
|
|
174
|
+
__param(5, Query()),
|
|
175
|
+
__param(6, Query())
|
|
137
176
|
], TaskController.prototype, "getTasks", null);
|
|
138
177
|
__decorate([
|
|
139
178
|
Example(task),
|
|
140
179
|
Get('{id}'),
|
|
180
|
+
Middlewares(acl({
|
|
181
|
+
resource: 'task',
|
|
182
|
+
action: 'read',
|
|
183
|
+
objectId: 'params.id',
|
|
184
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
185
|
+
})),
|
|
186
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
141
187
|
Response(notFoundResp.status, notFoundResp.description),
|
|
142
188
|
__param(0, Request()),
|
|
143
189
|
__param(1, Path()),
|
|
@@ -145,19 +191,34 @@ __decorate([
|
|
|
145
191
|
], TaskController.prototype, "getTask", null);
|
|
146
192
|
__decorate([
|
|
147
193
|
Delete(''),
|
|
194
|
+
Security('*', ['acl']),
|
|
148
195
|
SuccessResponse(noContentResp.status, noContentResp.description)
|
|
149
196
|
], TaskController.prototype, "deleteTasks", null);
|
|
150
197
|
__decorate([
|
|
151
198
|
Delete('{id}'),
|
|
199
|
+
Middlewares(acl({
|
|
200
|
+
resource: 'task',
|
|
201
|
+
action: 'delete',
|
|
202
|
+
objectId: 'params.id',
|
|
203
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
204
|
+
})),
|
|
152
205
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
206
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
153
207
|
Response(notFoundResp.status, notFoundResp.description),
|
|
154
208
|
__param(0, Path())
|
|
155
209
|
], TaskController.prototype, "deleteTask", null);
|
|
156
210
|
__decorate([
|
|
157
211
|
Example(taskLocation),
|
|
158
212
|
Post('{id}/actions/abort'),
|
|
213
|
+
Middlewares(acl({
|
|
214
|
+
resource: 'task',
|
|
215
|
+
action: 'abort',
|
|
216
|
+
objectId: 'params.id',
|
|
217
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
218
|
+
})),
|
|
159
219
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
160
220
|
Response(noContentResp.status, noContentResp.description),
|
|
221
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
161
222
|
Response(notFoundResp.status, notFoundResp.description),
|
|
162
223
|
__param(0, Path()),
|
|
163
224
|
__param(1, Query())
|
|
@@ -9,11 +9,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
import { Body, Delete, Deprecated, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
|
|
11
11
|
import { createLogger } from '@xen-orchestra/log';
|
|
12
|
+
import { forbiddenOperation } from 'xo-common/api-errors.js';
|
|
12
13
|
import { inject } from 'inversify';
|
|
13
14
|
import { json } from 'express';
|
|
14
15
|
import { provide } from 'inversify-binding-decorators';
|
|
16
|
+
import { acl, actionIfNotSelfUser, actionsFromBody } from '../middlewares/acl.middleware.mjs';
|
|
15
17
|
import { badRequestResp, createdResp, forbiddenOperationResp, internalServerErrorResp, invalidParameters, noContentResp, notFoundResp, resourceAlreadyExists, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
16
|
-
import { forbiddenOperation } from 'xo-common/api-errors.js';
|
|
17
18
|
import { partialUsers, user, authenticationTokens, userId, userIds, authenticationToken, } from '../open-api/oa-examples/user.oa-example.mjs';
|
|
18
19
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
19
20
|
import { limitAndFilterArray } from '../helpers/utils.helper.mjs';
|
|
@@ -22,6 +23,7 @@ import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
|
22
23
|
import { groupIds, partialGroups } from '../open-api/oa-examples/group.oa-example.mjs';
|
|
23
24
|
import { partialTasks, taskIds } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
24
25
|
import { redirectMeAlias } from './user.middleware.mjs';
|
|
26
|
+
import { aclPrivilegeIds, partialAclPrivileges } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
|
|
25
27
|
const log = createLogger('xo:rest-api:user-controller');
|
|
26
28
|
let UserController = class UserController extends XoController {
|
|
27
29
|
#userService;
|
|
@@ -37,21 +39,39 @@ let UserController = class UserController extends XoController {
|
|
|
37
39
|
return this.#userService.getUser(id);
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
42
|
+
* Returns all users that match the following privilege:
|
|
43
|
+
* - resource: user, action: read
|
|
44
|
+
*
|
|
40
45
|
* @example fields "permission,name,id"
|
|
41
46
|
* @example filter "permission:none"
|
|
42
47
|
* @example limit 42
|
|
43
48
|
*/
|
|
44
|
-
async getUsers(req, fields, ndjson, filter, limit) {
|
|
45
|
-
const users = Object.values(await this.getObjects({ filter
|
|
46
|
-
return this.sendObjects(users, req
|
|
49
|
+
async getUsers(req, fields, ndjson, markdown, filter, limit) {
|
|
50
|
+
const users = Object.values(await this.getObjects({ filter }));
|
|
51
|
+
return this.sendObjects(users, req, {
|
|
52
|
+
limit,
|
|
53
|
+
privilege: { action: 'read', resource: 'user' },
|
|
54
|
+
});
|
|
47
55
|
}
|
|
48
56
|
/**
|
|
57
|
+
* Required privilege:
|
|
58
|
+
* - resource: user, action: read (if not self)
|
|
59
|
+
*
|
|
49
60
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
50
61
|
*/
|
|
51
62
|
getUser(id) {
|
|
52
63
|
return this.getObject(id);
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
66
|
+
* You cannot change your own `permission` (even with the right privilege)
|
|
67
|
+
*
|
|
68
|
+
* Required privileges:
|
|
69
|
+
* - resource: user, action: update (grants all fields)
|
|
70
|
+
* - resource: user, action: update:name (if name is passed)
|
|
71
|
+
* - resource: user, action: update:password (if password is passed)
|
|
72
|
+
* - resource: user, action: update:permission (if permission is passed)
|
|
73
|
+
* - resource: user, action: update:preferences (if preferences is passed)
|
|
74
|
+
*
|
|
55
75
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
56
76
|
* @example body {
|
|
57
77
|
* "name": "updated user name",
|
|
@@ -62,14 +82,8 @@ let UserController = class UserController extends XoController {
|
|
|
62
82
|
*/
|
|
63
83
|
async updateUser(id, body) {
|
|
64
84
|
const currentUser = this.restApi.getCurrentUser();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (body.permission !== undefined && currentUser.id === id) {
|
|
68
|
-
throw forbiddenOperation('update user', 'cannot change own permission');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else if (body.name !== undefined || body.password !== undefined || body.permission !== undefined) {
|
|
72
|
-
throw forbiddenOperation('update user', 'cannot change these fields without admin rights');
|
|
85
|
+
if (body.permission !== undefined && currentUser.id === id) {
|
|
86
|
+
throw forbiddenOperation('update user', 'cannot change own permission');
|
|
73
87
|
}
|
|
74
88
|
const user = await this.getObject(id);
|
|
75
89
|
if (user.authProviders !== undefined &&
|
|
@@ -80,6 +94,9 @@ let UserController = class UserController extends XoController {
|
|
|
80
94
|
await this.restApi.xoApp.updateUser(user.id, body);
|
|
81
95
|
}
|
|
82
96
|
/**
|
|
97
|
+
* Required privilege:
|
|
98
|
+
* - resource: user, action: create
|
|
99
|
+
*
|
|
83
100
|
* @example body { "name": "new user", "password": "password", "permission": "none" }
|
|
84
101
|
*/
|
|
85
102
|
async createUser(body) {
|
|
@@ -87,23 +104,35 @@ let UserController = class UserController extends XoController {
|
|
|
87
104
|
return { id: user.id };
|
|
88
105
|
}
|
|
89
106
|
/**
|
|
107
|
+
* Required privilege:
|
|
108
|
+
* - resource: user, action: delete
|
|
109
|
+
*
|
|
90
110
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
91
111
|
*/
|
|
92
112
|
async deleteUser(id) {
|
|
93
113
|
await this.restApi.xoApp.deleteUser(id);
|
|
94
114
|
}
|
|
95
115
|
/**
|
|
116
|
+
* Returns all groups that match the following privilege:
|
|
117
|
+
* - resource: group, action: read
|
|
118
|
+
*
|
|
96
119
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
97
120
|
* @example fields "name,id,users"
|
|
98
121
|
* @example filter "users:length:>0"
|
|
99
122
|
* @example limit 42
|
|
100
123
|
*/
|
|
101
|
-
async getUserGroups(req, id, fields, ndjson, filter, limit) {
|
|
124
|
+
async getUserGroups(req, id, fields, ndjson, markdown, filter, limit) {
|
|
102
125
|
const user = await this.getObject(id);
|
|
103
126
|
const groups = await Promise.all(user.groups.map(group => this.restApi.xoApp.getGroup(group)));
|
|
104
|
-
return this.sendObjects(limitAndFilterArray(groups, { filter
|
|
127
|
+
return this.sendObjects(limitAndFilterArray(groups, { filter }), req, {
|
|
128
|
+
path: 'groups',
|
|
129
|
+
limit,
|
|
130
|
+
privilege: { action: 'read', resource: 'group' },
|
|
131
|
+
});
|
|
105
132
|
}
|
|
106
133
|
/**
|
|
134
|
+
* You can only see your own authentication tokens
|
|
135
|
+
*
|
|
107
136
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
108
137
|
* @example filter "expiration:>1757371582496"
|
|
109
138
|
* @example limit 42
|
|
@@ -118,14 +147,21 @@ let UserController = class UserController extends XoController {
|
|
|
118
147
|
return limitAndFilterArray(tokens, { filter, limit });
|
|
119
148
|
}
|
|
120
149
|
/**
|
|
150
|
+
* Returns all tasks that match the following privilege:
|
|
151
|
+
* - resource: task, action: read
|
|
152
|
+
*
|
|
121
153
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
122
154
|
* @example fields "id,status,properties"
|
|
123
155
|
* @example filter "status:failure"
|
|
124
156
|
* @example limit 42
|
|
125
157
|
*/
|
|
126
|
-
async getUserTasks(req, id, fields, ndjson, filter, limit) {
|
|
127
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
128
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
158
|
+
async getUserTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
159
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
160
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
161
|
+
path: 'tasks',
|
|
162
|
+
limit,
|
|
163
|
+
privilege: { action: 'read', resource: 'task' },
|
|
164
|
+
});
|
|
129
165
|
}
|
|
130
166
|
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
|
|
131
167
|
/**
|
|
@@ -142,6 +178,8 @@ let UserController = class UserController extends XoController {
|
|
|
142
178
|
}
|
|
143
179
|
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
|
|
144
180
|
/**
|
|
181
|
+
* You can only create authentication token for yourself
|
|
182
|
+
*
|
|
145
183
|
* @example id "me"
|
|
146
184
|
* @example body {"client": {"id": "my-fav-client"}, "description": "token for CLI usage", "expiresIn": "1 hour"}
|
|
147
185
|
*/
|
|
@@ -156,26 +194,62 @@ let UserController = class UserController extends XoController {
|
|
|
156
194
|
});
|
|
157
195
|
return { token };
|
|
158
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Returns all ACL privileges that match the following privilege:
|
|
199
|
+
* - resource: acl-privilege, action: read (if not self)
|
|
200
|
+
*
|
|
201
|
+
* @example id "me"
|
|
202
|
+
* @example fields "id,action,resource"
|
|
203
|
+
* @example filter "action:create"
|
|
204
|
+
* @example limit 42
|
|
205
|
+
*/
|
|
206
|
+
async getUserPrivileges(req, id, fields, ndjson, filter, limit) {
|
|
207
|
+
const user = await this.getObject(id);
|
|
208
|
+
const currentUser = this.restApi.getCurrentUser();
|
|
209
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
210
|
+
return this.sendObjects(limitAndFilterArray(userPrivileges, { filter }), req, {
|
|
211
|
+
path: 'acl-privileges',
|
|
212
|
+
limit,
|
|
213
|
+
privilege: currentUser.id === user.id ? undefined : { action: 'read', resource: 'acl-privilege' },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
159
216
|
};
|
|
160
217
|
__decorate([
|
|
161
218
|
Example(userIds),
|
|
162
219
|
Example(partialUsers),
|
|
163
220
|
Get(''),
|
|
221
|
+
Security('*', ['acl']),
|
|
164
222
|
__param(0, Request()),
|
|
165
223
|
__param(1, Query()),
|
|
166
224
|
__param(2, Query()),
|
|
167
225
|
__param(3, Query()),
|
|
168
|
-
__param(4, Query())
|
|
226
|
+
__param(4, Query()),
|
|
227
|
+
__param(5, Query())
|
|
169
228
|
], UserController.prototype, "getUsers", null);
|
|
170
229
|
__decorate([
|
|
171
230
|
Example(user),
|
|
172
231
|
Get('{id}'),
|
|
232
|
+
Middlewares(acl({
|
|
233
|
+
resource: 'user',
|
|
234
|
+
action: actionIfNotSelfUser('read'),
|
|
235
|
+
objectId: 'params.id',
|
|
236
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
237
|
+
})),
|
|
238
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
173
239
|
Response(notFoundResp.status, notFoundResp.description),
|
|
174
240
|
__param(0, Path())
|
|
175
241
|
], UserController.prototype, "getUser", null);
|
|
176
242
|
__decorate([
|
|
177
243
|
Patch('{id}'),
|
|
178
|
-
Middlewares(
|
|
244
|
+
Middlewares([
|
|
245
|
+
json(),
|
|
246
|
+
acl({
|
|
247
|
+
resource: 'user',
|
|
248
|
+
actions: actionsFromBody(['update:name', 'update:password', 'update:permission', 'update:preferences']),
|
|
249
|
+
objectId: 'params.id',
|
|
250
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
251
|
+
}),
|
|
252
|
+
]),
|
|
179
253
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
180
254
|
Response(notFoundResp.status, notFoundResp.description),
|
|
181
255
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
@@ -186,15 +260,23 @@ __decorate([
|
|
|
186
260
|
__decorate([
|
|
187
261
|
Example(userId),
|
|
188
262
|
Post(''),
|
|
189
|
-
Middlewares(json()),
|
|
263
|
+
Middlewares([json(), acl({ resource: 'user', action: 'create', object: ({ req }) => req.body })]),
|
|
190
264
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
191
265
|
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
266
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
192
267
|
Response(invalidParameters.status, invalidParameters.description),
|
|
193
268
|
__param(0, Body())
|
|
194
269
|
], UserController.prototype, "createUser", null);
|
|
195
270
|
__decorate([
|
|
196
271
|
Delete('{id}'),
|
|
272
|
+
Middlewares(acl({
|
|
273
|
+
resource: 'user',
|
|
274
|
+
action: 'delete',
|
|
275
|
+
objectId: 'params.id',
|
|
276
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
277
|
+
})),
|
|
197
278
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
279
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
198
280
|
Response(notFoundResp.status, notFoundResp.description),
|
|
199
281
|
__param(0, Path())
|
|
200
282
|
], UserController.prototype, "deleteUser", null);
|
|
@@ -202,6 +284,7 @@ __decorate([
|
|
|
202
284
|
Example(groupIds),
|
|
203
285
|
Example(partialGroups),
|
|
204
286
|
Get('{id}/groups'),
|
|
287
|
+
Security('*', ['acl']),
|
|
205
288
|
Tags('groups'),
|
|
206
289
|
Response(notFoundResp.status, notFoundResp.description),
|
|
207
290
|
__param(0, Request()),
|
|
@@ -209,11 +292,13 @@ __decorate([
|
|
|
209
292
|
__param(2, Query()),
|
|
210
293
|
__param(3, Query()),
|
|
211
294
|
__param(4, Query()),
|
|
212
|
-
__param(5, Query())
|
|
295
|
+
__param(5, Query()),
|
|
296
|
+
__param(6, Query())
|
|
213
297
|
], UserController.prototype, "getUserGroups", null);
|
|
214
298
|
__decorate([
|
|
215
299
|
Example(authenticationTokens),
|
|
216
300
|
Get('{id}/authentication_tokens'),
|
|
301
|
+
Security('*', ['acl']),
|
|
217
302
|
Response(notFoundResp.status, notFoundResp.description),
|
|
218
303
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
219
304
|
__param(0, Request()),
|
|
@@ -225,6 +310,7 @@ __decorate([
|
|
|
225
310
|
Example(taskIds),
|
|
226
311
|
Example(partialTasks),
|
|
227
312
|
Get('{id}/tasks'),
|
|
313
|
+
Security('*', ['acl']),
|
|
228
314
|
Tags('tasks'),
|
|
229
315
|
Response(notFoundResp.status, notFoundResp.description),
|
|
230
316
|
__param(0, Request()),
|
|
@@ -232,7 +318,8 @@ __decorate([
|
|
|
232
318
|
__param(2, Query()),
|
|
233
319
|
__param(3, Query()),
|
|
234
320
|
__param(4, Query()),
|
|
235
|
-
__param(5, Query())
|
|
321
|
+
__param(5, Query()),
|
|
322
|
+
__param(6, Query())
|
|
236
323
|
], UserController.prototype, "getUserTasks", null);
|
|
237
324
|
__decorate([
|
|
238
325
|
Example(authenticationToken),
|
|
@@ -247,12 +334,27 @@ __decorate([
|
|
|
247
334
|
Example(authenticationToken),
|
|
248
335
|
Post('{id}/authentication_tokens'),
|
|
249
336
|
Middlewares(json()),
|
|
337
|
+
Security('*', ['acl']),
|
|
250
338
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
251
339
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
252
340
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
253
341
|
__param(0, Body()),
|
|
254
342
|
__param(1, Path())
|
|
255
343
|
], UserController.prototype, "postAuthenticationTokens", null);
|
|
344
|
+
__decorate([
|
|
345
|
+
Example(aclPrivilegeIds),
|
|
346
|
+
Example(partialAclPrivileges),
|
|
347
|
+
Get('{id}/acl-privileges'),
|
|
348
|
+
Security('*', ['acl']),
|
|
349
|
+
Tags('acls'),
|
|
350
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
351
|
+
__param(0, Request()),
|
|
352
|
+
__param(1, Path()),
|
|
353
|
+
__param(2, Query()),
|
|
354
|
+
__param(3, Query()),
|
|
355
|
+
__param(4, Query()),
|
|
356
|
+
__param(5, Query())
|
|
357
|
+
], UserController.prototype, "getUserPrivileges", null);
|
|
256
358
|
UserController = __decorate([
|
|
257
359
|
Route('users'),
|
|
258
360
|
Security('*'),
|