Commit dc3358ce authored by A. Koch's avatar A. Koch

update generic api module, improve error handling a bit

parent 4eb781a6
......@@ -136,7 +136,7 @@
},
"@types/events": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA=="
},
"@types/express": {
......@@ -182,9 +182,9 @@
"integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA=="
},
"@types/node": {
"version": "10.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.11.6.tgz",
"integrity": "sha512-fnA7yvqg3oKQDb3skBif9w5RRKVKAaeKeNuLzZL37XcSiWL4IoSXQnnbchR3UnBu2EMLHBip7ZVEkqoIVBP8QQ=="
"version": "10.12.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz",
"integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ=="
},
"@types/range-parser": {
"version": "1.2.2",
......@@ -1058,7 +1058,7 @@
},
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"resolved": "http://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"requires": {
"env-variable": "0.0.x"
......@@ -1085,7 +1085,7 @@
},
"es6-promise": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
"resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
"integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q="
},
"escape-string-regexp": {
......@@ -1344,7 +1344,7 @@
"dependencies": {
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
}
}
......@@ -1636,7 +1636,7 @@
},
"http-errors": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"requires": {
"depd": "~1.1.2",
......@@ -2230,9 +2230,9 @@
}
},
"mbjs-generic-api": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/mbjs-generic-api/-/mbjs-generic-api-0.0.16.tgz",
"integrity": "sha512-dwA1tRE8eDN+HhY+BNZuC72lZYF1gEHL5VEhTK/NXnpymbVqUxBlKJ020gb+OLm6d3AReWiqFn62VC5Z7XxnoQ==",
"version": "0.0.19",
"resolved": "https://registry.npmjs.org/mbjs-generic-api/-/mbjs-generic-api-0.0.19.tgz",
"integrity": "sha512-3Gqg8adzgzRANAeItgXSrl9PXPh+fV3H0zcXOiDaHbtEPPkNX0mAcguZA3oUME1FnRvTz4HMNnQ5KF6kp9an0A==",
"requires": {
"@polka/send-type": "^0.4.0",
"acl": "^0.4.11",
......
......@@ -38,14 +38,6 @@ module.exports.setupArchives = (api, mapService, annotationService) => {
})
})
})
api.app.get('/archives/maps/:id', async (req, res) => {
const filename = `map_archive_${req.params.id}.zip`
const filePath = path.join(os.tmpdir(), filename)
const file = fs.createReadStream(filePath)
res.setHeader('Content-Type', 'application/zip')
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`)
file.pipe(res)
})
api.app.post('/archives/maps/upload', async function (req, res) {
upload.single('file')(req, res, async () => {
const results = await exports.readArchive(req.file.path)
......@@ -126,21 +118,24 @@ module.exports.setupArchives = (api, mapService, annotationService) => {
})
}
module.exports.createArchive = async (data) => {
module.exports.createArchive = async data => {
Assert.isType(data.map, 'object', 'data.map must be object')
Assert.ok(Array.isArray(data.annotations), 'data.annotations must be array')
const
dir = path.join(os.tmpdir(), `archive_${ObjectUtil.slug(data.map.title)}_${data.map.uuid}`),
archive = new yazl.ZipFile()
const dir = path.join(os.tmpdir(), `archive_${ObjectUtil.slug(data.map.title)}_${data.map.uuid}`)
await new Promise((resolve, reject) => {
rimraf(dir, err => {
if (err) return reject(err)
if (err) {
api.captureException(err)
return reject(err)
}
resolve()
})
})
const archive = new yazl.ZipFile()
await fs.mkdir(dir)
await fs.mkdir(path.join(dir, 'maps'))
await fs.mkdir(path.join(dir, 'annotations'))
......
......@@ -13,12 +13,20 @@ class Profiles extends TinyEmitter {
this._client = new MongoDB(ObjectUtil.merge({ name: 'profiles', logger: console }, config.get('profiles.mongodb')), 'uuid')
const _this = this
this._api = api
api.app.get('/profiles/:id', (req, res) => _this.getHandler(req, res))
api.app.post('/profiles', async (req, res) => {
req.body.uuid = ObjectUtil.uuid4()
const result = await this.client.create(req.body)
let result
try {
result = await this.client.create(req.body)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
if (result) {
return _this._response(req, res, result)
}
......@@ -30,7 +38,14 @@ class Profiles extends TinyEmitter {
req.body.uuid = undefined
req.body.user = undefined
const data = req.body
let results = await this.client.find({ user: req.params.id }, req.params)
let results
try {
results = await this.client.find({ user: req.params.id }, req.params)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
if (results.length) {
data.uuid = results[0].uuid
results = await this.client.update(data.uuid, data, req.params)
......@@ -40,7 +55,14 @@ class Profiles extends TinyEmitter {
})
api.app.patch('/profiles/:id', async (req, res) => {
let results = await this.client.find({ user: req.params.id }, req.params)
let results
try {
results = await this.client.find({user: req.params.id}, req.params)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
req.body._id = undefined
req.body.uuid = undefined
req.body.user = undefined
......@@ -50,16 +72,35 @@ class Profiles extends TinyEmitter {
})
if (results.length) {
results = ObjectUtil.merge(results[0], copy)
await this.client.update(results.uuid, results, req.params)
try {
await this.client.update(results.uuid, results, req.params)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
return _this._response(req, res, results)
}
send(res, 404)
})
api.app.delete('/profiles/:id', async (req, res) => {
let results = await this.client.find({ user: req.params.id }, req.params)
let results
try {
results = await this.client.find({user: req.params.id}, req.params)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
if (results.length) {
results = await this.client.remove(results[0].uuid, req.params)
try {
results = await this.client.remove(results[0].uuid, req.params)
}
catch (err) {
api.captureException(err)
return _this._errorResponse(res, 500)
}
if (results) {
return _this._response(req, res, results)
}
......@@ -69,7 +110,14 @@ class Profiles extends TinyEmitter {
}
async getHandler (req, res) {
const results = await this._client.find({ user: req.params.id }, req.params)
let results
try {
results = await this._client.find({user: req.params.id}, req.params)
}
catch (err) {
this._api.captureException(err)
return this._errorResponse(res, 500)
}
if (results.length) {
return this._response(req, res, results[0])
}
......
......@@ -12,6 +12,7 @@ class Service extends TinyEmitter {
const _this = this
this._name = name
this._captureException = api.captureException
this._acl = api.acl
this._logger = api.logger
this._Model = model
......@@ -27,7 +28,14 @@ class Service extends TinyEmitter {
}
async findHandler (req, res) {
let results = await this._client.find(JSON.parse(req.query.query || '{}'), req.params)
let results
try {
results = await this._client.find(JSON.parse(req.query.query || '{}'), req.params)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
const userId = req.user ? req.user.uuid : 'anon'
const roles = req.user ? req.user.profile.roles : ['public']
const items = []
......@@ -39,7 +47,7 @@ class Service extends TinyEmitter {
allowed = await this._acl.areAnyRolesAllowed(roles, entry.uuid, ['get'])
}
catch (err) {
this._logger.error(`ACL error: ${err.message}`)
this._captureException(err)
}
}
if (allowed) items.push(entry)
......@@ -48,7 +56,14 @@ class Service extends TinyEmitter {
}
async getHandler (req, res) {
const result = await this.client.get(req.params.id, req.params)
let result
try {
result = await this.client.get(req.params.id, req.params)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
const roles = req.user ? req.user.profile.roles : ['public']
if (result) {
let allowed = false
......@@ -58,7 +73,7 @@ class Service extends TinyEmitter {
allowed = await this._acl.areAnyRolesAllowed(['public'].concat(roles), result.uuid, ['get'])
}
catch (err) {
this._logger.error(`ACL error: ${err.message}`)
this._captureException(err)
}
}
if (allowed) {
......@@ -75,52 +90,104 @@ class Service extends TinyEmitter {
ctx = this,
data = req.body
if (Array.isArray(data)) {
const results = await Promise.all(data.map(entry => {
return ctx.create(entry, req.params)
}))
return this._response(req, res, results)
try {
const results = await Promise.all(data.map(entry => {
return ctx.create(entry, req.params)
}))
return this._response(req, res, results)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
}
// TODO: allow for full array inserts instead just single requests
const instance = new this.ModelConstructor(data),
result = await this.client.create(instance, req.params)
instance.populate(result)
return this._response(req, res, instance)
// TODO: throw bad request error / validate input
try {
const instance = new this.ModelConstructor(data),
result = await this.client.create(instance, req.params)
instance.populate(result)
this._response(req, res, instance)
}
catch (err) {
this._captureException(err)
this._errorResponse(res, 500)
}
}
async putHandler (req, res) {
const data = req.body
let result = await this.client.get(req.params.id)
let result
try {
result = await this.client.get(req.params.id)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
if (result) {
// TODO: transactions anyone?!
if (req.user.uuid !== result.author.id) return this._errorResponse(res, 403)
data.uuid = req.params.id
let instance = new this.ModelConstructor(data, req.params.id)
await this.client.update(req.params.id, instance, req.params)
return this._response(req, res, instance)
try {
let instance = new this.ModelConstructor(data, req.params.id)
await this.client.update(req.params.id, instance, req.params)
return this._response(req, res, instance)
}
catch (err) {
this._captureException(err)
this._errorResponse(res, 500)
}
}
else return this._errorResponse(res, 404)
}
async patchHandler (req, res) {
const data = req.body
let existing = await this.client.get(req.params.id)
let existing
try {
existing = await this.client.get(req.params.id)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
if (existing) {
if (req.user.uuid !== existing.author.id) return this._errorResponse(res, 403)
let instance = new this.ModelConstructor(existing, req.params.id)
instance.populate(ObjectUtil.merge(instance.toObject(), data))
await this.client.update(req.params.id, instance, req.params)
return this._response(req, res, instance)
try {
let instance = new this.ModelConstructor(existing, req.params.id)
instance.populate(ObjectUtil.merge(instance.toObject(), data))
await this.client.update(req.params.id, instance, req.params)
return this._response(req, res, instance)
}
catch (err) {
this._captureException(err)
this._errorResponse(res, 500)
}
}
else return this._errorResponse(res, 404)
}
async deleteHandler (req, res) {
let existing = await this.client.get(req.params.id)
let existing
try {
existing = await this.client.get(req.params.id)
}
catch (err) {
this._captureException(err)
return this._errorResponse(res, 500)
}
if (existing) {
if (req.user.uuid !== existing.author.id) return this._errorResponse(res, 403)
const result = await this.client.remove(req.params.id, req.params)
if (result) {
return this._response(req, res, existing)
try {
const result = await this.client.remove(req.params.id, req.params)
if (result) {
return this._response(req, res, existing)
}
}
catch (err) {
this._captureException(err)
this._errorResponse(res, 500)
}
}
else return this._errorResponse(res, 404)
......
......@@ -9,7 +9,13 @@ const setup = async function (api, profileService) {
},
user: req.user
}
const result = await profileService.getHandler(r)
let result
try {
result = await profileService.getHandler(r)
}
catch (err) {
api.captureException(err)
}
req.user.profile = ObjectUtil.merge({}, req.user.profile, result ? result.data : undefined)
if (req.method.toLowerCase() === 'post') {
req.body.author = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment