expressa 2.0.24 → 2.1.1
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/auth/index.js +81 -76
- package/index.js +314 -304
- package/modules/admin/dist/index.html +1 -1
- package/modules/admin/dist/static/js/{app.2dd732d9.js → app.4f835176.js} +2 -2
- package/modules/admin/dist/static/js/{app.2dd732d9.js.gz → app.4f835176.js.gz} +0 -0
- package/package.json +1 -1
- package/.vscode/launch.json +0 -19
- /package/modules/admin/dist/static/js/{197.36982650.js → 197.f9e1ba84.js} +0 -0
- /package/modules/admin/dist/static/js/{197.36982650.js.gz → 197.f9e1ba84.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{311.25e842dc.js → 311.ca6d5976.js} +0 -0
- /package/modules/admin/dist/static/js/{311.25e842dc.js.gz → 311.ca6d5976.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{430.53aea612.js → 430.86219146.js} +0 -0
- /package/modules/admin/dist/static/js/{430.53aea612.js.gz → 430.86219146.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{451.9f6dcdb1.js → 451.5e934bb6.js} +0 -0
- /package/modules/admin/dist/static/js/{451.9f6dcdb1.js.gz → 451.5e934bb6.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{460.351dad91.js → 460.b54cbaab.js} +0 -0
- /package/modules/admin/dist/static/js/{460.351dad91.js.gz → 460.b54cbaab.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{550.87e54b29.js → 550.938e8b79.js} +0 -0
- /package/modules/admin/dist/static/js/{550.87e54b29.js.gz → 550.938e8b79.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{569.52dba3a7.js → 569.128a8e27.js} +0 -0
- /package/modules/admin/dist/static/js/{569.52dba3a7.js.gz → 569.128a8e27.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{572.296cfd3b.js → 572.b3b13b2d.js} +0 -0
- /package/modules/admin/dist/static/js/{572.296cfd3b.js.gz → 572.b3b13b2d.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{603.98d5f5d9.js → 603.dc05e481.js} +0 -0
- /package/modules/admin/dist/static/js/{603.98d5f5d9.js.gz → 603.dc05e481.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{651.6dca6fbe.js → 651.29b10271.js} +0 -0
- /package/modules/admin/dist/static/js/{651.6dca6fbe.js.gz → 651.29b10271.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{653.0dff78dc.js → 653.9b512bd1.js} +0 -0
- /package/modules/admin/dist/static/js/{653.0dff78dc.js.gz → 653.9b512bd1.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{750.6877a6b8.js → 750.0b1c247a.js} +0 -0
- /package/modules/admin/dist/static/js/{750.6877a6b8.js.gz → 750.0b1c247a.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{950.4f40455a.js → 950.fe12a66b.js} +0 -0
- /package/modules/admin/dist/static/js/{950.4f40455a.js.gz → 950.fe12a66b.js.gz} +0 -0
- /package/modules/admin/dist/static/js/{app.2dd732d9.js.LICENSE.txt → app.4f835176.js.LICENSE.txt} +0 -0
- /package/modules/admin/dist/static/js/{app.2dd732d9.js.LICENSE.txt.gz → app.4f835176.js.LICENSE.txt.gz} +0 -0
package/index.js
CHANGED
|
@@ -1,304 +1,314 @@
|
|
|
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
|
-
|
|
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: (req) => {
|
|
219
|
-
const contentType = req.headers['content-type'] || ''
|
|
220
|
-
// Don't parse any multipart/* content - body-parser can't handle these
|
|
221
|
-
if (contentType.startsWith('multipart/')) {
|
|
222
|
-
return false
|
|
223
|
-
}
|
|
224
|
-
return true
|
|
225
|
-
},
|
|
226
|
-
limit: router.settings.body_limit || '1mb',
|
|
227
|
-
}))
|
|
228
|
-
|
|
229
|
-
router.use(function attachVariablesToReq(req, res, next) {
|
|
230
|
-
req.settings = router.settings
|
|
231
|
-
req.eventListeners = router.eventListeners
|
|
232
|
-
req.db = router.db
|
|
233
|
-
req.modules = router.modules
|
|
234
|
-
req.setupCollectionDb = router.setupCollectionDb
|
|
235
|
-
req.getSetting = router.getSetting
|
|
236
|
-
req.requestId = randomstring.generate(12)
|
|
237
|
-
res.header('X-Request-ID', req.requestId)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
router.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
router.get('
|
|
268
|
-
|
|
269
|
-
router.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
router.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return router
|
|
304
|
-
}
|
|
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
|
+
...auth.getTokenError(req)
|
|
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: (req) => {
|
|
219
|
+
const contentType = req.headers['content-type'] || ''
|
|
220
|
+
// Don't parse any multipart/* content - body-parser can't handle these
|
|
221
|
+
if (contentType.startsWith('multipart/')) {
|
|
222
|
+
return false
|
|
223
|
+
}
|
|
224
|
+
return true
|
|
225
|
+
},
|
|
226
|
+
limit: router.settings.body_limit || '1mb',
|
|
227
|
+
}))
|
|
228
|
+
|
|
229
|
+
router.use(function attachVariablesToReq(req, res, next) {
|
|
230
|
+
req.settings = router.settings
|
|
231
|
+
req.eventListeners = router.eventListeners
|
|
232
|
+
req.db = router.db
|
|
233
|
+
req.modules = router.modules
|
|
234
|
+
req.setupCollectionDb = router.setupCollectionDb
|
|
235
|
+
req.getSetting = router.getSetting
|
|
236
|
+
req.requestId = randomstring.generate(12)
|
|
237
|
+
res.header('X-Request-ID', req.requestId)
|
|
238
|
+
|
|
239
|
+
// Token error helpers for custom endpoints
|
|
240
|
+
req.getTokenError = () => auth.getTokenError(req)
|
|
241
|
+
res.sendApiError = function (status, message) {
|
|
242
|
+
return this.status(status).send({
|
|
243
|
+
error: message,
|
|
244
|
+
...auth.getTokenError(req)
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
next()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
router.use(loggingMiddleware)
|
|
252
|
+
|
|
253
|
+
router.notify = util.notify
|
|
254
|
+
|
|
255
|
+
router.post('/install', ph(async (req) => installApi.install(req, router)))
|
|
256
|
+
router.get('/install/settings/schema', ph(async (req) => installApi.getSettingsSchema(req, router)))
|
|
257
|
+
|
|
258
|
+
const loginCollections = await util.getLoginCollections(router)
|
|
259
|
+
|
|
260
|
+
for (const { _id: name } of loginCollections) {
|
|
261
|
+
router.post(`/${name}/login`, ph((req) => usersApi.login(req, name)))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
router.use(auth.middleware) // Add user id to request
|
|
265
|
+
router.use(permissions.middleware) // Add user and permissions to request
|
|
266
|
+
|
|
267
|
+
router.get('/status', ph(statusApi.getStatus(router)))
|
|
268
|
+
|
|
269
|
+
router.use(router.custom) // Externally added middleware
|
|
270
|
+
|
|
271
|
+
for (const { _id: name } of loginCollections) {
|
|
272
|
+
router.post(`/${name}/register`, ph((req) => usersApi.register(req, name)))
|
|
273
|
+
router.get(`/${name}/me`, ph((req) => usersApi.getMe(req, name)))
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
router.get('/:collection/schema', ph(collectionsApi.getSchema))
|
|
277
|
+
router.get('/:collection', ph(collectionsApi.get))
|
|
278
|
+
router.post('/:collection', ph(collectionsApi.insert))
|
|
279
|
+
router.get('/:collection/:id', ph(collectionsApi.getById))
|
|
280
|
+
router.put('/:collection/:id', ph(collectionsApi.replaceById))
|
|
281
|
+
router.post('/:collection/:id/update', ph(collectionsApi.updateById))
|
|
282
|
+
router.delete('/:collection/:id', ph(collectionsApi.deleteById))
|
|
283
|
+
|
|
284
|
+
// Error handler, log and send to user
|
|
285
|
+
// eslint-disable-next-line no-unused-vars
|
|
286
|
+
router.use(function safeErrorHandler(err, req, res, next) {
|
|
287
|
+
console.error('my err handler')
|
|
288
|
+
console.error(err.stack)
|
|
289
|
+
req.returnedError = err
|
|
290
|
+
res.status(res.errCode || 500)
|
|
291
|
+
if (process.env.DEBUG || (req.hasPermission && req.hasPermission('view errors'))) {
|
|
292
|
+
res.send({
|
|
293
|
+
error: err
|
|
294
|
+
})
|
|
295
|
+
} else {
|
|
296
|
+
res.send({
|
|
297
|
+
error: 'something wrong happened'
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return router
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
module.exports.admin = function (settings) {
|
|
307
|
+
const router = express.Router()
|
|
308
|
+
router.get('/settings.js', function (req, res) {
|
|
309
|
+
res.set('Content-Type', 'text/javascript')
|
|
310
|
+
res.send('window.settings = ' + JSON.stringify(settings || {}) + '')
|
|
311
|
+
})
|
|
312
|
+
router.use(express.static(__dirname + '/modules/admin/dist'))
|
|
313
|
+
return router
|
|
314
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js></script><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js></script><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet><script src=settings.js></script><title>Expressa Admin</title><link rel=icon href=/admin/favicon.ico><link href=/admin/css/app.1c3232a3.css rel=stylesheet></head><body><div id=app></div><script src=/admin/static/js/app.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js></script><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js></script><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet><script src=settings.js></script><title>Expressa Admin</title><link rel=icon href=/admin/favicon.ico><link href=/admin/css/app.1c3232a3.css rel=stylesheet></head><body><div id=app></div><script src=/admin/static/js/app.4f835176.js></script></body></html>
|