expressa 2.0.16 → 2.0.18
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/.circleci/config.yml +21 -21
- package/.eslintrc.json +29 -29
- package/LICENSE +21 -21
- package/README.md +137 -137
- package/auth/index.js +76 -76
- package/auth/jwt.js +31 -31
- package/controllers/collections.js +260 -258
- package/controllers/install.js +105 -105
- package/controllers/status.js +43 -43
- package/controllers/users.js +52 -52
- package/cypress/fixtures/example.json +4 -4
- package/cypress/integration/0_install_spec.js +8 -8
- package/cypress/integration/custom_collections.js +28 -28
- package/cypress/integration/home.js +9 -9
- package/cypress/integration/settings.js +34 -34
- package/cypress/integration/users.js +61 -61
- package/cypress/plugins/index.js +17 -17
- package/cypress/screenshots/users.js/User Management -- Can log in as non-admin, but cannot create users (failed).png +0 -0
- package/cypress/support/commands.js +54 -54
- package/cypress/support/index.js +20 -20
- package/cypress/support/util.js +10 -10
- package/cypress.json +4 -4
- package/db/cached.js +40 -40
- package/db/file.js +112 -112
- package/db/memory.js +79 -79
- package/db/mongo.js +86 -86
- package/db/postgres.js +93 -93
- package/doc/authentication.md +38 -38
- package/doc/automatic-fields.md +12 -12
- package/doc/blogexample.md +16 -16
- package/doc/custom-endpoints.md +20 -20
- package/doc/database.md +23 -23
- package/doc/development.md +33 -33
- package/doc/listeners.md +103 -103
- package/doc/modules.md +8 -8
- package/doc/permissions.md +14 -14
- package/doc/relationships.md +65 -65
- package/doc/testing.md +47 -47
- package/doc/uploading-files.md +53 -53
- package/index.js +297 -297
- package/listeners.js +65 -65
- package/listeners_collection_permissions.js +29 -29
- package/listeners_users.js +96 -96
- package/listeners_validation.js +43 -43
- package/middleware/logging.js +30 -30
- package/middleware/permissions.js +41 -41
- package/modules/access_keys/access_keys.js +32 -32
- package/modules/admin/.babelrc +20 -12
- package/modules/admin/.editorconfig +14 -14
- package/modules/admin/.eslintignore +5 -5
- package/modules/admin/.eslintrc.js +197 -197
- package/modules/admin/.postcssrc.js +10 -10
- package/modules/admin/.travis.yml +5 -5
- package/modules/admin/LICENSE +21 -21
- package/modules/admin/README.md +88 -88
- package/modules/admin/build/build.js +45 -45
- package/modules/admin/build/check-versions.js +64 -64
- package/modules/admin/build/utils.js +108 -108
- package/modules/admin/build/vue-loader.conf.js +5 -5
- package/modules/admin/build/webpack.base.conf.js +112 -108
- package/modules/admin/build/webpack.dev.conf.js +95 -95
- package/modules/admin/build/webpack.prod.conf.js +112 -171
- package/modules/admin/config/dev.env.js +8 -8
- package/modules/admin/config/index.js +86 -86
- package/modules/admin/config/prod.env.js +5 -5
- package/modules/admin/dist/favicon.ico +0 -0
- package/modules/admin/dist/index.html +1 -0
- package/modules/admin/dist/index.html.gz +0 -0
- package/modules/admin/dist/static/css/app.9dd57eea.css +1 -0
- package/modules/admin/dist/static/css/app.9dd57eea.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css +1 -0
- package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css +1 -0
- package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-621e.b826be8d.css +1 -0
- package/modules/admin/dist/static/css/chunk-621e.b826be8d.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-656b.9c828b00.css +1 -0
- package/modules/admin/dist/static/css/chunk-656b.9c828b00.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-7291.13514e45.css +0 -0
- package/modules/admin/dist/static/css/chunk-7291.13514e45.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-7f29.9c828b00.css +1 -0
- package/modules/admin/dist/static/css/chunk-7f29.9c828b00.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-9a95.c647a2ef.css +1 -0
- package/modules/admin/dist/static/css/chunk-9a95.c647a2ef.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-b423.5f239333.css +0 -0
- package/modules/admin/dist/static/css/chunk-b423.5f239333.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-bd5f.aefa49d7.css +1 -0
- package/modules/admin/dist/static/css/chunk-bd5f.aefa49d7.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-e374.025d58bb.css +1 -0
- package/modules/admin/dist/static/css/chunk-e374.025d58bb.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css +1 -0
- package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css +1 -0
- package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-libs.327ad89e.css +14 -0
- package/modules/admin/dist/static/css/chunk-libs.327ad89e.css.gz +0 -0
- package/modules/admin/dist/static/fonts/element-icons.6f0a763.ttf +0 -0
- package/modules/admin/dist/static/img/404.a57b6f3.png +0 -0
- package/modules/admin/dist/static/js/app.e9461593.js +1 -0
- package/modules/admin/dist/static/js/app.e9461593.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js +2 -0
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.LICENSE.txt +13 -0
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.LICENSE.txt.gz +0 -0
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-5061.83e6ccfa.js +1 -0
- package/modules/admin/dist/static/js/chunk-5061.83e6ccfa.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-5b97.ac360086.js +1 -0
- package/modules/admin/dist/static/js/chunk-5b97.ac360086.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js +1 -0
- package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-621e.ccf42393.js +1 -0
- package/modules/admin/dist/static/js/chunk-621e.ccf42393.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js +1 -0
- package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-7291.590524e9.js +1 -0
- package/modules/admin/dist/static/js/chunk-7291.590524e9.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js +1 -0
- package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js +1 -0
- package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-b423.387c504c.js +1 -0
- package/modules/admin/dist/static/js/chunk-b423.387c504c.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js +1 -0
- package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js +1 -0
- package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js +1 -0
- package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js +1 -0
- package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-f075.315ceec1.js +1 -0
- package/modules/admin/dist/static/js/chunk-f075.315ceec1.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js +2 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js.LICENSE.txt +126 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js.LICENSE.txt.gz +0 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js.gz +0 -0
- package/modules/admin/index.html +16 -16
- package/modules/admin/package.json +101 -98
- package/modules/admin/src/App.vue +11 -11
- package/modules/admin/src/api/login.js +26 -26
- package/modules/admin/src/api/table.js +9 -9
- package/modules/admin/src/components/Breadcrumb/index.vue +79 -79
- package/modules/admin/src/components/Hamburger/index.vue +62 -62
- package/modules/admin/src/components/JSONEditor.vue +180 -180
- package/modules/admin/src/components/SvgIcon/index.vue +43 -43
- package/modules/admin/src/icons/index.js +9 -9
- package/modules/admin/src/icons/svgo.yml +22 -22
- package/modules/admin/src/main.js +42 -41
- package/modules/admin/src/permission.js +49 -49
- package/modules/admin/src/router/index.js +200 -200
- package/modules/admin/src/store/getters.js +11 -11
- package/modules/admin/src/store/index.js +17 -17
- package/modules/admin/src/store/modules/app.js +43 -43
- package/modules/admin/src/store/modules/user.js +104 -104
- package/modules/admin/src/styles/element-ui.scss +29 -29
- package/modules/admin/src/styles/index.scss +78 -78
- package/modules/admin/src/styles/mixin.scss +27 -27
- package/modules/admin/src/styles/sidebar.scss +133 -133
- package/modules/admin/src/styles/transition.scss +46 -46
- package/modules/admin/src/styles/variables.scss +4 -4
- package/modules/admin/src/utils/auth.js +15 -15
- package/modules/admin/src/utils/index.js +74 -74
- package/modules/admin/src/utils/request.js +48 -48
- package/modules/admin/src/utils/validate.js +31 -31
- package/modules/admin/src/views/404.vue +235 -235
- package/modules/admin/src/views/Dev.vue +33 -33
- package/modules/admin/src/views/EditDocument.vue +116 -116
- package/modules/admin/src/views/Endpoints.vue +279 -279
- package/modules/admin/src/views/Home.vue +84 -84
- package/modules/admin/src/views/Install.vue +79 -79
- package/modules/admin/src/views/ListDocuments.vue +72 -72
- package/modules/admin/src/views/ListDocuments2.vue +462 -462
- package/modules/admin/src/views/ManageListeners.vue +67 -67
- package/modules/admin/src/views/ManageMiddleware.vue +43 -43
- package/modules/admin/src/views/ManagePermissions.vue +75 -75
- package/modules/admin/src/views/ViewRequest.vue +77 -77
- package/modules/admin/src/views/form/index.vue +91 -91
- package/modules/admin/src/views/layout/Layout.vue +69 -69
- package/modules/admin/src/views/layout/components/AppMain.vue +41 -41
- package/modules/admin/src/views/layout/components/Navbar.vue +97 -97
- package/modules/admin/src/views/layout/components/Sidebar/Item.vue +29 -29
- package/modules/admin/src/views/layout/components/Sidebar/Link.vue +39 -39
- package/modules/admin/src/views/layout/components/Sidebar/SidebarItem.vue +103 -103
- package/modules/admin/src/views/layout/components/Sidebar/index.vue +62 -62
- package/modules/admin/src/views/layout/components/index.js +3 -3
- package/modules/admin/src/views/layout/mixin/ResizeHandler.js +41 -41
- package/modules/admin/src/views/login/index.vue +195 -195
- package/modules/admin/src/views/tree/index.vue +77 -77
- package/modules/collections/collections.js +39 -39
- package/modules/core/core.js +197 -197
- package/modules/logging/logging.js +88 -88
- package/modules/permissions/permissions.js +106 -106
- package/package.json +59 -59
- package/scripts/expressa +12 -12
- package/scripts/run_cypress_tests.sh +5 -5
- package/scripts/run_db_tests.sh +8 -8
- package/test/0-install.js +96 -96
- package/test/collections.js +431 -431
- package/test/collections.querying.js +288 -289
- package/test/db.js +258 -258
- package/test/db.strings.js +73 -73
- package/test/db.updating.js +144 -144
- package/test/logging.js +29 -29
- package/test/test.js +93 -94
- package/test/testserver.js +17 -17
- package/test/testutils.js +136 -136
- package/test/users.js +425 -425
- package/util.js +522 -522
package/controllers/install.js
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
const util = require('../util')
|
|
2
|
-
|
|
3
|
-
exports.updateAdminPermissions = async function (api) {
|
|
4
|
-
if (!api.db.role) {
|
|
5
|
-
return // not installed yet
|
|
6
|
-
}
|
|
7
|
-
const modules = Object.values(api.modules)
|
|
8
|
-
const permissions = [].concat(...await Promise.all(modules.map((m) => util.resolve(m.permissions, api)))).filter(x => x !== undefined)
|
|
9
|
-
let adminRole = { permissions: {} }
|
|
10
|
-
try {
|
|
11
|
-
adminRole = await api.db.role.get('Admin')
|
|
12
|
-
} catch (e) {
|
|
13
|
-
// expected if not installed
|
|
14
|
-
}
|
|
15
|
-
const neededPermissions = permissions.reduce((obj, p) => { obj[p] = 1; return obj }, {})
|
|
16
|
-
adminRole.permissions = { ...neededPermissions, ...adminRole.permissions }
|
|
17
|
-
await api.db.role.update('Admin', adminRole)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
exports.install = async (req, api) => {
|
|
21
|
-
const selectedModules = req.body.modules
|
|
22
|
-
const installedModules = Object.keys(req.modules)
|
|
23
|
-
const missingModules = selectedModules.filter((module) => !installedModules.includes(module))
|
|
24
|
-
if (missingModules.length > 0) {
|
|
25
|
-
throw new util.ApiError(400, 'unknown modules')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const modules = selectedModules.map((name) => req.modules[name])
|
|
29
|
-
|
|
30
|
-
let settings = await api.db.settings.get(process.env.NODE_ENV).catch(() => {})
|
|
31
|
-
|
|
32
|
-
if (!settings) {
|
|
33
|
-
settings = JSON.parse(JSON.stringify(req.body.settings))
|
|
34
|
-
settings._id = process.env.NODE_ENV
|
|
35
|
-
settings.jwt_secret = util.createSecureRandomId()
|
|
36
|
-
// Remove fields that are not real settings
|
|
37
|
-
delete settings.email
|
|
38
|
-
delete settings.user_storage
|
|
39
|
-
delete settings.password
|
|
40
|
-
Object.assign(req.settings, settings)
|
|
41
|
-
await req.db.settings.create(settings)
|
|
42
|
-
|
|
43
|
-
for (const m of modules) {
|
|
44
|
-
const colls = await util.resolve(m.collections, api)
|
|
45
|
-
if (colls) {
|
|
46
|
-
for (const coll of colls) {
|
|
47
|
-
if (!coll.storage) {
|
|
48
|
-
coll.storage = 'file'
|
|
49
|
-
}
|
|
50
|
-
if (coll._id == 'users') {
|
|
51
|
-
if (req.body.settings.user_storage) {
|
|
52
|
-
coll.storage = req.body.settings.user_storage
|
|
53
|
-
}
|
|
54
|
-
coll.enableLogin = true
|
|
55
|
-
}
|
|
56
|
-
await req.db.collection.create(coll)
|
|
57
|
-
await api.notify('changed', req, 'collection', coll)
|
|
58
|
-
// await collectionsApi.insert(Object.assign({}, req, { body: coll }))
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
await util.resolve(m.install, api)
|
|
62
|
-
}
|
|
63
|
-
await exports.updateAdminPermissions(api)
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
if (settings.installed) {
|
|
67
|
-
throw new Error(`${process.env.NODE_ENV}.json exists and indicates expressa is already installed. Try setting 'installed' to false if you are attempting to reinstall.`)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
settings.installed = true
|
|
72
|
-
settings.enforce_permissions = true
|
|
73
|
-
Object.assign(req.settings, settings)
|
|
74
|
-
await req.db.settings.update(settings._id, settings)
|
|
75
|
-
return { }
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
exports.getSettingsSchema = async (req, api) => {
|
|
79
|
-
const colls = await util.resolve(api.modules.core.collections, api)
|
|
80
|
-
const settings = colls.find((m) => m._id === 'settings')
|
|
81
|
-
settings.schema.properties = {
|
|
82
|
-
/*collection_storage: {
|
|
83
|
-
type: 'string',
|
|
84
|
-
enum: ['file', 'mongo', 'postgres']
|
|
85
|
-
},*/
|
|
86
|
-
user_storage: {
|
|
87
|
-
type: 'string',
|
|
88
|
-
enum: ['file', 'mongo', 'postgres']
|
|
89
|
-
},
|
|
90
|
-
email: {
|
|
91
|
-
type: 'string',
|
|
92
|
-
description: 'Administrator Email'
|
|
93
|
-
},
|
|
94
|
-
password: {
|
|
95
|
-
type: 'string',
|
|
96
|
-
description: 'Administrator Password'
|
|
97
|
-
},
|
|
98
|
-
...settings.schema.properties
|
|
99
|
-
}
|
|
100
|
-
settings.schema.required = settings.schema.required || ['postgresql_uri', 'mongodb_uri']
|
|
101
|
-
settings.schema.required.push('email')
|
|
102
|
-
settings.schema.required.push('password')
|
|
103
|
-
settings.schema.required.push('user_storage')
|
|
104
|
-
return settings
|
|
105
|
-
}
|
|
1
|
+
const util = require('../util')
|
|
2
|
+
|
|
3
|
+
exports.updateAdminPermissions = async function (api) {
|
|
4
|
+
if (!api.db.role) {
|
|
5
|
+
return // not installed yet
|
|
6
|
+
}
|
|
7
|
+
const modules = Object.values(api.modules)
|
|
8
|
+
const permissions = [].concat(...await Promise.all(modules.map((m) => util.resolve(m.permissions, api)))).filter(x => x !== undefined)
|
|
9
|
+
let adminRole = { permissions: {} }
|
|
10
|
+
try {
|
|
11
|
+
adminRole = await api.db.role.get('Admin')
|
|
12
|
+
} catch (e) {
|
|
13
|
+
// expected if not installed
|
|
14
|
+
}
|
|
15
|
+
const neededPermissions = permissions.reduce((obj, p) => { obj[p] = 1; return obj }, {})
|
|
16
|
+
adminRole.permissions = { ...neededPermissions, ...adminRole.permissions }
|
|
17
|
+
await api.db.role.update('Admin', adminRole)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.install = async (req, api) => {
|
|
21
|
+
const selectedModules = req.body.modules
|
|
22
|
+
const installedModules = Object.keys(req.modules)
|
|
23
|
+
const missingModules = selectedModules.filter((module) => !installedModules.includes(module))
|
|
24
|
+
if (missingModules.length > 0) {
|
|
25
|
+
throw new util.ApiError(400, 'unknown modules')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const modules = selectedModules.map((name) => req.modules[name])
|
|
29
|
+
|
|
30
|
+
let settings = await api.db.settings.get(process.env.NODE_ENV).catch(() => {})
|
|
31
|
+
|
|
32
|
+
if (!settings) {
|
|
33
|
+
settings = JSON.parse(JSON.stringify(req.body.settings))
|
|
34
|
+
settings._id = process.env.NODE_ENV
|
|
35
|
+
settings.jwt_secret = util.createSecureRandomId()
|
|
36
|
+
// Remove fields that are not real settings
|
|
37
|
+
delete settings.email
|
|
38
|
+
delete settings.user_storage
|
|
39
|
+
delete settings.password
|
|
40
|
+
Object.assign(req.settings, settings)
|
|
41
|
+
await req.db.settings.create(settings)
|
|
42
|
+
|
|
43
|
+
for (const m of modules) {
|
|
44
|
+
const colls = await util.resolve(m.collections, api)
|
|
45
|
+
if (colls) {
|
|
46
|
+
for (const coll of colls) {
|
|
47
|
+
if (!coll.storage) {
|
|
48
|
+
coll.storage = 'file'
|
|
49
|
+
}
|
|
50
|
+
if (coll._id == 'users') {
|
|
51
|
+
if (req.body.settings.user_storage) {
|
|
52
|
+
coll.storage = req.body.settings.user_storage
|
|
53
|
+
}
|
|
54
|
+
coll.enableLogin = true
|
|
55
|
+
}
|
|
56
|
+
await req.db.collection.create(coll)
|
|
57
|
+
await api.notify('changed', req, 'collection', coll)
|
|
58
|
+
// await collectionsApi.insert(Object.assign({}, req, { body: coll }))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
await util.resolve(m.install, api)
|
|
62
|
+
}
|
|
63
|
+
await exports.updateAdminPermissions(api)
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
if (settings.installed) {
|
|
67
|
+
throw new Error(`${process.env.NODE_ENV}.json exists and indicates expressa is already installed. Try setting 'installed' to false if you are attempting to reinstall.`)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
settings.installed = true
|
|
72
|
+
settings.enforce_permissions = true
|
|
73
|
+
Object.assign(req.settings, settings)
|
|
74
|
+
await req.db.settings.update(settings._id, settings)
|
|
75
|
+
return { }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
exports.getSettingsSchema = async (req, api) => {
|
|
79
|
+
const colls = await util.resolve(api.modules.core.collections, api)
|
|
80
|
+
const settings = colls.find((m) => m._id === 'settings')
|
|
81
|
+
settings.schema.properties = {
|
|
82
|
+
/*collection_storage: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
enum: ['file', 'mongo', 'postgres']
|
|
85
|
+
},*/
|
|
86
|
+
user_storage: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
enum: ['file', 'mongo', 'postgres']
|
|
89
|
+
},
|
|
90
|
+
email: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Administrator Email'
|
|
93
|
+
},
|
|
94
|
+
password: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
description: 'Administrator Password'
|
|
97
|
+
},
|
|
98
|
+
...settings.schema.properties
|
|
99
|
+
}
|
|
100
|
+
settings.schema.required = settings.schema.required || ['postgresql_uri', 'mongodb_uri']
|
|
101
|
+
settings.schema.required.push('email')
|
|
102
|
+
settings.schema.required.push('password')
|
|
103
|
+
settings.schema.required.push('user_storage')
|
|
104
|
+
return settings
|
|
105
|
+
}
|
package/controllers/status.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
const util = require('../util')
|
|
2
|
-
|
|
3
|
-
exports.getStatus = function(router) {
|
|
4
|
-
return async (req) => {
|
|
5
|
-
if (!req.hasPermission('view server details')) {
|
|
6
|
-
return {
|
|
7
|
-
env: process.env.NODE_ENV,
|
|
8
|
-
installed: req.settings.installed || false,
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
const allListeners = [].concat.apply([], Object.values(req.eventListeners))
|
|
12
|
-
const middleware = router.stack.filter((item) => !item.route).map((item) => ({
|
|
13
|
-
name: item.name,
|
|
14
|
-
params: util.getFunctionParamNames(item.handle),
|
|
15
|
-
}))
|
|
16
|
-
const uniqueListeners = [...new Set(allListeners)]
|
|
17
|
-
const eventTypes = ['get', 'post', 'put', 'delete', 'changed', 'deleted']
|
|
18
|
-
const listeners = uniqueListeners.map(function (listener) {
|
|
19
|
-
const o = {}
|
|
20
|
-
o.name = listener.name
|
|
21
|
-
o.priority = listener.priority
|
|
22
|
-
o.collections = listener.collections
|
|
23
|
-
for (const type of eventTypes) {
|
|
24
|
-
if (router.eventListeners[type].includes(listener)) {
|
|
25
|
-
o[type] = true
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return o
|
|
29
|
-
})
|
|
30
|
-
listeners.sort((a, b) => a.priority - b.priority)
|
|
31
|
-
const collections = Object.keys(router.db)
|
|
32
|
-
.filter((collection) => req.hasPermission(`${collection}: view`) || req.hasPermission(`${collection}: view own`))
|
|
33
|
-
return {
|
|
34
|
-
nodeVersion: process.version,
|
|
35
|
-
uptime: util.friendlyDuration(process.uptime()),
|
|
36
|
-
env: process.env.NODE_ENV,
|
|
37
|
-
installed: req.settings.installed || false,
|
|
38
|
-
middleware,
|
|
39
|
-
listeners,
|
|
40
|
-
collections,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
1
|
+
const util = require('../util')
|
|
2
|
+
|
|
3
|
+
exports.getStatus = function(router) {
|
|
4
|
+
return async (req) => {
|
|
5
|
+
if (!req.hasPermission('view server details')) {
|
|
6
|
+
return {
|
|
7
|
+
env: process.env.NODE_ENV,
|
|
8
|
+
installed: req.settings.installed || false,
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const allListeners = [].concat.apply([], Object.values(req.eventListeners))
|
|
12
|
+
const middleware = router.stack.filter((item) => !item.route).map((item) => ({
|
|
13
|
+
name: item.name,
|
|
14
|
+
params: util.getFunctionParamNames(item.handle),
|
|
15
|
+
}))
|
|
16
|
+
const uniqueListeners = [...new Set(allListeners)]
|
|
17
|
+
const eventTypes = ['get', 'post', 'put', 'delete', 'changed', 'deleted']
|
|
18
|
+
const listeners = uniqueListeners.map(function (listener) {
|
|
19
|
+
const o = {}
|
|
20
|
+
o.name = listener.name
|
|
21
|
+
o.priority = listener.priority
|
|
22
|
+
o.collections = listener.collections
|
|
23
|
+
for (const type of eventTypes) {
|
|
24
|
+
if (router.eventListeners[type].includes(listener)) {
|
|
25
|
+
o[type] = true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return o
|
|
29
|
+
})
|
|
30
|
+
listeners.sort((a, b) => a.priority - b.priority)
|
|
31
|
+
const collections = Object.keys(router.db)
|
|
32
|
+
.filter((collection) => req.hasPermission(`${collection}: view`) || req.hasPermission(`${collection}: view own`))
|
|
33
|
+
return {
|
|
34
|
+
nodeVersion: process.version,
|
|
35
|
+
uptime: util.friendlyDuration(process.uptime()),
|
|
36
|
+
env: process.env.NODE_ENV,
|
|
37
|
+
installed: req.settings.installed || false,
|
|
38
|
+
middleware,
|
|
39
|
+
listeners,
|
|
40
|
+
collections,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/controllers/users.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
const auth = require('../auth')
|
|
2
|
-
const util = require('../util')
|
|
3
|
-
const collectionsApi = require('./collections')
|
|
4
|
-
const permissions = require('../middleware/permissions')
|
|
5
|
-
|
|
6
|
-
exports.login = async (req, collection) => {
|
|
7
|
-
const password = req.body.password
|
|
8
|
-
|
|
9
|
-
if (typeof req.body.email !== 'string') {
|
|
10
|
-
throw new util.ApiError(400, 'email must be a string')
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
req.body.email = req.body.email.toLowerCase()
|
|
14
|
-
|
|
15
|
-
// check if user exists
|
|
16
|
-
const result = await req.db[collection].find({
|
|
17
|
-
email: req.body.email
|
|
18
|
-
})
|
|
19
|
-
if (result.length === 0) {
|
|
20
|
-
throw new util.ApiError(400, 'No ' + collection + ' found with this email.')
|
|
21
|
-
}
|
|
22
|
-
const user = result[0]
|
|
23
|
-
if (!auth.isValidPassword(password, user.password)) {
|
|
24
|
-
throw new util.ApiError(401, 'Incorrect password')
|
|
25
|
-
}
|
|
26
|
-
const jwt_options = req.settings.jwt_expires_in ? { expiresIn: req.settings.jwt_expires_in } : {}
|
|
27
|
-
const payload = auth.doLogin({
|
|
28
|
-
id: user._id,
|
|
29
|
-
collection,
|
|
30
|
-
timestamp: user.meta.password_last_updated_at,
|
|
31
|
-
jwt_secret: req.getSetting('jwt_secret'),
|
|
32
|
-
jwt_options
|
|
33
|
-
})
|
|
34
|
-
req.uid = user._id
|
|
35
|
-
req.ucollection = collection
|
|
36
|
-
req.user = user
|
|
37
|
-
await permissions.addRolePermissionsAsync(req)
|
|
38
|
-
payload.canUseAdmin = req.hasPermission('login to admin')
|
|
39
|
-
return payload
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
exports.register = function (req, collection) {
|
|
43
|
-
req.url = `/${collection}`
|
|
44
|
-
req.params.collection = collection
|
|
45
|
-
return collectionsApi.insert(req)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
exports.getMe = function (req, collection) {
|
|
49
|
-
req.params.collection = collection
|
|
50
|
-
req.params.id = req.uid
|
|
51
|
-
return collectionsApi.getById(req)
|
|
52
|
-
}
|
|
1
|
+
const auth = require('../auth')
|
|
2
|
+
const util = require('../util')
|
|
3
|
+
const collectionsApi = require('./collections')
|
|
4
|
+
const permissions = require('../middleware/permissions')
|
|
5
|
+
|
|
6
|
+
exports.login = async (req, collection) => {
|
|
7
|
+
const password = req.body.password
|
|
8
|
+
|
|
9
|
+
if (typeof req.body.email !== 'string') {
|
|
10
|
+
throw new util.ApiError(400, 'email must be a string')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
req.body.email = req.body.email.toLowerCase()
|
|
14
|
+
|
|
15
|
+
// check if user exists
|
|
16
|
+
const result = await req.db[collection].find({
|
|
17
|
+
email: req.body.email
|
|
18
|
+
})
|
|
19
|
+
if (result.length === 0) {
|
|
20
|
+
throw new util.ApiError(400, 'No ' + collection + ' found with this email.')
|
|
21
|
+
}
|
|
22
|
+
const user = result[0]
|
|
23
|
+
if (!auth.isValidPassword(password, user.password)) {
|
|
24
|
+
throw new util.ApiError(401, 'Incorrect password')
|
|
25
|
+
}
|
|
26
|
+
const jwt_options = req.settings.jwt_expires_in ? { expiresIn: req.settings.jwt_expires_in } : {}
|
|
27
|
+
const payload = auth.doLogin({
|
|
28
|
+
id: user._id,
|
|
29
|
+
collection,
|
|
30
|
+
timestamp: user.meta.password_last_updated_at,
|
|
31
|
+
jwt_secret: req.getSetting('jwt_secret'),
|
|
32
|
+
jwt_options
|
|
33
|
+
})
|
|
34
|
+
req.uid = user._id
|
|
35
|
+
req.ucollection = collection
|
|
36
|
+
req.user = user
|
|
37
|
+
await permissions.addRolePermissionsAsync(req)
|
|
38
|
+
payload.canUseAdmin = req.hasPermission('login to admin')
|
|
39
|
+
return payload
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.register = function (req, collection) {
|
|
43
|
+
req.url = `/${collection}`
|
|
44
|
+
req.params.collection = collection
|
|
45
|
+
return collectionsApi.insert(req)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports.getMe = function (req, collection) {
|
|
49
|
+
req.params.collection = collection
|
|
50
|
+
req.params.id = req.uid
|
|
51
|
+
return collectionsApi.getById(req)
|
|
52
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Using fixtures to represent data",
|
|
3
|
-
"email": "hello@cypress.io",
|
|
4
|
-
"body": "Fixtures are a great way to mock data for responses to routes"
|
|
1
|
+
{
|
|
2
|
+
"name": "Using fixtures to represent data",
|
|
3
|
+
"email": "hello@cypress.io",
|
|
4
|
+
"body": "Fixtures are a great way to mock data for responses to routes"
|
|
5
5
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
describe('Install', function() {
|
|
2
|
-
it('Creates a user', function() {
|
|
3
|
-
cy.visit('/')
|
|
4
|
-
cy.get('input[name="root[email]"]').type('test@example.com')
|
|
5
|
-
cy.get('input[name="root[password]"]').type('expressa')
|
|
6
|
-
cy.get('.btn-primary').click()
|
|
7
|
-
cy.contains('Welcome: test@example.com')
|
|
8
|
-
})
|
|
1
|
+
describe('Install', function() {
|
|
2
|
+
it('Creates a user', function() {
|
|
3
|
+
cy.visit('/')
|
|
4
|
+
cy.get('input[name="root[email]"]').type('test@example.com')
|
|
5
|
+
cy.get('input[name="root[password]"]').type('expressa')
|
|
6
|
+
cy.get('.btn-primary').click()
|
|
7
|
+
cy.contains('Welcome: test@example.com')
|
|
8
|
+
})
|
|
9
9
|
})
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { randomId } from '../support/util'
|
|
2
|
-
|
|
3
|
-
// TODO: remove error from JSONSchemaEditor so that this isn't necessary
|
|
4
|
-
Cypress.on('uncaught:exception', (err, runnable) => {
|
|
5
|
-
// returning false here prevents Cypress from
|
|
6
|
-
// failing the test
|
|
7
|
-
return false
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
describe('Custom Collections', function() {
|
|
11
|
-
it('Supports creating new collections', function() {
|
|
12
|
-
cy.login()
|
|
13
|
-
cy.visit('/')
|
|
14
|
-
cy.get('.hamburger-container').click();
|
|
15
|
-
cy.wait(100)
|
|
16
|
-
cy.get('span').contains('Collection').click();
|
|
17
|
-
|
|
18
|
-
cy.get('.btn-primary').click();
|
|
19
|
-
let id = `coll-${randomId()}`;
|
|
20
|
-
cy.fillValue('_id', id)
|
|
21
|
-
|
|
22
|
-
cy.wait(100)
|
|
23
|
-
cy.get('button').contains('Add another field').click();
|
|
24
|
-
cy.wait(100)
|
|
25
|
-
cy.get('input[name="field"]').type('field_1')
|
|
26
|
-
|
|
27
|
-
cy.get('.btn-primary').click();
|
|
28
|
-
})
|
|
1
|
+
import { randomId } from '../support/util'
|
|
2
|
+
|
|
3
|
+
// TODO: remove error from JSONSchemaEditor so that this isn't necessary
|
|
4
|
+
Cypress.on('uncaught:exception', (err, runnable) => {
|
|
5
|
+
// returning false here prevents Cypress from
|
|
6
|
+
// failing the test
|
|
7
|
+
return false
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('Custom Collections', function() {
|
|
11
|
+
it('Supports creating new collections', function() {
|
|
12
|
+
cy.login()
|
|
13
|
+
cy.visit('/')
|
|
14
|
+
cy.get('.hamburger-container').click();
|
|
15
|
+
cy.wait(100)
|
|
16
|
+
cy.get('span').contains('Collection').click();
|
|
17
|
+
|
|
18
|
+
cy.get('.btn-primary').click();
|
|
19
|
+
let id = `coll-${randomId()}`;
|
|
20
|
+
cy.fillValue('_id', id)
|
|
21
|
+
|
|
22
|
+
cy.wait(100)
|
|
23
|
+
cy.get('button').contains('Add another field').click();
|
|
24
|
+
cy.wait(100)
|
|
25
|
+
cy.get('input[name="field"]').type('field_1')
|
|
26
|
+
|
|
27
|
+
cy.get('.btn-primary').click();
|
|
28
|
+
})
|
|
29
29
|
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
describe('Home', function() {
|
|
2
|
-
it('Logs and shows 404s', function() {
|
|
3
|
-
cy.request({ url: 'http://localhost:3001/api/notexist', failOnStatusCode: false })
|
|
4
|
-
cy.login()
|
|
5
|
-
cy.visit('/')
|
|
6
|
-
cy.get('.el-table__body').contains('notexist')
|
|
7
|
-
cy.get('.el-table__body').contains('404')
|
|
8
|
-
})
|
|
9
|
-
})
|
|
1
|
+
describe('Home', function() {
|
|
2
|
+
it('Logs and shows 404s', function() {
|
|
3
|
+
cy.request({ url: 'http://localhost:3001/api/notexist', failOnStatusCode: false })
|
|
4
|
+
cy.login()
|
|
5
|
+
cy.visit('/')
|
|
6
|
+
cy.get('.el-table__body').contains('notexist')
|
|
7
|
+
cy.get('.el-table__body').contains('404')
|
|
8
|
+
})
|
|
9
|
+
})
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
describe('Settings', function() {
|
|
2
|
-
it('Can turn off enforce permissions', function() {
|
|
3
|
-
cy.request({ url: 'http://localhost:3001/api/role/Admin', failOnStatusCode: false })
|
|
4
|
-
.then((response) => {
|
|
5
|
-
expect(response.status).to.equal(401)
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
cy.login()
|
|
9
|
-
cy.visit('/')
|
|
10
|
-
|
|
11
|
-
cy.wait(250)
|
|
12
|
-
cy.get('a').contains('(edit settings)').click()
|
|
13
|
-
cy.wait(1500)
|
|
14
|
-
|
|
15
|
-
cy.get('[name="root[enforce_permissions]"]').uncheck()
|
|
16
|
-
cy.get('button.btn-primary').click()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('Changed settings should take affect', function() {
|
|
20
|
-
cy.request({url: 'http://localhost:3001/api/role/Admin', failOnStatusCode: false})
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('Turn back on enforce permissions', function() {
|
|
24
|
-
cy.login()
|
|
25
|
-
cy.visit('/')
|
|
26
|
-
|
|
27
|
-
cy.wait(250)
|
|
28
|
-
cy.get('a').contains('(edit settings)').click()
|
|
29
|
-
cy.wait(1500)
|
|
30
|
-
|
|
31
|
-
cy.get('[name="root[enforce_permissions]"]').check()
|
|
32
|
-
cy.get('button.btn-primary').click()
|
|
33
|
-
})
|
|
34
|
-
})
|
|
1
|
+
describe('Settings', function() {
|
|
2
|
+
it('Can turn off enforce permissions', function() {
|
|
3
|
+
cy.request({ url: 'http://localhost:3001/api/role/Admin', failOnStatusCode: false })
|
|
4
|
+
.then((response) => {
|
|
5
|
+
expect(response.status).to.equal(401)
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
cy.login()
|
|
9
|
+
cy.visit('/')
|
|
10
|
+
|
|
11
|
+
cy.wait(250)
|
|
12
|
+
cy.get('a').contains('(edit settings)').click()
|
|
13
|
+
cy.wait(1500)
|
|
14
|
+
|
|
15
|
+
cy.get('[name="root[enforce_permissions]"]').uncheck()
|
|
16
|
+
cy.get('button.btn-primary').click()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('Changed settings should take affect', function() {
|
|
20
|
+
cy.request({url: 'http://localhost:3001/api/role/Admin', failOnStatusCode: false})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('Turn back on enforce permissions', function() {
|
|
24
|
+
cy.login()
|
|
25
|
+
cy.visit('/')
|
|
26
|
+
|
|
27
|
+
cy.wait(250)
|
|
28
|
+
cy.get('a').contains('(edit settings)').click()
|
|
29
|
+
cy.wait(1500)
|
|
30
|
+
|
|
31
|
+
cy.get('[name="root[enforce_permissions]"]').check()
|
|
32
|
+
cy.get('button.btn-primary').click()
|
|
33
|
+
})
|
|
34
|
+
})
|