rappopo-sob-marine
Version:
Rappopo Sob - Marine
151 lines (149 loc) • 5.22 kB
JavaScript
const { _, createError, toUnixPath, fg, fs, mime } = require('rappopo-sob').Helper
const context = require('rappopo-sob/lib/context')
const path = require('path')
module.exports = ({ sobr, sob }) => {
return {
settings: {
webApi: {
alias: {
'GET /:entity/:entityId': 'imageList',
'GET /:entity/:entityId/:file': 'imageGet',
'DELETE /:entity/:entityId/:file': 'imageRemove'
}
},
webRoot: {
anonymous: ['imageStream'],
alias: {
'GET /:entity/:entityId/:file': 'imageStream'
}
},
upload: {
/*
alias: {
'/:entity/:id': 'uploadImage'
}
params: {
busboyConfig: { limits: { files: 1 } }
}
*/
}
},
actions: {
upload (ctx) {
return new Promise((resolve, reject) => {
const entity = ctx.meta.$multipart.entity || ''
const entityId = ctx.meta.$multipart.entityId || ''
Promise.resolve()
.then(() => {
this.checkParams(ctx, { entity, entityId })
const action = `marine${_.upperFirst(_.camelCase(entity))}.find`
return ctx.broker.call(action, { query: { id: entityId }, limit: 1 })
})
.then(result => {
if (result.length === 0) throw createError('Entity not found', 404, { id: 'notFound' })
return context.upload(ctx, {
destDir: this.getDir(entity, entityId)
})
})
.then(resolve)
.catch(reject)
})
},
imageStream (ctx) {
return new Promise((resolve, reject) => {
const { entity, entityId, file } = ctx.params
Promise.resolve()
.then(() => {
this.checkParams(ctx, { entity, entityId, file }, true)
return fg(this.getDir(entity, entityId) + '/' + file)
})
.then(files => {
if (files.length === 0) throw createError('File not found', 404)
ctx.meta.$responseType = mime.lookup(path.basename(files[0]))
const f = fs.createReadStream(files[0])
f.on('error', err => {
throw err
})
resolve(f)
})
.catch(reject)
})
},
imageGet (ctx) {
return new Promise((resolve, reject) => {
const { entity, entityId, file } = ctx.params
Promise.resolve()
.then(() => {
this.checkParams(ctx, { entity, entityId, file }, true)
return fg(this.getDir(entity, entityId) + '/' + file)
})
.then(files => {
if (files.length === 0) throw createError('File not found', 404)
resolve(this.fileInfo(files[0]))
})
.catch(reject)
})
},
imageList (ctx) {
return new Promise((resolve, reject) => {
const { entity, entityId } = ctx.params
Promise.resolve()
.then(() => {
this.checkParams(ctx, { entity, entityId })
return fg(this.getDir(entity, entityId) + '/*')
})
.then(files => {
const result = {
page: 1,
pageSize: files.length,
total: files.length
}
result.rows = _.map(files, f => this.fileInfo(f))
resolve(result)
})
.catch(reject)
})
},
imageRemove (ctx) {
return new Promise((resolve, reject) => {
const { entity, entityId, file } = ctx.params
Promise.resolve()
.then(() => {
this.checkParams(ctx, { entity, entityId, file }, true)
return fg(this.getDir(entity, entityId) + '/' + file)
})
.then(files => {
if (files.length === 0) throw createError('File not found', 404)
_.each(files, f => {
try {
fs.unlinkSync(files[0])
} catch (err) {}
})
resolve({ msg: 'Image removed' })
})
.catch(reject)
})
}
},
methods: {
getDir (entity, entityId) {
return toUnixPath(path.join(this.broker.sobr.dataDir, 'upload', 'marineImage', entity, entityId))
},
checkParams (ctx, { entity, entityId, file }, withFile) {
if (!ctx.meta.user) throw createError('Unauthenticated', 403)
if (_.isEmpty(entity)) throw createError('Entity is required', 422, { entity: 'required' })
if (_.isEmpty(entityId)) throw createError('Entity ID is required', 422, { entityId: 'required' })
if (withFile && _.isEmpty(file)) throw createError('File is required', 422, { file: 'required' })
if (!['ship', 'organization', 'port'].includes(entity)) throw createError('Invalid entity', 422, { entity: 'invalid' })
},
fileInfo (file) {
const stats = fs.statSync(file)
return {
id: path.basename(file),
ts: stats.birthtime,
size: stats.size
}
}
}
}
}