@wbce-d9/api 9.26.3 → 9.26.5
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.
|
@@ -12,6 +12,6 @@ export declare class AuthorizationService {
|
|
|
12
12
|
/**
|
|
13
13
|
* Checks if the provided payload matches the configured permissions, and adds the presets to the payload.
|
|
14
14
|
*/
|
|
15
|
-
validatePayload(action: PermissionsAction, collection: string, data: Partial<Item
|
|
15
|
+
validatePayload(action: PermissionsAction, collection: string, data: Partial<Item>, keys?: PrimaryKey[]): Promise<Partial<Item>>;
|
|
16
16
|
checkAccess(action: PermissionsAction, collection: string, pk: PrimaryKey | PrimaryKey[]): Promise<void>;
|
|
17
17
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { FailedValidationException } from '@wbce-d9/exceptions';
|
|
2
2
|
import { validatePayload } from '@wbce-d9/utils';
|
|
3
|
-
import { cloneDeep, flatten, isArray, isNil, merge, reduce, uniq, uniqWith } from 'lodash-es';
|
|
3
|
+
import { cloneDeep, flatten, isArray, isNil, merge, reduce, uniq, uniqWith, clone } from 'lodash-es';
|
|
4
4
|
import { GENERATE_SPECIAL } from '../constants.js';
|
|
5
5
|
import getDatabase from '../database/index.js';
|
|
6
|
-
import { ForbiddenException } from '../exceptions/index.js';
|
|
6
|
+
import { ForbiddenException, UnprocessableEntityException } from '../exceptions/index.js';
|
|
7
7
|
import { getRelationInfo } from '../utils/get-relation-info.js';
|
|
8
8
|
import { stripFunction } from '../utils/strip-function.js';
|
|
9
9
|
import { ItemsService } from './items.js';
|
|
@@ -336,7 +336,7 @@ export class AuthorizationService {
|
|
|
336
336
|
/**
|
|
337
337
|
* Checks if the provided payload matches the configured permissions, and adds the presets to the payload.
|
|
338
338
|
*/
|
|
339
|
-
validatePayload(action, collection, data) {
|
|
339
|
+
async validatePayload(action, collection, data, keys) {
|
|
340
340
|
const payload = cloneDeep(data);
|
|
341
341
|
let permission;
|
|
342
342
|
if (this.accountability?.admin === true) {
|
|
@@ -368,14 +368,13 @@ export class AuthorizationService {
|
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
const preset = permission.presets ?? {};
|
|
371
|
+
const fields = Object.values(this.schema.collections[collection].fields);
|
|
371
372
|
const payloadWithPresets = merge({}, preset, payload);
|
|
372
|
-
const fieldValidationRules =
|
|
373
|
-
.map((field) => field.validation)
|
|
374
|
-
.filter((v) => v);
|
|
373
|
+
const fieldValidationRules = fields.map((field) => field.validation).filter((v) => v);
|
|
375
374
|
const hasValidationRules = isNil(permission.validation) === false && Object.keys(permission.validation ?? {}).length > 0;
|
|
376
375
|
const hasFieldValidationRules = fieldValidationRules && fieldValidationRules.length > 0;
|
|
377
376
|
const requiredColumns = [];
|
|
378
|
-
for (const field of
|
|
377
|
+
for (const field of fields) {
|
|
379
378
|
const specials = field?.special ?? [];
|
|
380
379
|
const hasGenerateSpecial = GENERATE_SPECIAL.some((name) => specials.includes(name));
|
|
381
380
|
const nullable = field.nullable || hasGenerateSpecial || field.generated;
|
|
@@ -412,7 +411,64 @@ export class AuthorizationService {
|
|
|
412
411
|
}
|
|
413
412
|
}
|
|
414
413
|
const validationErrors = [];
|
|
415
|
-
|
|
414
|
+
const payloadWithPresetsFlattened = clone(payloadWithPresets);
|
|
415
|
+
// In case the object has O2M relations, refactor it's arrays validation can 'count' on them
|
|
416
|
+
const relations = this.schema.relations.filter((relation) => {
|
|
417
|
+
return relation.related_collection === collection;
|
|
418
|
+
});
|
|
419
|
+
// Filter out 02M collections
|
|
420
|
+
const relationsToProcess = relations.filter((relation) => {
|
|
421
|
+
if (!relation.meta?.one_field)
|
|
422
|
+
return false;
|
|
423
|
+
return relation.meta.one_field in payloadWithPresets;
|
|
424
|
+
});
|
|
425
|
+
for (const relation of relationsToProcess) {
|
|
426
|
+
// Nested array of individual items
|
|
427
|
+
const fieldKey = relation.meta.one_field;
|
|
428
|
+
const field = payloadWithPresets[fieldKey];
|
|
429
|
+
if (!field || Array.isArray(field)) {
|
|
430
|
+
// if the field is already an array or is empty we do nothing
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
// Object w/ create/update/delete
|
|
434
|
+
// This is horribly intricated because this functions can apply to many items on updates
|
|
435
|
+
else {
|
|
436
|
+
// lets add object in create and update
|
|
437
|
+
const arrayToValidate = field.create.concat(field.update);
|
|
438
|
+
if (action == 'update') {
|
|
439
|
+
if (typeof keys === 'undefined') {
|
|
440
|
+
throw new UnprocessableEntityException('keys are required when updating an object');
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
// get the number of items already linked to the object
|
|
444
|
+
const mainItemService = new ItemsService(collection, {
|
|
445
|
+
accountability: this.accountability,
|
|
446
|
+
knex: this.knex,
|
|
447
|
+
schema: this.schema,
|
|
448
|
+
});
|
|
449
|
+
const originalItems = await mainItemService.readMany(keys);
|
|
450
|
+
for (let i = 0; i < originalItems.length; i++) {
|
|
451
|
+
const originalItem = originalItems[i];
|
|
452
|
+
const emptyItemsToAdd = originalItem[fieldKey].length - field.update?.length - field.delete?.length;
|
|
453
|
+
const finalArrayToValidate = arrayToValidate.concat(Array(emptyItemsToAdd).fill({}));
|
|
454
|
+
// validate partial items until the last key
|
|
455
|
+
if (i == keys.length - 1) {
|
|
456
|
+
payloadWithPresetsFlattened[fieldKey] = finalArrayToValidate;
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
const partialItemToValidate = { fieldKey: finalArrayToValidate };
|
|
460
|
+
validationErrors.push(...flatten(validatePayload(permission.validation, partialItemToValidate).map((error) => error.details.map((details) => new FailedValidationException(details)))));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
// set the payload to validate as a well formated array
|
|
467
|
+
payloadWithPresetsFlattened[fieldKey] = arrayToValidate;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
validationErrors.push(...flatten(validatePayload(permission.validation, payloadWithPresetsFlattened).map((error) => error.details.map((details) => new FailedValidationException(details)))));
|
|
416
472
|
if (validationErrors.length > 0)
|
|
417
473
|
throw validationErrors;
|
|
418
474
|
return payloadWithPresets;
|
package/dist/services/items.js
CHANGED
|
@@ -105,7 +105,7 @@ export class ItemsService {
|
|
|
105
105
|
})
|
|
106
106
|
: payload;
|
|
107
107
|
const payloadWithPresets = this.accountability
|
|
108
|
-
? authorizationService.validatePayload('create', this.collection, payloadAfterHooks)
|
|
108
|
+
? await authorizationService.validatePayload('create', this.collection, payloadAfterHooks)
|
|
109
109
|
: payloadAfterHooks;
|
|
110
110
|
if (opts.preMutationException) {
|
|
111
111
|
throw opts.preMutationException;
|
|
@@ -451,7 +451,7 @@ export class ItemsService {
|
|
|
451
451
|
await authorizationService.checkAccess('update', this.collection, keys);
|
|
452
452
|
}
|
|
453
453
|
const payloadWithPresets = this.accountability
|
|
454
|
-
? authorizationService.validatePayload('update', this.collection, payloadAfterHooks)
|
|
454
|
+
? await authorizationService.validatePayload('update', this.collection, payloadAfterHooks, keys)
|
|
455
455
|
: payloadAfterHooks;
|
|
456
456
|
if (opts.preMutationException) {
|
|
457
457
|
throw opts.preMutationException;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wbce-d9/api",
|
|
3
|
-
"version": "9.26.
|
|
3
|
+
"version": "9.26.5",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
],
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@authenio/samlify-node-xmllint": "2.0.0",
|
|
67
|
-
"@aws-sdk/client-ses": "3.
|
|
67
|
+
"@aws-sdk/client-ses": "3.363.0",
|
|
68
68
|
"@godaddy/terminus": "4.12.0",
|
|
69
69
|
"@rollup/plugin-alias": "5.0.0",
|
|
70
70
|
"@rollup/plugin-node-resolve": "15.0.2",
|
|
@@ -143,20 +143,20 @@
|
|
|
143
143
|
"uuid-validate": "0.0.3",
|
|
144
144
|
"vm2": "^3.9.19",
|
|
145
145
|
"wellknown": "0.5.0",
|
|
146
|
+
"@wbce-d9/app": "9.26.4",
|
|
147
|
+
"@wbce-d9/constants": "9.26.3",
|
|
146
148
|
"@wbce-d9/exceptions": "9.26.3",
|
|
149
|
+
"@wbce-d9/extensions-sdk": "9.26.4",
|
|
147
150
|
"@wbce-d9/schema": "9.26.3",
|
|
148
151
|
"@wbce-d9/specs": "9.26.3",
|
|
149
|
-
"@wbce-d9/app": "9.26.3",
|
|
150
|
-
"@wbce-d9/constants": "9.26.3",
|
|
151
|
-
"@wbce-d9/extensions-sdk": "9.26.3",
|
|
152
|
-
"@wbce-d9/storage-driver-azure": "9.26.3",
|
|
153
152
|
"@wbce-d9/storage": "9.26.3",
|
|
154
|
-
"@wbce-d9/storage-driver-
|
|
155
|
-
"@wbce-d9/storage-driver-cloudinary": "9.26.
|
|
156
|
-
"@wbce-d9/storage-driver-
|
|
157
|
-
"@wbce-d9/storage-driver-local": "9.26.
|
|
153
|
+
"@wbce-d9/storage-driver-azure": "9.26.4",
|
|
154
|
+
"@wbce-d9/storage-driver-cloudinary": "9.26.4",
|
|
155
|
+
"@wbce-d9/storage-driver-gcs": "9.26.4",
|
|
156
|
+
"@wbce-d9/storage-driver-local": "9.26.4",
|
|
157
|
+
"@wbce-d9/storage-driver-s3": "9.26.5",
|
|
158
158
|
"@wbce-d9/update-check": "9.26.3",
|
|
159
|
-
"@wbce-d9/utils": "9.
|
|
159
|
+
"@wbce-d9/utils": "9.27.0"
|
|
160
160
|
},
|
|
161
161
|
"devDependencies": {
|
|
162
162
|
"@ngneat/falso": "6.4.0",
|