@strapi/strapi 4.3.4 → 4.4.0-alpha.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 +1 -1
- package/bin/strapi.js +29 -26
- package/lib/Strapi.js +17 -9
- package/lib/commands/admin-create.js +2 -5
- package/lib/commands/admin-reset.js +1 -1
- package/lib/commands/build.js +1 -1
- package/lib/commands/builders/admin.js +1 -1
- package/lib/commands/builders/typescript.js +2 -2
- package/lib/commands/configurationDump.js +3 -3
- package/lib/commands/configurationRestore.js +5 -4
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +2 -2
- package/lib/commands/controllers/list.js +2 -2
- package/lib/commands/develop.js +16 -10
- package/lib/commands/hooks/list.js +2 -2
- package/lib/commands/install.js +4 -4
- package/lib/commands/middlewares/list.js +2 -2
- package/lib/commands/new.js +1 -1
- package/lib/commands/opt-in-telemetry.js +12 -13
- package/lib/commands/opt-out-telemetry.js +3 -3
- package/lib/commands/policies/list.js +2 -2
- package/lib/commands/routes/list.js +3 -3
- package/lib/commands/services/list.js +2 -2
- package/lib/commands/start.js +1 -0
- package/lib/commands/ts/generate-types.js +1 -1
- package/lib/commands/uninstall.js +4 -4
- package/lib/commands/watchAdmin.js +1 -1
- package/lib/compile.js +1 -1
- package/lib/container.js +1 -1
- package/lib/core/app-configuration/config-loader.js +2 -2
- package/lib/core/app-configuration/load-config-file.js +3 -3
- package/lib/core/bootstrap.js +1 -1
- package/lib/core/domain/component/validator.js +3 -9
- package/lib/core/domain/content-type/index.js +2 -2
- package/lib/core/domain/content-type/validator.js +9 -23
- package/lib/core/domain/module/index.js +1 -1
- package/lib/core/domain/module/validation.js +3 -4
- package/lib/core/loaders/admin.js +1 -1
- package/lib/core/loaders/apis.js +22 -30
- package/lib/core/loaders/components.js +2 -2
- package/lib/core/loaders/middlewares.js +1 -1
- package/lib/core/loaders/plugins/get-enabled-plugins.js +7 -7
- package/lib/core/loaders/plugins/index.js +7 -8
- package/lib/core/loaders/sanitizers.js +1 -1
- package/lib/core/loaders/src-index.js +2 -2
- package/lib/core/registries/apis.js +1 -1
- package/lib/core/registries/config.js +1 -1
- package/lib/core/registries/content-types.js +1 -1
- package/lib/core/registries/custom-fields.js +54 -0
- package/lib/core/registries/modules.js +1 -1
- package/lib/core/registries/plugins.js +1 -1
- package/lib/core/registries/services.js +1 -1
- package/lib/core/utils.js +3 -6
- package/lib/core-api/controller/transform.js +4 -4
- package/lib/core-api/service/collection-type.js +1 -1
- package/lib/core-api/service/index.d.ts +6 -3
- package/lib/core-api/service/pagination.js +5 -5
- package/lib/factories.js +5 -5
- package/lib/load/filepath-to-prop-path.js +2 -2
- package/lib/load/load-files.js +1 -1
- package/lib/load/package-path.js +1 -1
- package/lib/middlewares/body.js +10 -3
- package/lib/middlewares/compression.js +1 -1
- package/lib/middlewares/cors.js +3 -10
- package/lib/middlewares/ip.js +1 -1
- package/lib/middlewares/logger.js +4 -1
- package/lib/middlewares/powered-by.js +1 -1
- package/lib/middlewares/query.js +8 -2
- package/lib/middlewares/response-time.js +1 -1
- package/lib/middlewares/responses.js +1 -1
- package/lib/middlewares/security.js +22 -16
- package/lib/middlewares/session.js +2 -2
- package/lib/migrations/draft-publish.js +1 -5
- package/lib/services/auth/index.js +1 -3
- package/lib/services/core-store.js +4 -4
- package/lib/services/custom-fields.js +11 -0
- package/lib/services/entity-service/components.js +12 -18
- package/lib/services/entity-service/index.js +65 -51
- package/lib/services/entity-validator/index.js +134 -127
- package/lib/services/entity-validator/validators.js +18 -15
- package/lib/services/errors.js +6 -10
- package/lib/services/event-hub.js +1 -0
- package/lib/services/fs.js +1 -1
- package/lib/services/metrics/index.js +6 -9
- package/lib/services/metrics/is-truthy.js +1 -1
- package/lib/services/metrics/sender.js +4 -4
- package/lib/services/metrics/stringify-deep.js +1 -1
- package/lib/services/server/admin-api.js +1 -1
- package/lib/services/server/compose-endpoint.js +7 -7
- package/lib/services/server/content-api.js +1 -1
- package/lib/services/server/http-server.js +9 -9
- package/lib/services/server/index.js +4 -4
- package/lib/services/server/koa.js +9 -12
- package/lib/services/server/middleware.js +1 -1
- package/lib/services/server/policy.js +1 -1
- package/lib/services/server/register-middlewares.js +6 -8
- package/lib/services/server/register-routes.js +11 -11
- package/lib/services/server/routing.js +11 -26
- package/lib/services/utils/upload-files.js +3 -3
- package/lib/services/webhook-runner.js +8 -7
- package/lib/services/webhook-store.js +3 -2
- package/lib/services/worker-queue.js +1 -0
- package/lib/types/core/strapi/index.d.ts +4 -3
- package/lib/types/factories.d.ts +3 -3
- package/lib/utils/addSlash.js +3 -3
- package/lib/utils/convert-custom-field-type.js +22 -0
- package/lib/utils/ee.js +1 -1
- package/lib/utils/import-default.js +1 -1
- package/lib/utils/open-browser.js +1 -1
- package/lib/utils/run-checks.js +4 -4
- package/lib/utils/signals.js +2 -2
- package/lib/utils/startup-logger.js +2 -2
- package/lib/utils/success.js +1 -1
- package/lib/utils/update-notifier/index.js +4 -4
- package/package.json +15 -15
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const delegate = require('delegates');
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
InvalidDateError,
|
|
8
|
-
InvalidDateTimeError,
|
|
9
|
-
} = require('@strapi/database').errors;
|
|
5
|
+
const { InvalidTimeError, InvalidDateError, InvalidDateTimeError } =
|
|
6
|
+
require('@strapi/database').errors;
|
|
10
7
|
const {
|
|
11
8
|
webhook: webhookUtils,
|
|
12
9
|
contentTypes: contentTypesUtils,
|
|
@@ -37,51 +34,6 @@ const updatePipeline = (data, context) => {
|
|
|
37
34
|
return applyTransforms(data, context);
|
|
38
35
|
};
|
|
39
36
|
|
|
40
|
-
module.exports = ctx => {
|
|
41
|
-
const implementation = createDefaultImplementation(ctx);
|
|
42
|
-
|
|
43
|
-
const service = {
|
|
44
|
-
implementation,
|
|
45
|
-
decorate(decorator) {
|
|
46
|
-
if (typeof decorator !== 'function') {
|
|
47
|
-
throw new Error(`Decorator must be a function, received ${typeof decorator}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.implementation = Object.assign({}, this.implementation, decorator(this.implementation));
|
|
51
|
-
return this;
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const delegator = delegate(service, 'implementation');
|
|
56
|
-
|
|
57
|
-
// delegate every method in implementation
|
|
58
|
-
Object.keys(service.implementation).forEach(key => delegator.method(key));
|
|
59
|
-
|
|
60
|
-
// wrap methods to handle Database Errors
|
|
61
|
-
service.decorate(oldService => {
|
|
62
|
-
const newService = _.mapValues(
|
|
63
|
-
oldService,
|
|
64
|
-
(method, methodName) =>
|
|
65
|
-
async function(...args) {
|
|
66
|
-
try {
|
|
67
|
-
return await oldService[methodName].call(this, ...args);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
if (
|
|
70
|
-
databaseErrorsToTransform.some(errorToTransform => error instanceof errorToTransform)
|
|
71
|
-
) {
|
|
72
|
-
throw new ValidationError(error.message);
|
|
73
|
-
}
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
return newService;
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return service;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
37
|
/**
|
|
86
38
|
* @type {import('.').default}
|
|
87
39
|
*/
|
|
@@ -276,7 +228,19 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
276
228
|
// select / populate
|
|
277
229
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
278
230
|
|
|
279
|
-
|
|
231
|
+
const entitiesToDelete = await db.query(uid).findMany(query);
|
|
232
|
+
|
|
233
|
+
if (!entitiesToDelete.length) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const deletedEntities = await db.query(uid).deleteMany(query);
|
|
238
|
+
await Promise.all(entitiesToDelete.map((entity) => deleteComponents(uid, entity)));
|
|
239
|
+
|
|
240
|
+
// Trigger webhooks. One for each entity
|
|
241
|
+
await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity)));
|
|
242
|
+
|
|
243
|
+
return deletedEntities;
|
|
280
244
|
},
|
|
281
245
|
|
|
282
246
|
load(uid, entity, field, params = {}) {
|
|
@@ -303,8 +267,58 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
303
267
|
Object.assign(loadParams, transformParamsToQuery('plugin::upload.file', params));
|
|
304
268
|
break;
|
|
305
269
|
}
|
|
270
|
+
default: {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
306
273
|
}
|
|
307
274
|
|
|
308
275
|
return db.query(uid).load(entity, field, loadParams);
|
|
309
276
|
},
|
|
310
277
|
});
|
|
278
|
+
|
|
279
|
+
module.exports = (ctx) => {
|
|
280
|
+
const implementation = createDefaultImplementation(ctx);
|
|
281
|
+
|
|
282
|
+
const service = {
|
|
283
|
+
implementation,
|
|
284
|
+
decorate(decorator) {
|
|
285
|
+
if (typeof decorator !== 'function') {
|
|
286
|
+
throw new Error(`Decorator must be a function, received ${typeof decorator}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
this.implementation = { ...this.implementation, ...decorator(this.implementation) };
|
|
290
|
+
return this;
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const delegator = delegate(service, 'implementation');
|
|
295
|
+
|
|
296
|
+
// delegate every method in implementation
|
|
297
|
+
Object.keys(service.implementation).forEach((key) => delegator.method(key));
|
|
298
|
+
|
|
299
|
+
// wrap methods to handle Database Errors
|
|
300
|
+
service.decorate((oldService) => {
|
|
301
|
+
const newService = _.mapValues(
|
|
302
|
+
oldService,
|
|
303
|
+
(method, methodName) =>
|
|
304
|
+
async function (...args) {
|
|
305
|
+
try {
|
|
306
|
+
return await oldService[methodName].call(this, ...args);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (
|
|
309
|
+
databaseErrorsToTransform.some(
|
|
310
|
+
(errorToTransform) => error instanceof errorToTransform
|
|
311
|
+
)
|
|
312
|
+
) {
|
|
313
|
+
throw new ValidationError(error.message);
|
|
314
|
+
}
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
return newService;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
return service;
|
|
324
|
+
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Entity validator
|
|
3
3
|
* Module that will validate input data for entity creation or edition
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
'use strict';
|
|
6
7
|
|
|
7
8
|
const { has, assoc, prop, isObject } = require('lodash/fp');
|
|
@@ -25,110 +26,117 @@ const addMinMax = (validator, { attr, updatedAttribute }) => {
|
|
|
25
26
|
return validator;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
const addRequiredValidation =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
const addRequiredValidation =
|
|
30
|
+
(createOrUpdate) =>
|
|
31
|
+
(validator, { attr: { required } }) => {
|
|
32
|
+
if (required) {
|
|
33
|
+
if (createOrUpdate === 'creation') {
|
|
34
|
+
validator = validator.notNil();
|
|
35
|
+
} else if (createOrUpdate === 'update') {
|
|
36
|
+
validator = validator.notNull();
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
validator = validator.nullable();
|
|
34
40
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
return validator;
|
|
39
|
-
};
|
|
41
|
+
return validator;
|
|
42
|
+
};
|
|
40
43
|
|
|
41
|
-
const addDefault =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const addDefault =
|
|
45
|
+
(createOrUpdate) =>
|
|
46
|
+
(validator, { attr }) => {
|
|
47
|
+
if (createOrUpdate === 'creation') {
|
|
48
|
+
if (
|
|
49
|
+
((attr.type === 'component' && attr.repeatable) || attr.type === 'dynamiczone') &&
|
|
50
|
+
!attr.required
|
|
51
|
+
) {
|
|
52
|
+
validator = validator.default([]);
|
|
53
|
+
} else {
|
|
54
|
+
validator = validator.default(attr.default);
|
|
55
|
+
}
|
|
48
56
|
} else {
|
|
49
|
-
validator = validator.default(
|
|
57
|
+
validator = validator.default(undefined);
|
|
50
58
|
}
|
|
51
|
-
} else {
|
|
52
|
-
validator = validator.default(undefined);
|
|
53
|
-
}
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
};
|
|
60
|
+
return validator;
|
|
61
|
+
};
|
|
57
62
|
|
|
58
|
-
const preventCast = validator => validator.transform((val, originalVal) => originalVal);
|
|
63
|
+
const preventCast = (validator) => validator.transform((val, originalVal) => originalVal);
|
|
59
64
|
|
|
60
|
-
const createComponentValidator =
|
|
61
|
-
|
|
65
|
+
const createComponentValidator =
|
|
66
|
+
(createOrUpdate) =>
|
|
67
|
+
({ attr, updatedAttribute }, { isDraft }) => {
|
|
68
|
+
let validator;
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
const model = strapi.getModel(attr.component);
|
|
71
|
+
if (!model) {
|
|
72
|
+
throw new Error('Validation failed: Model not found');
|
|
73
|
+
}
|
|
67
74
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
if (prop('repeatable', attr) === true) {
|
|
76
|
+
validator = yup
|
|
77
|
+
.array()
|
|
78
|
+
.of(
|
|
79
|
+
yup.lazy((item) =>
|
|
80
|
+
createModelValidator(createOrUpdate)({ model, data: item }, { isDraft }).notNull()
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
validator = addRequiredValidation(createOrUpdate)(validator, { attr: { required: true } });
|
|
84
|
+
validator = addMinMax(validator, { attr, updatedAttribute });
|
|
85
|
+
} else {
|
|
86
|
+
validator = createModelValidator(createOrUpdate)({ model, updatedAttribute }, { isDraft });
|
|
87
|
+
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
88
|
+
attr: { required: !isDraft && attr.required },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return validator;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const createDzValidator =
|
|
96
|
+
(createOrUpdate) =>
|
|
97
|
+
({ attr, updatedAttribute }, { isDraft }) => {
|
|
98
|
+
let validator;
|
|
99
|
+
|
|
100
|
+
validator = yup.array().of(
|
|
101
|
+
yup.lazy((item) => {
|
|
102
|
+
const model = strapi.getModel(prop('__component', item));
|
|
103
|
+
const schema = yup
|
|
104
|
+
.object()
|
|
105
|
+
.shape({
|
|
106
|
+
__component: yup.string().required().oneOf(Object.keys(strapi.components)),
|
|
107
|
+
})
|
|
108
|
+
.notNull();
|
|
109
|
+
|
|
110
|
+
return model
|
|
111
|
+
? schema.concat(createModelValidator(createOrUpdate)({ model, data: item }, { isDraft }))
|
|
112
|
+
: schema;
|
|
113
|
+
})
|
|
114
|
+
);
|
|
76
115
|
validator = addRequiredValidation(createOrUpdate)(validator, { attr: { required: true } });
|
|
77
116
|
validator = addMinMax(validator, { attr, updatedAttribute });
|
|
78
|
-
} else {
|
|
79
|
-
validator = createModelValidator(createOrUpdate)({ model, updatedAttribute }, { isDraft });
|
|
80
|
-
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
81
|
-
attr: { required: !isDraft && attr.required },
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return validator;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const createDzValidator = createOrUpdate => ({ attr, updatedAttribute }, { isDraft }) => {
|
|
89
|
-
let validator;
|
|
90
|
-
|
|
91
|
-
validator = yup.array().of(
|
|
92
|
-
yup.lazy(item => {
|
|
93
|
-
const model = strapi.getModel(prop('__component', item));
|
|
94
|
-
const schema = yup
|
|
95
|
-
.object()
|
|
96
|
-
.shape({
|
|
97
|
-
__component: yup
|
|
98
|
-
.string()
|
|
99
|
-
.required()
|
|
100
|
-
.oneOf(Object.keys(strapi.components)),
|
|
101
|
-
})
|
|
102
|
-
.notNull();
|
|
103
|
-
|
|
104
|
-
return model
|
|
105
|
-
? schema.concat(createModelValidator(createOrUpdate)({ model, data: item }, { isDraft }))
|
|
106
|
-
: schema;
|
|
107
|
-
})
|
|
108
|
-
);
|
|
109
|
-
validator = addRequiredValidation(createOrUpdate)(validator, { attr: { required: true } });
|
|
110
|
-
validator = addMinMax(validator, { attr, updatedAttribute });
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
};
|
|
118
|
+
return validator;
|
|
119
|
+
};
|
|
114
120
|
|
|
115
|
-
const createRelationValidator =
|
|
116
|
-
|
|
121
|
+
const createRelationValidator =
|
|
122
|
+
(createOrUpdate) =>
|
|
123
|
+
({ attr, updatedAttribute }, { isDraft }) => {
|
|
124
|
+
let validator;
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
if (Array.isArray(updatedAttribute.value)) {
|
|
127
|
+
validator = yup.array().of(yup.mixed());
|
|
128
|
+
} else {
|
|
129
|
+
validator = yup.mixed();
|
|
130
|
+
}
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
133
|
+
attr: { required: !isDraft && attr.required },
|
|
134
|
+
});
|
|
127
135
|
|
|
128
|
-
|
|
129
|
-
};
|
|
136
|
+
return validator;
|
|
137
|
+
};
|
|
130
138
|
|
|
131
|
-
const createScalarAttributeValidator = createOrUpdate => (metas, options) => {
|
|
139
|
+
const createScalarAttributeValidator = (createOrUpdate) => (metas, options) => {
|
|
132
140
|
let validator;
|
|
133
141
|
|
|
134
142
|
if (has(metas.attr.type, validators)) {
|
|
@@ -145,7 +153,7 @@ const createScalarAttributeValidator = createOrUpdate => (metas, options) => {
|
|
|
145
153
|
return validator;
|
|
146
154
|
};
|
|
147
155
|
|
|
148
|
-
const createAttributeValidator = createOrUpdate => (metas, options) => {
|
|
156
|
+
const createAttributeValidator = (createOrUpdate) => (metas, options) => {
|
|
149
157
|
let validator;
|
|
150
158
|
|
|
151
159
|
if (isMediaAttribute(metas.attr)) {
|
|
@@ -169,50 +177,49 @@ const createAttributeValidator = createOrUpdate => (metas, options) => {
|
|
|
169
177
|
return validator;
|
|
170
178
|
};
|
|
171
179
|
|
|
172
|
-
const createModelValidator =
|
|
173
|
-
|
|
180
|
+
const createModelValidator =
|
|
181
|
+
(createOrUpdate) =>
|
|
182
|
+
({ model, data, entity }, options) => {
|
|
183
|
+
const writableAttributes = model ? getWritableAttributes(model) : [];
|
|
184
|
+
|
|
185
|
+
const schema = writableAttributes.reduce((validators, attributeName) => {
|
|
186
|
+
const validator = createAttributeValidator(createOrUpdate)(
|
|
187
|
+
{
|
|
188
|
+
attr: model.attributes[attributeName],
|
|
189
|
+
updatedAttribute: { name: attributeName, value: prop(attributeName, data) },
|
|
190
|
+
model,
|
|
191
|
+
entity,
|
|
192
|
+
},
|
|
193
|
+
options
|
|
194
|
+
);
|
|
174
195
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
attr: model.attributes[attributeName],
|
|
179
|
-
updatedAttribute: { name: attributeName, value: prop(attributeName, data) },
|
|
180
|
-
model,
|
|
181
|
-
entity,
|
|
182
|
-
},
|
|
183
|
-
options
|
|
184
|
-
);
|
|
196
|
+
return assoc(attributeName, validator)(validators);
|
|
197
|
+
}, {});
|
|
185
198
|
|
|
186
|
-
return
|
|
187
|
-
}
|
|
199
|
+
return yup.object().shape(schema);
|
|
200
|
+
};
|
|
188
201
|
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
const createValidateEntity =
|
|
203
|
+
(createOrUpdate) =>
|
|
204
|
+
async (model, data, { isDraft = false } = {}, entity = null) => {
|
|
205
|
+
if (!isObject(data)) {
|
|
206
|
+
const { displayName } = model.info;
|
|
191
207
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
entity = null
|
|
197
|
-
) => {
|
|
198
|
-
if (!isObject(data)) {
|
|
199
|
-
const { displayName } = model.info;
|
|
200
|
-
|
|
201
|
-
throw new ValidationError(
|
|
202
|
-
`Invalid payload submitted for the ${createOrUpdate} of an entity of type ${displayName}. Expected an object, but got ${typeof data}`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
208
|
+
throw new ValidationError(
|
|
209
|
+
`Invalid payload submitted for the ${createOrUpdate} of an entity of type ${displayName}. Expected an object, but got ${typeof data}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
205
212
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
};
|
|
213
|
+
const validator = createModelValidator(createOrUpdate)(
|
|
214
|
+
{
|
|
215
|
+
model,
|
|
216
|
+
data,
|
|
217
|
+
entity,
|
|
218
|
+
},
|
|
219
|
+
{ isDraft }
|
|
220
|
+
).required();
|
|
221
|
+
return validateYupSchema(validator, { strict: false, abortEarly: false })(data);
|
|
222
|
+
};
|
|
216
223
|
|
|
217
224
|
module.exports = {
|
|
218
225
|
validateEntityCreation: createValidateEntity('creation'),
|
|
@@ -13,17 +13,20 @@ const { yup } = require('@strapi/utils');
|
|
|
13
13
|
/**
|
|
14
14
|
* Utility function to compose validators
|
|
15
15
|
*/
|
|
16
|
-
const composeValidators =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
const composeValidators =
|
|
17
|
+
(...fns) =>
|
|
18
|
+
(...args) => {
|
|
19
|
+
let nextArgs = args;
|
|
20
|
+
let validator = yup.mixed();
|
|
21
|
+
|
|
22
|
+
// if we receive a schema then use it as base schema for nested composition
|
|
23
|
+
if (yup.isSchema(args[0])) {
|
|
24
|
+
validator = args[0];
|
|
25
|
+
nextArgs = args.slice(1);
|
|
26
|
+
}
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
};
|
|
28
|
+
return fns.reduce((validator, fn) => fn(validator, ...nextArgs), validator);
|
|
29
|
+
};
|
|
27
30
|
|
|
28
31
|
/* Validator utils */
|
|
29
32
|
|
|
@@ -124,7 +127,7 @@ const addUniqueValidator = (validator, { attr, model, updatedAttribute, entity }
|
|
|
124
127
|
return validator;
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
return validator.test('unique', 'This attribute must be unique', async value => {
|
|
130
|
+
return validator.test('unique', 'This attribute must be unique', async (value) => {
|
|
128
131
|
/**
|
|
129
132
|
* If the attribute value is `null` we want to skip the unique validation.
|
|
130
133
|
* Otherwise it'll only accept a single `null` entry in the database.
|
|
@@ -143,7 +146,7 @@ const addUniqueValidator = (validator, { attr, model, updatedAttribute, entity }
|
|
|
143
146
|
return true;
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
|
|
149
|
+
const whereParams = entity
|
|
147
150
|
? { $and: [{ [updatedAttribute.name]: value }, { $not: { id: entity.id } }] }
|
|
148
151
|
: { [updatedAttribute.name]: value };
|
|
149
152
|
|
|
@@ -166,12 +169,12 @@ const stringValidator = composeValidators(
|
|
|
166
169
|
addUniqueValidator
|
|
167
170
|
);
|
|
168
171
|
|
|
169
|
-
const emailValidator = composeValidators(stringValidator, validator =>
|
|
172
|
+
const emailValidator = composeValidators(stringValidator, (validator) =>
|
|
170
173
|
validator.email().min(1, '${path} cannot be empty')
|
|
171
174
|
);
|
|
172
175
|
|
|
173
|
-
const uidValidator = composeValidators(stringValidator, validator =>
|
|
174
|
-
validator.matches(
|
|
176
|
+
const uidValidator = composeValidators(stringValidator, (validator) =>
|
|
177
|
+
validator.matches(/^[A-Za-z0-9-_.~]*$/)
|
|
175
178
|
);
|
|
176
179
|
|
|
177
180
|
const enumerationValidator = ({ attr }) => {
|
package/lib/services/errors.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const createError = require('http-errors');
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
UnauthorizedError,
|
|
7
|
-
ForbiddenError,
|
|
8
|
-
PayloadTooLargeError,
|
|
9
|
-
} = require('@strapi/utils').errors;
|
|
4
|
+
const { NotFoundError, UnauthorizedError, ForbiddenError, PayloadTooLargeError } =
|
|
5
|
+
require('@strapi/utils').errors;
|
|
10
6
|
|
|
11
7
|
const mapErrorsAndStatus = [
|
|
12
8
|
{
|
|
@@ -27,8 +23,8 @@ const mapErrorsAndStatus = [
|
|
|
27
23
|
},
|
|
28
24
|
];
|
|
29
25
|
|
|
30
|
-
const formatApplicationError = error => {
|
|
31
|
-
const errorAndStatus = mapErrorsAndStatus.find(pair => error instanceof pair.classError);
|
|
26
|
+
const formatApplicationError = (error) => {
|
|
27
|
+
const errorAndStatus = mapErrorsAndStatus.find((pair) => error instanceof pair.classError);
|
|
32
28
|
const status = errorAndStatus ? errorAndStatus.status : 400;
|
|
33
29
|
|
|
34
30
|
return {
|
|
@@ -45,7 +41,7 @@ const formatApplicationError = error => {
|
|
|
45
41
|
};
|
|
46
42
|
};
|
|
47
43
|
|
|
48
|
-
const formatHttpError = error => {
|
|
44
|
+
const formatHttpError = (error) => {
|
|
49
45
|
return {
|
|
50
46
|
status: error.status,
|
|
51
47
|
body: {
|
|
@@ -60,7 +56,7 @@ const formatHttpError = error => {
|
|
|
60
56
|
};
|
|
61
57
|
};
|
|
62
58
|
|
|
63
|
-
const formatInternalError = error => {
|
|
59
|
+
const formatInternalError = (error) => {
|
|
64
60
|
const httpError = createError(error);
|
|
65
61
|
|
|
66
62
|
if (httpError.expose) {
|
package/lib/services/fs.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* Strapi telemetry package.
|
|
4
5
|
* You can learn more at https://docs.strapi.io/developer-docs/latest/getting-started/usage-information.html
|
|
@@ -22,7 +23,7 @@ const LIMITED_EVENTS = [
|
|
|
22
23
|
'didEnableResponsiveDimensions',
|
|
23
24
|
];
|
|
24
25
|
|
|
25
|
-
const createTelemetryInstance = strapi => {
|
|
26
|
+
const createTelemetryInstance = (strapi) => {
|
|
26
27
|
const uuid = strapi.config.get('uuid');
|
|
27
28
|
const telemetryDisabled = strapi.config.get('packageJsonStrapi.telemetryDisabled');
|
|
28
29
|
const isDisabled =
|
|
@@ -76,7 +77,7 @@ const createTelemetryInstance = strapi => {
|
|
|
76
77
|
},
|
|
77
78
|
destroy() {
|
|
78
79
|
// clear open handles
|
|
79
|
-
crons.forEach(cron => cron.cancel());
|
|
80
|
+
crons.forEach((cron) => cron.cancel());
|
|
80
81
|
},
|
|
81
82
|
async send(event, payload) {
|
|
82
83
|
if (isDisabled) return true;
|
|
@@ -85,16 +86,12 @@ const createTelemetryInstance = strapi => {
|
|
|
85
86
|
};
|
|
86
87
|
};
|
|
87
88
|
|
|
88
|
-
const hash = str =>
|
|
89
|
-
crypto
|
|
90
|
-
.createHash('sha256')
|
|
91
|
-
.update(str)
|
|
92
|
-
.digest('hex');
|
|
89
|
+
const hash = (str) => crypto.createHash('sha256').update(str).digest('hex');
|
|
93
90
|
|
|
94
|
-
const hashProject = strapi =>
|
|
91
|
+
const hashProject = (strapi) =>
|
|
95
92
|
hash(`${strapi.config.get('info.name')}${strapi.config.get('info.description')}`);
|
|
96
93
|
|
|
97
|
-
const hashDep = strapi => {
|
|
94
|
+
const hashDep = (strapi) => {
|
|
98
95
|
const depStr = JSON.stringify(strapi.config.info.dependencies);
|
|
99
96
|
const readmePath = path.join(strapi.dirs.app.root, 'README.md');
|
|
100
97
|
|
|
@@ -33,7 +33,7 @@ const addPackageJsonStrapiMetadata = (metadata, strapi) => {
|
|
|
33
33
|
* @param {Object} strapi strapi app
|
|
34
34
|
* @returns {Function} (event, payload) -> Promise{boolean}
|
|
35
35
|
*/
|
|
36
|
-
module.exports = strapi => {
|
|
36
|
+
module.exports = (strapi) => {
|
|
37
37
|
const { uuid } = strapi.config;
|
|
38
38
|
const deviceId = machineID();
|
|
39
39
|
const isEE = strapi.EE === true && ee.isEE === true;
|
|
@@ -41,7 +41,7 @@ module.exports = strapi => {
|
|
|
41
41
|
const serverRootPath = strapi.dirs.app.root;
|
|
42
42
|
const adminRootPath = path.join(strapi.dirs.app.root, 'src', 'admin');
|
|
43
43
|
|
|
44
|
-
const
|
|
44
|
+
const anonymousMetadata = {
|
|
45
45
|
environment: strapi.config.environment,
|
|
46
46
|
os: os.type(),
|
|
47
47
|
osPlatform: os.platform(),
|
|
@@ -56,7 +56,7 @@ module.exports = strapi => {
|
|
|
56
56
|
useTypescriptOnAdmin: isUsingTypeScriptSync(adminRootPath),
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
addPackageJsonStrapiMetadata(
|
|
59
|
+
addPackageJsonStrapiMetadata(anonymousMetadata, strapi);
|
|
60
60
|
|
|
61
61
|
return async (event, payload = {}, opts = {}) => {
|
|
62
62
|
const reqParams = {
|
|
@@ -67,7 +67,7 @@ module.exports = strapi => {
|
|
|
67
67
|
deviceId,
|
|
68
68
|
properties: stringifyDeep({
|
|
69
69
|
...payload,
|
|
70
|
-
...
|
|
70
|
+
...anonymousMetadata,
|
|
71
71
|
}),
|
|
72
72
|
}),
|
|
73
73
|
..._.merge({}, defaultQueryOpts, opts),
|
|
@@ -7,7 +7,7 @@ const { map, mapValues, isObject, isArray, toString } = require('lodash/fp');
|
|
|
7
7
|
* @param {object} obj
|
|
8
8
|
* @returns {object}
|
|
9
9
|
*/
|
|
10
|
-
const stringifyDeep = value => {
|
|
10
|
+
const stringifyDeep = (value) => {
|
|
11
11
|
if (isArray(value)) {
|
|
12
12
|
return map(stringifyDeep, value);
|
|
13
13
|
}
|