@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.
- package/LICENSE +22 -0
- package/README.md +144 -0
- package/bin/strapi.js +186 -0
- package/lib/Strapi.js +470 -0
- package/lib/commands/admin-reset.js +51 -0
- package/lib/commands/build.js +56 -0
- package/lib/commands/configurationDump.js +50 -0
- package/lib/commands/configurationRestore.js +169 -0
- package/lib/commands/console.js +26 -0
- package/lib/commands/develop.js +157 -0
- package/lib/commands/generate-template.js +97 -0
- package/lib/commands/install.js +48 -0
- package/lib/commands/new.js +11 -0
- package/lib/commands/start.js +8 -0
- package/lib/commands/uninstall.js +68 -0
- package/lib/commands/watchAdmin.js +45 -0
- package/lib/container.js +45 -0
- package/lib/core/app-configuration/config-loader.js +20 -0
- package/lib/core/app-configuration/index.js +75 -0
- package/lib/core/app-configuration/load-config-file.js +43 -0
- package/lib/core/app-configuration/load-functions.js +28 -0
- package/lib/core/bootstrap.js +60 -0
- package/lib/core/domain/component/index.js +24 -0
- package/lib/core/domain/component/validator.js +29 -0
- package/lib/core/domain/content-type/index.js +140 -0
- package/lib/core/domain/content-type/validator.js +64 -0
- package/lib/core/domain/module/index.js +106 -0
- package/lib/core/domain/module/validation.js +36 -0
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +157 -0
- package/lib/core/loaders/components.js +41 -0
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +86 -0
- package/lib/core/loaders/plugins/get-enabled-plugins.js +100 -0
- package/lib/core/loaders/plugins/index.js +109 -0
- package/lib/core/loaders/policies.js +28 -0
- package/lib/core/loaders/src-index.js +38 -0
- package/lib/core/registries/apis.js +43 -0
- package/lib/core/registries/config.js +21 -0
- package/lib/core/registries/content-types.js +53 -0
- package/lib/core/registries/controllers.js +43 -0
- package/lib/core/registries/hooks.js +37 -0
- package/lib/core/registries/middlewares.js +30 -0
- package/lib/core/registries/modules.js +44 -0
- package/lib/core/registries/plugins.js +28 -0
- package/lib/core/registries/policies.js +38 -0
- package/lib/core/registries/services.js +58 -0
- package/lib/core/utils.js +35 -0
- package/lib/core-api/controller/collection-type.js +84 -0
- package/lib/core-api/controller/index.js +26 -0
- package/lib/core-api/controller/single-type.js +44 -0
- package/lib/core-api/controller/transform.js +97 -0
- package/lib/core-api/index.js +39 -0
- package/lib/core-api/service/collection-type.js +84 -0
- package/lib/core-api/service/index.js +55 -0
- package/lib/core-api/service/pagination.js +125 -0
- package/lib/core-api/service/single-type.js +58 -0
- package/lib/index.d.ts +26 -0
- package/lib/index.js +3 -0
- package/lib/load/filepath-to-prop-path.js +22 -0
- package/lib/load/glob.js +15 -0
- package/lib/load/index.js +9 -0
- package/lib/load/load-files.js +56 -0
- package/lib/load/package-path.js +9 -0
- package/lib/middlewares/cors/index.js +66 -0
- package/lib/middlewares/error/defaults.json +5 -0
- package/lib/middlewares/error/index.js +147 -0
- package/lib/middlewares/favicon/defaults.json +7 -0
- package/lib/middlewares/favicon/index.js +31 -0
- package/lib/middlewares/gzip/defaults.json +6 -0
- package/lib/middlewares/gzip/index.js +19 -0
- package/lib/middlewares/helmet/defaults.json +18 -0
- package/lib/middlewares/helmet/index.js +9 -0
- package/lib/middlewares/index.js +120 -0
- package/lib/middlewares/ip/defaults.json +7 -0
- package/lib/middlewares/ip/index.js +25 -0
- package/lib/middlewares/logger/defaults.json +5 -0
- package/lib/middlewares/logger/index.js +37 -0
- package/lib/middlewares/parser/defaults.json +11 -0
- package/lib/middlewares/parser/index.js +75 -0
- package/lib/middlewares/poweredBy/defaults.json +5 -0
- package/lib/middlewares/poweredBy/index.js +16 -0
- package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
- package/lib/middlewares/public/assets/images/logo_login.png +0 -0
- package/lib/middlewares/public/defaults.json +8 -0
- package/lib/middlewares/public/index.html +66 -0
- package/lib/middlewares/public/index.js +130 -0
- package/lib/middlewares/public/serve-static.js +23 -0
- package/lib/middlewares/responseTime/defaults.json +5 -0
- package/lib/middlewares/responseTime/index.js +25 -0
- package/lib/middlewares/responses/defaults.json +5 -0
- package/lib/middlewares/responses/index.js +19 -0
- package/lib/middlewares/router/defaults.json +7 -0
- package/lib/middlewares/router/index.js +97 -0
- package/lib/middlewares/session/defaults.json +18 -0
- package/lib/middlewares/session/index.js +140 -0
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +92 -0
- package/lib/services/core-store.js +145 -0
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/components.js +365 -0
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +244 -0
- package/lib/services/entity-service/params.js +145 -0
- package/lib/services/entity-validator/index.js +187 -0
- package/lib/services/entity-validator/validators.js +123 -0
- package/lib/services/event-hub.js +15 -0
- package/lib/services/fs.js +58 -0
- package/lib/services/metrics/index.js +104 -0
- package/lib/services/metrics/is-truthy.js +9 -0
- package/lib/services/metrics/middleware.js +33 -0
- package/lib/services/metrics/rate-limiter.js +27 -0
- package/lib/services/metrics/sender.js +76 -0
- package/lib/services/metrics/stringify-deep.js +22 -0
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +32 -0
- package/lib/services/server/compose-endpoint.js +112 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/services/server/http-server.js +64 -0
- package/lib/services/server/index.js +108 -0
- package/lib/services/server/middleware.js +28 -0
- package/lib/services/server/policy.js +34 -0
- package/lib/services/server/routing.js +107 -0
- package/lib/services/utils/upload-files.js +79 -0
- package/lib/services/webhook-runner.js +155 -0
- package/lib/services/webhook-store.js +91 -0
- package/lib/services/worker-queue.js +58 -0
- package/lib/utils/addSlash.js +10 -0
- package/lib/utils/ee.js +123 -0
- package/lib/utils/get-dirs.js +15 -0
- package/lib/utils/get-prefixed-dependencies.js +7 -0
- package/lib/utils/index.js +11 -0
- package/lib/utils/is-initialized.js +23 -0
- package/lib/utils/open-browser.js +12 -0
- package/lib/utils/resources/key.pub +9 -0
- package/lib/utils/run-checks.js +22 -0
- package/lib/utils/startup-logger.js +90 -0
- package/lib/utils/success.js +31 -0
- package/lib/utils/update-notifier/index.js +97 -0
- package/lib/utils/url-from-segments.js +12 -0
- package/package.json +133 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const _ = require('lodash');
|
|
6
|
+
const { omit } = require('lodash/fp');
|
|
7
|
+
const dotenv = require('dotenv');
|
|
8
|
+
|
|
9
|
+
dotenv.config({ path: process.env.ENV_PATH });
|
|
10
|
+
|
|
11
|
+
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
|
12
|
+
|
|
13
|
+
const getPrefixedDeps = require('../../utils/get-prefixed-dependencies');
|
|
14
|
+
const loadConfigDir = require('./config-loader');
|
|
15
|
+
const loadFunction = require('./load-functions');
|
|
16
|
+
|
|
17
|
+
const { version: strapiVersion } = require(path.join(__dirname, '../../../package.json'));
|
|
18
|
+
|
|
19
|
+
const CONFIG_PATHS = {
|
|
20
|
+
config: 'config',
|
|
21
|
+
static: 'public',
|
|
22
|
+
views: 'views',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defaultConfig = {
|
|
26
|
+
server: {
|
|
27
|
+
host: process.env.HOST || os.hostname() || 'localhost',
|
|
28
|
+
port: process.env.PORT || 1337,
|
|
29
|
+
proxy: false,
|
|
30
|
+
cron: { enabled: false },
|
|
31
|
+
admin: { autoOpen: false },
|
|
32
|
+
},
|
|
33
|
+
admin: {},
|
|
34
|
+
middleware: {
|
|
35
|
+
timeout: 1000,
|
|
36
|
+
load: {
|
|
37
|
+
before: ['responseTime', 'logger', 'cors', 'responses', 'gzip'],
|
|
38
|
+
order: [],
|
|
39
|
+
after: ['parser', 'router'],
|
|
40
|
+
},
|
|
41
|
+
settings: {},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports = (dir, initialConfig = {}) => {
|
|
46
|
+
const { autoReload = false, serveAdminPanel = true } = initialConfig;
|
|
47
|
+
|
|
48
|
+
const pkgJSON = require(path.resolve(dir, 'package.json'));
|
|
49
|
+
|
|
50
|
+
const configDir = path.resolve(dir || process.cwd(), 'config');
|
|
51
|
+
|
|
52
|
+
const rootConfig = {
|
|
53
|
+
launchedAt: Date.now(),
|
|
54
|
+
appPath: dir,
|
|
55
|
+
paths: CONFIG_PATHS,
|
|
56
|
+
serveAdminPanel,
|
|
57
|
+
autoReload,
|
|
58
|
+
environment: process.env.NODE_ENV,
|
|
59
|
+
uuid: _.get(pkgJSON, 'strapi.uuid'),
|
|
60
|
+
packageJsonStrapi: _.omit(_.get(pkgJSON, 'strapi', {}), 'uuid'),
|
|
61
|
+
info: {
|
|
62
|
+
...pkgJSON,
|
|
63
|
+
strapi: strapiVersion,
|
|
64
|
+
},
|
|
65
|
+
functions: loadFunction(path.join(configDir, 'functions')),
|
|
66
|
+
installedMiddlewares: getPrefixedDeps('@strapi/middleware', pkgJSON),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const baseConfig = omit('plugins', loadConfigDir(configDir)); // plugin config will be loaded later
|
|
70
|
+
|
|
71
|
+
const envDir = path.resolve(configDir, 'env', process.env.NODE_ENV);
|
|
72
|
+
const envConfig = loadConfigDir(envDir);
|
|
73
|
+
|
|
74
|
+
return _.merge(rootConfig, defaultConfig, baseConfig, envConfig);
|
|
75
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { templateConfiguration, env } = require('@strapi/utils');
|
|
6
|
+
|
|
7
|
+
const loadJsFile = file => {
|
|
8
|
+
try {
|
|
9
|
+
const jsModule = require(file);
|
|
10
|
+
|
|
11
|
+
// call if function
|
|
12
|
+
if (typeof jsModule === 'function') {
|
|
13
|
+
return jsModule({ env });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return jsModule;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
throw new Error(`Could not load js config file ${file}: ${error.message}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const loadJSONFile = file => {
|
|
23
|
+
try {
|
|
24
|
+
return templateConfiguration(JSON.parse(fs.readFileSync(file)));
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new Error(`Could not load json config file ${file}: ${error.message}`);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const loadFile = file => {
|
|
31
|
+
const ext = path.extname(file);
|
|
32
|
+
|
|
33
|
+
switch (ext) {
|
|
34
|
+
case '.js':
|
|
35
|
+
return loadJsFile(file);
|
|
36
|
+
case '.json':
|
|
37
|
+
return loadJSONFile(file);
|
|
38
|
+
default:
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = loadFile;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join, extname, basename } = require('path');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
|
|
6
|
+
module.exports = function loadFunctions(dir) {
|
|
7
|
+
const functions = {};
|
|
8
|
+
|
|
9
|
+
if (!fse.pathExistsSync(dir)) {
|
|
10
|
+
return functions;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const paths = fse.readdirSync(dir, { withFileTypes: true });
|
|
14
|
+
|
|
15
|
+
for (const fd of paths) {
|
|
16
|
+
const { name } = fd;
|
|
17
|
+
const fullPath = join(dir, name);
|
|
18
|
+
|
|
19
|
+
if (fd.isDirectory()) {
|
|
20
|
+
functions[name] = loadFunctions(fullPath);
|
|
21
|
+
} else if (fd.isFile() && extname(name) === '.js') {
|
|
22
|
+
const key = basename(name, '.js');
|
|
23
|
+
functions[key] = require(fullPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return functions;
|
|
28
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { getConfigUrls } = require('@strapi/utils');
|
|
5
|
+
|
|
6
|
+
module.exports = function({ strapi }) {
|
|
7
|
+
// TODO: delete v3 code
|
|
8
|
+
_.forEach(strapi.api, api => {
|
|
9
|
+
_.forEach(api.middlewares, (middleware, middlewareName) => {
|
|
10
|
+
strapi.middleware[middlewareName] = middleware;
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
_.forEach(strapi.admin.middlewares, (middleware, middlewareName) => {
|
|
15
|
+
strapi.middleware[middlewareName] = middleware;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
_.forEach(strapi.plugins, plugin => {
|
|
19
|
+
_.forEach(plugin.middlewares, (middleware, middlewareName) => {
|
|
20
|
+
strapi.middleware[middlewareName] = middleware;
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Preset config in alphabetical order.
|
|
25
|
+
strapi.config.middleware.settings = Object.keys(strapi.middleware).reduce((acc, current) => {
|
|
26
|
+
// Try to find the settings in the current environment, then in the main configurations.
|
|
27
|
+
const currentSettings = _.merge(
|
|
28
|
+
_.cloneDeep(_.get(strapi.middleware[current], ['defaults', current], {})),
|
|
29
|
+
strapi.config.get(['middleware', 'settings', current], {})
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
acc[current] = !_.isObject(currentSettings) ? {} : currentSettings;
|
|
33
|
+
|
|
34
|
+
// Ensure that enabled key exist by forcing to false.
|
|
35
|
+
_.defaults(acc[current], { enabled: false });
|
|
36
|
+
|
|
37
|
+
return acc;
|
|
38
|
+
}, {});
|
|
39
|
+
|
|
40
|
+
// default settings
|
|
41
|
+
strapi.config.port = strapi.config.get('server.port') || strapi.config.port;
|
|
42
|
+
strapi.config.host = strapi.config.get('server.host') || strapi.config.host;
|
|
43
|
+
|
|
44
|
+
const { serverUrl, adminUrl, adminPath } = getConfigUrls(strapi.config.get('server'));
|
|
45
|
+
|
|
46
|
+
strapi.config.server = strapi.config.server || {};
|
|
47
|
+
strapi.config.server.url = serverUrl;
|
|
48
|
+
strapi.config.admin.url = adminUrl;
|
|
49
|
+
strapi.config.admin.path = adminPath;
|
|
50
|
+
|
|
51
|
+
// check if we should serve admin panel
|
|
52
|
+
const shouldServeAdmin = strapi.config.get(
|
|
53
|
+
'server.admin.serveAdminPanel',
|
|
54
|
+
strapi.config.get('serveAdminPanel')
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (!shouldServeAdmin) {
|
|
58
|
+
strapi.config.serveAdminPanel = false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { cloneDeep, camelCase } = require('lodash/fp');
|
|
4
|
+
const { validateComponentDefinition } = require('./validator');
|
|
5
|
+
|
|
6
|
+
const createComponent = (definition = {}) => {
|
|
7
|
+
validateComponentDefinition(definition);
|
|
8
|
+
|
|
9
|
+
const createdComponent = cloneDeep(definition);
|
|
10
|
+
const category = camelCase(definition.info.category);
|
|
11
|
+
|
|
12
|
+
const uid = `${category}.${definition.info.singularModelName}`;
|
|
13
|
+
|
|
14
|
+
Object.assign(createdComponent, {
|
|
15
|
+
uid,
|
|
16
|
+
category,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return createdComponent;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
createComponent,
|
|
24
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { yup } = require('@strapi/utils');
|
|
4
|
+
|
|
5
|
+
const componentSchemaValidator = () =>
|
|
6
|
+
yup.object().shape({
|
|
7
|
+
info: yup
|
|
8
|
+
.object()
|
|
9
|
+
.shape({
|
|
10
|
+
singularName: yup
|
|
11
|
+
.string()
|
|
12
|
+
.isCamelCase()
|
|
13
|
+
.required(),
|
|
14
|
+
pluralName: yup
|
|
15
|
+
.string()
|
|
16
|
+
.isCamelCase()
|
|
17
|
+
.required(),
|
|
18
|
+
displayName: yup.string().required(),
|
|
19
|
+
})
|
|
20
|
+
.required(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const validateComponentDefinition = data => {
|
|
24
|
+
return componentSchemaValidator.validateSync(data, { strict: true, abortEarly: false });
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
validateComponentDefinition,
|
|
29
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { cloneDeep } = require('lodash/fp');
|
|
4
|
+
const _ = require('lodash');
|
|
5
|
+
const { hasDraftAndPublish, getPrivateAttributes } = require('@strapi/utils').contentTypes;
|
|
6
|
+
const {
|
|
7
|
+
CREATED_AT_ATTRIBUTE,
|
|
8
|
+
UPDATED_AT_ATTRIBUTE,
|
|
9
|
+
PUBLISHED_AT_ATTRIBUTE,
|
|
10
|
+
CREATED_BY_ATTRIBUTE,
|
|
11
|
+
UPDATED_BY_ATTRIBUTE,
|
|
12
|
+
} = require('@strapi/utils').contentTypes.constants;
|
|
13
|
+
const { validateContentTypeDefinition } = require('./validator');
|
|
14
|
+
|
|
15
|
+
const createContentType = (uid, definition) => {
|
|
16
|
+
try {
|
|
17
|
+
validateContentTypeDefinition(definition);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
throw new Error(`Content Type Definition is invalid for ${uid}'.\n${e.errors}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { schema, actions, lifecycles } = cloneDeep(definition);
|
|
23
|
+
|
|
24
|
+
// general info
|
|
25
|
+
Object.assign(schema, {
|
|
26
|
+
kind: schema.kind || 'collectionType',
|
|
27
|
+
__schema__: pickSchema(definition.schema),
|
|
28
|
+
modelType: 'contentType',
|
|
29
|
+
modelName: definition.schema.info.singularName,
|
|
30
|
+
connection: 'default',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (uid.startsWith('api::')) {
|
|
34
|
+
Object.assign(schema, {
|
|
35
|
+
uid,
|
|
36
|
+
apiName: uid.split('::')[1].split('.')[0],
|
|
37
|
+
collectionName: schema.collectionName || schema.info.singularName,
|
|
38
|
+
globalId: getGlobalId(schema, schema.info.singularName),
|
|
39
|
+
});
|
|
40
|
+
} else if (uid.startsWith('plugin::')) {
|
|
41
|
+
const pluginName = uid.split('::')[1].split('.')[0];
|
|
42
|
+
Object.assign(schema, {
|
|
43
|
+
uid,
|
|
44
|
+
plugin: pluginName, // TODO: to be set in load-plugins.js
|
|
45
|
+
collectionName:
|
|
46
|
+
schema.collectionName || `${pluginName}_${schema.info.singularName}`.toLowerCase(),
|
|
47
|
+
globalId: getGlobalId(schema, schema.info.singularName, pluginName),
|
|
48
|
+
});
|
|
49
|
+
} else if (uid.startsWith('admin::')) {
|
|
50
|
+
Object.assign(schema, {
|
|
51
|
+
uid,
|
|
52
|
+
plugin: 'admin',
|
|
53
|
+
globalId: getGlobalId(schema, schema.info.singularName, 'admin'),
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Incorrect Content Type UID "${uid}". The UID should start with api::, plugin:: or strapi::.`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Object.defineProperty(schema, 'privateAttributes', {
|
|
62
|
+
get() {
|
|
63
|
+
return getPrivateAttributes(schema);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// attributes
|
|
68
|
+
Object.assign(schema.attributes, {
|
|
69
|
+
[CREATED_AT_ATTRIBUTE]: {
|
|
70
|
+
type: 'datetime',
|
|
71
|
+
},
|
|
72
|
+
// TODO: handle on edit set to new date
|
|
73
|
+
[UPDATED_AT_ATTRIBUTE]: {
|
|
74
|
+
type: 'datetime',
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (hasDraftAndPublish(schema)) {
|
|
79
|
+
schema.attributes[PUBLISHED_AT_ATTRIBUTE] = {
|
|
80
|
+
type: 'datetime',
|
|
81
|
+
configurable: false,
|
|
82
|
+
writable: true,
|
|
83
|
+
visible: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const isPrivate = !_.get(schema, 'options.populateCreatorFields', false);
|
|
88
|
+
|
|
89
|
+
schema.attributes[CREATED_BY_ATTRIBUTE] = {
|
|
90
|
+
type: 'relation',
|
|
91
|
+
relation: 'oneToOne',
|
|
92
|
+
target: 'admin::user',
|
|
93
|
+
configurable: false,
|
|
94
|
+
writable: false,
|
|
95
|
+
visible: false,
|
|
96
|
+
useJoinTable: false,
|
|
97
|
+
private: isPrivate,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
schema.attributes[UPDATED_BY_ATTRIBUTE] = {
|
|
101
|
+
type: 'relation',
|
|
102
|
+
relation: 'oneToOne',
|
|
103
|
+
target: 'admin::user',
|
|
104
|
+
configurable: false,
|
|
105
|
+
writable: false,
|
|
106
|
+
visible: false,
|
|
107
|
+
useJoinTable: false,
|
|
108
|
+
private: isPrivate,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
Object.assign(schema, { actions, lifecycles });
|
|
112
|
+
|
|
113
|
+
return schema;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const getGlobalId = (model, modelName, prefix) => {
|
|
117
|
+
let globalId = prefix ? `${prefix}-${modelName}` : modelName;
|
|
118
|
+
|
|
119
|
+
return model.globalId || _.upperFirst(_.camelCase(globalId));
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const pickSchema = model => {
|
|
123
|
+
const schema = _.cloneDeep(
|
|
124
|
+
_.pick(model, [
|
|
125
|
+
'connection',
|
|
126
|
+
'collectionName',
|
|
127
|
+
'info',
|
|
128
|
+
'options',
|
|
129
|
+
'pluginOptions',
|
|
130
|
+
'attributes',
|
|
131
|
+
])
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
schema.kind = model.kind || 'collectionType';
|
|
135
|
+
return schema;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
createContentType,
|
|
140
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { keyBy, mapValues } = require('lodash');
|
|
4
|
+
const { yup } = require('@strapi/utils');
|
|
5
|
+
|
|
6
|
+
const LIFECYCLES = [
|
|
7
|
+
'beforeCreate',
|
|
8
|
+
'afterCreate',
|
|
9
|
+
'beforeFindOne',
|
|
10
|
+
'afterFindOne',
|
|
11
|
+
'beforeFindMany',
|
|
12
|
+
'afterFindMany',
|
|
13
|
+
'beforeCount',
|
|
14
|
+
'afterCount',
|
|
15
|
+
'beforeCreateMany',
|
|
16
|
+
'afterCreateMany',
|
|
17
|
+
'beforeUpdate',
|
|
18
|
+
'afterUpdate',
|
|
19
|
+
'beforeUpdateMany',
|
|
20
|
+
'afterUpdateMany',
|
|
21
|
+
'beforeDelete',
|
|
22
|
+
'afterDelete',
|
|
23
|
+
'beforeDeleteMany',
|
|
24
|
+
'afterDeleteMany',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const lifecyclesShape = mapValues(keyBy(LIFECYCLES), () =>
|
|
28
|
+
yup
|
|
29
|
+
.mixed()
|
|
30
|
+
.nullable()
|
|
31
|
+
.isFunction()
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const contentTypeSchemaValidator = yup.object().shape({
|
|
35
|
+
schema: yup.object().shape({
|
|
36
|
+
info: yup
|
|
37
|
+
.object()
|
|
38
|
+
.shape({
|
|
39
|
+
displayName: yup.string().required(),
|
|
40
|
+
singularName: yup
|
|
41
|
+
.string()
|
|
42
|
+
.isKebabCase()
|
|
43
|
+
.required(),
|
|
44
|
+
pluralName: yup
|
|
45
|
+
.string()
|
|
46
|
+
.isKebabCase()
|
|
47
|
+
.required(),
|
|
48
|
+
})
|
|
49
|
+
.required(),
|
|
50
|
+
}),
|
|
51
|
+
actions: yup.object().onlyContainsFunctions(),
|
|
52
|
+
lifecycles: yup
|
|
53
|
+
.object()
|
|
54
|
+
.shape(lifecyclesShape)
|
|
55
|
+
.noUnknown(),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const validateContentTypeDefinition = data => {
|
|
59
|
+
return contentTypeSchemaValidator.validateSync(data, { strict: true, abortEarly: false });
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
validateContentTypeDefinition,
|
|
64
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { removeNamespace } = require('../../utils');
|
|
5
|
+
const { validateModule } = require('./validation');
|
|
6
|
+
|
|
7
|
+
const uidToPath = uid => uid.replace('::', '.');
|
|
8
|
+
|
|
9
|
+
// Removes the namespace from a map with keys prefixed with a namespace
|
|
10
|
+
const removeNamespacedKeys = (map, namespace) => {
|
|
11
|
+
return _.mapKeys(map, (value, key) => removeNamespace(key, namespace));
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const defaultModule = {
|
|
15
|
+
config: {},
|
|
16
|
+
routes: [],
|
|
17
|
+
controllers: {},
|
|
18
|
+
services: {},
|
|
19
|
+
contentTypes: {},
|
|
20
|
+
policies: {},
|
|
21
|
+
middlewares: {},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const createModule = (namespace, rawModule, strapi) => {
|
|
25
|
+
_.defaults(rawModule, defaultModule);
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
validateModule(rawModule);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
throw new Error(`strapi-server.js is invalid for '${namespace}'.\n${e.errors.join('\n')}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const called = {};
|
|
34
|
+
return {
|
|
35
|
+
async bootstrap() {
|
|
36
|
+
if (called.bootstrap) {
|
|
37
|
+
throw new Error(`Bootstrap for ${namespace} has already been called`);
|
|
38
|
+
}
|
|
39
|
+
called.bootstrap = true;
|
|
40
|
+
await (rawModule.bootstrap && rawModule.bootstrap({ strapi }));
|
|
41
|
+
},
|
|
42
|
+
async register() {
|
|
43
|
+
if (called.register) {
|
|
44
|
+
throw new Error(`Register for ${namespace} has already been called`);
|
|
45
|
+
}
|
|
46
|
+
called.register = true;
|
|
47
|
+
await (rawModule.register && rawModule.register({ strapi }));
|
|
48
|
+
},
|
|
49
|
+
async destroy() {
|
|
50
|
+
if (called.destroy) {
|
|
51
|
+
throw new Error(`Destroy for ${namespace} has already been called`);
|
|
52
|
+
}
|
|
53
|
+
called.destroy = true;
|
|
54
|
+
await (rawModule.destroy && rawModule.destroy({ strapi }));
|
|
55
|
+
},
|
|
56
|
+
load() {
|
|
57
|
+
strapi.container.get('content-types').add(namespace, rawModule.contentTypes);
|
|
58
|
+
strapi.container.get('services').add(namespace, rawModule.services);
|
|
59
|
+
strapi.container.get('policies').add(namespace, rawModule.policies);
|
|
60
|
+
strapi.container.get('middlewares').add(namespace, rawModule.middlewares);
|
|
61
|
+
strapi.container.get('controllers').add(namespace, rawModule.controllers);
|
|
62
|
+
strapi.container.get('config').set(uidToPath(namespace), rawModule.config);
|
|
63
|
+
},
|
|
64
|
+
routes: rawModule.routes,
|
|
65
|
+
config(path, defaultValue) {
|
|
66
|
+
return strapi.container.get('config').get(`${uidToPath(namespace)}.${path}`, defaultValue);
|
|
67
|
+
},
|
|
68
|
+
contentType(ctName) {
|
|
69
|
+
return strapi.container.get('content-types').get(`${namespace}.${ctName}`);
|
|
70
|
+
},
|
|
71
|
+
get contentTypes() {
|
|
72
|
+
const contentTypes = strapi.container.get('content-types').getAll(namespace);
|
|
73
|
+
return removeNamespacedKeys(contentTypes, namespace);
|
|
74
|
+
},
|
|
75
|
+
service(serviceName) {
|
|
76
|
+
return strapi.container.get('services').get(`${namespace}.${serviceName}`);
|
|
77
|
+
},
|
|
78
|
+
get services() {
|
|
79
|
+
const services = strapi.container.get('services').getAll(namespace);
|
|
80
|
+
return removeNamespacedKeys(services, namespace);
|
|
81
|
+
},
|
|
82
|
+
policy(policyName) {
|
|
83
|
+
return strapi.container.get('policies').get(`${namespace}.${policyName}`);
|
|
84
|
+
},
|
|
85
|
+
get policies() {
|
|
86
|
+
const policies = strapi.container.get('policies').getAll(namespace);
|
|
87
|
+
return removeNamespacedKeys(policies, namespace);
|
|
88
|
+
},
|
|
89
|
+
middleware(middlewareName) {
|
|
90
|
+
return strapi.container.get('middlewares').get(`${namespace}.${middlewareName}`);
|
|
91
|
+
},
|
|
92
|
+
get middlewares() {
|
|
93
|
+
const middlewares = strapi.container.get('middlewares').getAll(namespace);
|
|
94
|
+
return removeNamespacedKeys(middlewares, namespace);
|
|
95
|
+
},
|
|
96
|
+
controller(controllerName) {
|
|
97
|
+
return strapi.container.get('controllers').get(`${namespace}.${controllerName}`);
|
|
98
|
+
},
|
|
99
|
+
get controllers() {
|
|
100
|
+
const controllers = strapi.container.get('controllers').getAll(namespace);
|
|
101
|
+
return removeNamespacedKeys(controllers, namespace);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
module.exports = { createModule };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { yup } = require('@strapi/utils');
|
|
5
|
+
|
|
6
|
+
const strapiServerSchema = yup
|
|
7
|
+
.object()
|
|
8
|
+
.shape({
|
|
9
|
+
bootstrap: yup.mixed().isFunction(),
|
|
10
|
+
destroy: yup.mixed().isFunction(),
|
|
11
|
+
register: yup.mixed().isFunction(),
|
|
12
|
+
config: yup.object(),
|
|
13
|
+
routes: yup.lazy(value => {
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return yup.array();
|
|
16
|
+
} else {
|
|
17
|
+
const shape = _.mapValues(value, () => yup.object({ routes: yup.array().required() }));
|
|
18
|
+
|
|
19
|
+
return yup.object(shape);
|
|
20
|
+
}
|
|
21
|
+
}),
|
|
22
|
+
controllers: yup.object(),
|
|
23
|
+
services: yup.object(),
|
|
24
|
+
policies: yup.object(),
|
|
25
|
+
middlewares: yup.object(),
|
|
26
|
+
contentTypes: yup.object(),
|
|
27
|
+
})
|
|
28
|
+
.noUnknown();
|
|
29
|
+
|
|
30
|
+
const validateModule = data => {
|
|
31
|
+
return strapiServerSchema.validateSync(data, { strict: true, abortEarly: false });
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
validateModule,
|
|
36
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
module.exports = strapi => {
|
|
6
|
+
strapi.admin = require('@strapi/admin/strapi-server');
|
|
7
|
+
|
|
8
|
+
strapi.container.get('services').add(`admin::`, strapi.admin.services);
|
|
9
|
+
strapi.container.get('controllers').add(`admin::`, strapi.admin.controllers);
|
|
10
|
+
strapi.container.get('content-types').add(`admin::`, strapi.admin.contentTypes);
|
|
11
|
+
strapi.container.get('policies').add(`admin::`, strapi.admin.policies);
|
|
12
|
+
strapi.container.get('middlewares').add(`admin::`, strapi.admin.middlewares);
|
|
13
|
+
|
|
14
|
+
const userAdminConfig = strapi.config.get('server.admin');
|
|
15
|
+
strapi.container.get('config').set('server.admin', _.merge(strapi.admin.config, userAdminConfig));
|
|
16
|
+
};
|