@strapi/strapi 4.5.0 → 4.5.2
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/lib/services/entity-validator/index.js +144 -2
- package/package.json +16 -16
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { uniqBy, castArray, isNil, isArray, mergeWith } = require('lodash');
|
|
9
|
+
const { has, assoc, prop, isObject, isEmpty } = require('lodash/fp');
|
|
9
10
|
const strapiUtils = require('@strapi/utils');
|
|
10
11
|
const validators = require('./validators');
|
|
11
12
|
|
|
@@ -222,10 +223,151 @@ const createValidateEntity =
|
|
|
222
223
|
entity,
|
|
223
224
|
},
|
|
224
225
|
{ isDraft }
|
|
225
|
-
)
|
|
226
|
+
)
|
|
227
|
+
.test('relations-test', 'check that all relations exist', async function (data) {
|
|
228
|
+
try {
|
|
229
|
+
await checkRelationsExist(buildRelationsStore({ uid: model.uid, data }));
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return this.createError({
|
|
232
|
+
path: this.path,
|
|
233
|
+
message: e.message,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
})
|
|
238
|
+
.required();
|
|
239
|
+
|
|
226
240
|
return validateYupSchema(validator, { strict: false, abortEarly: false })(data);
|
|
227
241
|
};
|
|
228
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Builds an object containing all the media and relations being associated with an entity
|
|
245
|
+
* @param {String} uid of the model
|
|
246
|
+
* @param {Object} data
|
|
247
|
+
* @returns {Object}
|
|
248
|
+
*/
|
|
249
|
+
const buildRelationsStore = ({ uid, data }) => {
|
|
250
|
+
if (!uid) {
|
|
251
|
+
throw new ValidationError(`Cannot build relations store: "uid" is undefined`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (isEmpty(data)) {
|
|
255
|
+
return {};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const currentModel = strapi.getModel(uid);
|
|
259
|
+
|
|
260
|
+
return Object.keys(currentModel.attributes).reduce((result, attributeName) => {
|
|
261
|
+
const attribute = currentModel.attributes[attributeName];
|
|
262
|
+
const value = data[attributeName];
|
|
263
|
+
|
|
264
|
+
if (isNil(value)) {
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
switch (attribute.type) {
|
|
269
|
+
case 'relation':
|
|
270
|
+
case 'media': {
|
|
271
|
+
if (attribute.relation === 'morphToMany' || attribute.relation === 'morphToOne') {
|
|
272
|
+
// TODO: handle polymorphic relations
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const target = attribute.type === 'media' ? 'plugin::upload.file' : attribute.target;
|
|
277
|
+
// As there are multiple formats supported for associating relations
|
|
278
|
+
// with an entity, the value here can be an: array, object or number.
|
|
279
|
+
let source;
|
|
280
|
+
if (Array.isArray(value)) {
|
|
281
|
+
source = value;
|
|
282
|
+
} else if (isObject(value)) {
|
|
283
|
+
source = value.connect ?? value.set ?? [];
|
|
284
|
+
} else {
|
|
285
|
+
source = castArray(value);
|
|
286
|
+
}
|
|
287
|
+
const idArray = source.map((v) => ({ id: v.id || v }));
|
|
288
|
+
|
|
289
|
+
// Update the relationStore to keep track of all associations being made
|
|
290
|
+
// with relations and media.
|
|
291
|
+
result[target] = result[target] || [];
|
|
292
|
+
result[target].push(...idArray);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
case 'component': {
|
|
296
|
+
return castArray(value).reduce(
|
|
297
|
+
(relationsStore, componentValue) =>
|
|
298
|
+
mergeWith(
|
|
299
|
+
relationsStore,
|
|
300
|
+
buildRelationsStore({
|
|
301
|
+
uid: attribute.component,
|
|
302
|
+
data: componentValue,
|
|
303
|
+
}),
|
|
304
|
+
(objValue, srcValue) => {
|
|
305
|
+
if (isArray(objValue)) {
|
|
306
|
+
return objValue.concat(srcValue);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
),
|
|
310
|
+
result
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
case 'dynamiczone': {
|
|
314
|
+
return value.reduce(
|
|
315
|
+
(relationsStore, dzValue) =>
|
|
316
|
+
mergeWith(
|
|
317
|
+
relationsStore,
|
|
318
|
+
buildRelationsStore({
|
|
319
|
+
uid: dzValue.__component,
|
|
320
|
+
data: dzValue,
|
|
321
|
+
}),
|
|
322
|
+
(objValue, srcValue) => {
|
|
323
|
+
if (isArray(objValue)) {
|
|
324
|
+
return objValue.concat(srcValue);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
result
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
default:
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return result;
|
|
336
|
+
}, {});
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Iterate through the relations store and validates that every relation or media
|
|
341
|
+
* mentioned exists
|
|
342
|
+
*/
|
|
343
|
+
const checkRelationsExist = async (relationsStore = {}) => {
|
|
344
|
+
const promises = [];
|
|
345
|
+
|
|
346
|
+
for (const [key, value] of Object.entries(relationsStore)) {
|
|
347
|
+
const evaluate = async () => {
|
|
348
|
+
const uniqueValues = uniqBy(value, `id`);
|
|
349
|
+
const count = await strapi.db.query(key).count({
|
|
350
|
+
where: {
|
|
351
|
+
id: {
|
|
352
|
+
$in: uniqueValues.map((v) => v.id),
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
if (count !== uniqueValues.length) {
|
|
358
|
+
throw new ValidationError(
|
|
359
|
+
`${
|
|
360
|
+
uniqueValues.length - count
|
|
361
|
+
} relation(s) of type ${key} associated with this entity do not exist`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
promises.push(evaluate());
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return Promise.all(promises);
|
|
369
|
+
};
|
|
370
|
+
|
|
229
371
|
module.exports = {
|
|
230
372
|
validateEntityCreation: createValidateEntity('creation'),
|
|
231
373
|
validateEntityUpdate: createValidateEntity('update'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/strapi",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -80,23 +80,23 @@
|
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@koa/cors": "3.4.3",
|
|
82
82
|
"@koa/router": "10.1.1",
|
|
83
|
-
"@strapi/admin": "4.5.
|
|
84
|
-
"@strapi/database": "4.5.
|
|
85
|
-
"@strapi/generate-new": "4.5.
|
|
86
|
-
"@strapi/generators": "4.5.
|
|
87
|
-
"@strapi/logger": "4.5.
|
|
88
|
-
"@strapi/permissions": "4.5.
|
|
89
|
-
"@strapi/plugin-content-manager": "4.5.
|
|
90
|
-
"@strapi/plugin-content-type-builder": "4.5.
|
|
91
|
-
"@strapi/plugin-email": "4.5.
|
|
92
|
-
"@strapi/plugin-upload": "4.5.
|
|
93
|
-
"@strapi/typescript-utils": "4.5.
|
|
94
|
-
"@strapi/utils": "4.5.
|
|
83
|
+
"@strapi/admin": "4.5.2",
|
|
84
|
+
"@strapi/database": "4.5.2",
|
|
85
|
+
"@strapi/generate-new": "4.5.2",
|
|
86
|
+
"@strapi/generators": "4.5.2",
|
|
87
|
+
"@strapi/logger": "4.5.2",
|
|
88
|
+
"@strapi/permissions": "4.5.2",
|
|
89
|
+
"@strapi/plugin-content-manager": "4.5.2",
|
|
90
|
+
"@strapi/plugin-content-type-builder": "4.5.2",
|
|
91
|
+
"@strapi/plugin-email": "4.5.2",
|
|
92
|
+
"@strapi/plugin-upload": "4.5.2",
|
|
93
|
+
"@strapi/typescript-utils": "4.5.2",
|
|
94
|
+
"@strapi/utils": "4.5.2",
|
|
95
95
|
"bcryptjs": "2.4.3",
|
|
96
96
|
"boxen": "5.1.2",
|
|
97
97
|
"chalk": "4.1.2",
|
|
98
98
|
"chokidar": "3.5.2",
|
|
99
|
-
"ci-info": "3.
|
|
99
|
+
"ci-info": "3.5.0",
|
|
100
100
|
"cli-table3": "0.6.2",
|
|
101
101
|
"commander": "8.2.0",
|
|
102
102
|
"configstore": "5.0.1",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"package-json": "7.0.0",
|
|
129
129
|
"qs": "6.10.1",
|
|
130
130
|
"resolve-cwd": "3.0.0",
|
|
131
|
-
"semver": "7.3.
|
|
131
|
+
"semver": "7.3.8",
|
|
132
132
|
"statuses": "2.0.1",
|
|
133
133
|
"uuid": "^8.3.2"
|
|
134
134
|
},
|
|
@@ -140,5 +140,5 @@
|
|
|
140
140
|
"node": ">=14.19.1 <=18.x.x",
|
|
141
141
|
"npm": ">=6.0.0"
|
|
142
142
|
},
|
|
143
|
-
"gitHead": "
|
|
143
|
+
"gitHead": "bcb1b7f472aae2556a9b59d59ee66d241c497a3e"
|
|
144
144
|
}
|