@strapi/strapi 4.0.0-next.11 → 4.0.0-next.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.
Files changed (51) hide show
  1. package/bin/strapi.js +1 -4
  2. package/lib/Strapi.js +82 -28
  3. package/lib/commands/console.js +1 -1
  4. package/lib/commands/develop.js +4 -3
  5. package/lib/core/domain/content-type/index.js +3 -7
  6. package/lib/core/domain/module/index.js +2 -2
  7. package/lib/core/loaders/apis.js +4 -6
  8. package/lib/core/loaders/components.js +3 -5
  9. package/lib/core/loaders/index.js +1 -0
  10. package/lib/core/loaders/middlewares.js +1 -1
  11. package/lib/core/loaders/plugins/get-enabled-plugins.js +2 -2
  12. package/lib/core/loaders/plugins/index.js +7 -7
  13. package/lib/core/loaders/policies.js +1 -1
  14. package/lib/core/loaders/src-index.js +38 -0
  15. package/lib/core/registries/hooks.js +37 -0
  16. package/lib/core/registries/services.js +7 -7
  17. package/lib/core-api/controller/collection-type.js +5 -5
  18. package/lib/core-api/controller/single-type.js +3 -3
  19. package/lib/core-api/controller/transform.js +28 -3
  20. package/lib/core-api/service/collection-type.js +18 -19
  21. package/lib/core-api/service/single-type.js +10 -14
  22. package/lib/index.d.ts +9 -31
  23. package/lib/middlewares/cors/index.js +1 -1
  24. package/lib/middlewares/{boom → error}/defaults.json +1 -1
  25. package/lib/middlewares/{boom → error}/index.js +1 -1
  26. package/lib/middlewares/favicon/index.js +1 -2
  27. package/lib/middlewares/index.js +1 -1
  28. package/lib/middlewares/public/index.js +2 -2
  29. package/lib/middlewares/responses/index.js +2 -1
  30. package/lib/middlewares/router/index.js +5 -3
  31. package/lib/migrations/draft-publish.js +57 -0
  32. package/lib/services/auth/index.js +2 -2
  33. package/lib/services/core-store.js +64 -49
  34. package/lib/services/cron.js +54 -0
  35. package/lib/services/entity-service/components.js +37 -12
  36. package/lib/services/entity-service/index.d.ts +91 -0
  37. package/lib/services/entity-service/index.js +52 -50
  38. package/lib/services/entity-service/params.js +74 -57
  39. package/lib/services/fs.js +1 -1
  40. package/lib/services/metrics/index.js +1 -1
  41. package/lib/services/server/policy.js +15 -4
  42. package/lib/services/webhook-runner.js +1 -1
  43. package/lib/utils/ee.js +3 -3
  44. package/lib/utils/get-dirs.js +15 -0
  45. package/lib/utils/index.js +2 -0
  46. package/lib/utils/update-notifier/index.js +2 -1
  47. package/package.json +88 -98
  48. package/lib/middlewares/cron/defaults.json +0 -5
  49. package/lib/middlewares/cron/index.js +0 -43
  50. package/lib/middlewares/language/defaults.json +0 -9
  51. package/lib/middlewares/language/index.js +0 -40
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const _ = require('lodash');
4
- const { has, prop, omit } = require('lodash/fp');
4
+ const { has, prop, omit, toString } = require('lodash/fp');
5
5
 
6
6
  const { contentTypes: contentTypesUtils } = require('@strapi/utils');
7
7
 
@@ -131,11 +131,26 @@ const updateComponents = async (uid, entityToUpdate, data) => {
131
131
  componentValue.map(value => updateOrCreateComponent(componentUID, value))
132
132
  );
133
133
 
134
- // TODO: add order
135
- componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => id);
134
+ componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }, idx) => {
135
+ return {
136
+ id,
137
+ __pivot: {
138
+ order: idx + 1,
139
+ field: attributeName,
140
+ component_type: componentUID,
141
+ },
142
+ };
143
+ });
136
144
  } else {
137
145
  const component = await updateOrCreateComponent(componentUID, componentValue);
138
- componentBody[attributeName] = component && component.id;
146
+ componentBody[attributeName] = component && {
147
+ id: component.id,
148
+ __pivot: {
149
+ order: 1,
150
+ field: attributeName,
151
+ component_type: componentUID,
152
+ },
153
+ };
139
154
  }
140
155
 
141
156
  continue;
@@ -151,9 +166,17 @@ const updateComponents = async (uid, entityToUpdate, data) => {
151
166
  }
152
167
 
153
168
  componentBody[attributeName] = await Promise.all(
154
- dynamiczoneValues.map(async value => {
169
+ dynamiczoneValues.map(async (value, idx) => {
155
170
  const { id } = await updateOrCreateComponent(value.__component, value);
156
- return { id, __component: value.__component };
171
+
172
+ return {
173
+ id,
174
+ __component: value.__component,
175
+ __pivot: {
176
+ order: idx + 1,
177
+ field: attributeName,
178
+ },
179
+ };
157
180
  })
158
181
  );
159
182
 
@@ -175,11 +198,13 @@ const deleteOldComponents = async (
175
198
 
176
199
  const idsToKeep = _.castArray(componentValue)
177
200
  .filter(has('id'))
178
- .map(prop('id'));
201
+ .map(prop('id'))
202
+ .map(toString);
179
203
 
180
204
  const allIds = _.castArray(previousValue)
181
205
  .filter(has('id'))
182
- .map(prop('id'));
206
+ .map(prop('id'))
207
+ .map(toString);
183
208
 
184
209
  idsToKeep.forEach(id => {
185
210
  if (!allIds.includes(id)) {
@@ -206,14 +231,14 @@ const deleteOldDZComponents = async (uid, entityToUpdate, attributeName, dynamic
206
231
  const idsToKeep = _.castArray(dynamiczoneValues)
207
232
  .filter(has('id'))
208
233
  .map(({ id, __component }) => ({
209
- id,
234
+ id: toString(id),
210
235
  __component,
211
236
  }));
212
237
 
213
238
  const allIds = _.castArray(previousValue)
214
239
  .filter(has('id'))
215
240
  .map(({ id, __component }) => ({
216
- id,
241
+ id: toString(id),
217
242
  __component,
218
243
  }));
219
244
 
@@ -293,7 +318,7 @@ const createComponent = async (uid, data) => {
293
318
 
294
319
  const componentData = await createComponents(uid, data);
295
320
 
296
- return await strapi.query(uid).create({
321
+ return strapi.query(uid).create({
297
322
  data: Object.assign(omitComponentData(model, data), componentData),
298
323
  });
299
324
  };
@@ -304,7 +329,7 @@ const updateComponent = async (uid, componentToUpdate, data) => {
304
329
 
305
330
  const componentData = await updateComponents(uid, componentToUpdate, data);
306
331
 
307
- return await strapi.query(uid).update({
332
+ return strapi.query(uid).update({
308
333
  where: {
309
334
  id: componentToUpdate.id,
310
335
  },
@@ -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
+ 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,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  const delegate = require('delegates');
4
+ const { pipe } = require('lodash/fp');
5
+
4
6
  const {
5
7
  sanitizeEntity,
6
8
  webhook: webhookUtils,
7
9
  contentTypes: contentTypesUtils,
8
- relations: relationsUtils,
9
10
  } = require('@strapi/utils');
10
11
  const uploadFiles = require('../utils/upload-files');
11
12
 
@@ -15,9 +16,12 @@ const {
15
16
  updateComponents,
16
17
  deleteComponents,
17
18
  } = require('./components');
18
- const { transformParamsToQuery, pickSelectionParams } = require('./params');
19
-
20
- const { MANY_RELATIONS } = relationsUtils.constants;
19
+ const {
20
+ transformCommonParams,
21
+ transformPaginationParams,
22
+ transformParamsToQuery,
23
+ pickSelectionParams,
24
+ } = require('./params');
21
25
 
22
26
  // TODO: those should be strapi events used by the webhooks not the other way arround
23
27
  const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
@@ -45,10 +49,13 @@ module.exports = ctx => {
45
49
  return service;
46
50
  };
47
51
 
52
+ /**
53
+ * @type {import('.').default}
54
+ */
48
55
  const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) => ({
49
56
  uploadFiles,
50
57
 
51
- async wrapOptions(options = {}) {
58
+ async wrapParams(options = {}) {
52
59
  return options;
53
60
  },
54
61
 
@@ -61,13 +68,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
61
68
  });
62
69
  },
63
70
 
64
- // TODO: rename to findMany
65
- async find(uid, opts) {
71
+ async findMany(uid, opts) {
66
72
  const { kind } = strapi.getModel(uid);
67
73
 
68
- const { params } = await this.wrapOptions(opts, { uid, action: 'find' });
74
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
69
75
 
70
- const query = transformParamsToQuery(uid, params);
76
+ const query = transformParamsToQuery(uid, wrappedParams);
71
77
 
72
78
  if (kind === 'singleType') {
73
79
  return db.query(uid).findOne(query);
@@ -77,42 +83,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
77
83
  },
78
84
 
79
85
  async findPage(uid, opts) {
80
- const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
86
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
81
87
 
82
- const query = transformParamsToQuery(uid, params);
88
+ const query = transformParamsToQuery(uid, wrappedParams);
83
89
 
84
90
  return db.query(uid).findPage(query);
85
91
  },
86
92
 
87
93
  // TODO: streamline the logic based on the populate option
88
94
  async findWithRelationCounts(uid, opts) {
89
- const model = strapi.getModel(uid);
90
-
91
- const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
95
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findWithRelationCounts' });
92
96
 
93
- const query = transformParamsToQuery(uid, params);
94
-
95
- const { attributes } = model;
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
- }
97
+ const query = transformParamsToQuery(uid, wrappedParams);
108
98
 
109
- return populate;
110
- }, {});
111
-
112
- const { results, pagination } = await db.query(uid).findPage({
113
- ...query,
114
- populate,
115
- });
99
+ const { results, pagination } = await db.query(uid).findPage(query);
116
100
 
117
101
  return {
118
102
  results,
@@ -121,23 +105,24 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
121
105
  },
122
106
 
123
107
  async findOne(uid, entityId, opts) {
124
- const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' });
108
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'findOne' });
125
109
 
126
- const query = transformParamsToQuery(uid, pickSelectionParams(params));
110
+ const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
127
111
 
128
112
  return db.query(uid).findOne({ ...query, where: { id: entityId } });
129
113
  },
130
114
 
131
115
  async count(uid, opts) {
132
- const { params } = await this.wrapOptions(opts, { uid, action: 'count' });
116
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'count' });
133
117
 
134
- const query = transformParamsToQuery(uid, params);
118
+ const query = transformParamsToQuery(uid, wrappedParams);
135
119
 
136
120
  return db.query(uid).count(query);
137
121
  },
138
122
 
139
123
  async create(uid, opts) {
140
- const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' });
124
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'create' });
125
+ const { data, files } = wrappedParams;
141
126
 
142
127
  const model = strapi.getModel(uid);
143
128
 
@@ -145,7 +130,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
145
130
  const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
146
131
 
147
132
  // select / populate
148
- const query = transformParamsToQuery(uid, pickSelectionParams(params));
133
+ const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
149
134
 
150
135
  // TODO: wrap into transaction
151
136
  const componentData = await createComponents(uid, validData);
@@ -159,7 +144,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
159
144
  // FIXME: upload in components
160
145
  if (files && Object.keys(files).length > 0) {
161
146
  await this.uploadFiles(uid, entity, files);
162
- entity = await this.findOne(uid, entity.id, { params });
147
+ entity = await this.findOne(uid, entity.id, wrappedParams);
163
148
  }
164
149
 
165
150
  this.emitEvent(uid, ENTRY_CREATE, entity);
@@ -168,7 +153,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
168
153
  },
169
154
 
170
155
  async update(uid, entityId, opts) {
171
- const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' });
156
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'update' });
157
+ const { data, files } = wrappedParams;
172
158
 
173
159
  const model = strapi.getModel(uid);
174
160
 
@@ -184,7 +170,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
184
170
  isDraft,
185
171
  });
186
172
 
187
- const query = transformParamsToQuery(uid, pickSelectionParams(params));
173
+ const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
188
174
 
189
175
  // TODO: wrap in transaction
190
176
  const componentData = await updateComponents(uid, entityToUpdate, validData);
@@ -199,7 +185,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
199
185
  // FIXME: upload in components
200
186
  if (files && Object.keys(files).length > 0) {
201
187
  await this.uploadFiles(uid, entity, files);
202
- entity = await this.findOne(uid, entity.id, { params });
188
+ entity = await this.findOne(uid, entity.id, wrappedParams);
203
189
  }
204
190
 
205
191
  this.emitEvent(uid, ENTRY_UPDATE, entity);
@@ -208,10 +194,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
208
194
  },
209
195
 
210
196
  async delete(uid, entityId, opts) {
211
- const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
197
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
212
198
 
213
199
  // select / populate
214
- const query = transformParamsToQuery(uid, pickSelectionParams(params));
200
+ const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
215
201
 
216
202
  const entityToDelete = await db.query(uid).findOne({
217
203
  ...query,
@@ -232,11 +218,27 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
232
218
 
233
219
  // FIXME: used only for the CM to be removed
234
220
  async deleteMany(uid, opts) {
235
- const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
221
+ const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
236
222
 
237
223
  // select / populate
238
- const query = transformParamsToQuery(uid, params);
224
+ const query = transformParamsToQuery(uid, wrappedParams);
239
225
 
240
226
  return db.query(uid).deleteMany(query);
241
227
  },
228
+
229
+ load(uid, entity, field, params) {
230
+ const { attributes } = strapi.getModel(uid);
231
+
232
+ const attribute = attributes[field];
233
+
234
+ const loadParams =
235
+ attribute.type === 'relation'
236
+ ? transformParamsToQuery(attribute.target, params)
237
+ : pipe(
238
+ transformCommonParams,
239
+ transformPaginationParams
240
+ )(params);
241
+
242
+ return db.query(uid).load(entity, field, loadParams);
243
+ },
242
244
  });
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { pick } = require('lodash/fp');
3
+ const { pick, pipe, isNil } = require('lodash/fp');
4
4
 
5
5
  const {
6
6
  convertSortQueryParams,
@@ -15,45 +15,26 @@ const { contentTypes: contentTypesUtils } = require('@strapi/utils');
15
15
 
16
16
  const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
17
17
 
18
- // TODO: check invalid values / add defaults ....
19
- const transformParamsToQuery = (uid, params = {}) => {
20
- const model = strapi.getModel(uid);
21
-
18
+ // TODO: to remove once the front is migrated
19
+ const convertOldQuery = params => {
22
20
  const query = {};
23
21
 
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
- }
22
+ Object.keys(params).forEach(key => {
23
+ if (key.startsWith('_')) {
24
+ query[key.slice(1)] = params[key];
25
+ } else {
26
+ query[key] = params[key];
27
+ }
28
+ });
46
29
 
47
- if (pageSize) {
48
- query.pageSize = Number(pageSize);
49
- }
30
+ return query;
31
+ };
50
32
 
51
- if (start) {
52
- query.offset = convertStartQueryParams(start);
53
- }
33
+ const transformCommonParams = (params = {}) => {
34
+ const { _q, sort, filters, _where, fields, populate, ...query } = params;
54
35
 
55
- if (limit) {
56
- query.limit = convertLimitQueryParams(limit);
36
+ if (_q) {
37
+ query._q = _q;
57
38
  }
58
39
 
59
40
  if (sort) {
@@ -78,8 +59,50 @@ const transformParamsToQuery = (uid, params = {}) => {
78
59
  query.populate = convertPopulateQueryParams(populate);
79
60
  }
80
61
 
81
- // TODO: move to convert-query-params ?
82
- if (publicationState && contentTypesUtils.hasDraftAndPublish(model)) {
62
+ return { ...convertOldQuery(query), ...query };
63
+ };
64
+
65
+ const transformPaginationParams = (params = {}) => {
66
+ const { page, pageSize, start, limit, ...query } = params;
67
+
68
+ const isPagePagination = !isNil(page) || !isNil(pageSize);
69
+ const isOffsetPagination = !isNil(start) || !isNil(limit);
70
+
71
+ if (isPagePagination && isOffsetPagination) {
72
+ throw new Error(
73
+ 'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
74
+ );
75
+ }
76
+
77
+ if (page) {
78
+ query.page = Number(page);
79
+ }
80
+
81
+ if (pageSize) {
82
+ query.pageSize = Number(pageSize);
83
+ }
84
+
85
+ if (start) {
86
+ query.offset = convertStartQueryParams(start);
87
+ }
88
+
89
+ if (limit) {
90
+ query.limit = convertLimitQueryParams(limit);
91
+ }
92
+
93
+ return { ...convertOldQuery(query), ...query };
94
+ };
95
+
96
+ const transformPublicationStateParams = uid => (params = {}) => {
97
+ const contentType = strapi.getModel(uid);
98
+
99
+ if (!contentType) {
100
+ return params;
101
+ }
102
+
103
+ const { publicationState, ...query } = params;
104
+
105
+ if (publicationState && contentTypesUtils.hasDraftAndPublish(contentType)) {
83
106
  const { publicationState = 'live' } = params;
84
107
 
85
108
  const liveClause = {
@@ -97,32 +120,26 @@ const transformParamsToQuery = (uid, params = {}) => {
97
120
  }
98
121
  }
99
122
 
100
- const finalQuery = {
101
- ...convertOldQuery(rest),
102
- ...query,
103
- };
104
-
105
- return finalQuery;
123
+ return { ...convertOldQuery(query), ...query };
106
124
  };
107
125
 
108
- // TODO: to remove once the front is migrated
109
- const convertOldQuery = params => {
110
- const obj = {};
111
-
112
- Object.keys(params).forEach(key => {
113
- if (key.startsWith('_')) {
114
- obj[key.slice(1)] = params[key];
115
- } else {
116
- obj[key] = params[key];
117
- }
118
- });
126
+ const pickSelectionParams = pick(['fields', 'populate']);
119
127
 
120
- return obj;
128
+ const transformParamsToQuery = (uid, params) => {
129
+ return pipe(
130
+ // _q, _where, filters, etc...
131
+ transformCommonParams,
132
+ // page, pageSize, start, limit
133
+ transformPaginationParams,
134
+ // publicationState
135
+ transformPublicationStateParams(uid)
136
+ )(params);
121
137
  };
122
138
 
123
- const pickSelectionParams = pick(['fields', 'populate']);
124
-
125
139
  module.exports = {
140
+ transformCommonParams,
141
+ transformPublicationStateParams,
142
+ transformPaginationParams,
126
143
  transformParamsToQuery,
127
144
  pickSelectionParams,
128
145
  };
@@ -12,7 +12,7 @@ module.exports = strapi => {
12
12
 
13
13
  const normalizedPath = path.normalize(filePath).replace(/^\/?(\.\/|\.\.\/)+/, '');
14
14
 
15
- return path.join(strapi.dir, normalizedPath);
15
+ return path.join(strapi.dirs.root, normalizedPath);
16
16
  }
17
17
 
18
18
  const strapiFS = {
@@ -88,7 +88,7 @@ const hashProject = strapi =>
88
88
 
89
89
  const hashDep = strapi => {
90
90
  const depStr = JSON.stringify(strapi.config.info.dependencies);
91
- const readmePath = path.join(strapi.dir, 'README.md');
91
+ const readmePath = path.join(strapi.dirs.root, 'README.md');
92
92
 
93
93
  try {
94
94
  if (fs.existsSync(readmePath)) {
@@ -11,11 +11,22 @@ const resolvePolicies = route => {
11
11
  const { pluginName, apiName } = route.info || {};
12
12
  const policiesConfig = getPoliciesConfig(route);
13
13
 
14
- const policies = policiesConfig.map(policyName => {
15
- return policy.get(policyName, { pluginName, apiName });
16
- });
14
+ const policiesMiddleware = async (ctx, next) => {
15
+ const context = policy.createPolicyContext('koa', ctx);
17
16
 
18
- return [...policies, bodyPolicy];
17
+ for (const policyName of policiesConfig) {
18
+ const resolvedPolicy = await policy.get(policyName, { pluginName, apiName });
19
+ const result = await resolvedPolicy({ ctx: context, strapi });
20
+
21
+ if (![true, undefined].includes(result)) {
22
+ throw new Error('Policies failed.');
23
+ }
24
+ }
25
+
26
+ await next();
27
+ };
28
+
29
+ return [policiesMiddleware, bodyPolicy];
19
30
  };
20
31
 
21
32
  module.exports = {
@@ -79,7 +79,7 @@ class WebhookRunner {
79
79
  method: 'post',
80
80
  body: JSON.stringify({
81
81
  event,
82
- created_at: new Date(),
82
+ createdAt: new Date(),
83
83
  ...info,
84
84
  }),
85
85
  headers: {
package/lib/utils/ee.js CHANGED
@@ -78,7 +78,7 @@ module.exports = ({ dir, logger = noLog }) => {
78
78
  };
79
79
 
80
80
  Object.defineProperty(module.exports, 'licenseInfo', {
81
- get: () => {
81
+ get() {
82
82
  mustHaveKey('licenseInfo');
83
83
  return internals.licenseInfo;
84
84
  },
@@ -87,7 +87,7 @@ Object.defineProperty(module.exports, 'licenseInfo', {
87
87
  });
88
88
 
89
89
  Object.defineProperty(module.exports, 'isEE', {
90
- get: () => {
90
+ get() {
91
91
  mustHaveKey('isEE');
92
92
  return internals.isEE;
93
93
  },
@@ -96,7 +96,7 @@ Object.defineProperty(module.exports, 'isEE', {
96
96
  });
97
97
 
98
98
  Object.defineProperty(module.exports, 'features', {
99
- get: () => {
99
+ get() {
100
100
  mustHaveKey('licenseInfo');
101
101
 
102
102
  const { type: licenseType } = module.exports.licenseInfo;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const { join } = require('path');
4
+
5
+ const getDirs = root => ({
6
+ root,
7
+ src: join(root, 'src'),
8
+ api: join(root, 'src', 'api'),
9
+ components: join(root, 'src', 'components'),
10
+ extensions: join(root, 'src', 'extensions'),
11
+ policies: join(root, 'src', 'policies'),
12
+ config: join(root, 'config'),
13
+ });
14
+
15
+ module.exports = getDirs;