expressa 2.0.18 → 2.0.19
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 -260
- 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/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 +19 -19
- 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 -112
- package/modules/admin/build/webpack.dev.conf.js +95 -95
- package/modules/admin/build/webpack.prod.conf.js +112 -112
- 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/164c6167c1f3c497c07c.woff +1 -0
- package/modules/admin/dist/42ac07abc8473600c41f.ttf +1 -0
- package/modules/admin/dist/86dccb18a7eb4be8ef1a.woff +1 -0
- package/modules/admin/dist/c45297c558e0318fc9c5.ttf +1 -0
- package/modules/admin/dist/c717c9930715e24fa12c.woff +1 -0
- package/modules/admin/dist/ca6f07ef23f24cc2738a.ttf +1 -0
- package/modules/admin/dist/css/269.f7d5c7d5.css +37 -0
- package/modules/admin/dist/css/269.f7d5c7d5.css.gz +0 -0
- package/modules/admin/dist/css/451.c6646d20.css +1 -0
- package/modules/admin/dist/css/451.c6646d20.css.gz +0 -0
- package/modules/admin/dist/css/572.74d8e965.css +34 -0
- package/modules/admin/dist/css/572.74d8e965.css.gz +0 -0
- package/modules/admin/dist/css/651.e946bda7.css +6 -0
- package/modules/admin/dist/css/651.e946bda7.css.gz +0 -0
- package/modules/admin/dist/css/699.d1f90954.css +8 -0
- package/modules/admin/dist/css/699.d1f90954.css.gz +0 -0
- package/modules/admin/dist/css/750.4086915d.css +2 -0
- package/modules/admin/dist/css/750.4086915d.css.gz +0 -0
- package/modules/admin/dist/css/864.506917a4.css +7 -0
- package/modules/admin/dist/css/864.506917a4.css.gz +0 -0
- package/modules/admin/dist/css/899.506917a4.css +7 -0
- package/modules/admin/dist/css/899.506917a4.css.gz +0 -0
- package/modules/admin/dist/css/950.1fd9d57c.css +7 -0
- package/modules/admin/dist/css/950.1fd9d57c.css.gz +0 -0
- package/modules/admin/dist/css/app.11cc6245.css +39 -0
- package/modules/admin/dist/css/app.11cc6245.css.gz +0 -0
- package/modules/admin/dist/css/app.2e1b0d79.css +591 -0
- package/modules/admin/dist/css/app.2e1b0d79.css.gz +0 -0
- package/modules/admin/dist/css/app.4d43d0fd.css +592 -0
- package/modules/admin/dist/css/app.4d43d0fd.css.gz +0 -0
- package/modules/admin/dist/css/app.abace109.css +1 -0
- package/modules/admin/dist/css/app.abace109.css.gz +0 -0
- package/modules/admin/dist/css/chunk-elementUI.67ad86d7.css +1 -0
- package/modules/admin/dist/css/chunk-elementUI.67ad86d7.css.gz +0 -0
- package/modules/admin/dist/css/chunk-elementUI.9e660bfd.css +1 -0
- package/modules/admin/dist/css/chunk-elementUI.9e660bfd.css.gz +0 -0
- package/modules/admin/dist/css/chunk-elementUI.c77cf142.css +1 -0
- package/modules/admin/dist/css/chunk-elementUI.c77cf142.css.gz +0 -0
- package/modules/admin/dist/css/chunk-elementUI.f1625b35.css +1 -0
- package/modules/admin/dist/css/chunk-elementUI.f1625b35.css.gz +0 -0
- package/modules/admin/dist/css/chunk-elementUI.f25dfb9b.css +1 -0
- package/modules/admin/dist/css/chunk-elementUI.f25dfb9b.css.gz +0 -0
- package/modules/admin/dist/css/chunk-libs.de0d8484.css +551 -0
- package/modules/admin/dist/css/chunk-libs.de0d8484.css.gz +0 -0
- package/modules/admin/dist/index.html +1 -1
- package/modules/admin/dist/static/fonts/element-icons.313f7da.woff +0 -0
- package/modules/admin/dist/static/fonts/element-icons.4520188.ttf +0 -0
- package/modules/admin/dist/static/js/269.7245ceaf.js +1 -0
- package/modules/admin/dist/static/js/269.7245ceaf.js.gz +0 -0
- package/modules/admin/dist/static/js/451.645974a8.js +1 -0
- package/modules/admin/dist/static/js/451.645974a8.js.gz +0 -0
- package/modules/admin/dist/static/js/460.962d5bc0.js +1 -0
- package/modules/admin/dist/static/js/460.962d5bc0.js.gz +0 -0
- package/modules/admin/dist/static/js/556.1e08866a.js +1 -0
- package/modules/admin/dist/static/js/556.1e08866a.js.gz +0 -0
- package/modules/admin/dist/static/js/572.13392e1d.js +1 -0
- package/modules/admin/dist/static/js/572.13392e1d.js.gz +0 -0
- package/modules/admin/dist/static/js/603.7b34a650.js +1 -0
- package/modules/admin/dist/static/js/603.7b34a650.js.gz +0 -0
- package/modules/admin/dist/static/js/637.26413baa.js +1 -0
- package/modules/admin/dist/static/js/637.26413baa.js.gz +0 -0
- package/modules/admin/dist/static/js/651.564b24b6.js +1 -0
- package/modules/admin/dist/static/js/651.564b24b6.js.gz +0 -0
- package/modules/admin/dist/static/js/653.02ec1098.js +1 -0
- package/modules/admin/dist/static/js/653.02ec1098.js.gz +0 -0
- package/modules/admin/dist/static/js/699.c7564884.js +1 -0
- package/modules/admin/dist/static/js/699.c7564884.js.gz +0 -0
- package/modules/admin/dist/static/js/750.50c950da.js +1 -0
- package/modules/admin/dist/static/js/750.50c950da.js.gz +0 -0
- package/modules/admin/dist/static/js/864.4f43847d.js +1 -0
- package/modules/admin/dist/static/js/864.4f43847d.js.gz +0 -0
- package/modules/admin/dist/static/js/950.d4ff0a18.js +1 -0
- package/modules/admin/dist/static/js/950.d4ff0a18.js.gz +0 -0
- package/modules/admin/dist/static/js/app.981e71b3.js +2 -0
- package/modules/admin/dist/static/js/{chunk-libs.06c38828.js.LICENSE.txt → app.981e71b3.js.LICENSE.txt} +15 -18
- package/modules/admin/dist/static/js/app.981e71b3.js.LICENSE.txt.gz +0 -0
- package/modules/admin/dist/static/js/app.981e71b3.js.gz +0 -0
- package/modules/admin/index.html +16 -16
- package/modules/admin/package.json +101 -101
- 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 -42
- 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 -288
- 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 -93
- package/test/testserver.js +17 -17
- package/test/testutils.js +136 -136
- package/test/users.js +425 -425
- package/util.js +522 -522
- package/modules/admin/dist/index.html.gz +0 -0
- package/modules/admin/dist/static/css/app.9dd57eea.css +0 -1
- package/modules/admin/dist/static/css/app.9dd57eea.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css +0 -1
- package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css +0 -1
- package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-621e.b826be8d.css +0 -1
- package/modules/admin/dist/static/css/chunk-621e.b826be8d.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-656b.9c828b00.css +0 -1
- 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 +0 -1
- package/modules/admin/dist/static/css/chunk-7f29.9c828b00.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-9a95.c647a2ef.css +0 -1
- 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 +0 -1
- package/modules/admin/dist/static/css/chunk-bd5f.aefa49d7.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-e374.025d58bb.css +0 -1
- package/modules/admin/dist/static/css/chunk-e374.025d58bb.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css +0 -1
- package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css +0 -1
- package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css.gz +0 -0
- package/modules/admin/dist/static/css/chunk-libs.327ad89e.css +0 -14
- 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/js/app.e9461593.js +0 -1
- package/modules/admin/dist/static/js/app.e9461593.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js +0 -2
- package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.LICENSE.txt +0 -13
- 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 +0 -1
- package/modules/admin/dist/static/js/chunk-5061.83e6ccfa.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-5b97.ac360086.js +0 -1
- package/modules/admin/dist/static/js/chunk-5b97.ac360086.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js +0 -1
- package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-621e.ccf42393.js +0 -1
- package/modules/admin/dist/static/js/chunk-621e.ccf42393.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js +0 -1
- package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-7291.590524e9.js +0 -1
- package/modules/admin/dist/static/js/chunk-7291.590524e9.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js +0 -1
- package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js +0 -1
- package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-b423.387c504c.js +0 -1
- package/modules/admin/dist/static/js/chunk-b423.387c504c.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js +0 -1
- package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js +0 -1
- package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js +0 -1
- package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js +0 -1
- package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-f075.315ceec1.js +0 -1
- package/modules/admin/dist/static/js/chunk-f075.315ceec1.js.gz +0 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js +0 -2
- 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/dist/static/img/{404.a57b6f3.png → 404.4cf6930.png} +0 -0
package/db/memory.js
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
/* eslint no-unused-vars: ["error", { "args": "none" }] */
|
|
2
|
-
const util = require('../util')
|
|
3
|
-
|
|
4
|
-
module.exports = function (settings, collection) {
|
|
5
|
-
const store = {}
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
type: 'memory',
|
|
9
|
-
init: async function () {},
|
|
10
|
-
all: async function () {
|
|
11
|
-
return this.find({})
|
|
12
|
-
},
|
|
13
|
-
find: async function (query, offset, limit, orderby, fields) {
|
|
14
|
-
const arr = Object.values(store)
|
|
15
|
-
let matches = util.mongoSearch(arr, query)
|
|
16
|
-
if (orderby) {
|
|
17
|
-
matches = util.orderBy(matches, orderby)
|
|
18
|
-
}
|
|
19
|
-
if (typeof offset !== 'undefined' && typeof limit !== 'undefined') {
|
|
20
|
-
matches = matches.slice(offset, offset + limit)
|
|
21
|
-
} else if (typeof offset !== 'undefined') {
|
|
22
|
-
matches = matches.slice(offset)
|
|
23
|
-
} else if (typeof limit !== 'undefined') {
|
|
24
|
-
matches = matches.slice(0, limit)
|
|
25
|
-
}
|
|
26
|
-
if (fields) {
|
|
27
|
-
matches = matches.map((doc) => util.mongoProject(doc, fields))
|
|
28
|
-
}
|
|
29
|
-
return matches
|
|
30
|
-
},
|
|
31
|
-
count: async function(...params) {
|
|
32
|
-
return (await this.find(...params)).length
|
|
33
|
-
},
|
|
34
|
-
get: async function (id, fields) {
|
|
35
|
-
if (!store[id]) {
|
|
36
|
-
throw new util.ApiError(404, 'document not found')
|
|
37
|
-
}
|
|
38
|
-
let doc = util.clone(store[id])
|
|
39
|
-
if (fields) {
|
|
40
|
-
doc = util.mongoProject(doc, fields)
|
|
41
|
-
}
|
|
42
|
-
return doc
|
|
43
|
-
},
|
|
44
|
-
create: async function (data) {
|
|
45
|
-
util.addIdIfMissing(data)
|
|
46
|
-
const id = data._id
|
|
47
|
-
if (store[id]) {
|
|
48
|
-
throw new util.ApiError(409, 'document already exists')
|
|
49
|
-
}
|
|
50
|
-
store[id] = data
|
|
51
|
-
return id
|
|
52
|
-
},
|
|
53
|
-
update: async function (id, data) {
|
|
54
|
-
data._id = data._id || id
|
|
55
|
-
store[id] = data
|
|
56
|
-
return data
|
|
57
|
-
},
|
|
58
|
-
// Designed to match Mongo
|
|
59
|
-
// https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/
|
|
60
|
-
updateWithQuery: async function (query, update, options) {
|
|
61
|
-
const arr = Object.keys(store).map((id) => ({ _id: id, ...store[id]}) )
|
|
62
|
-
const matches = util.mongoSearch(arr, query)
|
|
63
|
-
matches.forEach((doc) => {
|
|
64
|
-
util.mongoUpdate(doc, update)
|
|
65
|
-
store[doc._id] = doc
|
|
66
|
-
})
|
|
67
|
-
return {
|
|
68
|
-
matchedCount: matches.length
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
delete: async function (id) {
|
|
72
|
-
if (store[id]) {
|
|
73
|
-
delete store[id]
|
|
74
|
-
} else {
|
|
75
|
-
throw new util.ApiError(404, 'document not found')
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
1
|
+
/* eslint no-unused-vars: ["error", { "args": "none" }] */
|
|
2
|
+
const util = require('../util')
|
|
3
|
+
|
|
4
|
+
module.exports = function (settings, collection) {
|
|
5
|
+
const store = {}
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
type: 'memory',
|
|
9
|
+
init: async function () {},
|
|
10
|
+
all: async function () {
|
|
11
|
+
return this.find({})
|
|
12
|
+
},
|
|
13
|
+
find: async function (query, offset, limit, orderby, fields) {
|
|
14
|
+
const arr = Object.values(store)
|
|
15
|
+
let matches = util.mongoSearch(arr, query)
|
|
16
|
+
if (orderby) {
|
|
17
|
+
matches = util.orderBy(matches, orderby)
|
|
18
|
+
}
|
|
19
|
+
if (typeof offset !== 'undefined' && typeof limit !== 'undefined') {
|
|
20
|
+
matches = matches.slice(offset, offset + limit)
|
|
21
|
+
} else if (typeof offset !== 'undefined') {
|
|
22
|
+
matches = matches.slice(offset)
|
|
23
|
+
} else if (typeof limit !== 'undefined') {
|
|
24
|
+
matches = matches.slice(0, limit)
|
|
25
|
+
}
|
|
26
|
+
if (fields) {
|
|
27
|
+
matches = matches.map((doc) => util.mongoProject(doc, fields))
|
|
28
|
+
}
|
|
29
|
+
return matches
|
|
30
|
+
},
|
|
31
|
+
count: async function(...params) {
|
|
32
|
+
return (await this.find(...params)).length
|
|
33
|
+
},
|
|
34
|
+
get: async function (id, fields) {
|
|
35
|
+
if (!store[id]) {
|
|
36
|
+
throw new util.ApiError(404, 'document not found')
|
|
37
|
+
}
|
|
38
|
+
let doc = util.clone(store[id])
|
|
39
|
+
if (fields) {
|
|
40
|
+
doc = util.mongoProject(doc, fields)
|
|
41
|
+
}
|
|
42
|
+
return doc
|
|
43
|
+
},
|
|
44
|
+
create: async function (data) {
|
|
45
|
+
util.addIdIfMissing(data)
|
|
46
|
+
const id = data._id
|
|
47
|
+
if (store[id]) {
|
|
48
|
+
throw new util.ApiError(409, 'document already exists')
|
|
49
|
+
}
|
|
50
|
+
store[id] = data
|
|
51
|
+
return id
|
|
52
|
+
},
|
|
53
|
+
update: async function (id, data) {
|
|
54
|
+
data._id = data._id || id
|
|
55
|
+
store[id] = data
|
|
56
|
+
return data
|
|
57
|
+
},
|
|
58
|
+
// Designed to match Mongo
|
|
59
|
+
// https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/
|
|
60
|
+
updateWithQuery: async function (query, update, options) {
|
|
61
|
+
const arr = Object.keys(store).map((id) => ({ _id: id, ...store[id]}) )
|
|
62
|
+
const matches = util.mongoSearch(arr, query)
|
|
63
|
+
matches.forEach((doc) => {
|
|
64
|
+
util.mongoUpdate(doc, update)
|
|
65
|
+
store[doc._id] = doc
|
|
66
|
+
})
|
|
67
|
+
return {
|
|
68
|
+
matchedCount: matches.length
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
delete: async function (id) {
|
|
72
|
+
if (store[id]) {
|
|
73
|
+
delete store[id]
|
|
74
|
+
} else {
|
|
75
|
+
throw new util.ApiError(404, 'document not found')
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
package/db/mongo.js
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
const mongo = require('mongodb')
|
|
2
|
-
const MongoClient = mongo.MongoClient
|
|
3
|
-
const util = require('../util')
|
|
4
|
-
|
|
5
|
-
module.exports = function (settings, collection) {
|
|
6
|
-
return {
|
|
7
|
-
getClient: async function () {
|
|
8
|
-
const client = await MongoClient.connect(settings.mongodb_uri, { useNewUrlParser: true })
|
|
9
|
-
const db = client.db(settings.mongodb_uri.split('/')[3])
|
|
10
|
-
return db
|
|
11
|
-
},
|
|
12
|
-
init: function () {
|
|
13
|
-
if (!settings.mongodb_uri) {
|
|
14
|
-
console.error('{collection} uses mongo, but mongodb_url is undefined.')
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
all: async function () {
|
|
18
|
-
return this.find({})
|
|
19
|
-
},
|
|
20
|
-
find: async function (query, skip, limit, orderby, fields) {
|
|
21
|
-
const db = await this.getClient()
|
|
22
|
-
const cursor = db.collection(collection).find(query, { skip, limit, projection: fields, sort: orderby })
|
|
23
|
-
const docs = await cursor.toArray()
|
|
24
|
-
docs.forEach((doc) => {
|
|
25
|
-
if (doc._id) {
|
|
26
|
-
doc._id = doc._id.toString()
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
return docs
|
|
30
|
-
},
|
|
31
|
-
count: async function(query, skip, limit) {
|
|
32
|
-
const db = await this.getClient()
|
|
33
|
-
const count = await db.collection(collection).count(query, { skip, limit })
|
|
34
|
-
return count
|
|
35
|
-
},
|
|
36
|
-
get: async function (id, fields) {
|
|
37
|
-
const db = await this.getClient()
|
|
38
|
-
const doc = await db.collection(collection).findOne({ _id: id }, { projection: fields })
|
|
39
|
-
if (doc) {
|
|
40
|
-
doc._id = doc._id.toString()
|
|
41
|
-
}
|
|
42
|
-
if (!doc) {
|
|
43
|
-
throw new util.ApiError(404, 'document not found')
|
|
44
|
-
}
|
|
45
|
-
return doc
|
|
46
|
-
},
|
|
47
|
-
create: async function (data) {
|
|
48
|
-
util.addIdIfMissing(data)
|
|
49
|
-
|
|
50
|
-
const db = await this.getClient()
|
|
51
|
-
try {
|
|
52
|
-
const doc = await db.collection(collection).insertOne(data)
|
|
53
|
-
return doc.insertedId.toString()
|
|
54
|
-
} catch (err) {
|
|
55
|
-
if (err && err.message && err.message.includes('duplicate key error')) {
|
|
56
|
-
throw new util.ApiError(409, 'document already exists')
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
update: async function (id, data) {
|
|
61
|
-
data._id = id
|
|
62
|
-
const db = await this.getClient()
|
|
63
|
-
await db.collection(collection).replaceOne({
|
|
64
|
-
_id: id
|
|
65
|
-
}, data)
|
|
66
|
-
// doc._id = doc._id.toString()
|
|
67
|
-
return data
|
|
68
|
-
},
|
|
69
|
-
updateWithQuery: async function (query, update, options) {
|
|
70
|
-
const db = await this.getClient()
|
|
71
|
-
const res = await db.collection(collection).updateMany(query, update, options)
|
|
72
|
-
return {
|
|
73
|
-
matchedCount: res.matchedCount
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
delete: async function (id) {
|
|
77
|
-
const db = await this.getClient()
|
|
78
|
-
const res = await db.collection(collection).deleteOne({
|
|
79
|
-
_id: id
|
|
80
|
-
})
|
|
81
|
-
if (res.result.n !== 1) {
|
|
82
|
-
throw new util.ApiError(404, 'document not found')
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
1
|
+
const mongo = require('mongodb')
|
|
2
|
+
const MongoClient = mongo.MongoClient
|
|
3
|
+
const util = require('../util')
|
|
4
|
+
|
|
5
|
+
module.exports = function (settings, collection) {
|
|
6
|
+
return {
|
|
7
|
+
getClient: async function () {
|
|
8
|
+
const client = await MongoClient.connect(settings.mongodb_uri, { useNewUrlParser: true })
|
|
9
|
+
const db = client.db(settings.mongodb_uri.split('/')[3])
|
|
10
|
+
return db
|
|
11
|
+
},
|
|
12
|
+
init: function () {
|
|
13
|
+
if (!settings.mongodb_uri) {
|
|
14
|
+
console.error('{collection} uses mongo, but mongodb_url is undefined.')
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
all: async function () {
|
|
18
|
+
return this.find({})
|
|
19
|
+
},
|
|
20
|
+
find: async function (query, skip, limit, orderby, fields) {
|
|
21
|
+
const db = await this.getClient()
|
|
22
|
+
const cursor = db.collection(collection).find(query, { skip, limit, projection: fields, sort: orderby })
|
|
23
|
+
const docs = await cursor.toArray()
|
|
24
|
+
docs.forEach((doc) => {
|
|
25
|
+
if (doc._id) {
|
|
26
|
+
doc._id = doc._id.toString()
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
return docs
|
|
30
|
+
},
|
|
31
|
+
count: async function(query, skip, limit) {
|
|
32
|
+
const db = await this.getClient()
|
|
33
|
+
const count = await db.collection(collection).count(query, { skip, limit })
|
|
34
|
+
return count
|
|
35
|
+
},
|
|
36
|
+
get: async function (id, fields) {
|
|
37
|
+
const db = await this.getClient()
|
|
38
|
+
const doc = await db.collection(collection).findOne({ _id: id }, { projection: fields })
|
|
39
|
+
if (doc) {
|
|
40
|
+
doc._id = doc._id.toString()
|
|
41
|
+
}
|
|
42
|
+
if (!doc) {
|
|
43
|
+
throw new util.ApiError(404, 'document not found')
|
|
44
|
+
}
|
|
45
|
+
return doc
|
|
46
|
+
},
|
|
47
|
+
create: async function (data) {
|
|
48
|
+
util.addIdIfMissing(data)
|
|
49
|
+
|
|
50
|
+
const db = await this.getClient()
|
|
51
|
+
try {
|
|
52
|
+
const doc = await db.collection(collection).insertOne(data)
|
|
53
|
+
return doc.insertedId.toString()
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (err && err.message && err.message.includes('duplicate key error')) {
|
|
56
|
+
throw new util.ApiError(409, 'document already exists')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
update: async function (id, data) {
|
|
61
|
+
data._id = id
|
|
62
|
+
const db = await this.getClient()
|
|
63
|
+
await db.collection(collection).replaceOne({
|
|
64
|
+
_id: id
|
|
65
|
+
}, data)
|
|
66
|
+
// doc._id = doc._id.toString()
|
|
67
|
+
return data
|
|
68
|
+
},
|
|
69
|
+
updateWithQuery: async function (query, update, options) {
|
|
70
|
+
const db = await this.getClient()
|
|
71
|
+
const res = await db.collection(collection).updateMany(query, update, options)
|
|
72
|
+
return {
|
|
73
|
+
matchedCount: res.matchedCount
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
delete: async function (id) {
|
|
77
|
+
const db = await this.getClient()
|
|
78
|
+
const res = await db.collection(collection).deleteOne({
|
|
79
|
+
_id: id
|
|
80
|
+
})
|
|
81
|
+
if (res.result.n !== 1) {
|
|
82
|
+
throw new util.ApiError(404, 'document not found')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/db/postgres.js
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
const util = require('../util')
|
|
2
|
-
|
|
3
|
-
module.exports = function (settings, collectionId, collection) {
|
|
4
|
-
const pool = util.getPgPool(settings.postgresql_uri)
|
|
5
|
-
|
|
6
|
-
return {
|
|
7
|
-
init: async function () {
|
|
8
|
-
if (collection.plainStringIds) {
|
|
9
|
-
await pool.query('CREATE TABLE IF NOT EXISTS ' + collectionId + ' (id text primary key, data jsonb)')
|
|
10
|
-
} else {
|
|
11
|
-
await pool.query('CREATE TABLE IF NOT EXISTS ' + collectionId + ' (id uuid primary key, data jsonb)')
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
all: async function () {
|
|
15
|
-
return this.find({})
|
|
16
|
-
},
|
|
17
|
-
find: async function (rawQuery, offset, limit, orderby, fields) {
|
|
18
|
-
const pgSelect = util.mongoToPostgresSelect(collectionId, fields)
|
|
19
|
-
const pgWhere = util.mongoToPostgresWhere(collectionId, rawQuery)
|
|
20
|
-
let query = 'SELECT ' + pgSelect + ' FROM ' + collectionId + (pgWhere ? ' WHERE ' + pgWhere : '')
|
|
21
|
-
if (typeof orderby !== 'undefined') {
|
|
22
|
-
query += ' ORDER BY '
|
|
23
|
-
query += util.mongoToPostgresOrderBy(collectionId, orderby)
|
|
24
|
-
}
|
|
25
|
-
if (typeof offset !== 'undefined') {
|
|
26
|
-
query += ' OFFSET ' + offset
|
|
27
|
-
}
|
|
28
|
-
if (typeof limit !== 'undefined') {
|
|
29
|
-
query += ' LIMIT ' + limit
|
|
30
|
-
}
|
|
31
|
-
const result = await pool.query(query)
|
|
32
|
-
return result.rows.map((row) => row.data)
|
|
33
|
-
},
|
|
34
|
-
count: async function(rawQuery, offset, limit) {
|
|
35
|
-
const pgWhere = util.mongoToPostgresWhere(collectionId, rawQuery)
|
|
36
|
-
let query = 'SELECT COUNT(*) FROM ' + collectionId + (pgWhere ? ' WHERE ' + pgWhere : '')
|
|
37
|
-
if (typeof offset !== 'undefined') {
|
|
38
|
-
query += ' OFFSET ' + offset
|
|
39
|
-
}
|
|
40
|
-
if (typeof limit !== 'undefined') {
|
|
41
|
-
query += ' LIMIT ' + limit
|
|
42
|
-
}
|
|
43
|
-
const result = await pool.query(query)
|
|
44
|
-
return parseInt(result.rows[0].count)
|
|
45
|
-
},
|
|
46
|
-
get: async function (id, fields) {
|
|
47
|
-
const pgSelect = util.mongoToPostgresSelect(collectionId, fields)
|
|
48
|
-
const result = await pool.query(`SELECT ${pgSelect} FROM ${collectionId} WHERE id = $1`, [id])
|
|
49
|
-
if (result.rowCount === 0) {
|
|
50
|
-
throw new util.ApiError(404, 'document not found')
|
|
51
|
-
}
|
|
52
|
-
return result.rows[0].data
|
|
53
|
-
},
|
|
54
|
-
create: async function (data) {
|
|
55
|
-
util.addIdIfMissing(data)
|
|
56
|
-
try {
|
|
57
|
-
await pool.query('INSERT INTO ' + collectionId + ' (id, data) VALUES ($1, $2)', [data._id, data])
|
|
58
|
-
} catch (e) {
|
|
59
|
-
if (e.message.includes('duplicate key')) {
|
|
60
|
-
throw new util.ApiError(409, 'document already exists')
|
|
61
|
-
}
|
|
62
|
-
throw e
|
|
63
|
-
}
|
|
64
|
-
return data._id
|
|
65
|
-
},
|
|
66
|
-
update: async function (id, data) {
|
|
67
|
-
if (typeof data._id === 'undefined') {
|
|
68
|
-
data._id = id
|
|
69
|
-
}
|
|
70
|
-
const result = await pool.query('UPDATE ' + collectionId + ' SET data=$2,id=$3 WHERE id=$1', [id, data, data._id])
|
|
71
|
-
if (result.rowCount === 0) {
|
|
72
|
-
throw new util.ApiError(404, 'document not found')
|
|
73
|
-
}
|
|
74
|
-
return data
|
|
75
|
-
},
|
|
76
|
-
// eslint-disable-next-line no-unused-vars
|
|
77
|
-
updateWithQuery: async function (query, update, options) {
|
|
78
|
-
const pgWhere = util.mongoToPostgresWhere(collectionId, query)
|
|
79
|
-
const updateSql = util.mongoToPostgresUpdate(collectionId, update)
|
|
80
|
-
const result = await pool.query('UPDATE ' + collectionId + ' SET data=' + updateSql + ' WHERE ' + pgWhere)
|
|
81
|
-
return {
|
|
82
|
-
matchedCount: result.rowCount
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
delete: async function (id) {
|
|
86
|
-
const result = await pool.query('DELETE FROM ' + collectionId + ' WHERE id=$1', [id])
|
|
87
|
-
if (result.rowCount === 0) {
|
|
88
|
-
throw new util.ApiError(404, 'document not found')
|
|
89
|
-
}
|
|
90
|
-
return 'OK'
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
1
|
+
const util = require('../util')
|
|
2
|
+
|
|
3
|
+
module.exports = function (settings, collectionId, collection) {
|
|
4
|
+
const pool = util.getPgPool(settings.postgresql_uri)
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
init: async function () {
|
|
8
|
+
if (collection.plainStringIds) {
|
|
9
|
+
await pool.query('CREATE TABLE IF NOT EXISTS ' + collectionId + ' (id text primary key, data jsonb)')
|
|
10
|
+
} else {
|
|
11
|
+
await pool.query('CREATE TABLE IF NOT EXISTS ' + collectionId + ' (id uuid primary key, data jsonb)')
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
all: async function () {
|
|
15
|
+
return this.find({})
|
|
16
|
+
},
|
|
17
|
+
find: async function (rawQuery, offset, limit, orderby, fields) {
|
|
18
|
+
const pgSelect = util.mongoToPostgresSelect(collectionId, fields)
|
|
19
|
+
const pgWhere = util.mongoToPostgresWhere(collectionId, rawQuery)
|
|
20
|
+
let query = 'SELECT ' + pgSelect + ' FROM ' + collectionId + (pgWhere ? ' WHERE ' + pgWhere : '')
|
|
21
|
+
if (typeof orderby !== 'undefined') {
|
|
22
|
+
query += ' ORDER BY '
|
|
23
|
+
query += util.mongoToPostgresOrderBy(collectionId, orderby)
|
|
24
|
+
}
|
|
25
|
+
if (typeof offset !== 'undefined') {
|
|
26
|
+
query += ' OFFSET ' + offset
|
|
27
|
+
}
|
|
28
|
+
if (typeof limit !== 'undefined') {
|
|
29
|
+
query += ' LIMIT ' + limit
|
|
30
|
+
}
|
|
31
|
+
const result = await pool.query(query)
|
|
32
|
+
return result.rows.map((row) => row.data)
|
|
33
|
+
},
|
|
34
|
+
count: async function(rawQuery, offset, limit) {
|
|
35
|
+
const pgWhere = util.mongoToPostgresWhere(collectionId, rawQuery)
|
|
36
|
+
let query = 'SELECT COUNT(*) FROM ' + collectionId + (pgWhere ? ' WHERE ' + pgWhere : '')
|
|
37
|
+
if (typeof offset !== 'undefined') {
|
|
38
|
+
query += ' OFFSET ' + offset
|
|
39
|
+
}
|
|
40
|
+
if (typeof limit !== 'undefined') {
|
|
41
|
+
query += ' LIMIT ' + limit
|
|
42
|
+
}
|
|
43
|
+
const result = await pool.query(query)
|
|
44
|
+
return parseInt(result.rows[0].count)
|
|
45
|
+
},
|
|
46
|
+
get: async function (id, fields) {
|
|
47
|
+
const pgSelect = util.mongoToPostgresSelect(collectionId, fields)
|
|
48
|
+
const result = await pool.query(`SELECT ${pgSelect} FROM ${collectionId} WHERE id = $1`, [id])
|
|
49
|
+
if (result.rowCount === 0) {
|
|
50
|
+
throw new util.ApiError(404, 'document not found')
|
|
51
|
+
}
|
|
52
|
+
return result.rows[0].data
|
|
53
|
+
},
|
|
54
|
+
create: async function (data) {
|
|
55
|
+
util.addIdIfMissing(data)
|
|
56
|
+
try {
|
|
57
|
+
await pool.query('INSERT INTO ' + collectionId + ' (id, data) VALUES ($1, $2)', [data._id, data])
|
|
58
|
+
} catch (e) {
|
|
59
|
+
if (e.message.includes('duplicate key')) {
|
|
60
|
+
throw new util.ApiError(409, 'document already exists')
|
|
61
|
+
}
|
|
62
|
+
throw e
|
|
63
|
+
}
|
|
64
|
+
return data._id
|
|
65
|
+
},
|
|
66
|
+
update: async function (id, data) {
|
|
67
|
+
if (typeof data._id === 'undefined') {
|
|
68
|
+
data._id = id
|
|
69
|
+
}
|
|
70
|
+
const result = await pool.query('UPDATE ' + collectionId + ' SET data=$2,id=$3 WHERE id=$1', [id, data, data._id])
|
|
71
|
+
if (result.rowCount === 0) {
|
|
72
|
+
throw new util.ApiError(404, 'document not found')
|
|
73
|
+
}
|
|
74
|
+
return data
|
|
75
|
+
},
|
|
76
|
+
// eslint-disable-next-line no-unused-vars
|
|
77
|
+
updateWithQuery: async function (query, update, options) {
|
|
78
|
+
const pgWhere = util.mongoToPostgresWhere(collectionId, query)
|
|
79
|
+
const updateSql = util.mongoToPostgresUpdate(collectionId, update)
|
|
80
|
+
const result = await pool.query('UPDATE ' + collectionId + ' SET data=' + updateSql + ' WHERE ' + pgWhere)
|
|
81
|
+
return {
|
|
82
|
+
matchedCount: result.rowCount
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
delete: async function (id) {
|
|
86
|
+
const result = await pool.query('DELETE FROM ' + collectionId + ' WHERE id=$1', [id])
|
|
87
|
+
if (result.rowCount === 0) {
|
|
88
|
+
throw new util.ApiError(404, 'document not found')
|
|
89
|
+
}
|
|
90
|
+
return 'OK'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
package/doc/authentication.md
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
## Authentication
|
|
2
|
-
Uses [JSON Web Tokens](https://jwt.io/)
|
|
3
|
-
|
|
4
|
-
| method | endpoint | description |
|
|
5
|
-
|--------|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
6
|
-
| POST | /users/login | expects JSON in the message body. e.g. `{"email": "email@example.com", password: "<the password>"} |
|
|
7
|
-
|
|
8
|
-
Returns the following
|
|
9
|
-
```javascript
|
|
10
|
-
{
|
|
11
|
-
"uid": "a52ee085-ff47-4ee1-bac3-a8a319f674ed",
|
|
12
|
-
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM"
|
|
13
|
-
}
|
|
14
|
-
```
|
|
15
|
-
Or it will respond with a status code of 401 and a message explaining why they can't login.
|
|
16
|
-
|
|
17
|
-
```javascript
|
|
18
|
-
{
|
|
19
|
-
"success": false,
|
|
20
|
-
"message": "Authentication failed. Wrong password."
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The returned token must then be passed in as a header on future requests using the header x-access-token
|
|
25
|
-
|
|
26
|
-
* `GET /users/me` - returns the logged in user's object
|
|
27
|
-
|
|
28
|
-
## Making authenticated requests
|
|
29
|
-
|
|
30
|
-
After obtaining a token as described above you need to pass it with your request in one of these ways
|
|
31
|
-
|
|
32
|
-
1. Using the `x-access-token`
|
|
33
|
-
|
|
34
|
-
`curl --header "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM" api.example.com/users/me`
|
|
35
|
-
|
|
36
|
-
2. Pass the token as a query parameter.
|
|
37
|
-
|
|
38
|
-
`curl api.example.com/users/me?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM`
|
|
1
|
+
## Authentication
|
|
2
|
+
Uses [JSON Web Tokens](https://jwt.io/)
|
|
3
|
+
|
|
4
|
+
| method | endpoint | description |
|
|
5
|
+
|--------|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
6
|
+
| POST | /users/login | expects JSON in the message body. e.g. `{"email": "email@example.com", password: "<the password>"} |
|
|
7
|
+
|
|
8
|
+
Returns the following
|
|
9
|
+
```javascript
|
|
10
|
+
{
|
|
11
|
+
"uid": "a52ee085-ff47-4ee1-bac3-a8a319f674ed",
|
|
12
|
+
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM"
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
Or it will respond with a status code of 401 and a message explaining why they can't login.
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
{
|
|
19
|
+
"success": false,
|
|
20
|
+
"message": "Authentication failed. Wrong password."
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The returned token must then be passed in as a header on future requests using the header x-access-token
|
|
25
|
+
|
|
26
|
+
* `GET /users/me` - returns the logged in user's object
|
|
27
|
+
|
|
28
|
+
## Making authenticated requests
|
|
29
|
+
|
|
30
|
+
After obtaining a token as described above you need to pass it with your request in one of these ways
|
|
31
|
+
|
|
32
|
+
1. Using the `x-access-token`
|
|
33
|
+
|
|
34
|
+
`curl --header "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM" api.example.com/users/me`
|
|
35
|
+
|
|
36
|
+
2. Pass the token as a query parameter.
|
|
37
|
+
|
|
38
|
+
`curl api.example.com/users/me?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NmNkNWM5NmY4MjA4N2I1MDQ0OTM3YjEiLCJ1bml2ZXJzaXR5IjoiQllVIiwiZnVsbE5hbWUiOiJUaG9tYXMgSGFuc2VuIiwicGFzc3dvcmQiOiIkMmEkMTAkb0prdlBnTTlkR2FJRTIzaWFabGEvT0tjZC9PL3phSGFJOHFRUDBuZ2pPUVV1Ums3Vng2QkciLCJlbWFpbCI6InRoNDAxOUBnbWFpbC5jb20iLCJfX3YiOjAsImxpc3RpbmdzIjpbXSwiaWF0IjoxNDU2NDMwMjE5LCJleHAiOjE0NTY1MTY2MTl9._ijngdgwLU9AJnAjbySUgEFsR8hJCSw8PhH1AnyBHuM`
|
package/doc/automatic-fields.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
## Automatic Fields
|
|
2
|
-
|
|
3
|
-
Each object will contain this meta property which has autogenerated fields shared across all collection types:
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
"meta": {
|
|
7
|
-
"created": "2016-05-16T23:56:11.615Z",
|
|
8
|
-
"updated": "2016-05-16T23:56:28.262Z",
|
|
9
|
-
"owner": "56cb5df7f56ef0b92f7b984b"
|
|
10
|
-
},
|
|
11
|
-
```
|
|
12
|
-
|
|
1
|
+
## Automatic Fields
|
|
2
|
+
|
|
3
|
+
Each object will contain this meta property which has autogenerated fields shared across all collection types:
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
"meta": {
|
|
7
|
+
"created": "2016-05-16T23:56:11.615Z",
|
|
8
|
+
"updated": "2016-05-16T23:56:28.262Z",
|
|
9
|
+
"owner": "56cb5df7f56ef0b92f7b984b"
|
|
10
|
+
},
|
|
11
|
+
```
|
|
12
|
+
|
package/doc/blogexample.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
## Blog Example
|
|
2
|
-
|
|
3
|
-
### Creating the blog "post" collection and its schema.
|
|
4
|
-
|
|
5
|
-
Here's what the UI looks like for adding this new custom collection type.
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
--------------------------------
|
|
10
|
-
|
|
11
|
-
### Creating a post
|
|
12
|
-
|
|
13
|
-
After creating the blog post collection, here's what adding a document of that type looks like using the built in editor.
|
|
14
|
-
|
|
15
|
-

|
|
16
|
-
|
|
1
|
+
## Blog Example
|
|
2
|
+
|
|
3
|
+
### Creating the blog "post" collection and its schema.
|
|
4
|
+
|
|
5
|
+
Here's what the UI looks like for adding this new custom collection type.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
--------------------------------
|
|
10
|
+
|
|
11
|
+
### Creating a post
|
|
12
|
+
|
|
13
|
+
After creating the blog post collection, here's what adding a document of that type looks like using the built in editor.
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|