@strapi/strapi 4.0.0-next.8 → 4.0.2

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 (147) hide show
  1. package/README.md +14 -14
  2. package/bin/strapi.js +46 -60
  3. package/lib/Strapi.js +152 -74
  4. package/lib/commands/build.js +19 -8
  5. package/lib/commands/console.js +1 -1
  6. package/lib/commands/content-types/list.js +22 -0
  7. package/lib/commands/controllers/list.js +22 -0
  8. package/lib/commands/develop.js +22 -27
  9. package/lib/commands/generate-template.js +4 -5
  10. package/lib/commands/hooks/list.js +22 -0
  11. package/lib/commands/middlewares/list.js +22 -0
  12. package/lib/commands/new.js +3 -1
  13. package/lib/commands/policies/list.js +22 -0
  14. package/lib/commands/routes/list.js +28 -0
  15. package/lib/commands/services/list.js +22 -0
  16. package/lib/commands/watchAdmin.js +18 -9
  17. package/lib/core/app-configuration/index.js +3 -19
  18. package/lib/core/bootstrap.js +3 -95
  19. package/lib/core/domain/content-type/index.js +5 -11
  20. package/lib/core/domain/module/index.js +42 -11
  21. package/lib/core/domain/module/validation.js +16 -19
  22. package/lib/core/loaders/admin.js +2 -2
  23. package/lib/core/loaders/apis.js +148 -9
  24. package/lib/core/loaders/components.js +4 -6
  25. package/lib/core/loaders/index.js +1 -0
  26. package/lib/core/loaders/middlewares.js +23 -123
  27. package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
  28. package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
  29. package/lib/core/loaders/plugins/index.js +30 -16
  30. package/lib/core/loaders/policies.js +1 -1
  31. package/lib/core/loaders/src-index.js +39 -0
  32. package/lib/core/registries/apis.js +29 -0
  33. package/lib/core/registries/content-types.js +61 -12
  34. package/lib/core/registries/controllers.d.ts +7 -0
  35. package/lib/core/registries/controllers.js +91 -7
  36. package/lib/core/registries/hooks.d.ts +20 -0
  37. package/lib/core/registries/hooks.js +87 -0
  38. package/lib/core/registries/middlewares.d.ts +5 -0
  39. package/lib/core/registries/middlewares.js +64 -5
  40. package/lib/core/registries/modules.js +3 -3
  41. package/lib/core/registries/plugins.js +2 -2
  42. package/lib/core/registries/policies.d.ts +9 -0
  43. package/lib/core/registries/policies.js +64 -5
  44. package/lib/core/registries/services.d.ts +7 -0
  45. package/lib/core/registries/services.js +86 -17
  46. package/lib/core/utils.js +22 -0
  47. package/lib/core-api/controller/collection-type.js +45 -26
  48. package/lib/core-api/controller/index.d.ts +25 -0
  49. package/lib/core-api/controller/index.js +33 -11
  50. package/lib/core-api/controller/single-type.js +29 -15
  51. package/lib/core-api/controller/transform.js +62 -6
  52. package/lib/core-api/routes/index.js +71 -0
  53. package/lib/core-api/service/collection-type.js +43 -21
  54. package/lib/core-api/service/index.d.ts +21 -0
  55. package/lib/core-api/service/index.js +8 -67
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +17 -19
  58. package/lib/factories.d.ts +48 -0
  59. package/lib/factories.js +84 -0
  60. package/lib/index.d.ts +10 -31
  61. package/lib/index.js +5 -1
  62. package/lib/middlewares/body.js +33 -0
  63. package/lib/middlewares/compression.js +8 -0
  64. package/lib/middlewares/cors.js +58 -0
  65. package/lib/middlewares/errors.js +40 -0
  66. package/lib/middlewares/favicon.js +19 -0
  67. package/lib/middlewares/index.d.ts +5 -0
  68. package/lib/middlewares/index.js +30 -116
  69. package/lib/middlewares/ip.js +8 -0
  70. package/lib/middlewares/logger.js +27 -0
  71. package/lib/middlewares/powered-by.js +20 -0
  72. package/lib/middlewares/public/index.js +72 -77
  73. package/lib/middlewares/query.js +46 -0
  74. package/lib/middlewares/response-time.js +15 -0
  75. package/lib/middlewares/responses.js +19 -0
  76. package/lib/middlewares/security.js +51 -0
  77. package/lib/middlewares/session/index.js +6 -6
  78. package/lib/migrations/draft-publish.js +57 -0
  79. package/lib/services/auth/index.js +87 -0
  80. package/lib/services/core-store.js +64 -49
  81. package/lib/services/cron.js +54 -0
  82. package/lib/services/entity-service/attributes/index.js +31 -0
  83. package/lib/services/entity-service/attributes/transforms.js +20 -0
  84. package/lib/services/entity-service/components.js +39 -15
  85. package/lib/services/entity-service/index.d.ts +91 -0
  86. package/lib/services/entity-service/index.js +118 -60
  87. package/lib/services/entity-service/params.js +52 -94
  88. package/lib/services/entity-validator/index.js +76 -43
  89. package/lib/services/entity-validator/validators.js +131 -43
  90. package/lib/services/errors.js +77 -0
  91. package/lib/services/fs.js +1 -1
  92. package/lib/services/metrics/index.js +38 -36
  93. package/lib/services/server/admin-api.js +14 -0
  94. package/lib/services/server/api.js +36 -0
  95. package/lib/services/server/compose-endpoint.js +141 -0
  96. package/lib/services/server/content-api.js +16 -0
  97. package/lib/{server.js → services/server/http-server.js} +0 -0
  98. package/lib/services/server/index.js +127 -0
  99. package/lib/services/server/koa.js +64 -0
  100. package/lib/services/server/middleware.js +122 -0
  101. package/lib/services/server/policy.js +32 -0
  102. package/lib/services/server/register-middlewares.js +110 -0
  103. package/lib/services/server/register-routes.js +106 -0
  104. package/lib/services/server/routing.js +120 -0
  105. package/lib/services/webhook-runner.js +1 -1
  106. package/lib/utils/ee.js +3 -3
  107. package/lib/utils/get-dirs.js +17 -0
  108. package/lib/utils/index.js +2 -0
  109. package/lib/utils/signals.js +24 -0
  110. package/lib/utils/update-notifier/index.js +2 -1
  111. package/package.json +94 -97
  112. package/lib/commands/generate.js +0 -76
  113. package/lib/core/app-configuration/load-functions.js +0 -28
  114. package/lib/core-api/index.js +0 -39
  115. package/lib/load/check-reserved-filename.js +0 -10
  116. package/lib/load/load-config-files.js +0 -22
  117. package/lib/load/require-file-parse.js +0 -15
  118. package/lib/middlewares/boom/defaults.json +0 -5
  119. package/lib/middlewares/boom/index.js +0 -147
  120. package/lib/middlewares/cors/index.js +0 -66
  121. package/lib/middlewares/cron/defaults.json +0 -5
  122. package/lib/middlewares/cron/index.js +0 -43
  123. package/lib/middlewares/favicon/defaults.json +0 -7
  124. package/lib/middlewares/favicon/index.js +0 -32
  125. package/lib/middlewares/gzip/defaults.json +0 -6
  126. package/lib/middlewares/gzip/index.js +0 -19
  127. package/lib/middlewares/helmet/defaults.json +0 -18
  128. package/lib/middlewares/helmet/index.js +0 -9
  129. package/lib/middlewares/ip/defaults.json +0 -7
  130. package/lib/middlewares/ip/index.js +0 -25
  131. package/lib/middlewares/language/defaults.json +0 -9
  132. package/lib/middlewares/language/index.js +0 -40
  133. package/lib/middlewares/logger/defaults.json +0 -5
  134. package/lib/middlewares/logger/index.js +0 -37
  135. package/lib/middlewares/parser/defaults.json +0 -11
  136. package/lib/middlewares/parser/index.js +0 -71
  137. package/lib/middlewares/poweredBy/defaults.json +0 -5
  138. package/lib/middlewares/poweredBy/index.js +0 -16
  139. package/lib/middlewares/public/defaults.json +0 -8
  140. package/lib/middlewares/responseTime/defaults.json +0 -5
  141. package/lib/middlewares/responseTime/index.js +0 -25
  142. package/lib/middlewares/responses/defaults.json +0 -5
  143. package/lib/middlewares/responses/index.js +0 -18
  144. package/lib/middlewares/router/defaults.json +0 -7
  145. package/lib/middlewares/router/index.js +0 -58
  146. package/lib/middlewares/router/utils/composeEndpoint.js +0 -177
  147. package/lib/utils/get-prefixed-dependencies.js +0 -7
@@ -9,7 +9,7 @@ const session = require('koa-session');
9
9
  */
10
10
  module.exports = strapi => {
11
11
  const requireStore = store => {
12
- return require(path.resolve(strapi.config.appPath, 'node_modules', 'koa-' + store));
12
+ return require(path.resolve(strapi.dirs.root, 'node_modules', 'koa-' + store));
13
13
  };
14
14
 
15
15
  const defineStore = session => {
@@ -93,7 +93,7 @@ module.exports = strapi => {
93
93
 
94
94
  return {
95
95
  initialize() {
96
- strapi.app.keys = strapi.config.get('middleware.settings.session.secretKeys');
96
+ strapi.server.app.keys = strapi.config.get('middleware.settings.session.secretKeys');
97
97
 
98
98
  if (
99
99
  _.has(strapi.config.middleware.settings.session, 'client') &&
@@ -112,8 +112,8 @@ module.exports = strapi => {
112
112
  strapi.config.middleware.settings.session
113
113
  );
114
114
 
115
- strapi.app.use(session(options, strapi.app));
116
- strapi.app.use((ctx, next) => {
115
+ strapi.server.use(session(options, strapi.server.app));
116
+ strapi.server.use((ctx, next) => {
117
117
  ctx.state = ctx.state || {};
118
118
  ctx.state.session = ctx.session || {};
119
119
 
@@ -127,8 +127,8 @@ module.exports = strapi => {
127
127
  ) {
128
128
  const options = _.assign(strapi.config.middleware.settings.session);
129
129
 
130
- strapi.app.use(session(options, strapi.app));
131
- strapi.app.use((ctx, next) => {
130
+ strapi.server.use(session(options, strapi.server.app));
131
+ strapi.server.use((ctx, next) => {
132
132
  ctx.state = ctx.state || {};
133
133
  ctx.state.session = ctx.session || {};
134
134
 
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ const { hasDraftAndPublish } = require('@strapi/utils').contentTypes;
4
+
5
+ const enableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => {
6
+ if (!oldContentTypes) {
7
+ return;
8
+ }
9
+ // run the after content types migrations
10
+
11
+ for (const uid in contentTypes) {
12
+ if (!oldContentTypes[uid]) {
13
+ continue;
14
+ }
15
+
16
+ const oldContentType = oldContentTypes[uid];
17
+ const contentType = contentTypes[uid];
18
+
19
+ // if d&p was enabled set publishedAt to eq createdAt
20
+ if (!hasDraftAndPublish(oldContentType) && hasDraftAndPublish(contentType)) {
21
+ const qb = strapi.db.queryBuilder(uid);
22
+ await qb
23
+ .update({ published_at: qb.ref('created_at') })
24
+ .where({ published_at: null })
25
+ .execute();
26
+ }
27
+ }
28
+ };
29
+
30
+ const disableDraftAndPublish = async ({ oldContentTypes, contentTypes }) => {
31
+ if (!oldContentTypes) {
32
+ return;
33
+ }
34
+
35
+ for (const uid in contentTypes) {
36
+ if (!oldContentTypes[uid]) {
37
+ continue;
38
+ }
39
+
40
+ const oldContentType = oldContentTypes[uid];
41
+ const contentType = contentTypes[uid];
42
+
43
+ // if d&p was disabled remove unpublish content before sync
44
+ if (hasDraftAndPublish(oldContentType) && !hasDraftAndPublish(contentType)) {
45
+ await strapi.db
46
+ .queryBuilder(uid)
47
+ .delete()
48
+ .where({ published_at: null })
49
+ .execute();
50
+ }
51
+ }
52
+ };
53
+
54
+ module.exports = {
55
+ enable: enableDraftAndPublish,
56
+ disable: disableDraftAndPublish,
57
+ };
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ const { strict: assert } = require('assert');
4
+ const { has, prop } = require('lodash/fp');
5
+
6
+ const { UnauthorizedError } = require('@strapi/utils').errors;
7
+
8
+ const INVALID_STRATEGY_MSG =
9
+ 'Invalid auth strategy. Expecting an object with properties {name: string, authenticate: function, verify: function}';
10
+
11
+ const validStrategy = strategy => {
12
+ assert(has('authenticate', strategy), INVALID_STRATEGY_MSG);
13
+ assert(typeof strategy.authenticate === 'function', INVALID_STRATEGY_MSG);
14
+
15
+ if (has('verify', strategy)) {
16
+ assert(typeof strategy.verify === 'function', INVALID_STRATEGY_MSG);
17
+ }
18
+ };
19
+
20
+ const createAuthentication = () => {
21
+ const strategies = {};
22
+
23
+ return {
24
+ register(type, strategy) {
25
+ validStrategy(strategy);
26
+
27
+ if (!strategies[type]) {
28
+ strategies[type] = [];
29
+ }
30
+
31
+ strategies[type].push(strategy);
32
+
33
+ return this;
34
+ },
35
+ async authenticate(ctx, next) {
36
+ const { route } = ctx.state;
37
+
38
+ // use route strategy
39
+ const config = prop('config.auth', route);
40
+
41
+ if (config === false) {
42
+ return next();
43
+ }
44
+
45
+ const strategiesToUse = strategies[route.info.type];
46
+
47
+ for (const strategy of strategiesToUse) {
48
+ const result = await strategy.authenticate(ctx);
49
+
50
+ const { authenticated = false, error = null, credentials } = result || {};
51
+
52
+ if (error !== null) {
53
+ return ctx.unauthorized(error);
54
+ }
55
+
56
+ if (authenticated) {
57
+ ctx.state.isAuthenticated = true;
58
+ ctx.state.auth = {
59
+ strategy,
60
+ credentials,
61
+ };
62
+
63
+ return next();
64
+ }
65
+ }
66
+
67
+ return ctx.unauthorized('Missing or invalid credentials');
68
+ },
69
+ async verify(auth, config = {}) {
70
+ if (config === false) {
71
+ return;
72
+ }
73
+
74
+ if (!auth) {
75
+ throw new UnauthorizedError();
76
+ }
77
+
78
+ if (typeof auth.strategy.verify === 'function') {
79
+ return auth.strategy.verify(auth, config);
80
+ }
81
+
82
+ return;
83
+ },
84
+ };
85
+ };
86
+
87
+ module.exports = createAuthentication;
@@ -22,21 +22,37 @@ const coreStoreModel = {
22
22
  },
23
23
  };
24
24
 
25
- const createCoreStore = ({ environment: defaultEnv, db }) => {
26
- return (source = {}) => {
27
- async function get(params = {}) {
28
- const { key, environment = defaultEnv, type = 'core', name = '', tag = '' } = Object.assign(
29
- {},
30
- source,
31
- params
32
- );
25
+ const createCoreStore = ({ db }) => {
26
+ const mergeParams = (defaultParams, params) => {
27
+ return {
28
+ ...defaultParams,
29
+ ...params,
30
+ };
31
+ };
32
+
33
+ const store = function(defaultParams = {}) {
34
+ return {
35
+ get: params => store.get(mergeParams(defaultParams, params)),
36
+ set: params => store.set(mergeParams(defaultParams, params)),
37
+ delete: params => store.delete(mergeParams(defaultParams, params)),
38
+ };
39
+ };
40
+
41
+ Object.assign(store, {
42
+ /**
43
+ * Get value from the core store
44
+ * @param {Object} params
45
+ * @returns {*}
46
+ */
47
+ async get(params = {}) {
48
+ const { key, type = 'core', environment, name, tag } = params;
33
49
 
34
50
  const prefix = `${type}${name ? `_${name}` : ''}`;
35
51
 
36
52
  const where = {
37
53
  key: `${prefix}_${key}`,
38
- environment,
39
- tag,
54
+ environment: environment || null,
55
+ tag: tag || null,
40
56
  };
41
57
 
42
58
  const data = await db.query('strapi::core-store').findOne({ where });
@@ -57,71 +73,70 @@ const createCoreStore = ({ environment: defaultEnv, db }) => {
57
73
  return new Date(data.value);
58
74
  }
59
75
  } else if (data.type === 'number') {
60
- return parseFloat(data.value);
76
+ return Number(data.value);
61
77
  } else {
62
78
  return null;
63
79
  }
64
- }
80
+ },
65
81
 
66
- async function set(params = {}) {
67
- const { key, value, environment = defaultEnv, type, name, tag = '' } = Object.assign(
68
- {},
69
- source,
70
- params
71
- );
82
+ /**
83
+ * Set value in the core store
84
+ * @param {Object} params
85
+ * @returns {*}
86
+ */
87
+ async set(params = {}) {
88
+ const { key, value, type, environment, name, tag } = params;
72
89
 
73
90
  const prefix = `${type}${name ? `_${name}` : ''}`;
74
91
 
75
92
  const where = {
76
93
  key: `${prefix}_${key}`,
77
- environment,
78
- tag,
94
+ environment: environment || null,
95
+ tag: tag || null,
79
96
  };
80
97
 
81
98
  const data = await db.query('strapi::core-store').findOne({ where });
82
99
 
83
100
  if (data) {
84
- Object.assign(data, {
85
- value: JSON.stringify(value) || value.toString(),
86
- type: (typeof value).toString(),
101
+ return db.query('strapi::core-store').update({
102
+ where: { id: data.id },
103
+ data: {
104
+ value: JSON.stringify(value) || value.toString(),
105
+ type: typeof value,
106
+ },
87
107
  });
108
+ }
88
109
 
89
- await db.query('strapi::core-store').update({ where: { id: data.id }, data });
90
- } else {
91
- const data = Object.assign({}, where, {
110
+ return db.query('strapi::core-store').create({
111
+ data: {
112
+ ...where,
92
113
  value: JSON.stringify(value) || value.toString(),
93
- type: (typeof value).toString(),
94
- tag,
95
- });
96
-
97
- await db.query('strapi::core-store').create({ data });
98
- }
99
- }
114
+ type: typeof value,
115
+ },
116
+ });
117
+ },
100
118
 
101
- async function deleteFn(params = {}) {
102
- const { key, environment = defaultEnv, type, name, tag = '' } = Object.assign(
103
- {},
104
- source,
105
- params
106
- );
119
+ /**
120
+ * Deletes a value from the core store
121
+ * @param {Object} params
122
+ * @returns {*}
123
+ */
124
+ async delete(params = {}) {
125
+ const { key, environment, type, name, tag } = params;
107
126
 
108
127
  const prefix = `${type}${name ? `_${name}` : ''}`;
109
128
 
110
129
  const where = {
111
130
  key: `${prefix}_${key}`,
112
- environment,
113
- tag,
131
+ environment: environment || null,
132
+ tag: tag || null,
114
133
  };
115
134
 
116
- await db.query('strapi::core-store').delete({ where });
117
- }
135
+ return db.query('strapi::core-store').delete({ where });
136
+ },
137
+ });
118
138
 
119
- return {
120
- get,
121
- set,
122
- delete: deleteFn,
123
- };
124
- };
139
+ return store;
125
140
  };
126
141
 
127
142
  module.exports = {
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const { Job } = require('node-schedule');
4
+ const { isFunction } = require('lodash/fp');
5
+
6
+ const createCronService = () => {
7
+ let jobsSpecs = [];
8
+
9
+ return {
10
+ add(tasks = {}) {
11
+ for (const taskExpression in tasks) {
12
+ const taskValue = tasks[taskExpression];
13
+
14
+ let fn;
15
+ let options;
16
+ if (isFunction(taskValue)) {
17
+ fn = taskValue.bind(tasks);
18
+ options = taskExpression;
19
+ } else if (isFunction(taskValue.task)) {
20
+ fn = taskValue.task.bind(taskValue);
21
+ options = taskValue.options;
22
+ } else {
23
+ throw new Error(
24
+ `Could not schedule a cron job for "${taskExpression}": no function found.`
25
+ );
26
+ }
27
+
28
+ const fnWithStrapi = (...args) => fn({ strapi }, ...args);
29
+
30
+ const job = new Job(null, fnWithStrapi);
31
+ jobsSpecs.push({ job, options });
32
+ }
33
+ return this;
34
+ },
35
+ start() {
36
+ if (!strapi.config.get('server.cron.enabled')) {
37
+ return;
38
+ }
39
+ jobsSpecs.forEach(({ job, options }) => job.schedule(options));
40
+ return this;
41
+ },
42
+ stop() {
43
+ jobsSpecs.forEach(({ job }) => job.cancel());
44
+ return this;
45
+ },
46
+ destroy() {
47
+ this.stop();
48
+ jobsSpecs = [];
49
+ return this;
50
+ },
51
+ };
52
+ };
53
+
54
+ module.exports = createCronService;
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const transforms = require('./transforms');
4
+
5
+ const applyTransforms = (data, context) => {
6
+ const { contentType } = context;
7
+
8
+ const entries = Object.entries(data);
9
+
10
+ for (const [attributeName, value] of entries) {
11
+ const attribute = contentType.attributes[attributeName];
12
+
13
+ if (!attribute) {
14
+ continue;
15
+ }
16
+
17
+ const transform = transforms[attribute.type];
18
+
19
+ if (transform) {
20
+ const attributeContext = { ...context, attributeName, attribute };
21
+
22
+ data[attributeName] = transform(value, attributeContext);
23
+ }
24
+ }
25
+
26
+ return data;
27
+ };
28
+
29
+ module.exports = {
30
+ applyTransforms,
31
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const { getOr, toNumber, isString, isBuffer } = require('lodash/fp');
4
+ const bcrypt = require('bcryptjs');
5
+
6
+ const transforms = {
7
+ password(value, context) {
8
+ const { attribute } = context;
9
+
10
+ if (!isString(value) && !isBuffer(value)) {
11
+ return value;
12
+ }
13
+
14
+ const rounds = toNumber(getOr(10, 'encryption.rounds', attribute));
15
+
16
+ return bcrypt.hashSync(value, rounds);
17
+ },
18
+ };
19
+
20
+ module.exports = transforms;
@@ -1,9 +1,10 @@
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
+ const { ApplicationError } = require('@strapi/utils').errors;
7
8
 
8
9
  const omitComponentData = (contentType, data) => {
9
10
  const { attributes } = contentType;
@@ -131,11 +132,26 @@ const updateComponents = async (uid, entityToUpdate, data) => {
131
132
  componentValue.map(value => updateOrCreateComponent(componentUID, value))
132
133
  );
133
134
 
134
- // TODO: add order
135
- componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => id);
135
+ componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }, idx) => {
136
+ return {
137
+ id,
138
+ __pivot: {
139
+ order: idx + 1,
140
+ field: attributeName,
141
+ component_type: componentUID,
142
+ },
143
+ };
144
+ });
136
145
  } else {
137
146
  const component = await updateOrCreateComponent(componentUID, componentValue);
138
- componentBody[attributeName] = component && component.id;
147
+ componentBody[attributeName] = component && {
148
+ id: component.id,
149
+ __pivot: {
150
+ order: 1,
151
+ field: attributeName,
152
+ component_type: componentUID,
153
+ },
154
+ };
139
155
  }
140
156
 
141
157
  continue;
@@ -151,9 +167,17 @@ const updateComponents = async (uid, entityToUpdate, data) => {
151
167
  }
152
168
 
153
169
  componentBody[attributeName] = await Promise.all(
154
- dynamiczoneValues.map(async value => {
170
+ dynamiczoneValues.map(async (value, idx) => {
155
171
  const { id } = await updateOrCreateComponent(value.__component, value);
156
- return { id, __component: value.__component };
172
+
173
+ return {
174
+ id,
175
+ __component: value.__component,
176
+ __pivot: {
177
+ order: idx + 1,
178
+ field: attributeName,
179
+ },
180
+ };
157
181
  })
158
182
  );
159
183
 
@@ -175,19 +199,19 @@ const deleteOldComponents = async (
175
199
 
176
200
  const idsToKeep = _.castArray(componentValue)
177
201
  .filter(has('id'))
178
- .map(prop('id'));
202
+ .map(prop('id'))
203
+ .map(toString);
179
204
 
180
205
  const allIds = _.castArray(previousValue)
181
206
  .filter(has('id'))
182
- .map(prop('id'));
207
+ .map(prop('id'))
208
+ .map(toString);
183
209
 
184
210
  idsToKeep.forEach(id => {
185
211
  if (!allIds.includes(id)) {
186
- const err = new Error(
212
+ throw new ApplicationError(
187
213
  `Some of the provided components in ${attributeName} are not related to the entity`
188
214
  );
189
- err.status = 400;
190
- throw err;
191
215
  }
192
216
  });
193
217
 
@@ -206,14 +230,14 @@ const deleteOldDZComponents = async (uid, entityToUpdate, attributeName, dynamic
206
230
  const idsToKeep = _.castArray(dynamiczoneValues)
207
231
  .filter(has('id'))
208
232
  .map(({ id, __component }) => ({
209
- id,
233
+ id: toString(id),
210
234
  __component,
211
235
  }));
212
236
 
213
237
  const allIds = _.castArray(previousValue)
214
238
  .filter(has('id'))
215
239
  .map(({ id, __component }) => ({
216
- id,
240
+ id: toString(id),
217
241
  __component,
218
242
  }));
219
243
 
@@ -293,7 +317,7 @@ const createComponent = async (uid, data) => {
293
317
 
294
318
  const componentData = await createComponents(uid, data);
295
319
 
296
- return await strapi.query(uid).create({
320
+ return strapi.query(uid).create({
297
321
  data: Object.assign(omitComponentData(model, data), componentData),
298
322
  });
299
323
  };
@@ -304,7 +328,7 @@ const updateComponent = async (uid, componentToUpdate, data) => {
304
328
 
305
329
  const componentData = await updateComponents(uid, componentToUpdate, data);
306
330
 
307
- return await strapi.query(uid).update({
331
+ return strapi.query(uid).update({
308
332
  where: {
309
333
  id: componentToUpdate.id,
310
334
  },
@@ -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;