@strapi/strapi 4.0.0-next.9 → 4.0.3
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 +14 -14
- package/bin/strapi.js +37 -6
- package/lib/Strapi.js +140 -72
- package/lib/commands/build.js +21 -11
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/controllers/list.js +22 -0
- package/lib/commands/develop.js +24 -27
- 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 -9
- package/lib/core/app-configuration/index.js +3 -19
- package/lib/core/bootstrap.js +3 -34
- package/lib/core/domain/content-type/index.js +3 -7
- package/lib/core/domain/module/index.js +8 -6
- package/lib/core/domain/module/validation.js +1 -4
- package/lib/core/loaders/admin.js +2 -2
- package/lib/core/loaders/apis.js +7 -7
- package/lib/core/loaders/components.js +3 -5
- package/lib/core/loaders/index.js +1 -0
- package/lib/core/loaders/middlewares.js +23 -123
- package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
- package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
- package/lib/core/loaders/plugins/index.js +30 -16
- package/lib/core/loaders/policies.js +1 -1
- package/lib/core/loaders/src-index.js +39 -0
- package/lib/core/registries/apis.js +2 -16
- package/lib/core/registries/content-types.js +50 -6
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +74 -3
- 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 +61 -2
- package/lib/core/registries/modules.js +3 -3
- package/lib/core/registries/plugins.js +2 -2
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +57 -6
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +71 -15
- package/lib/core-api/controller/collection-type.js +38 -11
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +30 -11
- package/lib/core-api/controller/single-type.js +26 -7
- package/lib/core-api/controller/transform.js +28 -3
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +22 -27
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +9 -19
- package/lib/core-api/service/pagination.js +16 -16
- package/lib/core-api/service/single-type.js +17 -20
- 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 -116
- 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 +72 -77
- 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 -49
- 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 +118 -60
- package/lib/services/entity-service/params.js +48 -81
- package/lib/services/entity-validator/index.js +76 -43
- package/lib/services/entity-validator/validators.js +131 -43
- package/lib/services/errors.js +77 -0
- package/lib/services/fs.js +1 -1
- package/lib/services/metrics/index.js +38 -36
- 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/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/signals.js +24 -0
- package/lib/utils/update-notifier/index.js +2 -1
- package/package.json +94 -93
- package/lib/core/app-configuration/load-functions.js +0 -28
- package/lib/core-api/index.js +0 -39
- 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 -72
- 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 -72
- package/lib/middlewares/router/utils/compose-endpoint.js +0 -169
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Database } from '@strapi/database';
|
|
2
|
+
import { Strapi } from '../../';
|
|
3
|
+
|
|
4
|
+
type ID = number | string;
|
|
5
|
+
|
|
6
|
+
type EntityServiceAction =
|
|
7
|
+
| 'findMany'
|
|
8
|
+
| 'findPage'
|
|
9
|
+
| 'findWithRelationCounts'
|
|
10
|
+
| 'findOne'
|
|
11
|
+
| 'count'
|
|
12
|
+
| 'create'
|
|
13
|
+
| 'update'
|
|
14
|
+
| 'delete';
|
|
15
|
+
|
|
16
|
+
type PaginationInfo = {
|
|
17
|
+
page: number;
|
|
18
|
+
pageSize: number;
|
|
19
|
+
pageCount: number;
|
|
20
|
+
total: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type Params<T> = {
|
|
24
|
+
fields?: (keyof T)[];
|
|
25
|
+
filters?: any;
|
|
26
|
+
_q?: string;
|
|
27
|
+
populate?: any;
|
|
28
|
+
sort?: any;
|
|
29
|
+
start?: number;
|
|
30
|
+
limit?: number;
|
|
31
|
+
page?: number;
|
|
32
|
+
pageSize?: number;
|
|
33
|
+
publicationState?: string;
|
|
34
|
+
data?: any;
|
|
35
|
+
files?: any;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface EntityService {
|
|
39
|
+
uploadFiles<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, entity, files);
|
|
40
|
+
wrapParams<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
41
|
+
params: Params<T>,
|
|
42
|
+
{ uid: K, action: EntityServiceAction }
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
findMany<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
46
|
+
uid: K,
|
|
47
|
+
params: Params<T>
|
|
48
|
+
): Promise<T[]>;
|
|
49
|
+
findPage<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
50
|
+
uid: K,
|
|
51
|
+
params: Params<T>
|
|
52
|
+
): Promise<{
|
|
53
|
+
results: T[];
|
|
54
|
+
pagination: PaginationInfo;
|
|
55
|
+
}>;
|
|
56
|
+
|
|
57
|
+
findWithRelationCounts<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
58
|
+
uid: K,
|
|
59
|
+
params: Params<T>
|
|
60
|
+
): Promise<{
|
|
61
|
+
results: T[];
|
|
62
|
+
pagination: PaginationInfo;
|
|
63
|
+
}>;
|
|
64
|
+
|
|
65
|
+
findOne<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
66
|
+
uid: K,
|
|
67
|
+
entityId: ID,
|
|
68
|
+
params: Params<T>
|
|
69
|
+
): Promise<T>;
|
|
70
|
+
|
|
71
|
+
count<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, params: Params<T>): Promise<any>;
|
|
72
|
+
create<K extends keyof AllTypes, T extends AllTypes[K]>(uid: K, params: Params<T>): Promise<any>;
|
|
73
|
+
update<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
74
|
+
uid: K,
|
|
75
|
+
entityId: ID,
|
|
76
|
+
params: Params<T>
|
|
77
|
+
): Promise<any>;
|
|
78
|
+
delete<K extends keyof AllTypes, T extends AllTypes[K]>(
|
|
79
|
+
uid: K,
|
|
80
|
+
entityId: ID,
|
|
81
|
+
params: Params<T>
|
|
82
|
+
): Promise<any>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default function(opts: {
|
|
86
|
+
strapi: Strapi;
|
|
87
|
+
db: Database;
|
|
88
|
+
// TODO: define types
|
|
89
|
+
eventHub: any;
|
|
90
|
+
entityValidator: any;
|
|
91
|
+
}): EntityService;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const _ = require('lodash');
|
|
3
4
|
const delegate = require('delegates');
|
|
4
5
|
const {
|
|
5
|
-
|
|
6
|
+
InvalidTimeError,
|
|
7
|
+
InvalidDateError,
|
|
8
|
+
InvalidDateTimeError,
|
|
9
|
+
} = require('@strapi/database').errors;
|
|
10
|
+
const {
|
|
6
11
|
webhook: webhookUtils,
|
|
7
12
|
contentTypes: contentTypesUtils,
|
|
8
|
-
|
|
13
|
+
sanitize,
|
|
9
14
|
} = require('@strapi/utils');
|
|
15
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
10
16
|
const uploadFiles = require('../utils/upload-files');
|
|
11
17
|
|
|
12
18
|
const {
|
|
@@ -16,12 +22,21 @@ const {
|
|
|
16
22
|
deleteComponents,
|
|
17
23
|
} = require('./components');
|
|
18
24
|
const { transformParamsToQuery, pickSelectionParams } = require('./params');
|
|
19
|
-
|
|
20
|
-
const { MANY_RELATIONS } = relationsUtils.constants;
|
|
25
|
+
const { applyTransforms } = require('./attributes');
|
|
21
26
|
|
|
22
27
|
// TODO: those should be strapi events used by the webhooks not the other way arround
|
|
23
28
|
const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
|
|
24
29
|
|
|
30
|
+
const databaseErrorsToTransform = [InvalidTimeError, InvalidDateTimeError, InvalidDateError];
|
|
31
|
+
|
|
32
|
+
const creationPipeline = (data, context) => {
|
|
33
|
+
return applyTransforms(data, context);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const updatePipeline = (data, context) => {
|
|
37
|
+
return applyTransforms(data, context);
|
|
38
|
+
};
|
|
39
|
+
|
|
25
40
|
module.exports = ctx => {
|
|
26
41
|
const implementation = createDefaultImplementation(ctx);
|
|
27
42
|
|
|
@@ -42,32 +57,57 @@ module.exports = ctx => {
|
|
|
42
57
|
// delegate every method in implementation
|
|
43
58
|
Object.keys(service.implementation).forEach(key => delegator.method(key));
|
|
44
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
|
+
|
|
45
82
|
return service;
|
|
46
83
|
};
|
|
47
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @type {import('.').default}
|
|
87
|
+
*/
|
|
48
88
|
const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) => ({
|
|
49
89
|
uploadFiles,
|
|
50
90
|
|
|
51
|
-
async
|
|
91
|
+
async wrapParams(options = {}) {
|
|
52
92
|
return options;
|
|
53
93
|
},
|
|
54
94
|
|
|
55
|
-
emitEvent(uid, event, entity) {
|
|
95
|
+
async emitEvent(uid, event, entity) {
|
|
56
96
|
const model = strapi.getModel(uid);
|
|
97
|
+
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
|
|
57
98
|
|
|
58
99
|
eventHub.emit(event, {
|
|
59
100
|
model: model.modelName,
|
|
60
|
-
entry:
|
|
101
|
+
entry: sanitizedEntity,
|
|
61
102
|
});
|
|
62
103
|
},
|
|
63
104
|
|
|
64
|
-
|
|
65
|
-
async find(uid, opts) {
|
|
105
|
+
async findMany(uid, opts) {
|
|
66
106
|
const { kind } = strapi.getModel(uid);
|
|
67
107
|
|
|
68
|
-
const
|
|
108
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
|
|
69
109
|
|
|
70
|
-
const query = transformParamsToQuery(uid,
|
|
110
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
71
111
|
|
|
72
112
|
if (kind === 'singleType') {
|
|
73
113
|
return db.query(uid).findOne(query);
|
|
@@ -77,42 +117,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
77
117
|
},
|
|
78
118
|
|
|
79
119
|
async findPage(uid, opts) {
|
|
80
|
-
const
|
|
120
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
|
|
81
121
|
|
|
82
|
-
const query = transformParamsToQuery(uid,
|
|
122
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
83
123
|
|
|
84
124
|
return db.query(uid).findPage(query);
|
|
85
125
|
},
|
|
86
126
|
|
|
87
127
|
// TODO: streamline the logic based on the populate option
|
|
88
128
|
async findWithRelationCounts(uid, opts) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
|
|
129
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findWithRelationCounts' });
|
|
92
130
|
|
|
93
|
-
const query = transformParamsToQuery(uid,
|
|
131
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
94
132
|
|
|
95
|
-
const {
|
|
96
|
-
|
|
97
|
-
const populate = (query.populate || []).reduce((populate, attributeName) => {
|
|
98
|
-
const attribute = attributes[attributeName];
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
MANY_RELATIONS.includes(attribute.relation) &&
|
|
102
|
-
contentTypesUtils.isVisibleAttribute(model, attributeName)
|
|
103
|
-
) {
|
|
104
|
-
populate[attributeName] = { count: true };
|
|
105
|
-
} else {
|
|
106
|
-
populate[attributeName] = true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return populate;
|
|
110
|
-
}, {});
|
|
111
|
-
|
|
112
|
-
const { results, pagination } = await db.query(uid).findPage({
|
|
113
|
-
...query,
|
|
114
|
-
populate,
|
|
115
|
-
});
|
|
133
|
+
const { results, pagination } = await db.query(uid).findPage(query);
|
|
116
134
|
|
|
117
135
|
return {
|
|
118
136
|
results,
|
|
@@ -121,23 +139,24 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
121
139
|
},
|
|
122
140
|
|
|
123
141
|
async findOne(uid, entityId, opts) {
|
|
124
|
-
const
|
|
142
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findOne' });
|
|
125
143
|
|
|
126
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
144
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
127
145
|
|
|
128
146
|
return db.query(uid).findOne({ ...query, where: { id: entityId } });
|
|
129
147
|
},
|
|
130
148
|
|
|
131
149
|
async count(uid, opts) {
|
|
132
|
-
const
|
|
150
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'count' });
|
|
133
151
|
|
|
134
|
-
const query = transformParamsToQuery(uid,
|
|
152
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
135
153
|
|
|
136
154
|
return db.query(uid).count(query);
|
|
137
155
|
},
|
|
138
156
|
|
|
139
157
|
async create(uid, opts) {
|
|
140
|
-
const
|
|
158
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'create' });
|
|
159
|
+
const { data, files } = wrappedParams;
|
|
141
160
|
|
|
142
161
|
const model = strapi.getModel(uid);
|
|
143
162
|
|
|
@@ -145,30 +164,33 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
145
164
|
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
|
146
165
|
|
|
147
166
|
// select / populate
|
|
148
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
167
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
149
168
|
|
|
150
169
|
// TODO: wrap into transaction
|
|
151
170
|
const componentData = await createComponents(uid, validData);
|
|
152
171
|
|
|
153
172
|
let entity = await db.query(uid).create({
|
|
154
173
|
...query,
|
|
155
|
-
data: Object.assign(omitComponentData(model, validData), componentData),
|
|
174
|
+
data: creationPipeline(Object.assign(omitComponentData(model, validData), componentData), {
|
|
175
|
+
contentType: model,
|
|
176
|
+
}),
|
|
156
177
|
});
|
|
157
178
|
|
|
158
179
|
// TODO: upload the files then set the links in the entity like with compo to avoid making too many queries
|
|
159
180
|
// FIXME: upload in components
|
|
160
181
|
if (files && Object.keys(files).length > 0) {
|
|
161
182
|
await this.uploadFiles(uid, entity, files);
|
|
162
|
-
entity = await this.findOne(uid, entity.id,
|
|
183
|
+
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
163
184
|
}
|
|
164
185
|
|
|
165
|
-
this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
186
|
+
await this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
166
187
|
|
|
167
188
|
return entity;
|
|
168
189
|
},
|
|
169
190
|
|
|
170
191
|
async update(uid, entityId, opts) {
|
|
171
|
-
const
|
|
192
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'update' });
|
|
193
|
+
const { data, files } = wrappedParams;
|
|
172
194
|
|
|
173
195
|
const model = strapi.getModel(uid);
|
|
174
196
|
|
|
@@ -180,11 +202,16 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
180
202
|
|
|
181
203
|
const isDraft = contentTypesUtils.isDraft(entityToUpdate, model);
|
|
182
204
|
|
|
183
|
-
const validData = await entityValidator.validateEntityUpdate(
|
|
184
|
-
|
|
185
|
-
|
|
205
|
+
const validData = await entityValidator.validateEntityUpdate(
|
|
206
|
+
model,
|
|
207
|
+
data,
|
|
208
|
+
{
|
|
209
|
+
isDraft,
|
|
210
|
+
},
|
|
211
|
+
entityToUpdate
|
|
212
|
+
);
|
|
186
213
|
|
|
187
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
214
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
188
215
|
|
|
189
216
|
// TODO: wrap in transaction
|
|
190
217
|
const componentData = await updateComponents(uid, entityToUpdate, validData);
|
|
@@ -192,26 +219,28 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
192
219
|
let entity = await db.query(uid).update({
|
|
193
220
|
...query,
|
|
194
221
|
where: { id: entityId },
|
|
195
|
-
data: Object.assign(omitComponentData(model, validData), componentData),
|
|
222
|
+
data: updatePipeline(Object.assign(omitComponentData(model, validData), componentData), {
|
|
223
|
+
contentType: model,
|
|
224
|
+
}),
|
|
196
225
|
});
|
|
197
226
|
|
|
198
227
|
// TODO: upload the files then set the links in the entity like with compo to avoid making too many queries
|
|
199
228
|
// FIXME: upload in components
|
|
200
229
|
if (files && Object.keys(files).length > 0) {
|
|
201
230
|
await this.uploadFiles(uid, entity, files);
|
|
202
|
-
entity = await this.findOne(uid, entity.id,
|
|
231
|
+
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
203
232
|
}
|
|
204
233
|
|
|
205
|
-
this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
234
|
+
await this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
206
235
|
|
|
207
236
|
return entity;
|
|
208
237
|
},
|
|
209
238
|
|
|
210
239
|
async delete(uid, entityId, opts) {
|
|
211
|
-
const
|
|
240
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
|
212
241
|
|
|
213
242
|
// select / populate
|
|
214
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
243
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
215
244
|
|
|
216
245
|
const entityToDelete = await db.query(uid).findOne({
|
|
217
246
|
...query,
|
|
@@ -225,18 +254,47 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
225
254
|
await deleteComponents(uid, entityToDelete);
|
|
226
255
|
await db.query(uid).delete({ where: { id: entityToDelete.id } });
|
|
227
256
|
|
|
228
|
-
this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
257
|
+
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
229
258
|
|
|
230
259
|
return entityToDelete;
|
|
231
260
|
},
|
|
232
261
|
|
|
233
262
|
// FIXME: used only for the CM to be removed
|
|
234
263
|
async deleteMany(uid, opts) {
|
|
235
|
-
const
|
|
264
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
|
236
265
|
|
|
237
266
|
// select / populate
|
|
238
|
-
const query = transformParamsToQuery(uid,
|
|
267
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
239
268
|
|
|
240
269
|
return db.query(uid).deleteMany(query);
|
|
241
270
|
},
|
|
271
|
+
|
|
272
|
+
load(uid, entity, field, params = {}) {
|
|
273
|
+
const { attributes } = strapi.getModel(uid);
|
|
274
|
+
|
|
275
|
+
const attribute = attributes[field];
|
|
276
|
+
|
|
277
|
+
const loadParams = {};
|
|
278
|
+
|
|
279
|
+
switch (attribute.type) {
|
|
280
|
+
case 'relation': {
|
|
281
|
+
Object.assign(loadParams, transformParamsToQuery(attribute.target, params));
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
case 'component': {
|
|
285
|
+
Object.assign(loadParams, transformParamsToQuery(attribute.component, params));
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case 'dynamiczone': {
|
|
289
|
+
Object.assign(loadParams, transformParamsToQuery(null, params));
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case 'media': {
|
|
293
|
+
Object.assign(loadParams, transformParamsToQuery('plugin::upload.file', params));
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return db.query(uid).load(entity, field, loadParams);
|
|
299
|
+
},
|
|
242
300
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { pick } = require('lodash/fp');
|
|
3
|
+
const { pick, isNil, toNumber, isInteger } = require('lodash/fp');
|
|
4
|
+
const { PaginationError } = require('@strapi/utils').errors;
|
|
4
5
|
|
|
5
6
|
const {
|
|
6
7
|
convertSortQueryParams,
|
|
@@ -9,118 +10,84 @@ const {
|
|
|
9
10
|
convertPopulateQueryParams,
|
|
10
11
|
convertFiltersQueryParams,
|
|
11
12
|
convertFieldsQueryParams,
|
|
13
|
+
convertPublicationStateParams,
|
|
12
14
|
} = require('@strapi/utils/lib/convert-query-params');
|
|
13
15
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
|
|
16
|
+
const pickSelectionParams = pick(['fields', 'populate']);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
18
|
+
const transformParamsToQuery = (uid, params) => {
|
|
19
|
+
// NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
|
|
20
|
+
const type = strapi.getModel(uid);
|
|
21
21
|
|
|
22
22
|
const query = {};
|
|
23
23
|
|
|
24
|
-
const {
|
|
25
|
-
start,
|
|
26
|
-
page,
|
|
27
|
-
pageSize,
|
|
28
|
-
limit,
|
|
29
|
-
sort,
|
|
30
|
-
filters,
|
|
31
|
-
fields,
|
|
32
|
-
populate,
|
|
33
|
-
publicationState,
|
|
34
|
-
_q,
|
|
35
|
-
_where,
|
|
36
|
-
...rest
|
|
37
|
-
} = params;
|
|
38
|
-
|
|
39
|
-
if (_q) {
|
|
40
|
-
query._q = _q;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (page) {
|
|
44
|
-
query.page = Number(page);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (pageSize) {
|
|
48
|
-
query.pageSize = Number(pageSize);
|
|
49
|
-
}
|
|
24
|
+
const { _q, sort, filters, fields, populate, page, pageSize, start, limit } = params;
|
|
50
25
|
|
|
51
|
-
if (
|
|
52
|
-
query.
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (limit) {
|
|
56
|
-
query.limit = convertLimitQueryParams(limit);
|
|
26
|
+
if (!isNil(_q)) {
|
|
27
|
+
query._q = _q;
|
|
57
28
|
}
|
|
58
29
|
|
|
59
|
-
if (sort) {
|
|
30
|
+
if (!isNil(sort)) {
|
|
60
31
|
query.orderBy = convertSortQueryParams(sort);
|
|
61
32
|
}
|
|
62
33
|
|
|
63
|
-
if (filters) {
|
|
34
|
+
if (!isNil(filters)) {
|
|
64
35
|
query.where = convertFiltersQueryParams(filters);
|
|
65
36
|
}
|
|
66
37
|
|
|
67
|
-
if (
|
|
68
|
-
query.where = {
|
|
69
|
-
$and: [_where].concat(query.where || []),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (fields) {
|
|
38
|
+
if (!isNil(fields)) {
|
|
74
39
|
query.select = convertFieldsQueryParams(fields);
|
|
75
40
|
}
|
|
76
41
|
|
|
77
|
-
if (populate) {
|
|
42
|
+
if (!isNil(populate)) {
|
|
78
43
|
query.populate = convertPopulateQueryParams(populate);
|
|
79
44
|
}
|
|
80
45
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const { publicationState = 'live' } = params;
|
|
46
|
+
const isPagePagination = !isNil(page) || !isNil(pageSize);
|
|
47
|
+
const isOffsetPagination = !isNil(start) || !isNil(limit);
|
|
84
48
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
49
|
+
if (isPagePagination && isOffsetPagination) {
|
|
50
|
+
throw new PaginationError(
|
|
51
|
+
'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
|
|
52
|
+
);
|
|
53
|
+
}
|
|
90
54
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
$and: [liveClause].concat(query.where || []),
|
|
94
|
-
};
|
|
55
|
+
if (!isNil(page)) {
|
|
56
|
+
const pageVal = toNumber(page);
|
|
95
57
|
|
|
96
|
-
|
|
58
|
+
if (!isInteger(pageVal) || pageVal <= 0) {
|
|
59
|
+
throw new PaginationError(
|
|
60
|
+
`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
|
|
61
|
+
);
|
|
97
62
|
}
|
|
63
|
+
|
|
64
|
+
query.page = pageVal;
|
|
98
65
|
}
|
|
99
66
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
...query,
|
|
103
|
-
};
|
|
67
|
+
if (!isNil(pageSize)) {
|
|
68
|
+
const pageSizeVal = toNumber(pageSize);
|
|
104
69
|
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
71
|
+
throw new PaginationError(
|
|
72
|
+
`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
107
75
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const obj = {};
|
|
76
|
+
query.pageSize = pageSizeVal;
|
|
77
|
+
}
|
|
111
78
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} else {
|
|
116
|
-
obj[key] = params[key];
|
|
117
|
-
}
|
|
118
|
-
});
|
|
79
|
+
if (!isNil(start)) {
|
|
80
|
+
query.offset = convertStartQueryParams(start);
|
|
81
|
+
}
|
|
119
82
|
|
|
120
|
-
|
|
121
|
-
|
|
83
|
+
if (!isNil(limit)) {
|
|
84
|
+
query.limit = convertLimitQueryParams(limit);
|
|
85
|
+
}
|
|
122
86
|
|
|
123
|
-
|
|
87
|
+
convertPublicationStateParams(type, params, query);
|
|
88
|
+
|
|
89
|
+
return query;
|
|
90
|
+
};
|
|
124
91
|
|
|
125
92
|
module.exports = {
|
|
126
93
|
transformParamsToQuery,
|