@adminforth/crud-approve-plugin 1.0.17 → 1.0.18
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/build.log +15 -0
- package/dist/custom/ListPageDiffView.vue +0 -6
- package/dist/custom/ShowPageDiffView.vue +0 -6
- package/dist/index.js +36 -26
- package/index.ts +51 -30
- package/package.json +1 -1
- package/types.ts +6 -0
package/build.log
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
> @adminforth/crud-approve-plugin@1.0.0 build
|
|
3
|
+
> tsc && rsync -av --exclude 'node_modules' custom dist/
|
|
4
|
+
|
|
5
|
+
sending incremental file list
|
|
6
|
+
custom/
|
|
7
|
+
custom/ListPageDiffView.vue
|
|
8
|
+
custom/ShowPageDiffView.vue
|
|
9
|
+
custom/package-lock.json
|
|
10
|
+
custom/package.json
|
|
11
|
+
custom/pnpm-lock.yaml
|
|
12
|
+
custom/tsconfig.json
|
|
13
|
+
|
|
14
|
+
sent 32,578 bytes received 134 bytes 65,424.00 bytes/sec
|
|
15
|
+
total size is 32,075 speedup is 0.98
|
|
@@ -20,16 +20,10 @@ const diffFile = ref();
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
async function sendApproveRequest(approved) {
|
|
23
|
-
let code = '123456'
|
|
24
|
-
if (approved) {
|
|
25
|
-
code = await (window).adminforthTwoFaModal?.get2FaConfirmationResult?.("Approve Action Confirmation");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
const data = await callAdminForthApi({
|
|
29
24
|
path: `/plugin/crud-approve/update-status`,
|
|
30
25
|
method: 'POST',
|
|
31
26
|
body: {
|
|
32
|
-
meta: { confirmationResult: code },
|
|
33
27
|
connectorId: props.resource.connectorId,
|
|
34
28
|
resourceId: props.resource.resourceId,
|
|
35
29
|
action: props.record[props.meta.resourceColumns.actionColumnName],
|
|
@@ -22,16 +22,10 @@ const newContent = JSON.stringify(props.record[props.meta.resourceColumns.dataCo
|
|
|
22
22
|
const diffFile = ref();
|
|
23
23
|
|
|
24
24
|
async function sendApproveRequest(approved) {
|
|
25
|
-
let code = '123456'
|
|
26
|
-
if (approved) {
|
|
27
|
-
code = await (window).adminforthTwoFaModal?.get2FaConfirmationResult?.("Approve Action Confirmation");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
25
|
const data = await callAdminForthApi({
|
|
31
26
|
path: `/plugin/crud-approve/update-status`,
|
|
32
27
|
method: 'POST',
|
|
33
28
|
body: {
|
|
34
|
-
meta: { confirmationResult: code },
|
|
35
29
|
connectorId: props.resource.connectorId,
|
|
36
30
|
resourceId: props.resource.resourceId,
|
|
37
31
|
action: props.record[props.meta.resourceColumns.actionColumnName],
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { ActionCheckSource, AdminForthPlugin, AdminForthSortDirections, Filters } from "adminforth";
|
|
10
|
+
import { ActionCheckSource, AdminForthPlugin, AdminForthSortDirections, Filters, interpretResource } from "adminforth";
|
|
11
11
|
import { AdminForthDataTypes, AllowedActionsEnum } from "adminforth";
|
|
12
12
|
import { AllowedForReviewActionsEnum, ApprovalStatusEnum } from './types.js';
|
|
13
13
|
import dayjs from "dayjs";
|
|
@@ -179,19 +179,6 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
|
-
this.verifyAuth = (cookies) => __awaiter(this, void 0, void 0, function* () {
|
|
183
|
-
let authCookie;
|
|
184
|
-
for (const i in cookies) {
|
|
185
|
-
if (cookies[i].key === `adminforth_${this.adminforth.config.customization.brandNameSlug}_jwt`) {
|
|
186
|
-
authCookie = cookies[i].value;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
const authRes = yield this.adminforth.auth.verify(authCookie, 'auth', true);
|
|
190
|
-
if ('error' in authRes) {
|
|
191
|
-
return { error: authRes.error, authRes: null };
|
|
192
|
-
}
|
|
193
|
-
return { error: null, authRes: authRes };
|
|
194
|
-
});
|
|
195
182
|
this.createRecord = (resource, diffData, adminUser) => __awaiter(this, void 0, void 0, function* () {
|
|
196
183
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
197
184
|
//@ts-ignore
|
|
@@ -289,16 +276,8 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
289
276
|
server.endpoint({
|
|
290
277
|
method: 'POST',
|
|
291
278
|
path: `/plugin/crud-approve/update-status`,
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const authRes = yield this.verifyAuth(cookies);
|
|
295
|
-
if (authRes.error) {
|
|
296
|
-
//@ts-ignore
|
|
297
|
-
response.status = 403;
|
|
298
|
-
return { error: authRes.error };
|
|
299
|
-
}
|
|
300
|
-
const adminUser = authRes.authRes;
|
|
301
|
-
const { resourceId, diffId, recordId, action, approved, code } = body;
|
|
279
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response, cookies, adminUser }) {
|
|
280
|
+
const { diffId, approved, code } = body;
|
|
302
281
|
const diffRecord = yield this.adminforth.resource(this.diffResource.resourceId).get(Filters.EQ(this.options.resourceColumns.idColumnName, diffId));
|
|
303
282
|
if (!diffRecord) {
|
|
304
283
|
//@ts-ignore
|
|
@@ -310,9 +289,40 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
310
289
|
response.status = 400;
|
|
311
290
|
return { error: 'Diff record is not pending' };
|
|
312
291
|
}
|
|
292
|
+
const action = diffRecord[this.options.resourceColumns.actionColumnName];
|
|
293
|
+
const recordId = diffRecord[this.options.resourceColumns.recordIdColumnName];
|
|
294
|
+
const targetResource = this.adminforth.config.resources.find((res) => res.resourceId == diffRecord[this.options.resourceColumns.resourceIdColumnName]);
|
|
295
|
+
const diffResource = this.adminforth.config.resources.find((res) => res.resourceId === this.diffResource.resourceId);
|
|
296
|
+
const { allowedActions } = yield interpretResource(adminUser, diffResource, { requestBody: body, pk: diffId, record: diffRecord }, ActionCheckSource.ShowRequest, this.adminforth);
|
|
297
|
+
const showAllowed = allowedActions[AllowedActionsEnum.show];
|
|
298
|
+
if (showAllowed !== true) {
|
|
299
|
+
//@ts-ignore
|
|
300
|
+
response.status = 403;
|
|
301
|
+
return {
|
|
302
|
+
error: typeof showAllowed === 'string'
|
|
303
|
+
? showAllowed
|
|
304
|
+
: 'You do not have permission to approve or reject this change request'
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
// separation of duties: author of the request is not a valid reviewer for it
|
|
308
|
+
const requesterId = diffRecord[this.options.resourceColumns.userIdColumnName];
|
|
309
|
+
if (!this.options.allowSelfApproval
|
|
310
|
+
&& requesterId !== undefined && requesterId !== null
|
|
311
|
+
&& `${requesterId}` === `${adminUser.pk}`) {
|
|
312
|
+
//@ts-ignore
|
|
313
|
+
response.status = 403;
|
|
314
|
+
return { error: 'You can not approve or reject your own change request' };
|
|
315
|
+
}
|
|
313
316
|
let beforeSaveResp;
|
|
314
317
|
if (approved === true) {
|
|
315
|
-
|
|
318
|
+
if (!targetResource) {
|
|
319
|
+
//@ts-ignore
|
|
320
|
+
response.status = 404;
|
|
321
|
+
return {
|
|
322
|
+
error: `Resource ${diffRecord[this.options.resourceColumns.resourceIdColumnName]} not found`
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
const resource = targetResource;
|
|
316
326
|
const diffData = diffRecord[this.options.resourceColumns.dataColumnName];
|
|
317
327
|
const extra = diffRecord[this.options.resourceColumns.extraColumnName] || {};
|
|
318
328
|
extra.body = body;
|
|
@@ -377,7 +387,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
377
387
|
adminUser: adminUser, oldRecord: diffRecord,
|
|
378
388
|
updates: {
|
|
379
389
|
[this.options.resourceColumns.statusColumnName]: approved ? ApprovalStatusEnum.approved : ApprovalStatusEnum.rejected,
|
|
380
|
-
[this.options.resourceColumns.responserIdColumnName]:
|
|
390
|
+
[this.options.resourceColumns.responserIdColumnName]: adminUser.pk,
|
|
381
391
|
},
|
|
382
392
|
extra: {
|
|
383
393
|
//@ts-ignore
|
package/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionCheckSource, AdminForthPlugin, AdminForthSortDirections, Filters, IAdminForthDataSourceConnectorBase, IHttpServer } from "adminforth";
|
|
1
|
+
import { ActionCheckSource, AdminForthPlugin, AdminForthSortDirections, Filters, IAdminForthDataSourceConnectorBase, IHttpServer, interpretResource } from "adminforth";
|
|
2
2
|
import { IAdminForth, AdminForthDataTypes, AdminForthResource, AllowedActionsEnum, HttpExtra, AdminUser } from "adminforth";
|
|
3
3
|
import { AllowedForReviewActionsEnum, ApprovalStatusEnum, type PluginOptions } from './types.js';
|
|
4
4
|
|
|
@@ -250,21 +250,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
|
|
254
|
-
verifyAuth = async (cookies: Array<{key: string, value: string}>) => {
|
|
255
|
-
let authCookie;
|
|
256
|
-
for (const i in cookies) {
|
|
257
|
-
if (cookies[i].key === `adminforth_${this.adminforth.config.customization.brandNameSlug}_jwt`) {
|
|
258
|
-
authCookie = cookies[i].value;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
const authRes = await this.adminforth.auth.verify(authCookie, 'auth', true);
|
|
262
|
-
if ('error' in authRes) {
|
|
263
|
-
return { error: authRes.error, authRes: null };
|
|
264
|
-
}
|
|
265
|
-
return { error: null, authRes: authRes };
|
|
266
|
-
}
|
|
267
|
-
|
|
253
|
+
|
|
268
254
|
createRecord = async (resource: AdminForthResource, diffData: any, adminUser: AdminUser) => {
|
|
269
255
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
270
256
|
//@ts-ignore
|
|
@@ -325,17 +311,9 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
325
311
|
server.endpoint({
|
|
326
312
|
method: 'POST',
|
|
327
313
|
path: `/plugin/crud-approve/update-status`,
|
|
328
|
-
|
|
329
|
-
handler: async ({ body, response, cookies }) => {
|
|
330
|
-
const authRes = await this.verifyAuth(cookies);
|
|
331
|
-
if (authRes.error) {
|
|
332
|
-
//@ts-ignore
|
|
333
|
-
response.status = 403;
|
|
334
|
-
return { error: authRes.error };
|
|
335
|
-
}
|
|
336
|
-
const adminUser = authRes.authRes;
|
|
314
|
+
handler: async ({ body, response, cookies, adminUser }) => {
|
|
337
315
|
|
|
338
|
-
const {
|
|
316
|
+
const { diffId, approved, code } = body;
|
|
339
317
|
const diffRecord = await this.adminforth.resource(this.diffResource.resourceId).get(
|
|
340
318
|
Filters.EQ(this.options.resourceColumns.idColumnName, diffId),
|
|
341
319
|
)
|
|
@@ -350,11 +328,54 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
350
328
|
response.status = 400;
|
|
351
329
|
return { error: 'Diff record is not pending' };
|
|
352
330
|
}
|
|
331
|
+
|
|
332
|
+
const action = diffRecord[this.options.resourceColumns.actionColumnName];
|
|
333
|
+
const recordId = diffRecord[this.options.resourceColumns.recordIdColumnName];
|
|
334
|
+
const targetResource = this.adminforth.config.resources.find(
|
|
335
|
+
(res) => res.resourceId == diffRecord[this.options.resourceColumns.resourceIdColumnName]
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const diffResource = this.adminforth.config.resources.find(
|
|
339
|
+
(res) => res.resourceId === this.diffResource.resourceId
|
|
340
|
+
);
|
|
341
|
+
const { allowedActions } = await interpretResource(
|
|
342
|
+
adminUser,
|
|
343
|
+
diffResource,
|
|
344
|
+
{ requestBody: body, pk: diffId, record: diffRecord },
|
|
345
|
+
ActionCheckSource.ShowRequest,
|
|
346
|
+
this.adminforth
|
|
347
|
+
);
|
|
348
|
+
const showAllowed = allowedActions[AllowedActionsEnum.show] as boolean | string | undefined;
|
|
349
|
+
if (showAllowed !== true) {
|
|
350
|
+
//@ts-ignore
|
|
351
|
+
response.status = 403;
|
|
352
|
+
return {
|
|
353
|
+
error: typeof showAllowed === 'string'
|
|
354
|
+
? showAllowed
|
|
355
|
+
: 'You do not have permission to approve or reject this change request'
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// separation of duties: author of the request is not a valid reviewer for it
|
|
360
|
+
const requesterId = diffRecord[this.options.resourceColumns.userIdColumnName];
|
|
361
|
+
if (!this.options.allowSelfApproval
|
|
362
|
+
&& requesterId !== undefined && requesterId !== null
|
|
363
|
+
&& `${requesterId}` === `${adminUser.pk}`) {
|
|
364
|
+
//@ts-ignore
|
|
365
|
+
response.status = 403;
|
|
366
|
+
return { error: 'You can not approve or reject your own change request' };
|
|
367
|
+
}
|
|
368
|
+
|
|
353
369
|
let beforeSaveResp;
|
|
354
370
|
if (approved === true) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
371
|
+
if (!targetResource) {
|
|
372
|
+
//@ts-ignore
|
|
373
|
+
response.status = 404;
|
|
374
|
+
return {
|
|
375
|
+
error: `Resource ${diffRecord[this.options.resourceColumns.resourceIdColumnName]} not found`
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const resource = targetResource;
|
|
358
379
|
const diffData = diffRecord[this.options.resourceColumns.dataColumnName];
|
|
359
380
|
const extra = diffRecord[this.options.resourceColumns.extraColumnName] || {};
|
|
360
381
|
extra.body = body;
|
|
@@ -439,7 +460,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
439
460
|
adminUser: adminUser, oldRecord: diffRecord,
|
|
440
461
|
updates: {
|
|
441
462
|
[this.options.resourceColumns.statusColumnName]: approved ? ApprovalStatusEnum.approved : ApprovalStatusEnum.rejected,
|
|
442
|
-
[this.options.resourceColumns.responserIdColumnName]:
|
|
463
|
+
[this.options.resourceColumns.responserIdColumnName]: adminUser.pk,
|
|
443
464
|
},
|
|
444
465
|
extra: {
|
|
445
466
|
//@ts-ignore
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -16,6 +16,12 @@ export interface PluginOptions {
|
|
|
16
16
|
createdAtColumnName: string;
|
|
17
17
|
extraColumnName: string;
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* By default the user who created the approval request can't approve or reject it himself
|
|
22
|
+
* (separation of duties / four-eyes principle). Set to true to disable this check.
|
|
23
|
+
*/
|
|
24
|
+
allowSelfApproval?: boolean;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
export enum AllowedForReviewActionsEnum {
|