@strapi/strapi 4.0.0-beta.11 → 4.0.0-beta.15
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/Strapi.js +3 -3
- package/lib/commands/new.js +3 -1
- package/lib/core/domain/module/index.js +3 -1
- package/lib/core/domain/module/validation.js +1 -4
- package/lib/core/loaders/plugins/get-enabled-plugins.js +25 -9
- package/lib/core/loaders/plugins/index.js +16 -6
- package/lib/core/registries/apis.js +2 -16
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +74 -3
- package/lib/core/registries/services.js +15 -6
- package/lib/core-api/controller/collection-type.js +37 -23
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +15 -10
- package/lib/core-api/controller/single-type.js +23 -16
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +5 -7
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +9 -12
- package/lib/core-api/service/single-type.js +6 -4
- package/lib/factories.d.ts +48 -0
- package/lib/factories.js +84 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +5 -1
- package/lib/middlewares/errors.js +1 -1
- package/lib/middlewares/index.d.ts +1 -0
- package/lib/middlewares/security.js +7 -2
- package/lib/services/entity-service/index.d.ts +1 -1
- package/lib/services/entity-service/index.js +8 -7
- package/lib/services/entity-validator/index.js +10 -1
- package/lib/services/errors.js +8 -3
- package/lib/services/server/compose-endpoint.js +21 -7
- package/lib/services/server/policy.js +5 -9
- package/lib/services/server/register-routes.js +1 -3
- package/package.json +13 -13
- package/lib/core-api/index.js +0 -39
|
@@ -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 };
|
|
@@ -22,14 +22,12 @@ const setPublishedAt = data => {
|
|
|
22
22
|
*
|
|
23
23
|
* Returns a collection type service to handle default core-api actions
|
|
24
24
|
*/
|
|
25
|
-
const createCollectionTypeService = ({
|
|
26
|
-
const { uid } =
|
|
27
|
-
|
|
28
|
-
const { getFetchParams } = utils;
|
|
25
|
+
const createCollectionTypeService = ({ contentType }) => {
|
|
26
|
+
const { uid } = contentType;
|
|
29
27
|
|
|
30
28
|
return {
|
|
31
29
|
async find(params = {}) {
|
|
32
|
-
const fetchParams = getFetchParams(params);
|
|
30
|
+
const fetchParams = this.getFetchParams(params);
|
|
33
31
|
|
|
34
32
|
const paginationInfo = getPaginationInfo(fetchParams);
|
|
35
33
|
|
|
@@ -54,13 +52,13 @@ const createCollectionTypeService = ({ model, strapi, utils }) => {
|
|
|
54
52
|
},
|
|
55
53
|
|
|
56
54
|
findOne(entityId, params = {}) {
|
|
57
|
-
return strapi.entityService.findOne(uid, entityId, getFetchParams(params));
|
|
55
|
+
return strapi.entityService.findOne(uid, entityId, this.getFetchParams(params));
|
|
58
56
|
},
|
|
59
57
|
|
|
60
58
|
create(params = {}) {
|
|
61
59
|
const { data } = params;
|
|
62
60
|
|
|
63
|
-
if (hasDraftAndPublish(
|
|
61
|
+
if (hasDraftAndPublish(contentType)) {
|
|
64
62
|
setPublishedAt(data);
|
|
65
63
|
}
|
|
66
64
|
|
|
@@ -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;
|
|
@@ -13,14 +13,18 @@ const createCollectionTypeService = require('./collection-type');
|
|
|
13
13
|
* @param {{ model: object, strapi: object }} context
|
|
14
14
|
* @returns {object}
|
|
15
15
|
*/
|
|
16
|
-
const createService = ({
|
|
17
|
-
const
|
|
16
|
+
const createService = ({ contentType }) => {
|
|
17
|
+
const proto = { getFetchParams };
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
let service;
|
|
20
|
+
|
|
21
|
+
if (isSingleType(contentType)) {
|
|
22
|
+
service = createSingleTypeService({ contentType });
|
|
23
|
+
} else {
|
|
24
|
+
service = createCollectionTypeService({ contentType });
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
return
|
|
27
|
+
return Object.assign(Object.create(proto), service);
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
/**
|
|
@@ -35,13 +39,6 @@ const getFetchParams = (params = {}) => {
|
|
|
35
39
|
};
|
|
36
40
|
};
|
|
37
41
|
|
|
38
|
-
/**
|
|
39
|
-
* Mixins
|
|
40
|
-
*/
|
|
41
|
-
const createUtils = () => ({
|
|
42
|
-
getFetchParams,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
42
|
module.exports = {
|
|
46
43
|
createService,
|
|
47
44
|
getFetchParams,
|
|
@@ -5,10 +5,12 @@ const { ValidationError } = require('@strapi/utils').errors;
|
|
|
5
5
|
/**
|
|
6
6
|
* Returns a single type service to handle default core-api actions
|
|
7
7
|
*/
|
|
8
|
-
const createSingleTypeService = ({
|
|
9
|
-
const { uid } =
|
|
10
|
-
const { getFetchParams } = utils;
|
|
8
|
+
const createSingleTypeService = ({ contentType }) => {
|
|
9
|
+
const { uid } = contentType;
|
|
11
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @type {import('./').SingleTypeService}
|
|
13
|
+
*/
|
|
12
14
|
return {
|
|
13
15
|
/**
|
|
14
16
|
* Returns singleType content
|
|
@@ -16,7 +18,7 @@ const createSingleTypeService = ({ model, strapi, utils }) => {
|
|
|
16
18
|
* @return {Promise}
|
|
17
19
|
*/
|
|
18
20
|
find(params = {}) {
|
|
19
|
-
return strapi.entityService.findMany(uid, getFetchParams(params));
|
|
21
|
+
return strapi.entityService.findMany(uid, this.getFetchParams(params));
|
|
20
22
|
},
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Service } from './core-api/service';
|
|
2
|
+
import { Controller } from './core-api/controller';
|
|
3
|
+
import { Middleware } from './middlewares';
|
|
4
|
+
import { Policy } from './core/registries/policies';
|
|
5
|
+
|
|
6
|
+
type ControllerConfig = Controller;
|
|
7
|
+
|
|
8
|
+
type ServiceConfig = Service;
|
|
9
|
+
|
|
10
|
+
type HandlerConfig = {
|
|
11
|
+
auth: false | { scope: string[] };
|
|
12
|
+
policies: Array<string | Policy>;
|
|
13
|
+
middlewares: Array<string | Middleware>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type SingleTypeRouterConfig = {
|
|
17
|
+
find: HandlerConfig;
|
|
18
|
+
update: HandlerConfig;
|
|
19
|
+
delete: HandlerConfig;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type CollectionTypeRouterConfig = {
|
|
23
|
+
find: HandlerConfig;
|
|
24
|
+
findOne: HandlerConfig;
|
|
25
|
+
create: HandlerConfig;
|
|
26
|
+
update: HandlerConfig;
|
|
27
|
+
delete: HandlerConfig;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type RouterConfig = {
|
|
31
|
+
prefix: string;
|
|
32
|
+
only: string[];
|
|
33
|
+
except: string[];
|
|
34
|
+
config: SingleTypeRouterConfig | CollectionTypeRouterConfig;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
interface Route {
|
|
38
|
+
method: string;
|
|
39
|
+
path: string;
|
|
40
|
+
}
|
|
41
|
+
interface Router {
|
|
42
|
+
prefix: string;
|
|
43
|
+
routes: Route[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function createCoreRouter(uid: string, cfg: RouterConfig): () => Router;
|
|
47
|
+
export function createCoreController(uid: string, cfg: ControllerConfig): () => Controller;
|
|
48
|
+
export function createCoreService(uid: string, cfg: ServiceConfig): () => Service;
|
package/lib/factories.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { pipe, omit, pick } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { createController } = require('./core-api/controller');
|
|
6
|
+
const { createService } = require('./core-api/service');
|
|
7
|
+
const { createRoutes } = require('./core-api/routes');
|
|
8
|
+
|
|
9
|
+
const createCoreController = (uid, cfg = {}) => {
|
|
10
|
+
return ({ strapi }) => {
|
|
11
|
+
const baseController = createController({
|
|
12
|
+
contentType: strapi.contentType(uid),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
let userCtrl = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
|
|
16
|
+
|
|
17
|
+
for (const methodName of Object.keys(baseController)) {
|
|
18
|
+
if (userCtrl[methodName] === undefined) {
|
|
19
|
+
userCtrl[methodName] = baseController[methodName];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Object.setPrototypeOf(userCtrl, baseController);
|
|
24
|
+
return userCtrl;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const createCoreService = (uid, cfg = {}) => {
|
|
29
|
+
return ({ strapi }) => {
|
|
30
|
+
const baseService = createService({
|
|
31
|
+
contentType: strapi.contentType(uid),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
let userService = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
|
|
35
|
+
|
|
36
|
+
for (const methodName of Object.keys(baseService)) {
|
|
37
|
+
if (userService[methodName] === undefined) {
|
|
38
|
+
userService[methodName] = baseService[methodName];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Object.setPrototypeOf(userService, baseService);
|
|
43
|
+
return userService;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const createCoreRouter = (uid, cfg = {}) => {
|
|
48
|
+
const { prefix, config = {}, only, except } = cfg;
|
|
49
|
+
let routes;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
get prefix() {
|
|
53
|
+
return prefix;
|
|
54
|
+
},
|
|
55
|
+
get routes() {
|
|
56
|
+
if (!routes) {
|
|
57
|
+
const contentType = strapi.contentType(uid);
|
|
58
|
+
|
|
59
|
+
const defaultRoutes = createRoutes({ contentType });
|
|
60
|
+
|
|
61
|
+
Object.keys(defaultRoutes).forEach(routeName => {
|
|
62
|
+
const defaultRoute = defaultRoutes[routeName];
|
|
63
|
+
|
|
64
|
+
Object.assign(defaultRoute.config, config[routeName] || {});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const selectedRoutes = pipe(
|
|
68
|
+
routes => (except ? omit(except, routes) : routes),
|
|
69
|
+
routes => (only ? pick(only, routes) : routes)
|
|
70
|
+
)(defaultRoutes);
|
|
71
|
+
|
|
72
|
+
routes = Object.values(selectedRoutes);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return routes;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
createCoreController,
|
|
82
|
+
createCoreService,
|
|
83
|
+
createCoreRouter,
|
|
84
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Database } from '@strapi/database';
|
|
|
2
2
|
import { EntityService } from './services/entity-service';
|
|
3
3
|
import { Strapi as StrapiClass } from './Strapi';
|
|
4
4
|
|
|
5
|
+
export * as factories from './factories';
|
|
5
6
|
interface StrapiInterface extends StrapiClass {
|
|
6
7
|
query: Database['query'];
|
|
7
8
|
entityService: EntityService;
|
package/lib/index.js
CHANGED
|
@@ -12,6 +12,8 @@ const defaults = {
|
|
|
12
12
|
useDefaults: true,
|
|
13
13
|
directives: {
|
|
14
14
|
'connect-src': ["'self'", 'https:'],
|
|
15
|
+
'img-src': ["'self'", 'data:', 'blob:'],
|
|
16
|
+
'media-src': ["'self'", 'data:', 'blob:'],
|
|
15
17
|
},
|
|
16
18
|
},
|
|
17
19
|
xssFilter: false,
|
|
@@ -30,12 +32,15 @@ const defaults = {
|
|
|
30
32
|
module.exports = config => (ctx, next) => {
|
|
31
33
|
let helmetConfig = defaultsDeep(defaults, config);
|
|
32
34
|
|
|
33
|
-
if (
|
|
35
|
+
if (
|
|
36
|
+
ctx.method === 'GET' &&
|
|
37
|
+
['/graphql', '/documentation'].some(str => ctx.path.startsWith(str))
|
|
38
|
+
) {
|
|
34
39
|
helmetConfig = merge(helmetConfig, {
|
|
35
40
|
contentSecurityPolicy: {
|
|
36
41
|
directives: {
|
|
37
42
|
'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
|
|
38
|
-
'img-src': ["'self'", 'data:', 'cdn.jsdelivr.net'],
|
|
43
|
+
'img-src': ["'self'", 'data:', 'cdn.jsdelivr.net', 'strapi.io'],
|
|
39
44
|
},
|
|
40
45
|
},
|
|
41
46
|
});
|
|
@@ -35,7 +35,7 @@ type Params<T> = {
|
|
|
35
35
|
files?: any;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
interface EntityService {
|
|
38
|
+
export interface EntityService {
|
|
39
39
|
uploadFiles<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, entity, files);
|
|
40
40
|
wrapParams<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
41
41
|
params: Params<T>,
|
|
@@ -8,9 +8,9 @@ const {
|
|
|
8
8
|
InvalidDateTimeError,
|
|
9
9
|
} = require('@strapi/database').errors;
|
|
10
10
|
const {
|
|
11
|
-
sanitize,
|
|
12
11
|
webhook: webhookUtils,
|
|
13
12
|
contentTypes: contentTypesUtils,
|
|
13
|
+
sanitize,
|
|
14
14
|
} = require('@strapi/utils');
|
|
15
15
|
const { ValidationError } = require('@strapi/utils').errors;
|
|
16
16
|
const uploadFiles = require('../utils/upload-files');
|
|
@@ -92,12 +92,13 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
92
92
|
return options;
|
|
93
93
|
},
|
|
94
94
|
|
|
95
|
-
emitEvent(uid, event, entity) {
|
|
95
|
+
async emitEvent(uid, event, entity) {
|
|
96
96
|
const model = strapi.getModel(uid);
|
|
97
|
+
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
|
|
97
98
|
|
|
98
99
|
eventHub.emit(event, {
|
|
99
100
|
model: model.modelName,
|
|
100
|
-
entry:
|
|
101
|
+
entry: sanitizedEntity,
|
|
101
102
|
});
|
|
102
103
|
},
|
|
103
104
|
|
|
@@ -182,7 +183,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
182
183
|
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
186
|
+
await this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
186
187
|
|
|
187
188
|
return entity;
|
|
188
189
|
},
|
|
@@ -225,7 +226,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
225
226
|
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
226
227
|
}
|
|
227
228
|
|
|
228
|
-
this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
229
|
+
await this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
229
230
|
|
|
230
231
|
return entity;
|
|
231
232
|
},
|
|
@@ -248,7 +249,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
248
249
|
await deleteComponents(uid, entityToDelete);
|
|
249
250
|
await db.query(uid).delete({ where: { id: entityToDelete.id } });
|
|
250
251
|
|
|
251
|
-
this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
252
|
+
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
252
253
|
|
|
253
254
|
return entityToDelete;
|
|
254
255
|
},
|
|
@@ -263,7 +264,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
263
264
|
return db.query(uid).deleteMany(query);
|
|
264
265
|
},
|
|
265
266
|
|
|
266
|
-
load(uid, entity, field, params) {
|
|
267
|
+
load(uid, entity, field, params = {}) {
|
|
267
268
|
const { attributes } = strapi.getModel(uid);
|
|
268
269
|
|
|
269
270
|
const attribute = attributes[field];
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
-
const { has, assoc, prop } = require('lodash/fp');
|
|
7
|
+
const { has, assoc, prop, isObject } = require('lodash/fp');
|
|
8
8
|
const strapiUtils = require('@strapi/utils');
|
|
9
9
|
const validators = require('./validators');
|
|
10
10
|
|
|
11
11
|
const { yup, validateYupSchema } = strapiUtils;
|
|
12
12
|
const { isMediaAttribute, isScalarAttribute, getWritableAttributes } = strapiUtils.contentTypes;
|
|
13
|
+
const { ValidationError } = strapiUtils.errors;
|
|
13
14
|
|
|
14
15
|
const addMinMax = (attr, validator, data) => {
|
|
15
16
|
if (Number.isInteger(attr.min) && (attr.required || (Array.isArray(data) && data.length > 0))) {
|
|
@@ -173,6 +174,14 @@ const createModelValidator = createOrUpdate => (model, data, { isDraft }) => {
|
|
|
173
174
|
};
|
|
174
175
|
|
|
175
176
|
const createValidateEntity = createOrUpdate => async (model, data, { isDraft = false } = {}) => {
|
|
177
|
+
if (!isObject(data)) {
|
|
178
|
+
const { displayName } = model.info;
|
|
179
|
+
|
|
180
|
+
throw new ValidationError(
|
|
181
|
+
`Invalid payload submitted for the ${createOrUpdate} of an entity of type ${displayName}. Expected an object, but got ${typeof data}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
176
185
|
const validator = createModelValidator(createOrUpdate)(model, data, { isDraft }).required();
|
|
177
186
|
return validateYupSchema(validator, { strict: false, abortEarly: false })(data);
|
|
178
187
|
};
|
package/lib/services/errors.js
CHANGED
|
@@ -60,9 +60,14 @@ const formatHttpError = error => {
|
|
|
60
60
|
};
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
const formatInternalError =
|
|
64
|
-
const
|
|
65
|
-
|
|
63
|
+
const formatInternalError = error => {
|
|
64
|
+
const httpError = createError(error);
|
|
65
|
+
|
|
66
|
+
if (httpError.expose) {
|
|
67
|
+
return formatHttpError(httpError);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return formatHttpError(createError(httpError.status || 500));
|
|
66
71
|
};
|
|
67
72
|
|
|
68
73
|
module.exports = {
|
|
@@ -82,23 +82,37 @@ module.exports = strapi => {
|
|
|
82
82
|
|
|
83
83
|
router[method](path, routeHandler);
|
|
84
84
|
} catch (error) {
|
|
85
|
-
|
|
85
|
+
error.message = `Error creating endpoint ${route.method} ${route.path}: ${error.message}`;
|
|
86
|
+
throw error;
|
|
86
87
|
}
|
|
87
88
|
};
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
const getController = (name, { pluginName, apiName }, strapi) => {
|
|
92
|
+
let ctrl;
|
|
93
|
+
|
|
91
94
|
if (pluginName) {
|
|
92
95
|
if (pluginName === 'admin') {
|
|
93
|
-
|
|
96
|
+
ctrl = strapi.controller(`admin::${name}`);
|
|
97
|
+
} else {
|
|
98
|
+
ctrl = strapi.plugin(pluginName).controller(name);
|
|
94
99
|
}
|
|
95
|
-
|
|
96
|
-
return strapi.plugin(pluginName).controller(name);
|
|
97
100
|
} else if (apiName) {
|
|
98
|
-
|
|
101
|
+
ctrl = strapi.controller(`api::${apiName}.${name}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!ctrl) {
|
|
105
|
+
return strapi.controller(name);
|
|
99
106
|
}
|
|
100
107
|
|
|
101
|
-
return
|
|
108
|
+
return ctrl;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const extractHandlerParts = name => {
|
|
112
|
+
const controllerName = name.slice(0, name.lastIndexOf('.'));
|
|
113
|
+
const actionName = name.slice(name.lastIndexOf('.') + 1);
|
|
114
|
+
|
|
115
|
+
return { controllerName, actionName };
|
|
102
116
|
};
|
|
103
117
|
|
|
104
118
|
const getAction = (route, strapi) => {
|
|
@@ -109,7 +123,7 @@ const getAction = (route, strapi) => {
|
|
|
109
123
|
return handler;
|
|
110
124
|
}
|
|
111
125
|
|
|
112
|
-
const
|
|
126
|
+
const { controllerName, actionName } = extractHandlerParts(trim(handler));
|
|
113
127
|
|
|
114
128
|
const controller = getController(controllerName, { pluginName, apiName }, strapi);
|
|
115
129
|
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { propOr } = require('lodash/fp');
|
|
4
|
-
const policy = require('@strapi/utils/lib/policy');
|
|
5
4
|
const { ForbiddenError } = require('@strapi/utils').errors;
|
|
5
|
+
const { policy: policyUtils } = require('@strapi/utils');
|
|
6
6
|
|
|
7
7
|
const getPoliciesConfig = propOr([], 'config.policies');
|
|
8
8
|
|
|
9
9
|
const resolvePolicies = route => {
|
|
10
|
-
const { pluginName, apiName } = route.info || {};
|
|
11
10
|
const policiesConfig = getPoliciesConfig(route);
|
|
12
|
-
|
|
13
|
-
const resolvedPolicies = policiesConfig.map(policyConfig =>
|
|
14
|
-
policy.get(policyConfig, { pluginName, apiName })
|
|
15
|
-
);
|
|
11
|
+
const resolvedPolicies = policyUtils.resolve(policiesConfig, route.info);
|
|
16
12
|
|
|
17
13
|
const policiesMiddleware = async (ctx, next) => {
|
|
18
|
-
const context =
|
|
14
|
+
const context = policyUtils.createPolicyContext('koa', ctx);
|
|
19
15
|
|
|
20
|
-
for (const
|
|
21
|
-
const result = await
|
|
16
|
+
for (const { handler, config } of resolvedPolicies) {
|
|
17
|
+
const result = await handler(context, config, { strapi });
|
|
22
18
|
|
|
23
19
|
if (![true, undefined].includes(result)) {
|
|
24
20
|
throw new ForbiddenError('Policies failed.');
|
|
@@ -6,12 +6,10 @@ const createRouteScopeGenerator = namespace => route => {
|
|
|
6
6
|
const prefix = namespace.endsWith('::') ? namespace : `${namespace}.`;
|
|
7
7
|
|
|
8
8
|
if (typeof route.handler === 'string') {
|
|
9
|
-
const [controller, action] = route.handler.split('.');
|
|
10
|
-
|
|
11
9
|
_.defaultsDeep(route, {
|
|
12
10
|
config: {
|
|
13
11
|
auth: {
|
|
14
|
-
scope: [`${prefix}${
|
|
12
|
+
scope: [`${route.handler.startsWith(prefix) ? '' : prefix}${route.handler}`],
|
|
15
13
|
},
|
|
16
14
|
},
|
|
17
15
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/strapi",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.15",
|
|
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",
|
|
@@ -79,16 +79,16 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@koa/cors": "3.1.0",
|
|
81
81
|
"@koa/router": "10.1.1",
|
|
82
|
-
"@strapi/admin": "4.0.0-beta.
|
|
83
|
-
"@strapi/database": "4.0.0-beta.
|
|
84
|
-
"@strapi/generate-new": "4.0.0-beta.
|
|
85
|
-
"@strapi/generators": "4.0.0-beta.
|
|
86
|
-
"@strapi/logger": "4.0.0-beta.
|
|
87
|
-
"@strapi/plugin-content-manager": "4.0.0-beta.
|
|
88
|
-
"@strapi/plugin-content-type-builder": "4.0.0-beta.
|
|
89
|
-
"@strapi/plugin-email": "4.0.0-beta.
|
|
90
|
-
"@strapi/plugin-upload": "4.0.0-beta.
|
|
91
|
-
"@strapi/utils": "4.0.0-beta.
|
|
82
|
+
"@strapi/admin": "4.0.0-beta.15",
|
|
83
|
+
"@strapi/database": "4.0.0-beta.15",
|
|
84
|
+
"@strapi/generate-new": "4.0.0-beta.15",
|
|
85
|
+
"@strapi/generators": "4.0.0-beta.15",
|
|
86
|
+
"@strapi/logger": "4.0.0-beta.15",
|
|
87
|
+
"@strapi/plugin-content-manager": "4.0.0-beta.15",
|
|
88
|
+
"@strapi/plugin-content-type-builder": "4.0.0-beta.15",
|
|
89
|
+
"@strapi/plugin-email": "4.0.0-beta.15",
|
|
90
|
+
"@strapi/plugin-upload": "4.0.0-beta.15",
|
|
91
|
+
"@strapi/utils": "4.0.0-beta.15",
|
|
92
92
|
"bcryptjs": "2.4.3",
|
|
93
93
|
"boxen": "5.1.2",
|
|
94
94
|
"chalk": "4.1.2",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"fs-extra": "10.0.0",
|
|
105
105
|
"glob": "7.2.0",
|
|
106
106
|
"http-errors": "1.8.0",
|
|
107
|
-
"inquirer": "8.
|
|
107
|
+
"inquirer": "8.2.0",
|
|
108
108
|
"is-docker": "2.2.1",
|
|
109
109
|
"koa": "2.13.3",
|
|
110
110
|
"koa-body": "4.2.0",
|
|
@@ -134,5 +134,5 @@
|
|
|
134
134
|
"node": ">=12.x.x <=16.x.x",
|
|
135
135
|
"npm": ">=6.0.0"
|
|
136
136
|
},
|
|
137
|
-
"gitHead": "
|
|
137
|
+
"gitHead": "c69713bf7f437a7cee66ffdeed95227d6246a872"
|
|
138
138
|
}
|