@strapi/strapi 4.0.0-next.6 → 4.0.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 +12 -12
- package/bin/strapi.js +41 -60
- package/lib/Strapi.js +234 -114
- package/lib/commands/build.js +16 -6
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/develop.js +17 -18
- package/lib/commands/generate-template.js +4 -5
- package/lib/commands/hooks/list.js +22 -0
- package/lib/commands/middlewares/list.js +22 -0
- package/lib/commands/new.js +3 -1
- package/lib/commands/policies/list.js +22 -0
- package/lib/commands/routes/list.js +28 -0
- package/lib/commands/services/list.js +22 -0
- package/lib/commands/watchAdmin.js +18 -8
- package/lib/container.js +6 -6
- package/lib/core/app-configuration/config-loader.js +1 -37
- package/lib/core/app-configuration/index.js +6 -46
- package/lib/core/app-configuration/load-config-file.js +43 -0
- package/lib/core/bootstrap.js +5 -117
- package/lib/core/domain/component/index.js +24 -0
- package/lib/core/domain/component/validator.js +29 -0
- package/lib/core/domain/content-type/index.js +140 -0
- package/lib/core/domain/content-type/validator.js +64 -0
- package/lib/core/domain/module/index.js +108 -0
- package/lib/core/domain/module/validation.js +33 -0
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +159 -0
- package/lib/core/{load-components.js → loaders/components.js} +5 -7
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +36 -0
- package/lib/core/loaders/plugins/get-enabled-plugins.js +116 -0
- package/lib/core/loaders/plugins/index.js +123 -0
- package/lib/core/loaders/policies.js +28 -0
- package/lib/core/loaders/src-index.js +39 -0
- package/lib/core/registries/apis.js +29 -0
- package/lib/core/{app-configuration/config-provider.js → registries/config.js} +4 -11
- package/lib/core/registries/content-types.js +97 -0
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +114 -0
- package/lib/core/registries/hooks.d.ts +20 -0
- package/lib/core/registries/hooks.js +87 -0
- package/lib/core/registries/middlewares.d.ts +5 -0
- package/lib/core/registries/middlewares.js +89 -0
- package/lib/core/registries/modules.js +44 -0
- package/lib/core/registries/plugins.js +28 -0
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +89 -0
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +114 -0
- package/lib/core/utils.js +35 -0
- package/lib/core-api/controller/collection-type.js +45 -26
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +33 -11
- package/lib/core-api/controller/single-type.js +29 -15
- package/lib/core-api/controller/transform.js +62 -6
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +43 -21
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +8 -67
- package/lib/core-api/service/pagination.js +130 -0
- package/lib/core-api/service/single-type.js +17 -19
- package/lib/factories.d.ts +48 -0
- package/lib/factories.js +84 -0
- package/lib/index.d.ts +10 -31
- package/lib/index.js +5 -1
- package/lib/middlewares/body.js +33 -0
- package/lib/middlewares/compression.js +8 -0
- package/lib/middlewares/cors.js +58 -0
- package/lib/middlewares/errors.js +40 -0
- package/lib/middlewares/favicon.js +19 -0
- package/lib/middlewares/index.d.ts +5 -0
- package/lib/middlewares/index.js +30 -117
- package/lib/middlewares/ip.js +8 -0
- package/lib/middlewares/logger.js +27 -0
- package/lib/middlewares/powered-by.js +20 -0
- package/lib/middlewares/public/index.js +98 -73
- package/lib/middlewares/query.js +46 -0
- package/lib/middlewares/response-time.js +15 -0
- package/lib/middlewares/responses.js +19 -0
- package/lib/middlewares/security.js +51 -0
- package/lib/middlewares/session/index.js +6 -6
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +87 -0
- package/lib/services/core-store.js +64 -51
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/attributes/index.js +31 -0
- package/lib/services/entity-service/attributes/transforms.js +20 -0
- package/lib/services/entity-service/components.js +39 -15
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +120 -59
- package/lib/services/entity-service/params.js +52 -94
- package/lib/services/entity-validator/index.js +76 -43
- package/lib/services/entity-validator/validators.js +129 -43
- package/lib/services/errors.js +77 -0
- package/lib/{core → services}/fs.js +10 -2
- package/lib/services/metrics/index.js +41 -38
- package/lib/services/metrics/sender.js +2 -2
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +36 -0
- package/lib/services/server/compose-endpoint.js +141 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/{server.js → services/server/http-server.js} +0 -0
- package/lib/services/server/index.js +127 -0
- package/lib/services/server/koa.js +64 -0
- package/lib/services/server/middleware.js +122 -0
- package/lib/services/server/policy.js +32 -0
- package/lib/services/server/register-middlewares.js +110 -0
- package/lib/services/server/register-routes.js +106 -0
- package/lib/services/server/routing.js +120 -0
- package/lib/services/utils/upload-files.js +1 -1
- package/lib/services/webhook-runner.js +1 -1
- package/lib/utils/ee.js +3 -3
- package/lib/utils/get-dirs.js +17 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/is-initialized.js +1 -1
- package/lib/utils/run-checks.js +0 -15
- package/lib/utils/signals.js +24 -0
- package/lib/utils/startup-logger.js +2 -2
- package/lib/utils/update-notifier/index.js +3 -2
- package/package.json +93 -96
- package/lib/commands/generate.js +0 -76
- package/lib/core/index.js +0 -17
- package/lib/core/load-apis.js +0 -20
- package/lib/core/load-extensions.js +0 -71
- package/lib/core/load-functions.js +0 -21
- package/lib/core/load-middlewares.js +0 -130
- package/lib/core/load-modules.js +0 -55
- package/lib/core/load-plugins.js +0 -68
- package/lib/core/load-policies.js +0 -36
- package/lib/core/walk.js +0 -27
- package/lib/core-api/index.js +0 -39
- package/lib/load/check-reserved-filename.js +0 -10
- package/lib/load/load-config-files.js +0 -22
- package/lib/load/require-file-parse.js +0 -15
- package/lib/middlewares/boom/defaults.json +0 -5
- package/lib/middlewares/boom/index.js +0 -147
- package/lib/middlewares/cors/index.js +0 -66
- package/lib/middlewares/cron/defaults.json +0 -5
- package/lib/middlewares/cron/index.js +0 -43
- package/lib/middlewares/favicon/defaults.json +0 -7
- package/lib/middlewares/favicon/index.js +0 -32
- package/lib/middlewares/gzip/defaults.json +0 -6
- package/lib/middlewares/gzip/index.js +0 -19
- package/lib/middlewares/helmet/defaults.json +0 -18
- package/lib/middlewares/helmet/index.js +0 -9
- package/lib/middlewares/ip/defaults.json +0 -7
- package/lib/middlewares/ip/index.js +0 -25
- package/lib/middlewares/language/defaults.json +0 -9
- package/lib/middlewares/language/index.js +0 -40
- package/lib/middlewares/logger/defaults.json +0 -5
- package/lib/middlewares/logger/index.js +0 -37
- package/lib/middlewares/parser/defaults.json +0 -11
- package/lib/middlewares/parser/index.js +0 -71
- package/lib/middlewares/poweredBy/defaults.json +0 -5
- package/lib/middlewares/poweredBy/index.js +0 -16
- package/lib/middlewares/public/defaults.json +0 -8
- package/lib/middlewares/responseTime/defaults.json +0 -5
- package/lib/middlewares/responseTime/index.js +0 -25
- package/lib/middlewares/responses/defaults.json +0 -5
- package/lib/middlewares/responses/index.js +0 -18
- package/lib/middlewares/router/defaults.json +0 -7
- package/lib/middlewares/router/index.js +0 -64
- package/lib/middlewares/router/utils/composeEndpoint.js +0 -25
- package/lib/middlewares/router/utils/routerChecker.js +0 -92
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { isObject } = require('lodash/fp');
|
|
4
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
5
|
+
|
|
6
|
+
const { parseBody } = require('./transform');
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Returns a single type controller to handle default core-api actions
|
|
7
10
|
*/
|
|
8
|
-
const createSingleTypeController = ({
|
|
11
|
+
const createSingleTypeController = ({ contentType }) => {
|
|
12
|
+
const { uid } = contentType;
|
|
13
|
+
|
|
9
14
|
return {
|
|
10
15
|
/**
|
|
11
16
|
* Retrieve single type content
|
|
@@ -14,8 +19,11 @@ const createSingleTypeController = ({ service, parseMultipartData, sanitize }) =
|
|
|
14
19
|
*/
|
|
15
20
|
async find(ctx) {
|
|
16
21
|
const { query } = ctx;
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
|
|
23
|
+
const entity = await strapi.service(uid).find(query);
|
|
24
|
+
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
|
|
25
|
+
|
|
26
|
+
return this.transformResponse(sanitizedEntity);
|
|
19
27
|
},
|
|
20
28
|
|
|
21
29
|
/**
|
|
@@ -24,24 +32,30 @@ const createSingleTypeController = ({ service, parseMultipartData, sanitize }) =
|
|
|
24
32
|
* @return {Object}
|
|
25
33
|
*/
|
|
26
34
|
async update(ctx) {
|
|
27
|
-
const {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
entity = await service.createOrUpdate({ params: query, data, files });
|
|
33
|
-
} else {
|
|
34
|
-
entity = await service.createOrUpdate({ params: query, data: body });
|
|
35
|
+
const { query } = ctx.request;
|
|
36
|
+
const { data, files } = parseBody(ctx);
|
|
37
|
+
|
|
38
|
+
if (!isObject(data)) {
|
|
39
|
+
throw new ValidationError('Missing "data" payload in the request body');
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
const sanitizedInputData = await this.sanitizeInput(data, ctx);
|
|
43
|
+
|
|
44
|
+
const entity = await strapi
|
|
45
|
+
.service(uid)
|
|
46
|
+
.createOrUpdate({ ...query, data: sanitizedInputData, files });
|
|
47
|
+
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
|
|
48
|
+
|
|
49
|
+
return this.transformResponse(sanitizedEntity);
|
|
38
50
|
},
|
|
39
51
|
|
|
40
52
|
async delete(ctx) {
|
|
41
53
|
const { query } = ctx;
|
|
42
54
|
|
|
43
|
-
const entity = await service.delete(
|
|
44
|
-
|
|
55
|
+
const entity = await strapi.service(uid).delete(query);
|
|
56
|
+
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
|
|
57
|
+
|
|
58
|
+
return this.transformResponse(sanitizedEntity);
|
|
45
59
|
},
|
|
46
60
|
};
|
|
47
61
|
};
|
|
@@ -1,41 +1,97 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { isNil, isPlainObject } = require('lodash/fp');
|
|
4
|
+
const { parseMultipartData } = require('@strapi/utils');
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
+
const parseBody = ctx => {
|
|
7
|
+
if (ctx.is('multipart')) {
|
|
8
|
+
return parseMultipartData(ctx);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { data } = ctx.request.body || {};
|
|
12
|
+
|
|
13
|
+
return { data };
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const transformResponse = (resource, meta = {}, { contentType } = {}) => {
|
|
6
17
|
if (isNil(resource)) {
|
|
7
18
|
return resource;
|
|
8
19
|
}
|
|
9
20
|
|
|
10
21
|
return {
|
|
11
|
-
data: transformEntry(resource),
|
|
22
|
+
data: transformEntry(resource, contentType),
|
|
12
23
|
meta,
|
|
13
24
|
};
|
|
14
25
|
};
|
|
15
26
|
|
|
16
|
-
const
|
|
27
|
+
const transformComponent = (data, component) => {
|
|
28
|
+
if (Array.isArray(data)) {
|
|
29
|
+
return data.map(datum => transformComponent(datum, component));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const res = transformEntry(data, component);
|
|
33
|
+
|
|
34
|
+
if (isNil(res)) {
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const { id, attributes } = res;
|
|
39
|
+
return { id, ...attributes };
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const transformEntry = (entry, type) => {
|
|
17
43
|
if (isNil(entry)) {
|
|
18
44
|
return entry;
|
|
19
45
|
}
|
|
20
46
|
|
|
21
47
|
if (Array.isArray(entry)) {
|
|
22
|
-
return entry.map(singleEntry => transformEntry(singleEntry));
|
|
48
|
+
return entry.map(singleEntry => transformEntry(singleEntry, type));
|
|
23
49
|
}
|
|
24
50
|
|
|
25
51
|
if (!isPlainObject(entry)) {
|
|
26
52
|
throw new Error('Entry must be an object');
|
|
27
53
|
}
|
|
28
54
|
|
|
29
|
-
const { id, ...
|
|
55
|
+
const { id, ...properties } = entry;
|
|
56
|
+
|
|
57
|
+
const attributeValues = {};
|
|
58
|
+
|
|
59
|
+
for (const key in properties) {
|
|
60
|
+
const property = properties[key];
|
|
61
|
+
const attribute = type && type.attributes[key];
|
|
62
|
+
|
|
63
|
+
if (attribute && attribute.type === 'relation') {
|
|
64
|
+
const data = transformEntry(property, strapi.contentType(attribute.target));
|
|
65
|
+
|
|
66
|
+
attributeValues[key] = { data };
|
|
67
|
+
} else if (attribute && attribute.type === 'component') {
|
|
68
|
+
attributeValues[key] = transformComponent(property, strapi.components[attribute.component]);
|
|
69
|
+
} else if (attribute && attribute.type === 'dynamiczone') {
|
|
70
|
+
if (isNil(property)) {
|
|
71
|
+
attributeValues[key] = property;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
attributeValues[key] = property.map(subProperty => {
|
|
75
|
+
return transformComponent(subProperty, strapi.components[subProperty.__component]);
|
|
76
|
+
});
|
|
77
|
+
} else if (attribute && attribute.type === 'media') {
|
|
78
|
+
const data = transformEntry(property, strapi.contentType('plugin::upload.file'));
|
|
79
|
+
|
|
80
|
+
attributeValues[key] = { data };
|
|
81
|
+
} else {
|
|
82
|
+
attributeValues[key] = property;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
30
85
|
|
|
31
86
|
return {
|
|
32
87
|
id,
|
|
33
|
-
attributes,
|
|
88
|
+
attributes: attributeValues,
|
|
34
89
|
// NOTE: not necessary for now
|
|
35
90
|
// meta: {},
|
|
36
91
|
};
|
|
37
92
|
};
|
|
38
93
|
|
|
39
94
|
module.exports = {
|
|
95
|
+
parseBody,
|
|
40
96
|
transformResponse,
|
|
41
97
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isSingleType } = require('@strapi/utils').contentTypes;
|
|
4
|
+
|
|
5
|
+
const createRoutes = ({ contentType }) => {
|
|
6
|
+
if (isSingleType(contentType)) {
|
|
7
|
+
return getSingleTypeRoutes(contentType);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return getCollectionTypeRoutes(contentType);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getSingleTypeRoutes = ({ uid, info }) => {
|
|
14
|
+
return {
|
|
15
|
+
find: {
|
|
16
|
+
method: 'GET',
|
|
17
|
+
path: `/${info.singularName}`,
|
|
18
|
+
handler: `${uid}.find`,
|
|
19
|
+
config: {},
|
|
20
|
+
},
|
|
21
|
+
update: {
|
|
22
|
+
method: 'PUT',
|
|
23
|
+
path: `/${info.singularName}`,
|
|
24
|
+
handler: `${uid}.update`,
|
|
25
|
+
config: {},
|
|
26
|
+
},
|
|
27
|
+
delete: {
|
|
28
|
+
method: 'DELETE',
|
|
29
|
+
path: `/${info.singularName}`,
|
|
30
|
+
handler: `${uid}.delete`,
|
|
31
|
+
config: {},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getCollectionTypeRoutes = ({ uid, info }) => {
|
|
37
|
+
return {
|
|
38
|
+
find: {
|
|
39
|
+
method: 'GET',
|
|
40
|
+
path: `/${info.pluralName}`,
|
|
41
|
+
handler: `${uid}.find`,
|
|
42
|
+
config: {},
|
|
43
|
+
},
|
|
44
|
+
findOne: {
|
|
45
|
+
method: 'GET',
|
|
46
|
+
path: `/${info.pluralName}/:id`,
|
|
47
|
+
handler: `${uid}.findOne`,
|
|
48
|
+
config: {},
|
|
49
|
+
},
|
|
50
|
+
create: {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
path: `/${info.pluralName}`,
|
|
53
|
+
handler: `${uid}.create`,
|
|
54
|
+
config: {},
|
|
55
|
+
},
|
|
56
|
+
update: {
|
|
57
|
+
method: 'PUT',
|
|
58
|
+
path: `/${info.pluralName}/:id`,
|
|
59
|
+
handler: `${uid}.update`,
|
|
60
|
+
config: {},
|
|
61
|
+
},
|
|
62
|
+
delete: {
|
|
63
|
+
method: 'DELETE',
|
|
64
|
+
path: `/${info.pluralName}/:id`,
|
|
65
|
+
handler: `${uid}.delete`,
|
|
66
|
+
config: {},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
module.exports = { createRoutes };
|
|
@@ -7,6 +7,13 @@ const {
|
|
|
7
7
|
constants: { PUBLISHED_AT_ATTRIBUTE },
|
|
8
8
|
} = require('@strapi/utils').contentTypes;
|
|
9
9
|
|
|
10
|
+
const {
|
|
11
|
+
getPaginationInfo,
|
|
12
|
+
convertPagedToStartLimit,
|
|
13
|
+
shouldCount,
|
|
14
|
+
transformPaginationResponse,
|
|
15
|
+
} = require('./pagination');
|
|
16
|
+
|
|
10
17
|
const setPublishedAt = data => {
|
|
11
18
|
data[PUBLISHED_AT_ATTRIBUTE] = propOr(new Date(), PUBLISHED_AT_ATTRIBUTE, data);
|
|
12
19
|
};
|
|
@@ -15,42 +22,57 @@ const setPublishedAt = data => {
|
|
|
15
22
|
*
|
|
16
23
|
* Returns a collection type service to handle default core-api actions
|
|
17
24
|
*/
|
|
18
|
-
const createCollectionTypeService = ({
|
|
19
|
-
const { uid } =
|
|
20
|
-
|
|
21
|
-
const { sanitizeInput, getFetchParams } = utils;
|
|
25
|
+
const createCollectionTypeService = ({ contentType }) => {
|
|
26
|
+
const { uid } = contentType;
|
|
22
27
|
|
|
23
28
|
return {
|
|
24
|
-
find(
|
|
25
|
-
const
|
|
29
|
+
async find(params = {}) {
|
|
30
|
+
const fetchParams = this.getFetchParams(params);
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
const paginationInfo = getPaginationInfo(fetchParams);
|
|
33
|
+
|
|
34
|
+
const results = await strapi.entityService.findMany(uid, {
|
|
35
|
+
...fetchParams,
|
|
36
|
+
...convertPagedToStartLimit(paginationInfo),
|
|
37
|
+
});
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
if (shouldCount(fetchParams)) {
|
|
40
|
+
const count = await strapi.entityService.count(uid, { ...fetchParams, ...paginationInfo });
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
results,
|
|
44
|
+
pagination: transformPaginationResponse(paginationInfo, count),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
results,
|
|
50
|
+
pagination: paginationInfo,
|
|
51
|
+
};
|
|
52
|
+
},
|
|
32
53
|
|
|
33
|
-
|
|
54
|
+
findOne(entityId, params = {}) {
|
|
55
|
+
return strapi.entityService.findOne(uid, entityId, this.getFetchParams(params));
|
|
34
56
|
},
|
|
35
57
|
|
|
36
|
-
create(
|
|
37
|
-
const
|
|
58
|
+
create(params = {}) {
|
|
59
|
+
const { data } = params;
|
|
38
60
|
|
|
39
|
-
if (hasDraftAndPublish(
|
|
40
|
-
setPublishedAt(
|
|
61
|
+
if (hasDraftAndPublish(contentType)) {
|
|
62
|
+
setPublishedAt(data);
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
return strapi.entityService.create(uid, { params, data
|
|
65
|
+
return strapi.entityService.create(uid, { ...params, data });
|
|
44
66
|
},
|
|
45
67
|
|
|
46
|
-
update(entityId,
|
|
47
|
-
const
|
|
68
|
+
update(entityId, params = {}) {
|
|
69
|
+
const { data } = params;
|
|
48
70
|
|
|
49
|
-
return strapi.entityService.update(uid, entityId, { params, data
|
|
71
|
+
return strapi.entityService.update(uid, entityId, { ...params, data });
|
|
50
72
|
},
|
|
51
73
|
|
|
52
|
-
delete(entityId,
|
|
53
|
-
return strapi.entityService.delete(uid, entityId,
|
|
74
|
+
delete(entityId, params = {}) {
|
|
75
|
+
return strapi.entityService.delete(uid, entityId, params);
|
|
54
76
|
},
|
|
55
77
|
};
|
|
56
78
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Entity = object;
|
|
2
|
+
|
|
3
|
+
interface BaseService {
|
|
4
|
+
getFetchParams(params: object): object;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface SingleTypeService extends BaseService {
|
|
8
|
+
find(params: object): Promise<Entity>;
|
|
9
|
+
createOrUpdate(params: object): Promise<Entity>;
|
|
10
|
+
delete(params: object): Promise<Entity>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CollectionTypeService extends BaseService {
|
|
14
|
+
find(params: object): Promise<Entity[]>;
|
|
15
|
+
findOne(params: object): Promise<Entity>;
|
|
16
|
+
create(params: object): Promise<Entity>;
|
|
17
|
+
update(params: object): Promise<Entity>;
|
|
18
|
+
delete(params: object): Promise<Entity>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Service = SingleTypeService | CollectionTypeService;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
|
|
5
3
|
const {
|
|
6
4
|
isSingleType,
|
|
7
|
-
getNonWritableAttributes,
|
|
8
5
|
constants: { DP_PUB_STATE_LIVE },
|
|
9
6
|
} = require('@strapi/utils').contentTypes;
|
|
10
7
|
|
|
@@ -16,62 +13,18 @@ const createCollectionTypeService = require('./collection-type');
|
|
|
16
13
|
* @param {{ model: object, strapi: object }} context
|
|
17
14
|
* @returns {object}
|
|
18
15
|
*/
|
|
19
|
-
const createService = ({
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
if (isSingleType(model)) {
|
|
23
|
-
return createSingleTypeService({ model, strapi, utils });
|
|
24
|
-
}
|
|
16
|
+
const createService = ({ contentType }) => {
|
|
17
|
+
const proto = { getFetchParams };
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Default limit values from config
|
|
31
|
-
* @return {{maxLimit: number, defaultLimit: number}}
|
|
32
|
-
*/
|
|
33
|
-
const getLimitConfigDefaults = () => ({
|
|
34
|
-
defaultLimit: _.toNumber(strapi.config.get('api.rest.defaultLimit', 100)),
|
|
35
|
-
maxLimit: _.toNumber(strapi.config.get('api.rest.maxLimit')) || null,
|
|
36
|
-
});
|
|
19
|
+
let service;
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
* @returns {number}
|
|
43
|
-
*/
|
|
44
|
-
const applyMaxLimit = (limit, maxLimit) => {
|
|
45
|
-
if (maxLimit && (limit === -1 || limit > maxLimit)) {
|
|
46
|
-
return maxLimit;
|
|
21
|
+
if (isSingleType(contentType)) {
|
|
22
|
+
service = createSingleTypeService({ contentType });
|
|
23
|
+
} else {
|
|
24
|
+
service = createCollectionTypeService({ contentType });
|
|
47
25
|
}
|
|
48
26
|
|
|
49
|
-
return
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const applyDefaultPagination = params => {
|
|
53
|
-
const { defaultLimit, maxLimit } = getLimitConfigDefaults();
|
|
54
|
-
|
|
55
|
-
if (_.isUndefined(params.pagination) || !_.isPlainObject(params.pagination)) {
|
|
56
|
-
return {
|
|
57
|
-
limit: defaultLimit,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const { pagination } = params;
|
|
62
|
-
|
|
63
|
-
if (!_.isUndefined(pagination.pageSize)) {
|
|
64
|
-
return {
|
|
65
|
-
page: pagination.page,
|
|
66
|
-
pageSize: applyMaxLimit(_.toNumber(pagination.pageSize), maxLimit),
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const limit = _.isUndefined(pagination.limit) ? defaultLimit : _.toNumber(pagination.limit);
|
|
71
|
-
return {
|
|
72
|
-
start: pagination.start,
|
|
73
|
-
limit: applyMaxLimit(limit, maxLimit),
|
|
74
|
-
};
|
|
27
|
+
return Object.assign(Object.create(proto), service);
|
|
75
28
|
};
|
|
76
29
|
|
|
77
30
|
/**
|
|
@@ -83,18 +36,6 @@ const getFetchParams = (params = {}) => {
|
|
|
83
36
|
return {
|
|
84
37
|
publicationState: DP_PUB_STATE_LIVE,
|
|
85
38
|
...params,
|
|
86
|
-
pagination: applyDefaultPagination(params),
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Mixins
|
|
92
|
-
*/
|
|
93
|
-
const createUtils = ({ model }) => {
|
|
94
|
-
return {
|
|
95
|
-
// make sure to keep the call to getNonWritableAttributes dynamic
|
|
96
|
-
sanitizeInput: data => _.omit(data, getNonWritableAttributes(model)),
|
|
97
|
-
getFetchParams,
|
|
98
39
|
};
|
|
99
40
|
};
|
|
100
41
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { has, toNumber, isUndefined } = require('lodash/fp');
|
|
4
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default limit values from config
|
|
8
|
+
* @return {{maxLimit: number, defaultLimit: number}}
|
|
9
|
+
*/
|
|
10
|
+
const getLimitConfigDefaults = () => ({
|
|
11
|
+
defaultLimit: toNumber(strapi.config.get('api.rest.defaultLimit', 25)),
|
|
12
|
+
maxLimit: toNumber(strapi.config.get('api.rest.maxLimit')) || null,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* if there is max limit set and limit exceeds this number, return configured max limit
|
|
17
|
+
* @param {number} limit - limit you want to cap
|
|
18
|
+
* @param {number?} maxLimit - maxlimit used has capping
|
|
19
|
+
* @returns {number}
|
|
20
|
+
*/
|
|
21
|
+
const applyMaxLimit = (limit, maxLimit) => {
|
|
22
|
+
if (maxLimit && (limit === -1 || limit > maxLimit)) {
|
|
23
|
+
return maxLimit;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return limit;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const shouldCount = params => {
|
|
30
|
+
if (has('pagination.withCount', params)) {
|
|
31
|
+
const { withCount } = params.pagination;
|
|
32
|
+
|
|
33
|
+
if (typeof withCount === 'boolean') {
|
|
34
|
+
return withCount;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (['true', 't', '1', 1].includes(withCount)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (['false', 'f', '0', 0].includes(withCount)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new ValidationError(
|
|
46
|
+
'Invalid withCount parameter. Expected "t","1","true","false","0","f"'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return Boolean(strapi.config.get('api.rest.withCount', true));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const isOffsetPagination = pagination => has('start', pagination) || has('limit', pagination);
|
|
54
|
+
const isPagedPagination = pagination => has('page', pagination) || has('pageSize', pagination);
|
|
55
|
+
|
|
56
|
+
const getPaginationInfo = params => {
|
|
57
|
+
const { defaultLimit, maxLimit } = getLimitConfigDefaults();
|
|
58
|
+
|
|
59
|
+
const { pagination } = params;
|
|
60
|
+
|
|
61
|
+
const isPaged = isPagedPagination(pagination);
|
|
62
|
+
const isOffset = isOffsetPagination(pagination);
|
|
63
|
+
|
|
64
|
+
if (!isPaged && !isOffset) {
|
|
65
|
+
return {
|
|
66
|
+
page: 1,
|
|
67
|
+
pageSize: defaultLimit,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (isOffset && isPaged) {
|
|
72
|
+
throw new ValidationError(
|
|
73
|
+
'Invalid pagination parameters. Expected either start/limit or page/pageSize'
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isPagedPagination(pagination)) {
|
|
78
|
+
const pageSize = isUndefined(pagination.pageSize)
|
|
79
|
+
? defaultLimit
|
|
80
|
+
: Math.max(1, toNumber(pagination.pageSize));
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
page: Math.max(1, toNumber(pagination.page || 1)),
|
|
84
|
+
pageSize: applyMaxLimit(pageSize, maxLimit),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const limit = isUndefined(pagination.limit)
|
|
89
|
+
? defaultLimit
|
|
90
|
+
: Math.max(1, toNumber(pagination.limit));
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
start: Math.max(0, toNumber(pagination.start || 0)),
|
|
94
|
+
limit: applyMaxLimit(limit, maxLimit),
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const convertPagedToStartLimit = pagination => {
|
|
99
|
+
if (isPagedPagination(pagination)) {
|
|
100
|
+
const { page, pageSize } = pagination;
|
|
101
|
+
return {
|
|
102
|
+
start: (page - 1) * pageSize,
|
|
103
|
+
limit: pageSize,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return pagination;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const transformPaginationResponse = (paginationInfo, count) => {
|
|
111
|
+
if (paginationInfo.page) {
|
|
112
|
+
return {
|
|
113
|
+
...paginationInfo,
|
|
114
|
+
pageCount: Math.ceil(count / paginationInfo.pageSize),
|
|
115
|
+
total: count,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...paginationInfo,
|
|
121
|
+
total: count,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
getPaginationInfo,
|
|
127
|
+
convertPagedToStartLimit,
|
|
128
|
+
transformPaginationResponse,
|
|
129
|
+
shouldCount,
|
|
130
|
+
};
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Returns a single type service to handle default core-api actions
|
|
5
7
|
*/
|
|
6
|
-
const createSingleTypeService = ({
|
|
7
|
-
const { uid } =
|
|
8
|
-
const { sanitizeInput, getFetchParams } = utils;
|
|
8
|
+
const createSingleTypeService = ({ contentType }) => {
|
|
9
|
+
const { uid } = contentType;
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @type {import('./').SingleTypeService}
|
|
13
|
+
*/
|
|
10
14
|
return {
|
|
11
15
|
/**
|
|
12
16
|
* Returns singleType content
|
|
13
17
|
*
|
|
14
18
|
* @return {Promise}
|
|
15
19
|
*/
|
|
16
|
-
find(
|
|
17
|
-
return strapi.entityService.
|
|
20
|
+
find(params = {}) {
|
|
21
|
+
return strapi.entityService.findMany(uid, this.getFetchParams(params));
|
|
18
22
|
},
|
|
19
23
|
|
|
20
24
|
/**
|
|
@@ -22,25 +26,19 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
|
|
|
22
26
|
*
|
|
23
27
|
* @return {Promise}
|
|
24
28
|
*/
|
|
25
|
-
async createOrUpdate({
|
|
26
|
-
const entity = await this.find(
|
|
27
|
-
|
|
28
|
-
const sanitizedData = sanitizeInput(data);
|
|
29
|
+
async createOrUpdate({ data, ...params } = {}) {
|
|
30
|
+
const entity = await this.find(params);
|
|
29
31
|
|
|
30
32
|
if (!entity) {
|
|
31
33
|
const count = await strapi.query(uid).count();
|
|
32
34
|
if (count >= 1) {
|
|
33
|
-
throw
|
|
35
|
+
throw new ValidationError('singleType.alreadyExists');
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
return strapi.entityService.create(uid, { params, data
|
|
37
|
-
} else {
|
|
38
|
-
return strapi.entityService.update(uid, entity.id, {
|
|
39
|
-
params,
|
|
40
|
-
data: sanitizedData,
|
|
41
|
-
files,
|
|
42
|
-
});
|
|
38
|
+
return strapi.entityService.create(uid, { ...params, data });
|
|
43
39
|
}
|
|
40
|
+
|
|
41
|
+
return strapi.entityService.update(uid, entity.id, { ...params, data });
|
|
44
42
|
},
|
|
45
43
|
|
|
46
44
|
/**
|
|
@@ -48,8 +46,8 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
|
|
|
48
46
|
*
|
|
49
47
|
* @return {Promise}
|
|
50
48
|
*/
|
|
51
|
-
async delete(
|
|
52
|
-
const entity = await this.find(
|
|
49
|
+
async delete(params = {}) {
|
|
50
|
+
const entity = await this.find(params);
|
|
53
51
|
|
|
54
52
|
if (!entity) return;
|
|
55
53
|
|