@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,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { prop, isFunction } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @type {import('./').MiddlewareFactory}
|
|
7
|
+
*/
|
|
8
|
+
module.exports = (config = {}) => {
|
|
9
|
+
return async (ctx, next) => {
|
|
10
|
+
await next();
|
|
11
|
+
|
|
12
|
+
const status = ctx.status;
|
|
13
|
+
const handler = prop(`handlers.${status}`, config);
|
|
14
|
+
|
|
15
|
+
if (isFunction(handler)) {
|
|
16
|
+
await handler(ctx);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { defaultsDeep, merge } = require('lodash/fp');
|
|
4
|
+
const helmet = require('koa-helmet');
|
|
5
|
+
|
|
6
|
+
const defaults = {
|
|
7
|
+
crossOriginEmbedderPolicy: false,
|
|
8
|
+
crossOriginOpenerPolicy: false,
|
|
9
|
+
crossOriginResourcePolicy: false,
|
|
10
|
+
originAgentCluster: false,
|
|
11
|
+
contentSecurityPolicy: {
|
|
12
|
+
useDefaults: true,
|
|
13
|
+
directives: {
|
|
14
|
+
'connect-src': ["'self'", 'https:'],
|
|
15
|
+
'img-src': ["'self'", 'data:', 'blob:'],
|
|
16
|
+
'media-src': ["'self'", 'data:', 'blob:'],
|
|
17
|
+
upgradeInsecureRequests: null,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
xssFilter: false,
|
|
21
|
+
hsts: {
|
|
22
|
+
maxAge: 31536000,
|
|
23
|
+
includeSubDomains: true,
|
|
24
|
+
},
|
|
25
|
+
frameguard: {
|
|
26
|
+
action: 'sameorigin',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @type {import('./').MiddlewareFactory}
|
|
32
|
+
*/
|
|
33
|
+
module.exports = config => (ctx, next) => {
|
|
34
|
+
let helmetConfig = defaultsDeep(defaults, config);
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
ctx.method === 'GET' &&
|
|
38
|
+
['/graphql', '/documentation'].some(str => ctx.path.startsWith(str))
|
|
39
|
+
) {
|
|
40
|
+
helmetConfig = merge(helmetConfig, {
|
|
41
|
+
contentSecurityPolicy: {
|
|
42
|
+
directives: {
|
|
43
|
+
'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
|
|
44
|
+
'img-src': ["'self'", 'data:', 'cdn.jsdelivr.net', 'strapi.io'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return helmet(helmetConfig)(ctx, next);
|
|
51
|
+
};
|
|
@@ -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.
|
|
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.
|
|
116
|
-
strapi.
|
|
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.
|
|
131
|
-
strapi.
|
|
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 = ({
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
76
|
+
return Number(data.value);
|
|
61
77
|
} else {
|
|
62
78
|
return null;
|
|
63
79
|
}
|
|
64
|
-
}
|
|
80
|
+
},
|
|
65
81
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
return db.query('strapi::core-store').create({
|
|
111
|
+
data: {
|
|
112
|
+
...where,
|
|
92
113
|
value: JSON.stringify(value) || value.toString(),
|
|
93
|
-
type:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
await db.query('strapi::core-store').create({ data });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
114
|
+
type: typeof value,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
},
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
117
|
-
}
|
|
135
|
+
return db.query('strapi::core-store').delete({ where });
|
|
136
|
+
},
|
|
137
|
+
});
|
|
118
138
|
|
|
119
|
-
|
|
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
|
-
|
|
135
|
-
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
331
|
+
return strapi.query(uid).update({
|
|
308
332
|
where: {
|
|
309
333
|
id: componentToUpdate.id,
|
|
310
334
|
},
|