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.
Files changed (281) hide show
  1. package/.circleci/config.yml +21 -21
  2. package/.eslintrc.json +29 -29
  3. package/LICENSE +21 -21
  4. package/README.md +137 -137
  5. package/auth/index.js +76 -76
  6. package/auth/jwt.js +31 -31
  7. package/controllers/collections.js +260 -260
  8. package/controllers/install.js +105 -105
  9. package/controllers/status.js +43 -43
  10. package/controllers/users.js +52 -52
  11. package/cypress/fixtures/example.json +4 -4
  12. package/cypress/integration/0_install_spec.js +8 -8
  13. package/cypress/integration/custom_collections.js +28 -28
  14. package/cypress/integration/home.js +9 -9
  15. package/cypress/integration/settings.js +34 -34
  16. package/cypress/integration/users.js +61 -61
  17. package/cypress/plugins/index.js +17 -17
  18. package/cypress/support/commands.js +54 -54
  19. package/cypress/support/index.js +20 -20
  20. package/cypress/support/util.js +10 -10
  21. package/cypress.json +4 -4
  22. package/db/cached.js +40 -40
  23. package/db/file.js +112 -112
  24. package/db/memory.js +79 -79
  25. package/db/mongo.js +86 -86
  26. package/db/postgres.js +93 -93
  27. package/doc/authentication.md +38 -38
  28. package/doc/automatic-fields.md +12 -12
  29. package/doc/blogexample.md +16 -16
  30. package/doc/custom-endpoints.md +20 -20
  31. package/doc/database.md +23 -23
  32. package/doc/development.md +33 -33
  33. package/doc/listeners.md +103 -103
  34. package/doc/modules.md +8 -8
  35. package/doc/permissions.md +14 -14
  36. package/doc/relationships.md +65 -65
  37. package/doc/testing.md +47 -47
  38. package/doc/uploading-files.md +53 -53
  39. package/index.js +297 -297
  40. package/listeners.js +65 -65
  41. package/listeners_collection_permissions.js +29 -29
  42. package/listeners_users.js +96 -96
  43. package/listeners_validation.js +43 -43
  44. package/middleware/logging.js +30 -30
  45. package/middleware/permissions.js +41 -41
  46. package/modules/access_keys/access_keys.js +32 -32
  47. package/modules/admin/.babelrc +19 -19
  48. package/modules/admin/.editorconfig +14 -14
  49. package/modules/admin/.eslintignore +5 -5
  50. package/modules/admin/.eslintrc.js +197 -197
  51. package/modules/admin/.postcssrc.js +10 -10
  52. package/modules/admin/.travis.yml +5 -5
  53. package/modules/admin/LICENSE +21 -21
  54. package/modules/admin/README.md +88 -88
  55. package/modules/admin/build/build.js +45 -45
  56. package/modules/admin/build/check-versions.js +64 -64
  57. package/modules/admin/build/utils.js +108 -108
  58. package/modules/admin/build/vue-loader.conf.js +5 -5
  59. package/modules/admin/build/webpack.base.conf.js +112 -112
  60. package/modules/admin/build/webpack.dev.conf.js +95 -95
  61. package/modules/admin/build/webpack.prod.conf.js +112 -112
  62. package/modules/admin/config/dev.env.js +8 -8
  63. package/modules/admin/config/index.js +86 -86
  64. package/modules/admin/config/prod.env.js +5 -5
  65. package/modules/admin/dist/164c6167c1f3c497c07c.woff +1 -0
  66. package/modules/admin/dist/42ac07abc8473600c41f.ttf +1 -0
  67. package/modules/admin/dist/86dccb18a7eb4be8ef1a.woff +1 -0
  68. package/modules/admin/dist/c45297c558e0318fc9c5.ttf +1 -0
  69. package/modules/admin/dist/c717c9930715e24fa12c.woff +1 -0
  70. package/modules/admin/dist/ca6f07ef23f24cc2738a.ttf +1 -0
  71. package/modules/admin/dist/css/269.f7d5c7d5.css +37 -0
  72. package/modules/admin/dist/css/269.f7d5c7d5.css.gz +0 -0
  73. package/modules/admin/dist/css/451.c6646d20.css +1 -0
  74. package/modules/admin/dist/css/451.c6646d20.css.gz +0 -0
  75. package/modules/admin/dist/css/572.74d8e965.css +34 -0
  76. package/modules/admin/dist/css/572.74d8e965.css.gz +0 -0
  77. package/modules/admin/dist/css/651.e946bda7.css +6 -0
  78. package/modules/admin/dist/css/651.e946bda7.css.gz +0 -0
  79. package/modules/admin/dist/css/699.d1f90954.css +8 -0
  80. package/modules/admin/dist/css/699.d1f90954.css.gz +0 -0
  81. package/modules/admin/dist/css/750.4086915d.css +2 -0
  82. package/modules/admin/dist/css/750.4086915d.css.gz +0 -0
  83. package/modules/admin/dist/css/864.506917a4.css +7 -0
  84. package/modules/admin/dist/css/864.506917a4.css.gz +0 -0
  85. package/modules/admin/dist/css/899.506917a4.css +7 -0
  86. package/modules/admin/dist/css/899.506917a4.css.gz +0 -0
  87. package/modules/admin/dist/css/950.1fd9d57c.css +7 -0
  88. package/modules/admin/dist/css/950.1fd9d57c.css.gz +0 -0
  89. package/modules/admin/dist/css/app.11cc6245.css +39 -0
  90. package/modules/admin/dist/css/app.11cc6245.css.gz +0 -0
  91. package/modules/admin/dist/css/app.2e1b0d79.css +591 -0
  92. package/modules/admin/dist/css/app.2e1b0d79.css.gz +0 -0
  93. package/modules/admin/dist/css/app.4d43d0fd.css +592 -0
  94. package/modules/admin/dist/css/app.4d43d0fd.css.gz +0 -0
  95. package/modules/admin/dist/css/app.abace109.css +1 -0
  96. package/modules/admin/dist/css/app.abace109.css.gz +0 -0
  97. package/modules/admin/dist/css/chunk-elementUI.67ad86d7.css +1 -0
  98. package/modules/admin/dist/css/chunk-elementUI.67ad86d7.css.gz +0 -0
  99. package/modules/admin/dist/css/chunk-elementUI.9e660bfd.css +1 -0
  100. package/modules/admin/dist/css/chunk-elementUI.9e660bfd.css.gz +0 -0
  101. package/modules/admin/dist/css/chunk-elementUI.c77cf142.css +1 -0
  102. package/modules/admin/dist/css/chunk-elementUI.c77cf142.css.gz +0 -0
  103. package/modules/admin/dist/css/chunk-elementUI.f1625b35.css +1 -0
  104. package/modules/admin/dist/css/chunk-elementUI.f1625b35.css.gz +0 -0
  105. package/modules/admin/dist/css/chunk-elementUI.f25dfb9b.css +1 -0
  106. package/modules/admin/dist/css/chunk-elementUI.f25dfb9b.css.gz +0 -0
  107. package/modules/admin/dist/css/chunk-libs.de0d8484.css +551 -0
  108. package/modules/admin/dist/css/chunk-libs.de0d8484.css.gz +0 -0
  109. package/modules/admin/dist/index.html +1 -1
  110. package/modules/admin/dist/static/fonts/element-icons.313f7da.woff +0 -0
  111. package/modules/admin/dist/static/fonts/element-icons.4520188.ttf +0 -0
  112. package/modules/admin/dist/static/js/269.7245ceaf.js +1 -0
  113. package/modules/admin/dist/static/js/269.7245ceaf.js.gz +0 -0
  114. package/modules/admin/dist/static/js/451.645974a8.js +1 -0
  115. package/modules/admin/dist/static/js/451.645974a8.js.gz +0 -0
  116. package/modules/admin/dist/static/js/460.962d5bc0.js +1 -0
  117. package/modules/admin/dist/static/js/460.962d5bc0.js.gz +0 -0
  118. package/modules/admin/dist/static/js/556.1e08866a.js +1 -0
  119. package/modules/admin/dist/static/js/556.1e08866a.js.gz +0 -0
  120. package/modules/admin/dist/static/js/572.13392e1d.js +1 -0
  121. package/modules/admin/dist/static/js/572.13392e1d.js.gz +0 -0
  122. package/modules/admin/dist/static/js/603.7b34a650.js +1 -0
  123. package/modules/admin/dist/static/js/603.7b34a650.js.gz +0 -0
  124. package/modules/admin/dist/static/js/637.26413baa.js +1 -0
  125. package/modules/admin/dist/static/js/637.26413baa.js.gz +0 -0
  126. package/modules/admin/dist/static/js/651.564b24b6.js +1 -0
  127. package/modules/admin/dist/static/js/651.564b24b6.js.gz +0 -0
  128. package/modules/admin/dist/static/js/653.02ec1098.js +1 -0
  129. package/modules/admin/dist/static/js/653.02ec1098.js.gz +0 -0
  130. package/modules/admin/dist/static/js/699.c7564884.js +1 -0
  131. package/modules/admin/dist/static/js/699.c7564884.js.gz +0 -0
  132. package/modules/admin/dist/static/js/750.50c950da.js +1 -0
  133. package/modules/admin/dist/static/js/750.50c950da.js.gz +0 -0
  134. package/modules/admin/dist/static/js/864.4f43847d.js +1 -0
  135. package/modules/admin/dist/static/js/864.4f43847d.js.gz +0 -0
  136. package/modules/admin/dist/static/js/950.d4ff0a18.js +1 -0
  137. package/modules/admin/dist/static/js/950.d4ff0a18.js.gz +0 -0
  138. package/modules/admin/dist/static/js/app.981e71b3.js +2 -0
  139. package/modules/admin/dist/static/js/{chunk-libs.06c38828.js.LICENSE.txt → app.981e71b3.js.LICENSE.txt} +15 -18
  140. package/modules/admin/dist/static/js/app.981e71b3.js.LICENSE.txt.gz +0 -0
  141. package/modules/admin/dist/static/js/app.981e71b3.js.gz +0 -0
  142. package/modules/admin/index.html +16 -16
  143. package/modules/admin/package.json +101 -101
  144. package/modules/admin/src/App.vue +11 -11
  145. package/modules/admin/src/api/login.js +26 -26
  146. package/modules/admin/src/api/table.js +9 -9
  147. package/modules/admin/src/components/Breadcrumb/index.vue +79 -79
  148. package/modules/admin/src/components/Hamburger/index.vue +62 -62
  149. package/modules/admin/src/components/JSONEditor.vue +180 -180
  150. package/modules/admin/src/components/SvgIcon/index.vue +43 -43
  151. package/modules/admin/src/icons/index.js +9 -9
  152. package/modules/admin/src/icons/svgo.yml +22 -22
  153. package/modules/admin/src/main.js +42 -42
  154. package/modules/admin/src/permission.js +49 -49
  155. package/modules/admin/src/router/index.js +200 -200
  156. package/modules/admin/src/store/getters.js +11 -11
  157. package/modules/admin/src/store/index.js +17 -17
  158. package/modules/admin/src/store/modules/app.js +43 -43
  159. package/modules/admin/src/store/modules/user.js +104 -104
  160. package/modules/admin/src/styles/element-ui.scss +29 -29
  161. package/modules/admin/src/styles/index.scss +78 -78
  162. package/modules/admin/src/styles/mixin.scss +27 -27
  163. package/modules/admin/src/styles/sidebar.scss +133 -133
  164. package/modules/admin/src/styles/transition.scss +46 -46
  165. package/modules/admin/src/styles/variables.scss +4 -4
  166. package/modules/admin/src/utils/auth.js +15 -15
  167. package/modules/admin/src/utils/index.js +74 -74
  168. package/modules/admin/src/utils/request.js +48 -48
  169. package/modules/admin/src/utils/validate.js +31 -31
  170. package/modules/admin/src/views/404.vue +235 -235
  171. package/modules/admin/src/views/Dev.vue +33 -33
  172. package/modules/admin/src/views/EditDocument.vue +116 -116
  173. package/modules/admin/src/views/Endpoints.vue +279 -279
  174. package/modules/admin/src/views/Home.vue +84 -84
  175. package/modules/admin/src/views/Install.vue +79 -79
  176. package/modules/admin/src/views/ListDocuments.vue +72 -72
  177. package/modules/admin/src/views/ListDocuments2.vue +462 -462
  178. package/modules/admin/src/views/ManageListeners.vue +67 -67
  179. package/modules/admin/src/views/ManageMiddleware.vue +43 -43
  180. package/modules/admin/src/views/ManagePermissions.vue +75 -75
  181. package/modules/admin/src/views/ViewRequest.vue +77 -77
  182. package/modules/admin/src/views/form/index.vue +91 -91
  183. package/modules/admin/src/views/layout/Layout.vue +69 -69
  184. package/modules/admin/src/views/layout/components/AppMain.vue +41 -41
  185. package/modules/admin/src/views/layout/components/Navbar.vue +97 -97
  186. package/modules/admin/src/views/layout/components/Sidebar/Item.vue +29 -29
  187. package/modules/admin/src/views/layout/components/Sidebar/Link.vue +39 -39
  188. package/modules/admin/src/views/layout/components/Sidebar/SidebarItem.vue +103 -103
  189. package/modules/admin/src/views/layout/components/Sidebar/index.vue +62 -62
  190. package/modules/admin/src/views/layout/components/index.js +3 -3
  191. package/modules/admin/src/views/layout/mixin/ResizeHandler.js +41 -41
  192. package/modules/admin/src/views/login/index.vue +195 -195
  193. package/modules/admin/src/views/tree/index.vue +77 -77
  194. package/modules/collections/collections.js +39 -39
  195. package/modules/core/core.js +197 -197
  196. package/modules/logging/logging.js +88 -88
  197. package/modules/permissions/permissions.js +106 -106
  198. package/package.json +59 -59
  199. package/scripts/expressa +12 -12
  200. package/scripts/run_cypress_tests.sh +5 -5
  201. package/scripts/run_db_tests.sh +8 -8
  202. package/test/0-install.js +96 -96
  203. package/test/collections.js +431 -431
  204. package/test/collections.querying.js +288 -288
  205. package/test/db.js +258 -258
  206. package/test/db.strings.js +73 -73
  207. package/test/db.updating.js +144 -144
  208. package/test/logging.js +29 -29
  209. package/test/test.js +93 -93
  210. package/test/testserver.js +17 -17
  211. package/test/testutils.js +136 -136
  212. package/test/users.js +425 -425
  213. package/util.js +522 -522
  214. package/modules/admin/dist/index.html.gz +0 -0
  215. package/modules/admin/dist/static/css/app.9dd57eea.css +0 -1
  216. package/modules/admin/dist/static/css/app.9dd57eea.css.gz +0 -0
  217. package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css +0 -1
  218. package/modules/admin/dist/static/css/chunk-5061.ce0e4bdb.css.gz +0 -0
  219. package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css +0 -1
  220. package/modules/admin/dist/static/css/chunk-5b97.7f9cb53e.css.gz +0 -0
  221. package/modules/admin/dist/static/css/chunk-621e.b826be8d.css +0 -1
  222. package/modules/admin/dist/static/css/chunk-621e.b826be8d.css.gz +0 -0
  223. package/modules/admin/dist/static/css/chunk-656b.9c828b00.css +0 -1
  224. package/modules/admin/dist/static/css/chunk-656b.9c828b00.css.gz +0 -0
  225. package/modules/admin/dist/static/css/chunk-7291.13514e45.css +0 -0
  226. package/modules/admin/dist/static/css/chunk-7291.13514e45.css.gz +0 -0
  227. package/modules/admin/dist/static/css/chunk-7f29.9c828b00.css +0 -1
  228. package/modules/admin/dist/static/css/chunk-7f29.9c828b00.css.gz +0 -0
  229. package/modules/admin/dist/static/css/chunk-9a95.c647a2ef.css +0 -1
  230. package/modules/admin/dist/static/css/chunk-9a95.c647a2ef.css.gz +0 -0
  231. package/modules/admin/dist/static/css/chunk-b423.5f239333.css +0 -0
  232. package/modules/admin/dist/static/css/chunk-b423.5f239333.css.gz +0 -0
  233. package/modules/admin/dist/static/css/chunk-bd5f.aefa49d7.css +0 -1
  234. package/modules/admin/dist/static/css/chunk-bd5f.aefa49d7.css.gz +0 -0
  235. package/modules/admin/dist/static/css/chunk-e374.025d58bb.css +0 -1
  236. package/modules/admin/dist/static/css/chunk-e374.025d58bb.css.gz +0 -0
  237. package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css +0 -1
  238. package/modules/admin/dist/static/css/chunk-elementUI.3d004d9f.css.gz +0 -0
  239. package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css +0 -1
  240. package/modules/admin/dist/static/css/chunk-f075.3a895a1e.css.gz +0 -0
  241. package/modules/admin/dist/static/css/chunk-libs.327ad89e.css +0 -14
  242. package/modules/admin/dist/static/css/chunk-libs.327ad89e.css.gz +0 -0
  243. package/modules/admin/dist/static/fonts/element-icons.6f0a763.ttf +0 -0
  244. package/modules/admin/dist/static/js/app.e9461593.js +0 -1
  245. package/modules/admin/dist/static/js/app.e9461593.js.gz +0 -0
  246. package/modules/admin/dist/static/js/chunk-09d8.561880e0.js +0 -2
  247. package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.LICENSE.txt +0 -13
  248. package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.LICENSE.txt.gz +0 -0
  249. package/modules/admin/dist/static/js/chunk-09d8.561880e0.js.gz +0 -0
  250. package/modules/admin/dist/static/js/chunk-5061.83e6ccfa.js +0 -1
  251. package/modules/admin/dist/static/js/chunk-5061.83e6ccfa.js.gz +0 -0
  252. package/modules/admin/dist/static/js/chunk-5b97.ac360086.js +0 -1
  253. package/modules/admin/dist/static/js/chunk-5b97.ac360086.js.gz +0 -0
  254. package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js +0 -1
  255. package/modules/admin/dist/static/js/chunk-5e17.a2b69611.js.gz +0 -0
  256. package/modules/admin/dist/static/js/chunk-621e.ccf42393.js +0 -1
  257. package/modules/admin/dist/static/js/chunk-621e.ccf42393.js.gz +0 -0
  258. package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js +0 -1
  259. package/modules/admin/dist/static/js/chunk-656b.9d5b03c0.js.gz +0 -0
  260. package/modules/admin/dist/static/js/chunk-7291.590524e9.js +0 -1
  261. package/modules/admin/dist/static/js/chunk-7291.590524e9.js.gz +0 -0
  262. package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js +0 -1
  263. package/modules/admin/dist/static/js/chunk-7f29.6ffc142e.js.gz +0 -0
  264. package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js +0 -1
  265. package/modules/admin/dist/static/js/chunk-9a95.bdd76583.js.gz +0 -0
  266. package/modules/admin/dist/static/js/chunk-b423.387c504c.js +0 -1
  267. package/modules/admin/dist/static/js/chunk-b423.387c504c.js.gz +0 -0
  268. package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js +0 -1
  269. package/modules/admin/dist/static/js/chunk-bd5f.e9509f10.js.gz +0 -0
  270. package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js +0 -1
  271. package/modules/admin/dist/static/js/chunk-e374.7c87a0dd.js.gz +0 -0
  272. package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js +0 -1
  273. package/modules/admin/dist/static/js/chunk-e7c3.e5df8ceb.js.gz +0 -0
  274. package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js +0 -1
  275. package/modules/admin/dist/static/js/chunk-elementUI.b0c99c08.js.gz +0 -0
  276. package/modules/admin/dist/static/js/chunk-f075.315ceec1.js +0 -1
  277. package/modules/admin/dist/static/js/chunk-f075.315ceec1.js.gz +0 -0
  278. package/modules/admin/dist/static/js/chunk-libs.06c38828.js +0 -2
  279. package/modules/admin/dist/static/js/chunk-libs.06c38828.js.LICENSE.txt.gz +0 -0
  280. package/modules/admin/dist/static/js/chunk-libs.06c38828.js.gz +0 -0
  281. /package/modules/admin/dist/static/img/{404.a57b6f3.png → 404.4cf6930.png} +0 -0
package/index.js CHANGED
@@ -1,297 +1,297 @@
1
- const fs = require('fs')
2
- const express = require('express')
3
- const bodyParser = require('body-parser')
4
- const debug = require('debug')('expressa')
5
- const randomstring = require('randomstring')
6
-
7
- const dbTypeNames = ['cached', 'file', 'memory', 'postgres', 'mongo']
8
- const dbTypes = dbTypeNames.reduce((obj, name) => {
9
- obj[name] = require('./db/' + name)
10
- return obj
11
- }, {})
12
- dbTypes['mongodb'] = dbTypes['mongo'] // alias
13
- const auth = require('./auth')
14
- const util = require('./util')
15
-
16
- const collectionsApi = require('./controllers/collections')
17
- const usersApi = require('./controllers/users')
18
- const installApi = require('./controllers/install')
19
- const statusApi = require('./controllers/status')
20
- const permissions = require('./middleware/permissions')
21
- const loggingMiddleware = require('./middleware/logging')
22
-
23
- process.env.NODE_ENV = process.env.NODE_ENV || 'development'
24
-
25
- async function bootstrapCollections (router) {
26
- const collections = await router.db.collection.all()
27
- await Promise.all(collections.map((collection) => {
28
- if (!dbTypes[collection.storage]) {
29
- console.error('missing ' + collection.storage + ' dbtype which is used by ' + collection._id)
30
- console.error('try updating to the latest version of expressa')
31
- }
32
- return router.setupCollectionDb(collection)
33
- }))
34
- }
35
-
36
- async function initCollections (db, router) {
37
- debug('init collections')
38
- try {
39
- const data = await db.settings.get(process.env.NODE_ENV)
40
- Object.assign(router.settings, data)
41
- } catch (err) {
42
- const filePath = router.settings.file_storage_path || 'data'
43
- if (!fs.existsSync(filePath + '/settings/' + process.env.NODE_ENV + '.json')) {
44
- console.error('Settings not found. Please visit the expressa admin page for the installation process.')
45
- console.error('This is likely at http://localhost:3000/admin but may be different if you changed ports, etc.')
46
- } else {
47
- console.error('error reading settings')
48
- console.error(err.stack)
49
- }
50
- }
51
- console.log('Starting expressa server using environment: ' + process.env.NODE_ENV) // eslint-disable-line no-console
52
- db.collection = dbTypes[router.settings.collection_db_type || 'file'](router.settings, 'collection')
53
- await bootstrapCollections(router)
54
- debug('collections loaded.')
55
-
56
- await Promise.all([
57
- require('./listeners_collection_permissions')(router),
58
- require('./listeners')(router),
59
- require('./listeners_validation')(router),
60
- require('./listeners_users')(router),
61
- ])
62
- debug('added standard listeners')
63
- }
64
-
65
- function ph (requestHandler) {
66
- return async function wrapper (req, res, next) {
67
- const collectionName = req.params.collection
68
- let collection = {}
69
- try {
70
- collection = collectionName ? await req.db.collection.get(collectionName) : {}
71
- } catch (e) {
72
- if (!e.message.includes('document not found')) {
73
- console.error(e)
74
- }
75
- }
76
- if (!collection.allowHTTPCaching) {
77
- res.header('Cache-Control', 'no-cache, no-store, must-revalidate')
78
- res.header('Expires', '-1')
79
- res.header('Pragma', 'no-cache')
80
- }
81
- try {
82
- const result = await requestHandler(req, res, next)
83
- if (typeof result !== 'object') {
84
- res.status(500).send('invalid result')
85
- }
86
- debug(`${200} ${req.method} ${req.url} body: ${JSON.stringify(req.body)} result: ${JSON.stringify(result)}`)
87
- res.send(result)
88
- } catch (err) {
89
- err.status = err.status || 500
90
- debug(`${err.status} ${req.method} ${req.url} ${err.stack} ${req.uerror}`)
91
- if ((req.settings.print_400_errors) || err.status >= 500) {
92
- console.error(err + ' | ' + req.uerror)
93
- }
94
- req.returnedError = err
95
- res.status(err.status).send({
96
- error: err.result || err.message || err,
97
- tokenError: req.uerror ? (req.uerror === 'jwt expired' ? 'expired token' : 'jwt error') : undefined
98
- })
99
- }
100
- }
101
- }
102
-
103
- module.exports.api = function (settings) {
104
- const router = express.Router()
105
- router.initialized = false
106
- router.custom = express.Router()
107
- router.dbTypes = dbTypes
108
- router.settings = settings || {}
109
- router.db = {
110
- settings: dbTypes[router.settings.settings_db_type || 'file'](router.settings, 'settings')
111
- }
112
- router.util = {
113
- get pgpool() {
114
- return util.getPgPool(router.settings.postgresql_uri)
115
- },
116
- ...util,
117
- }
118
- router.eventListeners = {}
119
-
120
- router.setupCollectionDb = async function(collection) {
121
- debug(`init collection db ${collection._id} ${collection.storage}`)
122
- router.db[collection._id] = dbTypes[collection.storage](router.settings, collection._id, collection)
123
- if (collection.cacheInMemory) {
124
- router.db[collection._id] = dbTypes['cached'](router.db[collection._id])
125
- debug('initializing ' + collection._id + ' as a memory cached collection')
126
- }
127
- return Promise.resolve(router.db[collection._id].init())
128
- }
129
-
130
- router.addSingleCollectionListener = function (event, listener) {
131
- if (!router.eventListeners[event]) {
132
- router.eventListeners[event] = []
133
- }
134
- router.eventListeners[event].push(listener)
135
- router.eventListeners[event].sort((a, b) => a.priority - b.priority)
136
- if (event === 'ready' && router.initialized) {
137
- listener(router)
138
- }
139
- }
140
-
141
- router.addCollectionListenerWithPriority = function (events, collections, priority, listener) {
142
- listener.priority = priority
143
- router.addCollectionListener(events, collections, listener)
144
- }
145
-
146
- router.addLateCollectionListener = function (events, collections, listener) {
147
- listener.priority = 10
148
- router.addCollectionListener(events, collections, listener)
149
- }
150
-
151
- router.addCollectionListener = function (events, collections, listener) {
152
- events = util.castArray(events)
153
- collections = util.castArray(collections)
154
- listener.priority = listener.priority || 0
155
- listener.collections = collections
156
- if (!listener.name) {
157
- throw new Error('Listeners must be named')
158
- }
159
- events.forEach(function (event) {
160
- router.addSingleCollectionListener(event, listener)
161
- })
162
- }
163
-
164
- router.addListener = function addListener (events, priority, listener) {
165
- events = util.castArray(events)
166
- if (typeof priority === 'function') {
167
- listener = priority
168
- priority = 0
169
- }
170
- if (!listener.name) {
171
- throw new Error('Listeners must be named')
172
- }
173
- listener.priority = priority
174
- events.forEach(function (event) {
175
- router.addSingleCollectionListener(event, listener)
176
- })
177
- }
178
-
179
- router.getSetting = function (name) {
180
- return util.getPath(router.settings, name)
181
- };
182
-
183
- (async function setup() {
184
- await initCollections(router.db, router)
185
-
186
- const modules = ['collections', 'core', 'logging', 'permissions', 'access_keys']
187
- router.modules = {}
188
- for (const module of modules) {
189
- router.modules[module] = require(`./modules/${module}/${module}`)
190
- if (router.modules[module].init) {
191
- router.modules[module].init(router)
192
- }
193
- }
194
-
195
- await addRoutesAndMiddleware()
196
-
197
- try {
198
- await installApi.updateAdminPermissions(router)
199
- } catch (e) {
200
- console.error('Error while attempting to update admin permissions')
201
- console.error(e)
202
- }
203
-
204
- router.initialized = true
205
- await util.notify('ready', router)
206
- })()
207
-
208
- async function addRoutesAndMiddleware() {
209
- // Allow CORS
210
- router.use(function addCorsHeaders(req, res, next) {
211
- res.header('Access-Control-Allow-Origin', '*')
212
- res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
213
- res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-access-token')
214
- next()
215
- })
216
-
217
- router.use(bodyParser.json({
218
- type: '*/*', // The wildcard type ensures it works even without the application/json header
219
- limit: router.settings.body_limit || '1mb',
220
- }))
221
-
222
- router.use(function attachVariablesToReq(req, res, next) {
223
- req.settings = router.settings
224
- req.eventListeners = router.eventListeners
225
- req.db = router.db
226
- req.modules = router.modules
227
- req.setupCollectionDb = router.setupCollectionDb
228
- req.getSetting = router.getSetting
229
- req.requestId = randomstring.generate(12)
230
- res.header('X-Request-ID', req.requestId)
231
- next()
232
- })
233
-
234
- router.use(loggingMiddleware)
235
-
236
- router.notify = util.notify
237
-
238
- router.post('/install', ph(async (req) => installApi.install(req, router)))
239
- router.get('/install/settings/schema', ph(async (req) => installApi.getSettingsSchema(req, router)))
240
-
241
- const loginCollections = await util.getLoginCollections(router)
242
-
243
- for (const { _id: name } of loginCollections) {
244
- router.post(`/${name}/login`, ph((req) => usersApi.login(req, name)))
245
- }
246
-
247
- router.use(auth.middleware) // Add user id to request
248
- router.use(permissions.middleware) // Add user and permissions to request
249
-
250
- router.get('/status', ph(statusApi.getStatus(router)))
251
-
252
- router.use(router.custom) // Externally added middleware
253
-
254
- for (const { _id: name } of loginCollections) {
255
- router.post(`/${name}/register`, ph((req) => usersApi.register(req, name)))
256
- router.get(`/${name}/me`, ph((req) => usersApi.getMe(req, name)))
257
- }
258
-
259
- router.get('/:collection/schema', ph(collectionsApi.getSchema))
260
- router.get('/:collection', ph(collectionsApi.get))
261
- router.post('/:collection', ph(collectionsApi.insert))
262
- router.get('/:collection/:id', ph(collectionsApi.getById))
263
- router.put('/:collection/:id', ph(collectionsApi.replaceById))
264
- router.post('/:collection/:id/update', ph(collectionsApi.updateById))
265
- router.delete('/:collection/:id', ph(collectionsApi.deleteById))
266
-
267
- // Error handler, log and send to user
268
- // eslint-disable-next-line no-unused-vars
269
- router.use(function safeErrorHandler(err, req, res, next) {
270
- console.error('my err handler')
271
- console.error(err.stack)
272
- req.returnedError = err
273
- res.status(res.errCode || 500)
274
- if (process.env.DEBUG || (req.hasPermission && req.hasPermission('view errors'))) {
275
- res.send({
276
- error: err
277
- })
278
- } else {
279
- res.send({
280
- error: 'something wrong happened'
281
- })
282
- }
283
- })
284
- }
285
-
286
- return router
287
- }
288
-
289
- module.exports.admin = function (settings) {
290
- const router = express.Router()
291
- router.get('/settings.js', function (req, res) {
292
- res.set('Content-Type', 'text/javascript')
293
- res.send('window.settings = ' + JSON.stringify(settings || {}) + '')
294
- })
295
- router.use(express.static(__dirname + '/modules/admin/dist'))
296
- return router
297
- }
1
+ const fs = require('fs')
2
+ const express = require('express')
3
+ const bodyParser = require('body-parser')
4
+ const debug = require('debug')('expressa')
5
+ const randomstring = require('randomstring')
6
+
7
+ const dbTypeNames = ['cached', 'file', 'memory', 'postgres', 'mongo']
8
+ const dbTypes = dbTypeNames.reduce((obj, name) => {
9
+ obj[name] = require('./db/' + name)
10
+ return obj
11
+ }, {})
12
+ dbTypes['mongodb'] = dbTypes['mongo'] // alias
13
+ const auth = require('./auth')
14
+ const util = require('./util')
15
+
16
+ const collectionsApi = require('./controllers/collections')
17
+ const usersApi = require('./controllers/users')
18
+ const installApi = require('./controllers/install')
19
+ const statusApi = require('./controllers/status')
20
+ const permissions = require('./middleware/permissions')
21
+ const loggingMiddleware = require('./middleware/logging')
22
+
23
+ process.env.NODE_ENV = process.env.NODE_ENV || 'development'
24
+
25
+ async function bootstrapCollections (router) {
26
+ const collections = await router.db.collection.all()
27
+ await Promise.all(collections.map((collection) => {
28
+ if (!dbTypes[collection.storage]) {
29
+ console.error('missing ' + collection.storage + ' dbtype which is used by ' + collection._id)
30
+ console.error('try updating to the latest version of expressa')
31
+ }
32
+ return router.setupCollectionDb(collection)
33
+ }))
34
+ }
35
+
36
+ async function initCollections (db, router) {
37
+ debug('init collections')
38
+ try {
39
+ const data = await db.settings.get(process.env.NODE_ENV)
40
+ Object.assign(router.settings, data)
41
+ } catch (err) {
42
+ const filePath = router.settings.file_storage_path || 'data'
43
+ if (!fs.existsSync(filePath + '/settings/' + process.env.NODE_ENV + '.json')) {
44
+ console.error('Settings not found. Please visit the expressa admin page for the installation process.')
45
+ console.error('This is likely at http://localhost:3000/admin but may be different if you changed ports, etc.')
46
+ } else {
47
+ console.error('error reading settings')
48
+ console.error(err.stack)
49
+ }
50
+ }
51
+ console.log('Starting expressa server using environment: ' + process.env.NODE_ENV) // eslint-disable-line no-console
52
+ db.collection = dbTypes[router.settings.collection_db_type || 'file'](router.settings, 'collection')
53
+ await bootstrapCollections(router)
54
+ debug('collections loaded.')
55
+
56
+ await Promise.all([
57
+ require('./listeners_collection_permissions')(router),
58
+ require('./listeners')(router),
59
+ require('./listeners_validation')(router),
60
+ require('./listeners_users')(router),
61
+ ])
62
+ debug('added standard listeners')
63
+ }
64
+
65
+ function ph (requestHandler) {
66
+ return async function wrapper (req, res, next) {
67
+ const collectionName = req.params.collection
68
+ let collection = {}
69
+ try {
70
+ collection = collectionName ? await req.db.collection.get(collectionName) : {}
71
+ } catch (e) {
72
+ if (!e.message.includes('document not found')) {
73
+ console.error(e)
74
+ }
75
+ }
76
+ if (!collection.allowHTTPCaching) {
77
+ res.header('Cache-Control', 'no-cache, no-store, must-revalidate')
78
+ res.header('Expires', '-1')
79
+ res.header('Pragma', 'no-cache')
80
+ }
81
+ try {
82
+ const result = await requestHandler(req, res, next)
83
+ if (typeof result !== 'object') {
84
+ res.status(500).send('invalid result')
85
+ }
86
+ debug(`${200} ${req.method} ${req.url} body: ${JSON.stringify(req.body)} result: ${JSON.stringify(result)}`)
87
+ res.send(result)
88
+ } catch (err) {
89
+ err.status = err.status || 500
90
+ debug(`${err.status} ${req.method} ${req.url} ${err.stack} ${req.uerror}`)
91
+ if ((req.settings.print_400_errors) || err.status >= 500) {
92
+ console.error(err + ' | ' + req.uerror)
93
+ }
94
+ req.returnedError = err
95
+ res.status(err.status).send({
96
+ error: err.result || err.message || err,
97
+ tokenError: req.uerror ? (req.uerror === 'jwt expired' ? 'expired token' : 'jwt error') : undefined
98
+ })
99
+ }
100
+ }
101
+ }
102
+
103
+ module.exports.api = function (settings) {
104
+ const router = express.Router()
105
+ router.initialized = false
106
+ router.custom = express.Router()
107
+ router.dbTypes = dbTypes
108
+ router.settings = settings || {}
109
+ router.db = {
110
+ settings: dbTypes[router.settings.settings_db_type || 'file'](router.settings, 'settings')
111
+ }
112
+ router.util = {
113
+ get pgpool() {
114
+ return util.getPgPool(router.settings.postgresql_uri)
115
+ },
116
+ ...util,
117
+ }
118
+ router.eventListeners = {}
119
+
120
+ router.setupCollectionDb = async function(collection) {
121
+ debug(`init collection db ${collection._id} ${collection.storage}`)
122
+ router.db[collection._id] = dbTypes[collection.storage](router.settings, collection._id, collection)
123
+ if (collection.cacheInMemory) {
124
+ router.db[collection._id] = dbTypes['cached'](router.db[collection._id])
125
+ debug('initializing ' + collection._id + ' as a memory cached collection')
126
+ }
127
+ return Promise.resolve(router.db[collection._id].init())
128
+ }
129
+
130
+ router.addSingleCollectionListener = function (event, listener) {
131
+ if (!router.eventListeners[event]) {
132
+ router.eventListeners[event] = []
133
+ }
134
+ router.eventListeners[event].push(listener)
135
+ router.eventListeners[event].sort((a, b) => a.priority - b.priority)
136
+ if (event === 'ready' && router.initialized) {
137
+ listener(router)
138
+ }
139
+ }
140
+
141
+ router.addCollectionListenerWithPriority = function (events, collections, priority, listener) {
142
+ listener.priority = priority
143
+ router.addCollectionListener(events, collections, listener)
144
+ }
145
+
146
+ router.addLateCollectionListener = function (events, collections, listener) {
147
+ listener.priority = 10
148
+ router.addCollectionListener(events, collections, listener)
149
+ }
150
+
151
+ router.addCollectionListener = function (events, collections, listener) {
152
+ events = util.castArray(events)
153
+ collections = util.castArray(collections)
154
+ listener.priority = listener.priority || 0
155
+ listener.collections = collections
156
+ if (!listener.name) {
157
+ throw new Error('Listeners must be named')
158
+ }
159
+ events.forEach(function (event) {
160
+ router.addSingleCollectionListener(event, listener)
161
+ })
162
+ }
163
+
164
+ router.addListener = function addListener (events, priority, listener) {
165
+ events = util.castArray(events)
166
+ if (typeof priority === 'function') {
167
+ listener = priority
168
+ priority = 0
169
+ }
170
+ if (!listener.name) {
171
+ throw new Error('Listeners must be named')
172
+ }
173
+ listener.priority = priority
174
+ events.forEach(function (event) {
175
+ router.addSingleCollectionListener(event, listener)
176
+ })
177
+ }
178
+
179
+ router.getSetting = function (name) {
180
+ return util.getPath(router.settings, name)
181
+ };
182
+
183
+ (async function setup() {
184
+ await initCollections(router.db, router)
185
+
186
+ const modules = ['collections', 'core', 'logging', 'permissions', 'access_keys']
187
+ router.modules = {}
188
+ for (const module of modules) {
189
+ router.modules[module] = require(`./modules/${module}/${module}`)
190
+ if (router.modules[module].init) {
191
+ router.modules[module].init(router)
192
+ }
193
+ }
194
+
195
+ await addRoutesAndMiddleware()
196
+
197
+ try {
198
+ await installApi.updateAdminPermissions(router)
199
+ } catch (e) {
200
+ console.error('Error while attempting to update admin permissions')
201
+ console.error(e)
202
+ }
203
+
204
+ router.initialized = true
205
+ await util.notify('ready', router)
206
+ })()
207
+
208
+ async function addRoutesAndMiddleware() {
209
+ // Allow CORS
210
+ router.use(function addCorsHeaders(req, res, next) {
211
+ res.header('Access-Control-Allow-Origin', '*')
212
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
213
+ res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-access-token')
214
+ next()
215
+ })
216
+
217
+ router.use(bodyParser.json({
218
+ type: '*/*', // The wildcard type ensures it works even without the application/json header
219
+ limit: router.settings.body_limit || '1mb',
220
+ }))
221
+
222
+ router.use(function attachVariablesToReq(req, res, next) {
223
+ req.settings = router.settings
224
+ req.eventListeners = router.eventListeners
225
+ req.db = router.db
226
+ req.modules = router.modules
227
+ req.setupCollectionDb = router.setupCollectionDb
228
+ req.getSetting = router.getSetting
229
+ req.requestId = randomstring.generate(12)
230
+ res.header('X-Request-ID', req.requestId)
231
+ next()
232
+ })
233
+
234
+ router.use(loggingMiddleware)
235
+
236
+ router.notify = util.notify
237
+
238
+ router.post('/install', ph(async (req) => installApi.install(req, router)))
239
+ router.get('/install/settings/schema', ph(async (req) => installApi.getSettingsSchema(req, router)))
240
+
241
+ const loginCollections = await util.getLoginCollections(router)
242
+
243
+ for (const { _id: name } of loginCollections) {
244
+ router.post(`/${name}/login`, ph((req) => usersApi.login(req, name)))
245
+ }
246
+
247
+ router.use(auth.middleware) // Add user id to request
248
+ router.use(permissions.middleware) // Add user and permissions to request
249
+
250
+ router.get('/status', ph(statusApi.getStatus(router)))
251
+
252
+ router.use(router.custom) // Externally added middleware
253
+
254
+ for (const { _id: name } of loginCollections) {
255
+ router.post(`/${name}/register`, ph((req) => usersApi.register(req, name)))
256
+ router.get(`/${name}/me`, ph((req) => usersApi.getMe(req, name)))
257
+ }
258
+
259
+ router.get('/:collection/schema', ph(collectionsApi.getSchema))
260
+ router.get('/:collection', ph(collectionsApi.get))
261
+ router.post('/:collection', ph(collectionsApi.insert))
262
+ router.get('/:collection/:id', ph(collectionsApi.getById))
263
+ router.put('/:collection/:id', ph(collectionsApi.replaceById))
264
+ router.post('/:collection/:id/update', ph(collectionsApi.updateById))
265
+ router.delete('/:collection/:id', ph(collectionsApi.deleteById))
266
+
267
+ // Error handler, log and send to user
268
+ // eslint-disable-next-line no-unused-vars
269
+ router.use(function safeErrorHandler(err, req, res, next) {
270
+ console.error('my err handler')
271
+ console.error(err.stack)
272
+ req.returnedError = err
273
+ res.status(res.errCode || 500)
274
+ if (process.env.DEBUG || (req.hasPermission && req.hasPermission('view errors'))) {
275
+ res.send({
276
+ error: err
277
+ })
278
+ } else {
279
+ res.send({
280
+ error: 'something wrong happened'
281
+ })
282
+ }
283
+ })
284
+ }
285
+
286
+ return router
287
+ }
288
+
289
+ module.exports.admin = function (settings) {
290
+ const router = express.Router()
291
+ router.get('/settings.js', function (req, res) {
292
+ res.set('Content-Type', 'text/javascript')
293
+ res.send('window.settings = ' + JSON.stringify(settings || {}) + '')
294
+ })
295
+ router.use(express.static(__dirname + '/modules/admin/dist'))
296
+ return router
297
+ }