@strapi/strapi 4.0.0-beta.0

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 (143) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +144 -0
  3. package/bin/strapi.js +186 -0
  4. package/lib/Strapi.js +470 -0
  5. package/lib/commands/admin-reset.js +51 -0
  6. package/lib/commands/build.js +56 -0
  7. package/lib/commands/configurationDump.js +50 -0
  8. package/lib/commands/configurationRestore.js +169 -0
  9. package/lib/commands/console.js +26 -0
  10. package/lib/commands/develop.js +157 -0
  11. package/lib/commands/generate-template.js +97 -0
  12. package/lib/commands/install.js +48 -0
  13. package/lib/commands/new.js +11 -0
  14. package/lib/commands/start.js +8 -0
  15. package/lib/commands/uninstall.js +68 -0
  16. package/lib/commands/watchAdmin.js +45 -0
  17. package/lib/container.js +45 -0
  18. package/lib/core/app-configuration/config-loader.js +20 -0
  19. package/lib/core/app-configuration/index.js +75 -0
  20. package/lib/core/app-configuration/load-config-file.js +43 -0
  21. package/lib/core/app-configuration/load-functions.js +28 -0
  22. package/lib/core/bootstrap.js +60 -0
  23. package/lib/core/domain/component/index.js +24 -0
  24. package/lib/core/domain/component/validator.js +29 -0
  25. package/lib/core/domain/content-type/index.js +140 -0
  26. package/lib/core/domain/content-type/validator.js +64 -0
  27. package/lib/core/domain/module/index.js +106 -0
  28. package/lib/core/domain/module/validation.js +36 -0
  29. package/lib/core/loaders/admin.js +16 -0
  30. package/lib/core/loaders/apis.js +157 -0
  31. package/lib/core/loaders/components.js +41 -0
  32. package/lib/core/loaders/index.js +11 -0
  33. package/lib/core/loaders/middlewares.js +86 -0
  34. package/lib/core/loaders/plugins/get-enabled-plugins.js +100 -0
  35. package/lib/core/loaders/plugins/index.js +109 -0
  36. package/lib/core/loaders/policies.js +28 -0
  37. package/lib/core/loaders/src-index.js +38 -0
  38. package/lib/core/registries/apis.js +43 -0
  39. package/lib/core/registries/config.js +21 -0
  40. package/lib/core/registries/content-types.js +53 -0
  41. package/lib/core/registries/controllers.js +43 -0
  42. package/lib/core/registries/hooks.js +37 -0
  43. package/lib/core/registries/middlewares.js +30 -0
  44. package/lib/core/registries/modules.js +44 -0
  45. package/lib/core/registries/plugins.js +28 -0
  46. package/lib/core/registries/policies.js +38 -0
  47. package/lib/core/registries/services.js +58 -0
  48. package/lib/core/utils.js +35 -0
  49. package/lib/core-api/controller/collection-type.js +84 -0
  50. package/lib/core-api/controller/index.js +26 -0
  51. package/lib/core-api/controller/single-type.js +44 -0
  52. package/lib/core-api/controller/transform.js +97 -0
  53. package/lib/core-api/index.js +39 -0
  54. package/lib/core-api/service/collection-type.js +84 -0
  55. package/lib/core-api/service/index.js +55 -0
  56. package/lib/core-api/service/pagination.js +125 -0
  57. package/lib/core-api/service/single-type.js +58 -0
  58. package/lib/index.d.ts +26 -0
  59. package/lib/index.js +3 -0
  60. package/lib/load/filepath-to-prop-path.js +22 -0
  61. package/lib/load/glob.js +15 -0
  62. package/lib/load/index.js +9 -0
  63. package/lib/load/load-files.js +56 -0
  64. package/lib/load/package-path.js +9 -0
  65. package/lib/middlewares/cors/index.js +66 -0
  66. package/lib/middlewares/error/defaults.json +5 -0
  67. package/lib/middlewares/error/index.js +147 -0
  68. package/lib/middlewares/favicon/defaults.json +7 -0
  69. package/lib/middlewares/favicon/index.js +31 -0
  70. package/lib/middlewares/gzip/defaults.json +6 -0
  71. package/lib/middlewares/gzip/index.js +19 -0
  72. package/lib/middlewares/helmet/defaults.json +18 -0
  73. package/lib/middlewares/helmet/index.js +9 -0
  74. package/lib/middlewares/index.js +120 -0
  75. package/lib/middlewares/ip/defaults.json +7 -0
  76. package/lib/middlewares/ip/index.js +25 -0
  77. package/lib/middlewares/logger/defaults.json +5 -0
  78. package/lib/middlewares/logger/index.js +37 -0
  79. package/lib/middlewares/parser/defaults.json +11 -0
  80. package/lib/middlewares/parser/index.js +75 -0
  81. package/lib/middlewares/poweredBy/defaults.json +5 -0
  82. package/lib/middlewares/poweredBy/index.js +16 -0
  83. package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
  84. package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
  85. package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
  86. package/lib/middlewares/public/assets/images/logo_login.png +0 -0
  87. package/lib/middlewares/public/defaults.json +8 -0
  88. package/lib/middlewares/public/index.html +66 -0
  89. package/lib/middlewares/public/index.js +130 -0
  90. package/lib/middlewares/public/serve-static.js +23 -0
  91. package/lib/middlewares/responseTime/defaults.json +5 -0
  92. package/lib/middlewares/responseTime/index.js +25 -0
  93. package/lib/middlewares/responses/defaults.json +5 -0
  94. package/lib/middlewares/responses/index.js +19 -0
  95. package/lib/middlewares/router/defaults.json +7 -0
  96. package/lib/middlewares/router/index.js +97 -0
  97. package/lib/middlewares/session/defaults.json +18 -0
  98. package/lib/middlewares/session/index.js +140 -0
  99. package/lib/migrations/draft-publish.js +57 -0
  100. package/lib/services/auth/index.js +92 -0
  101. package/lib/services/core-store.js +145 -0
  102. package/lib/services/cron.js +54 -0
  103. package/lib/services/entity-service/components.js +365 -0
  104. package/lib/services/entity-service/index.d.ts +91 -0
  105. package/lib/services/entity-service/index.js +244 -0
  106. package/lib/services/entity-service/params.js +145 -0
  107. package/lib/services/entity-validator/index.js +187 -0
  108. package/lib/services/entity-validator/validators.js +123 -0
  109. package/lib/services/event-hub.js +15 -0
  110. package/lib/services/fs.js +58 -0
  111. package/lib/services/metrics/index.js +104 -0
  112. package/lib/services/metrics/is-truthy.js +9 -0
  113. package/lib/services/metrics/middleware.js +33 -0
  114. package/lib/services/metrics/rate-limiter.js +27 -0
  115. package/lib/services/metrics/sender.js +76 -0
  116. package/lib/services/metrics/stringify-deep.js +22 -0
  117. package/lib/services/server/admin-api.js +14 -0
  118. package/lib/services/server/api.js +32 -0
  119. package/lib/services/server/compose-endpoint.js +112 -0
  120. package/lib/services/server/content-api.js +16 -0
  121. package/lib/services/server/http-server.js +64 -0
  122. package/lib/services/server/index.js +108 -0
  123. package/lib/services/server/middleware.js +28 -0
  124. package/lib/services/server/policy.js +34 -0
  125. package/lib/services/server/routing.js +107 -0
  126. package/lib/services/utils/upload-files.js +79 -0
  127. package/lib/services/webhook-runner.js +155 -0
  128. package/lib/services/webhook-store.js +91 -0
  129. package/lib/services/worker-queue.js +58 -0
  130. package/lib/utils/addSlash.js +10 -0
  131. package/lib/utils/ee.js +123 -0
  132. package/lib/utils/get-dirs.js +15 -0
  133. package/lib/utils/get-prefixed-dependencies.js +7 -0
  134. package/lib/utils/index.js +11 -0
  135. package/lib/utils/is-initialized.js +23 -0
  136. package/lib/utils/open-browser.js +12 -0
  137. package/lib/utils/resources/key.pub +9 -0
  138. package/lib/utils/run-checks.js +22 -0
  139. package/lib/utils/startup-logger.js +90 -0
  140. package/lib/utils/success.js +31 -0
  141. package/lib/utils/update-notifier/index.js +97 -0
  142. package/lib/utils/url-from-segments.js +12 -0
  143. package/package.json +133 -0
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const { toLower } = require('lodash/fp');
5
+
6
+ const createRouteScopeGenerator = namespace => route => {
7
+ const prefix = namespace.endsWith('::') ? namespace : `${namespace}.`;
8
+
9
+ if (typeof route.handler === 'string') {
10
+ const [controller, action] = route.handler.split('.');
11
+
12
+ _.defaultsDeep(route, {
13
+ config: {
14
+ auth: {
15
+ scope: `${prefix}${controller}.${toLower(action)}`,
16
+ },
17
+ },
18
+ });
19
+ }
20
+ };
21
+
22
+ module.exports = strapi => {
23
+ const registerAdminRoutes = () => {
24
+ const generateRouteScope = createRouteScopeGenerator(`admin::`);
25
+
26
+ strapi.admin.routes.forEach(route => {
27
+ generateRouteScope(route);
28
+ route.info = { pluginName: 'admin' };
29
+ });
30
+
31
+ strapi.server.routes({
32
+ type: 'admin',
33
+ prefix: '/admin',
34
+ routes: strapi.admin.routes,
35
+ });
36
+ };
37
+
38
+ const registerPluginRoutes = () => {
39
+ for (const pluginName in strapi.plugins) {
40
+ const plugin = strapi.plugins[pluginName];
41
+
42
+ const generateRouteScope = createRouteScopeGenerator(`plugin::${pluginName}`);
43
+
44
+ if (Array.isArray(plugin.routes)) {
45
+ plugin.routes.forEach(route => {
46
+ generateRouteScope(route);
47
+ route.info = { pluginName };
48
+ });
49
+
50
+ strapi.server.routes({
51
+ type: 'admin',
52
+ prefix: `/${pluginName}`,
53
+ routes: plugin.routes,
54
+ });
55
+ } else {
56
+ _.forEach(plugin.routes, router => {
57
+ router.type = router.type || 'admin';
58
+ router.prefix = `/${pluginName}`;
59
+ router.routes.forEach(route => {
60
+ generateRouteScope(route);
61
+ route.info = { pluginName };
62
+ });
63
+
64
+ strapi.server.routes(router);
65
+ });
66
+ }
67
+ }
68
+ };
69
+
70
+ const registerAPIRoutes = () => {
71
+ for (const apiName in strapi.api) {
72
+ const api = strapi.api[apiName];
73
+
74
+ const generateRouteScope = createRouteScopeGenerator(`api::${apiName}`);
75
+
76
+ _.forEach(api.routes, router => {
77
+ // TODO: remove once auth setup
78
+ // pass meta down to compose endpoint
79
+ router.type = 'content-api';
80
+ router.routes.forEach(route => {
81
+ generateRouteScope(route);
82
+ route.info = { apiName };
83
+ });
84
+
85
+ return strapi.server.routes(router);
86
+ });
87
+ }
88
+ };
89
+
90
+ return {
91
+ initialize() {
92
+ registerAdminRoutes();
93
+ registerAPIRoutes();
94
+ registerPluginRoutes();
95
+ },
96
+ };
97
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "session": {
3
+ "enabled": true,
4
+ "client": "cookie",
5
+ "key": "strapi.sid",
6
+ "prefix": "strapi:sess:",
7
+ "ttl": 864000000,
8
+ "rolling": false,
9
+ "secretKeys": ["mySecretKey1", "mySecretKey2"],
10
+ "cookie": {
11
+ "path": "/",
12
+ "httpOnly": true,
13
+ "maxAge": 864000000,
14
+ "rewrite": true,
15
+ "signed": false
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const _ = require('lodash');
5
+ const session = require('koa-session');
6
+
7
+ /**
8
+ * Session middleware
9
+ */
10
+ module.exports = strapi => {
11
+ const requireStore = store => {
12
+ return require(path.resolve(strapi.config.appPath, 'node_modules', 'koa-' + store));
13
+ };
14
+
15
+ const defineStore = session => {
16
+ if (_.isEmpty(_.get(session, 'client'))) {
17
+ return strapi.log.error(
18
+ '(middleware:session) please provide a valid client to store session'
19
+ );
20
+ } else if (_.isEmpty(_.get(session, 'connection'))) {
21
+ return strapi.log.error(
22
+ '(middleware:session) please provide connection for the session store'
23
+ );
24
+ } else if (!strapi.config.get(`database.connections.${session.connection}`)) {
25
+ return strapi.log.error(
26
+ '(middleware:session) please provide a valid connection for the session store'
27
+ );
28
+ }
29
+
30
+ session.settings = strapi.config.get(`database.connections.${session.connection}`);
31
+
32
+ // Define correct store name to avoid require to failed.
33
+ switch (session.client.toLowerCase()) {
34
+ case 'redis': {
35
+ const store = requireStore('redis');
36
+
37
+ session.settings.db = session.settings.database;
38
+
39
+ return store(session.settings);
40
+ }
41
+ case 'mysql': {
42
+ const Store = requireStore('mysql-session');
43
+
44
+ return new Store(session.settings);
45
+ }
46
+ case 'mongo': {
47
+ const Store = requireStore('generic-session-mongo');
48
+
49
+ session.settings.db = session.settings.database;
50
+
51
+ return new Store(session.settings);
52
+ }
53
+ case 'postgresql': {
54
+ const Store = requireStore('pg-session');
55
+
56
+ return new Store(session.settings, session.options);
57
+ }
58
+ case 'rethink': {
59
+ const Store = requireStore('generic-session-rethinkdb');
60
+
61
+ session.settings.dbName = session.settings.database;
62
+ session.settings.tableName = session.settings.table;
63
+
64
+ const sessionStore = new Store({
65
+ connection: session.settings,
66
+ });
67
+
68
+ // Create the DB, tables and indexes to store sessions.
69
+ sessionStore.setup();
70
+
71
+ return sessionStore;
72
+ }
73
+ case 'sqlite': {
74
+ const Store = requireStore('sqlite3-session');
75
+
76
+ return new Store(session.fileName, session.options);
77
+ }
78
+ case 'sequelize': {
79
+ const Store = requireStore('generic-session-sequelize');
80
+
81
+ // Sequelize needs to be instantiated.
82
+ if (!_.isObject(strapi.sequelize)) {
83
+ return null;
84
+ }
85
+
86
+ return new Store(strapi.sequelize, session.options);
87
+ }
88
+ default: {
89
+ return null;
90
+ }
91
+ }
92
+ };
93
+
94
+ return {
95
+ initialize() {
96
+ strapi.server.app.keys = strapi.config.get('middleware.settings.session.secretKeys');
97
+
98
+ if (
99
+ _.has(strapi.config.middleware.settings.session, 'client') &&
100
+ _.isString(strapi.config.middleware.settings.session.client) &&
101
+ strapi.config.middleware.settings.session.client !== 'cookie'
102
+ ) {
103
+ const store = defineStore(strapi.config.middleware.settings.session);
104
+
105
+ if (!_.isEmpty(store)) {
106
+ // Options object contains the defined store, the custom middlewares configurations
107
+ // and also the function which are located to `./config/functions/session.js`
108
+ const options = _.assign(
109
+ {
110
+ store,
111
+ },
112
+ strapi.config.middleware.settings.session
113
+ );
114
+
115
+ strapi.server.use(session(options, strapi.server.app));
116
+ strapi.server.use((ctx, next) => {
117
+ ctx.state = ctx.state || {};
118
+ ctx.state.session = ctx.session || {};
119
+
120
+ return next();
121
+ });
122
+ }
123
+ } else if (
124
+ _.has(strapi.config.middleware.settings.session, 'client') &&
125
+ _.isString(strapi.config.middleware.settings.session.client) &&
126
+ strapi.config.middleware.settings.session.client === 'cookie'
127
+ ) {
128
+ const options = _.assign(strapi.config.middleware.settings.session);
129
+
130
+ strapi.server.use(session(options, strapi.server.app));
131
+ strapi.server.use((ctx, next) => {
132
+ ctx.state = ctx.state || {};
133
+ ctx.state.session = ctx.session || {};
134
+
135
+ return next();
136
+ });
137
+ }
138
+ },
139
+ };
140
+ };
@@ -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,92 @@
1
+ 'use strict';
2
+
3
+ const { strict: assert } = require('assert');
4
+ const { has, prop } = require('lodash/fp');
5
+
6
+ class UnauthorizedError extends Error {}
7
+ class ForbiddenError extends Error {}
8
+
9
+ const INVALID_STRATEGY_MSG =
10
+ 'Invalid auth strategy. Expecting an object with properties {name: string, authenticate: function, verify: function}';
11
+
12
+ const validStrategy = strategy => {
13
+ assert(has('authenticate', strategy), INVALID_STRATEGY_MSG);
14
+ assert(typeof strategy.authenticate === 'function', INVALID_STRATEGY_MSG);
15
+
16
+ if (has('verify', strategy)) {
17
+ assert(typeof strategy.verify === 'function', INVALID_STRATEGY_MSG);
18
+ }
19
+ };
20
+
21
+ const createAuthentication = () => {
22
+ const strategies = {};
23
+
24
+ return {
25
+ errors: {
26
+ UnauthorizedError,
27
+ ForbiddenError,
28
+ },
29
+ register(type, strategy) {
30
+ validStrategy(strategy);
31
+
32
+ if (!strategies[type]) {
33
+ strategies[type] = [];
34
+ }
35
+
36
+ strategies[type].push(strategy);
37
+
38
+ return this;
39
+ },
40
+ async authenticate(ctx, next) {
41
+ const { route } = ctx.state;
42
+
43
+ // use route strategy
44
+ const config = prop('config.auth', route);
45
+
46
+ if (config === false) {
47
+ return next();
48
+ }
49
+
50
+ const strategiesToUse = strategies[route.info.type];
51
+
52
+ for (const strategy of strategiesToUse) {
53
+ const result = await strategy.authenticate(ctx);
54
+
55
+ const { authenticated = false, error = null, credentials } = result || {};
56
+
57
+ if (error !== null) {
58
+ return ctx.unauthorized(error);
59
+ }
60
+
61
+ if (authenticated) {
62
+ ctx.state.isAuthenticated = true;
63
+ ctx.state.auth = {
64
+ strategy,
65
+ credentials,
66
+ };
67
+
68
+ return next();
69
+ }
70
+ }
71
+
72
+ return ctx.unauthorized('Missing or invalid credentials');
73
+ },
74
+ async verify(auth, config = {}) {
75
+ if (config === false) {
76
+ return;
77
+ }
78
+
79
+ if (!auth) {
80
+ throw new UnauthorizedError();
81
+ }
82
+
83
+ if (typeof auth.strategy.verify === 'function') {
84
+ return auth.strategy.verify(auth, config);
85
+ }
86
+
87
+ return;
88
+ },
89
+ };
90
+ };
91
+
92
+ module.exports = createAuthentication;
@@ -0,0 +1,145 @@
1
+ 'use strict';
2
+
3
+ const coreStoreModel = {
4
+ uid: 'strapi::core-store',
5
+ collectionName: 'strapi_core_store_settings',
6
+ attributes: {
7
+ key: {
8
+ type: 'string',
9
+ },
10
+ value: {
11
+ type: 'text',
12
+ },
13
+ type: {
14
+ type: 'string',
15
+ },
16
+ environment: {
17
+ type: 'string',
18
+ },
19
+ tag: {
20
+ type: 'string',
21
+ },
22
+ },
23
+ };
24
+
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;
49
+
50
+ const prefix = `${type}${name ? `_${name}` : ''}`;
51
+
52
+ const where = {
53
+ key: `${prefix}_${key}`,
54
+ environment: environment || null,
55
+ tag: tag || null,
56
+ };
57
+
58
+ const data = await db.query('strapi::core-store').findOne({ where });
59
+
60
+ if (!data) {
61
+ return null;
62
+ }
63
+
64
+ if (
65
+ data.type === 'object' ||
66
+ data.type === 'array' ||
67
+ data.type === 'boolean' ||
68
+ data.type === 'string'
69
+ ) {
70
+ try {
71
+ return JSON.parse(data.value);
72
+ } catch (err) {
73
+ return new Date(data.value);
74
+ }
75
+ } else if (data.type === 'number') {
76
+ return Number(data.value);
77
+ } else {
78
+ return null;
79
+ }
80
+ },
81
+
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;
89
+
90
+ const prefix = `${type}${name ? `_${name}` : ''}`;
91
+
92
+ const where = {
93
+ key: `${prefix}_${key}`,
94
+ environment: environment || null,
95
+ tag: tag || null,
96
+ };
97
+
98
+ const data = await db.query('strapi::core-store').findOne({ where });
99
+
100
+ if (data) {
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
+ },
107
+ });
108
+ }
109
+
110
+ return db.query('strapi::core-store').create({
111
+ data: {
112
+ ...where,
113
+ value: JSON.stringify(value) || value.toString(),
114
+ type: typeof value,
115
+ },
116
+ });
117
+ },
118
+
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;
126
+
127
+ const prefix = `${type}${name ? `_${name}` : ''}`;
128
+
129
+ const where = {
130
+ key: `${prefix}_${key}`,
131
+ environment: environment || null,
132
+ tag: tag || null,
133
+ };
134
+
135
+ return db.query('strapi::core-store').delete({ where });
136
+ },
137
+ });
138
+
139
+ return store;
140
+ };
141
+
142
+ module.exports = {
143
+ coreStoreModel,
144
+ createCoreStore,
145
+ };
@@ -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;