@xen-orchestra/rest-api 0.29.0 → 0.30.1

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.
Files changed (53) hide show
  1. package/README.md +101 -1
  2. package/dist/abstract-classes/base-controller.mjs +20 -3
  3. package/dist/abstract-classes/listener.mjs +116 -12
  4. package/dist/acl-privileges/acl-privilege.controller.mjs +172 -0
  5. package/dist/acl-roles/acl-role.controller.mjs +384 -0
  6. package/dist/alarms/alarm.controller.mjs +22 -9
  7. package/dist/alarms/alarm.service.mjs +8 -0
  8. package/dist/backup-archives/backup-archive.controller.mjs +30 -21
  9. package/dist/backup-archives/backup-archive.service.mjs +21 -0
  10. package/dist/backup-jobs/backup-job.controller.mjs +59 -15
  11. package/dist/backup-jobs/backup-job.service.mjs +7 -0
  12. package/dist/backup-logs/backup-log.controller.mjs +25 -11
  13. package/dist/backup-logs/backup-log.service.mjs +19 -0
  14. package/dist/backup-repositories/backup-repositories.controller.mjs +21 -3
  15. package/dist/events/event.class.mjs +24 -9
  16. package/dist/events/event.controller.mjs +3 -0
  17. package/dist/events/event.service.mjs +2 -1
  18. package/dist/groups/group.controller.mjs +90 -6
  19. package/dist/hosts/host.controller.mjs +78 -7
  20. package/dist/ioc/ioc.mjs +13 -4
  21. package/dist/messages/message.controller.mjs +29 -8
  22. package/dist/middlewares/acl.middleware.mjs +206 -0
  23. package/dist/middlewares/authentication.middleware.mjs +15 -6
  24. package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
  25. package/dist/networks/network.controller.mjs +60 -9
  26. package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
  27. package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
  28. package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
  29. package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
  30. package/dist/open-api/routes/routes.js +676 -132
  31. package/dist/pbds/pbd.controller.mjs +17 -3
  32. package/dist/pcis/pci.controller.mjs +16 -3
  33. package/dist/pgpus/pgpu.controller.mjs +16 -3
  34. package/dist/pifs/pif.controller.mjs +44 -8
  35. package/dist/pools/pool.controller.mjs +154 -9
  36. package/dist/proxies/proxy.controller.mjs +22 -4
  37. package/dist/restore-logs/restore-log.controller.mjs +36 -19
  38. package/dist/schedules/schedule.controller.mjs +33 -3
  39. package/dist/servers/server.controller.mjs +65 -5
  40. package/dist/sms/sm.controller.mjs +14 -2
  41. package/dist/srs/sr.controller.mjs +62 -10
  42. package/dist/tasks/task.controller.mjs +75 -11
  43. package/dist/users/user.controller.mjs +115 -16
  44. package/dist/vbds/vbd.controller.mjs +65 -31
  45. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +36 -6
  46. package/dist/vdis/vdi.controller.mjs +69 -8
  47. package/dist/vifs/vif.controller.mjs +43 -7
  48. package/dist/vm-controller/vm-controller.controller.mjs +62 -9
  49. package/dist/vm-snapshots/vm-snapshot.controller.mjs +70 -8
  50. package/dist/vm-templates/vm-template.controller.mjs +71 -8
  51. package/dist/vms/vm.controller.mjs +164 -12
  52. package/open-api/spec/swagger.json +10907 -3265
  53. package/package.json +4 -3
@@ -0,0 +1,384 @@
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, Put, 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 { aclPrivilegeIds, partialAclPrivileges } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
15
+ import { aclRole, aclRoleIds, partialAclRoles } from '../open-api/oa-examples/acl-role.oa-example.mjs';
16
+ import { asynchronousActionResp, badRequestResp, createdResp, forbiddenOperationResp, invalidParameters, noContentResp, notFoundResp, resourceAlreadyExists, unauthorizedResp, } from '../open-api/common/response.common.mjs';
17
+ import { BASE_URL } from '../index.mjs';
18
+ import { limitAndFilterArray } from '../helpers/utils.helper.mjs';
19
+ import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
20
+ import { XoController } from '../abstract-classes/xo-controller.mjs';
21
+ import { entityId } from '../open-api/oa-examples/common.oa-example.mjs';
22
+ import { inject } from 'inversify';
23
+ import { RestApi } from '../rest-api/rest-api.mjs';
24
+ let AclRoleController = class AclRoleController extends XoController {
25
+ constructor(restApi) {
26
+ super('acl-role', restApi);
27
+ }
28
+ getAllCollectionObjects() {
29
+ return this.restApi.xoApp.getAclV2Roles();
30
+ }
31
+ getCollectionObject(id) {
32
+ return this.restApi.xoApp.getAclV2Role(id);
33
+ }
34
+ /**
35
+ * Returns all ACL roles that match the following privilege:
36
+ * - resource: acl-role, action: read
37
+ *
38
+ * @example fields "id,name,isTemplate"
39
+ * @example filter "name:read only"
40
+ * @example limit 42
41
+ */
42
+ async getAclV2Roles(req, fields, ndjson, filter, limit) {
43
+ return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
44
+ limit,
45
+ privilege: { resource: 'acl-role', action: 'read' },
46
+ });
47
+ }
48
+ /**
49
+ * Required privilege:
50
+ * - resource: acl-role, action: create
51
+ *
52
+ * @example body {
53
+ * "name": "VMs creator",
54
+ * "description": "Allow to create VMs"
55
+ * }
56
+ */
57
+ async createAclV2Role(body) {
58
+ const newRole = await this.restApi.xoApp.createAclV2Role(body);
59
+ return { id: newRole.id };
60
+ }
61
+ /**
62
+ * Required privilege:
63
+ * - resource: acl-role, action: read
64
+ *
65
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
66
+ */
67
+ getAclV2Role(id) {
68
+ return this.getObject(id);
69
+ }
70
+ /**
71
+ * Required privilege:
72
+ * - resource: acl-role, action: delete
73
+ *
74
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
75
+ */
76
+ async deleteAclV2Role(id) {
77
+ await this.restApi.xoApp.deleteAclV2Role(id);
78
+ }
79
+ /**
80
+ * Required privileges:
81
+ * - resource: acl-role, action: update (grants all fields)
82
+ * - resource: acl-role, action: update:name (if name is passed)
83
+ * - resource: acl-role, action: update:description (if description is passed)
84
+ *
85
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
86
+ * @example body {
87
+ * "name": "VMs creator",
88
+ * "description": "Allow to create VMs"
89
+ * }
90
+ */
91
+ async updateAclV2Role(id, body) {
92
+ await this.restApi.xoApp.updateAclV2Role(id, body);
93
+ }
94
+ /**
95
+ * Copy a role with all its privileges. Possibility to modify the name and description of the copied role.
96
+ *
97
+ * Required privileges:
98
+ * - resource: acl-role, action: create
99
+ * - resource: acl-privilege, action: create (if copied role has privileges)
100
+ *
101
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
102
+ * @example body {"name": "Copied role"}
103
+ */
104
+ copyAclV2Role(id, body, sync) {
105
+ const roleId = id;
106
+ const action = async () => {
107
+ const id = await this.restApi.xoApp.copyAclV2Role(roleId, body);
108
+ if (sync) {
109
+ this.setHeader('Location', `${BASE_URL}/acl-roles/${id}`);
110
+ }
111
+ return { id };
112
+ };
113
+ return this.createAction(action, {
114
+ sync,
115
+ statusCode: createdResp.status,
116
+ taskProperties: {
117
+ args: body,
118
+ name: 'copy role',
119
+ objectId: roleId,
120
+ },
121
+ });
122
+ }
123
+ /**
124
+ * Returns all ACL privileges that match the following privilege:
125
+ * - resource: acl-privilege, action: read
126
+ *
127
+ * @example id "426622cc-b2db-4545-a2f0-6ec47b3a6450"
128
+ * @example fields "id,action,resource"
129
+ * @example filter "action:create"
130
+ * @example limit 42
131
+ */
132
+ async getAclV2RolePrivileges(req, id, fields, ndjson, filter, limit) {
133
+ const privileges = (await this.restApi.xoApp.getAclV2RolePrivileges(id));
134
+ return this.sendObjects(limitAndFilterArray(privileges, { filter }), req, {
135
+ path: 'acl-privileges',
136
+ limit,
137
+ privilege: { resource: 'acl-privilege', action: 'read' },
138
+ });
139
+ }
140
+ /**
141
+ * Attach an ACL V2 role to a group.
142
+ *
143
+ * Required privilege:
144
+ * - resource: acl-role, action: update:groups
145
+ *
146
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
147
+ * @example groupId "ee4965bf-d8af-4ca2-aa0e-5f29d0c5f9e2"
148
+ */
149
+ async attachAclV2Group(id, groupId) {
150
+ const roleId = id;
151
+ // addAclV2GroupRole does not check if the group exists so we get the group here to make sure it exists.
152
+ const group = await this.restApi.xoApp.getGroup(groupId);
153
+ await this.restApi.xoApp.addAclV2GroupRole(group.id, roleId);
154
+ }
155
+ /**
156
+ * Detach an ACL V2 role from a group.
157
+ *
158
+ * Required privilege:
159
+ * - resource: acl-role, action: update:groups
160
+ *
161
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
162
+ * @example groupId "ee4965bf-d8af-4ca2-aa0e-5f29d0c5f9e2"
163
+ */
164
+ async detachAclV2Group(id, groupId) {
165
+ const roleId = id;
166
+ // deleteAclV2GroupRole does not check if the group exists so we get the group here to make sure it exists.
167
+ const group = await this.restApi.xoApp.getGroup(groupId);
168
+ await this.restApi.xoApp.deleteAclV2GroupRole(group.id, roleId);
169
+ }
170
+ /**
171
+ * Attach an ACL V2 role to a user.
172
+ *
173
+ * Required privilege:
174
+ * - resource: acl-role, action: update:users
175
+ *
176
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
177
+ * @example userId "ee4965bf-d8af-4ca2-aa0e-5f29d0c5f9e2"
178
+ */
179
+ async attachAclV2User(id, userId) {
180
+ const roleId = id;
181
+ // addAclV2UserRole does not check if the user exists so we get the user here to make sure it exists.
182
+ const user = await this.restApi.xoApp.getUser(userId);
183
+ await this.restApi.xoApp.addAclV2UserRole(user.id, roleId);
184
+ }
185
+ /**
186
+ * Detach an ACL V2 role from a user.
187
+ *
188
+ * Required privilege:
189
+ * - resource: acl-role, action: update:users
190
+ *
191
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
192
+ * @example userId "ee4965bf-d8af-4ca2-aa0e-5f29d0c5f9e2"
193
+ */
194
+ async detachAclV2User(id, userId) {
195
+ const roleId = id;
196
+ // deleteAclV2UserRole does not check if the user exists so we get the user here to make sure it exists.
197
+ const user = await this.restApi.xoApp.getUser(userId);
198
+ await this.restApi.xoApp.deleteAclV2UserRole(user.id, roleId);
199
+ }
200
+ };
201
+ __decorate([
202
+ Example(aclRoleIds),
203
+ Example(partialAclRoles),
204
+ Get(''),
205
+ Security('*', ['acl']),
206
+ __param(0, Request()),
207
+ __param(1, Query()),
208
+ __param(2, Query()),
209
+ __param(3, Query()),
210
+ __param(4, Query())
211
+ ], AclRoleController.prototype, "getAclV2Roles", null);
212
+ __decorate([
213
+ Example(entityId),
214
+ Post(''),
215
+ Middlewares([
216
+ json(),
217
+ acl({
218
+ resource: 'acl-role',
219
+ action: 'create',
220
+ object: ({ req }) => req.body,
221
+ }),
222
+ ]),
223
+ SuccessResponse(createdResp.status, createdResp.description),
224
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
225
+ Response(invalidParameters.status, invalidParameters.description),
226
+ __param(0, Body())
227
+ ], AclRoleController.prototype, "createAclV2Role", null);
228
+ __decorate([
229
+ Example(aclRole),
230
+ Get('{id}'),
231
+ Middlewares(acl({
232
+ resource: 'acl-role',
233
+ action: 'read',
234
+ objectId: 'params.id',
235
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
236
+ })),
237
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
238
+ Response(notFoundResp.status, notFoundResp.description),
239
+ __param(0, Path())
240
+ ], AclRoleController.prototype, "getAclV2Role", null);
241
+ __decorate([
242
+ Delete('{id}'),
243
+ Middlewares(acl({
244
+ resource: 'acl-role',
245
+ action: 'delete',
246
+ objectId: 'params.id',
247
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
248
+ })),
249
+ SuccessResponse(noContentResp.status, noContentResp.description),
250
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
251
+ Response(notFoundResp.status, notFoundResp.description),
252
+ __param(0, Path())
253
+ ], AclRoleController.prototype, "deleteAclV2Role", null);
254
+ __decorate([
255
+ Patch('{id}'),
256
+ Middlewares([
257
+ json(),
258
+ acl({
259
+ resource: 'acl-role',
260
+ actions: actionsFromBody(['update:name', 'update:description']),
261
+ objectId: 'params.id',
262
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
263
+ }),
264
+ ]),
265
+ SuccessResponse(noContentResp.status, noContentResp.description),
266
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
267
+ Response(notFoundResp.status, notFoundResp.description),
268
+ Response(invalidParameters.status, invalidParameters.description),
269
+ __param(0, Path()),
270
+ __param(1, Body())
271
+ ], AclRoleController.prototype, "updateAclV2Role", null);
272
+ __decorate([
273
+ Example(taskLocation),
274
+ Post('{id}/actions/copy'),
275
+ Middlewares([
276
+ json(),
277
+ acl([
278
+ {
279
+ resource: 'acl-role',
280
+ action: 'create',
281
+ object: async ({ req, restApi }) => {
282
+ const model = await restApi.xoApp.getAclV2Role(req.params.id);
283
+ return { name: req.body.name ?? model.name, description: req.body.description ?? model.description };
284
+ },
285
+ },
286
+ {
287
+ resource: 'acl-privilege',
288
+ action: 'create',
289
+ objects: async ({ req, restApi }) => {
290
+ const privileges = await restApi.xoApp.getAclV2RolePrivileges(req.params.id);
291
+ return privileges.map(({ id, ...rest }) => rest);
292
+ },
293
+ },
294
+ ]),
295
+ ]),
296
+ SuccessResponse(createdResp.status, createdResp.description),
297
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
298
+ Response(asynchronousActionResp.status, asynchronousActionResp.description),
299
+ Response(notFoundResp.status, notFoundResp.description),
300
+ __param(0, Path()),
301
+ __param(1, Body()),
302
+ __param(2, Query())
303
+ ], AclRoleController.prototype, "copyAclV2Role", null);
304
+ __decorate([
305
+ Example(aclPrivilegeIds),
306
+ Example(partialAclPrivileges),
307
+ Get('{id}/privileges'),
308
+ Security('*', ['acl']),
309
+ Response(notFoundResp.status, notFoundResp.description),
310
+ __param(0, Request()),
311
+ __param(1, Path()),
312
+ __param(2, Query()),
313
+ __param(3, Query()),
314
+ __param(4, Query()),
315
+ __param(5, Query())
316
+ ], AclRoleController.prototype, "getAclV2RolePrivileges", null);
317
+ __decorate([
318
+ Put('{id}/groups/{groupId}'),
319
+ Middlewares(acl({
320
+ resource: 'acl-role',
321
+ action: 'update:groups',
322
+ objectId: 'params.id',
323
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
324
+ })),
325
+ SuccessResponse(noContentResp.status, noContentResp.description),
326
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
327
+ Response(notFoundResp.status, notFoundResp.description),
328
+ Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
329
+ __param(0, Path()),
330
+ __param(1, Path())
331
+ ], AclRoleController.prototype, "attachAclV2Group", null);
332
+ __decorate([
333
+ Delete('{id}/groups/{groupId}'),
334
+ Middlewares(acl({
335
+ resource: 'acl-role',
336
+ action: 'update:groups',
337
+ objectId: 'params.id',
338
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
339
+ })),
340
+ SuccessResponse(noContentResp.status, noContentResp.description),
341
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
342
+ Response(notFoundResp.status, notFoundResp.description),
343
+ __param(0, Path()),
344
+ __param(1, Path())
345
+ ], AclRoleController.prototype, "detachAclV2Group", null);
346
+ __decorate([
347
+ Put('{id}/users/{userId}'),
348
+ Middlewares(acl({
349
+ resource: 'acl-role',
350
+ action: 'update:users',
351
+ objectId: 'params.id',
352
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
353
+ })),
354
+ SuccessResponse(noContentResp.status, noContentResp.description),
355
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
356
+ Response(notFoundResp.status, notFoundResp.description),
357
+ Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
358
+ __param(0, Path()),
359
+ __param(1, Path())
360
+ ], AclRoleController.prototype, "attachAclV2User", null);
361
+ __decorate([
362
+ Delete('{id}/users/{userId}'),
363
+ Middlewares(acl({
364
+ resource: 'acl-role',
365
+ action: 'update:users',
366
+ objectId: 'params.id',
367
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Role,
368
+ })),
369
+ SuccessResponse(noContentResp.status, noContentResp.description),
370
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
371
+ Response(notFoundResp.status, notFoundResp.description),
372
+ __param(0, Path()),
373
+ __param(1, Path())
374
+ ], AclRoleController.prototype, "detachAclV2User", null);
375
+ AclRoleController = __decorate([
376
+ Route('acl-roles'),
377
+ Security('*'),
378
+ Response(badRequestResp.status, badRequestResp.description),
379
+ Response(unauthorizedResp.status, unauthorizedResp.description),
380
+ Tags('acls'),
381
+ provide(AclRoleController),
382
+ __param(0, inject(RestApi))
383
+ ], AclRoleController);
384
+ export { AclRoleController };
@@ -7,12 +7,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
- import { noSuchObject } from 'xo-common/api-errors.js';
13
12
  import { provide } from 'inversify-binding-decorators';
14
13
  import { alarm, alarmIds, partialAlarms } from '../open-api/oa-examples/alarm.oa-example.mjs';
15
- import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
14
+ import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
15
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
16
16
  import { RestApi } from '../rest-api/rest-api.mjs';
17
17
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
18
18
  import { AlarmService } from './alarm.service.mjs';
@@ -32,21 +32,26 @@ let AlarmController = class AlarmController extends XapiXoController {
32
32
  * Override parent getObject in order to only get `ALARM` message
33
33
  */
34
34
  getObject(id) {
35
- const maybeAlarm = this.restApi.getObject(id, 'message');
36
- if (!this.#alarmService.isAlarm(maybeAlarm)) {
37
- throw noSuchObject(id, 'alarm');
38
- }
39
- return this.#alarmService.parseAlarm(maybeAlarm);
35
+ return this.#alarmService.getAlarm(id);
40
36
  }
41
37
  /**
38
+ * Returns all alarms that match the following privilege:
39
+ * - resource: alarm, action: read
40
+ *
42
41
  * @example fields "body,id,object"
43
42
  * @example filter "body:name:physical_utilisation"
44
43
  * @example limit 42
45
44
  */
46
45
  getAlarms(req, fields, ndjson, markdown, filter, limit) {
47
- return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
46
+ return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
47
+ limit,
48
+ privilege: { action: 'read', resource: 'alarm' },
49
+ });
48
50
  }
49
51
  /**
52
+ * Required privilege:
53
+ * - resource: alarm, action: read
54
+ *
50
55
  * @example id "0c98c71c-2f9c-d5c2-b9b6-2c8371730eab"
51
56
  */
52
57
  getAlarm(id) {
@@ -57,6 +62,7 @@ __decorate([
57
62
  Example(alarmIds),
58
63
  Example(partialAlarms),
59
64
  Get(''),
65
+ Security('*', ['acl']),
60
66
  __param(0, Request()),
61
67
  __param(1, Query()),
62
68
  __param(2, Query()),
@@ -67,6 +73,13 @@ __decorate([
67
73
  __decorate([
68
74
  Example(alarm),
69
75
  Get('{id}'),
76
+ Middlewares(acl({
77
+ resource: 'alarm',
78
+ action: 'read',
79
+ objectId: 'params.id',
80
+ getObject: autoBindService(AlarmService, 'getAlarm'),
81
+ })),
82
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
70
83
  Response(notFoundResp.status, notFoundResp.description),
71
84
  __param(0, Path())
72
85
  ], AlarmController.prototype, "getAlarm", null);
@@ -1,3 +1,4 @@
1
+ import { noSuchObject } from 'xo-common/api-errors.js';
1
2
  import { BASE_URL } from '../index.mjs';
2
3
  import { safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
3
4
  // E.g: 'value: 0.6\nconfig:\n<variable>\n<name value="cpu_usage"/>\n<alarm_trigger_level value="0.4"/>\n<alarm_trigger_period value ="60"/>\n</variable>';
@@ -65,4 +66,11 @@ export class AlarmService {
65
66
  }
66
67
  return alarms;
67
68
  }
69
+ getAlarm(id) {
70
+ const maybeAlarm = this.#restApi.getObject(id, 'message');
71
+ if (!this.isAlarm(maybeAlarm)) {
72
+ throw noSuchObject(id, 'alarm');
73
+ }
74
+ return this.parseAlarm(maybeAlarm);
75
+ }
68
76
  }
@@ -7,19 +7,20 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
- import { noSuchObject } from 'xo-common/api-errors.js';
13
12
  import { provide } from 'inversify-binding-decorators';
14
- import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
13
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
15
14
  import { XoController } from '../abstract-classes/xo-controller.mjs';
16
15
  import { RestApi } from '../rest-api/rest-api.mjs';
17
16
  import { backupArchive, backupArchiveIds, partialBackupArchives, } from '../open-api/oa-examples/backup-archive.oa-example.mjs';
18
- // BR uuid/xo-vm-backups/VM uuid/(ISO 8601 compact).json
19
- const BACKUP_ARCHIVE_ID_REGEX = /^([0-9a-fA-F-]{36})\/+xo-vm-backups\/+([0-9a-fA-F-]{36})\/+(\d{8}T\d{6}Z)\.json$/;
17
+ import { BackupArchiveService } from './backup-archive.service.mjs';
18
+ import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
20
19
  let BackupArchiveController = class BackupArchiveController extends XoController {
21
- constructor(restApi) {
20
+ #backupArchiveService;
21
+ constructor(restApi, backupArchiveService) {
22
22
  super('backup-archive', restApi);
23
+ this.#backupArchiveService = backupArchiveService;
23
24
  }
24
25
  async getAllCollectionObjects({ backupRepositories = [], } = {}) {
25
26
  const backupRepositoryIds = [];
@@ -40,19 +41,12 @@ let BackupArchiveController = class BackupArchiveController extends XoController
40
41
  .flat(2);
41
42
  return vmBackupArchives;
42
43
  }
43
- async getCollectionObject(id) {
44
- const match = id.match(BACKUP_ARCHIVE_ID_REGEX);
45
- if (match === null) {
46
- throw noSuchObject(id, 'backup-archive');
47
- }
48
- const [, brId, vmId] = match;
49
- const backupArchive = (await this.restApi.xoApp.listVmBackupsNg([brId]))[brId]?.[vmId]?.find(ba => ba.id === id);
50
- if (backupArchive === undefined) {
51
- throw noSuchObject(id, 'backup-archive');
52
- }
53
- return backupArchive;
44
+ getCollectionObject(id) {
45
+ return this.#backupArchiveService.getBackupArchive(id);
54
46
  }
55
47
  /**
48
+ * Returns all backup archives that match the following privilege:
49
+ * - resource: backup-archive, action: read
56
50
  *
57
51
  * You can use the alias "*" in "backup-repository" to select all backup repositories.
58
52
  *
@@ -62,11 +56,17 @@ let BackupArchiveController = class BackupArchiveController extends XoController
62
56
  * @example limit 42
63
57
  */
64
58
  async getBackupArchives(req, backupRepositories, fields, ndjson, markdown, filter, limit) {
65
- const backupArchives = await this.getObjects({ backupRepositories, filter, limit });
66
- return this.sendObjects(Object.values(backupArchives), req);
59
+ const backupArchives = await this.getObjects({ backupRepositories, filter });
60
+ return this.sendObjects(Object.values(backupArchives), req, {
61
+ limit,
62
+ privilege: { action: 'read', resource: 'backup-archive' },
63
+ });
67
64
  }
68
65
  /**
69
- * @example id "231264c3-af43-4ec0-a3be-394c5b1fdbfc//xo-vm-backups/6ef7c09e-677b-1e6f-0546-7ab30413c61c/20250801T080832Z.json"
66
+ * Required privilege:
67
+ * - resource: backup-archive, action: read
68
+ *
69
+ * @example id "231264c3-af43-4ec0-a3be-394c5b1fdbfc/xo-vm-backups/6ef7c09e-677b-1e6f-0546-7ab30413c61c/20250801T080832Z.json"
70
70
  */
71
71
  async getBackupArchive(id) {
72
72
  const backupArchive = await this.getObject(id);
@@ -77,6 +77,7 @@ __decorate([
77
77
  Example(backupArchiveIds),
78
78
  Example(partialBackupArchives),
79
79
  Get(''),
80
+ Security('*', ['acl']),
80
81
  Response(notFoundResp.status, notFoundResp.description),
81
82
  __param(0, Request()),
82
83
  __param(1, Query('backup-repository')),
@@ -89,6 +90,13 @@ __decorate([
89
90
  __decorate([
90
91
  Example(backupArchive),
91
92
  Get('{id}'),
93
+ Middlewares(acl({
94
+ resource: 'backup-archive',
95
+ action: 'read',
96
+ objectId: 'params.id',
97
+ getObject: autoBindService(BackupArchiveService, 'getBackupArchive'),
98
+ })),
99
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
92
100
  Response(notFoundResp.status, notFoundResp.description),
93
101
  __param(0, Path())
94
102
  ], BackupArchiveController.prototype, "getBackupArchive", null);
@@ -99,6 +107,7 @@ BackupArchiveController = __decorate([
99
107
  Response(unauthorizedResp.status, unauthorizedResp.description),
100
108
  Tags('backup-archives'),
101
109
  provide(BackupArchiveController),
102
- __param(0, inject(RestApi))
110
+ __param(0, inject(RestApi)),
111
+ __param(1, inject(BackupArchiveService))
103
112
  ], BackupArchiveController);
104
113
  export { BackupArchiveController };
@@ -0,0 +1,21 @@
1
+ import { noSuchObject } from 'xo-common/api-errors.js';
2
+ // BR uuid/xo-vm-backups/VM uuid/(ISO 8601 compact).json
3
+ const BACKUP_ARCHIVE_ID_REGEX = /^([0-9a-fA-F-]{36})\/+xo-vm-backups\/+([0-9a-fA-F-]{36})\/+(\d{8}T\d{6}Z)\.json$/;
4
+ export class BackupArchiveService {
5
+ #restApi;
6
+ constructor(restApi) {
7
+ this.#restApi = restApi;
8
+ }
9
+ async getBackupArchive(id) {
10
+ const match = id.match(BACKUP_ARCHIVE_ID_REGEX);
11
+ if (match === null) {
12
+ throw noSuchObject(id, 'backup-archive');
13
+ }
14
+ const [, brId, vmId] = match;
15
+ const backupArchive = (await this.#restApi.xoApp.listVmBackupsNg([brId]))[brId]?.[vmId]?.find(ba => ba.id === id);
16
+ if (backupArchive === undefined) {
17
+ throw noSuchObject(id, 'backup-archive');
18
+ }
19
+ return backupArchive;
20
+ }
21
+ }