Add new file box API
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Garrett Mills 2021-02-04 09:19:04 -06:00
parent a59255a39b
commit 1545505c22
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
4 changed files with 326 additions and 0 deletions

View File

@ -0,0 +1,177 @@
const { Controller } = require('libflitter')
class FileBoxController extends Controller {
static get services() {
return [...super.services, 'models']
}
async create(req, res, next) {
const FileBox = this.models.get('models:files:FileBox')
if ( !req.body.name ) {
return res.message('Missing required field: name')
.status(400)
.api()
}
if ( req.body.rootUUID ) {
const root = await FileBox.findOne({
active: true,
UUID: req.body.rootUUID,
})
if ( !root || root.pageId !== req.form.page.UUID ) {
return res.status(400)
.message('Invalid rootUUID.')
.api()
}
}
if ( req.body.parentUUID ) {
if ( !req.body.rootUUID ) {
return res.status(400)
.message('File boxes with a parent MUST also have a root.')
.api()
}
const parent = await FileBox.findOne({
active: true,
UUID: req.body.parentUUID,
})
if ( !parent || parent.pageId !== req.form.page.UUID ) {
return res.status(400)
.message('Invalid parentUUID')
.api()
}
}
const box = new FileBox({
name: req.body.name,
pageId: req.form.page.UUID,
})
if ( req.body.rootUUID ) {
box.rootUUID = req.body.rootUUID
}
if ( req.body.parentUUID ) {
box.parentUUID = req.body.parentUUID
}
await box.save()
return res.api(await box.to_api())
}
async update(req, res, next) {
const FileBox = this.models.get('api:files:FileBox')
const { file_box, page } = req.form
if ( req.body.name ) {
file_box.name = req.body.name
}
if ( req.body.parentUUID && req.body.parentUUID !== file_box.parentUUID ) {
const new_parent = await FileBox.findOne({
UUID: req.body.parentUUID,
active: true,
rootUUID: file_box.rootUUID,
pageId: page.UUID,
})
if ( !new_parent || new_parent.UUID === file_box.UUID ) {
return res.status(400)
.message('Invalid parentUUID.')
.api()
}
file_box.parentUUID = new_parent.UUID
}
await file_box.save()
return res.api(await file_box.to_api())
}
async update_file(req, res, next) {
const FileBox = this.models.get('api:files:FileBox')
const { file_box, file } = req.form
if ( req.body.name ) {
file.name = req.body.name
}
if ( req.body.parentUUID && req.body.parentUUID !== file_box.UUID ) {
const new_parent = await FileBox.findOne({
active: true,
UUID: req.body.parentUUID,
rootUUID: file_box.rootUUID,
})
if ( !new_parent ) {
return res.status(400)
.message('Invalid parentUUID.')
.api()
}
file_box.fileIds = file_box.fileIds.filter(x => `${x}` !== `${file.id}`)
new_parent.fileIds.push(file.id)
await new_parent.save()
await file_box.save()
}
await file.save()
return res.api(this.file_to_api(file))
}
async upload_files(req, res, next) {
const { file_box } = req.form
// const n_files = Object.values(req.uploads).length
for ( const key in req.uploads ) {
if ( !req.uploads.hasOwnProperty(key) ) continue
if ( !key.startsWith('uploaded_file_') ) continue
file_box.fileIds.push(req.uploads[key].id)
}
await file_box.save()
return res.api()
}
async get_box(req, res, next) {
return res.api(await req.form.file_box.to_api())
}
async get_files(req, res, next) {
const { file_box, page } = req.form
const files = await file_box.files()
return res.api(files.map(x => this.file_to_api(x)))
}
async delete_box(req, res, next) {
const { file_box } = req.form
file_box.active = false;
await file_box.save()
return res.api()
}
async delete_file(req, res, next) {
const { file_box, file } = req.form
file_box.fileIds = file_box.fileIds.filter(x => `${x}` !== `${file.id}`)
await file_box.save()
return res.api()
}
file_to_api(file) {
return {
name: file.upload_name,
mime: file.mime_type,
uploaded: file.upload_date,
id: file.id,
_id: file._id,
}
}
}
module.exports = exports = FileBoxController

View File

@ -0,0 +1,53 @@
const { Model } = require('flitter-orm')
const uuid = require('uuid').v4
const { ObjectId } = require('mongodb')
class FileBoxModel extends Model {
static get schema() {
return {
UUID: { type: String, default: uuid },
name: String,
pageId: String,
parentUUID: String,
rootUUID: String,
fileIds: [String],
active: { type: Boolean, default: true },
}
}
async parent() {
return this.constructor.findOne({
UUID: this.parentUUID,
active: true,
})
}
async root() {
return this.constructor.findOne({
UUID: this.rootUUID,
active: true,
})
}
async files() {
const File = this.models.get('upload::File')
return await File.find({
_id: {
$in: this.fileIds.map(x => ObjectId(x)),
}
})
}
async to_api() {
return {
UUID: this.UUID,
name: this.name,
pageId: this.pageId,
parentUUID: this.parentUUID,
rootUUID: this.rootUUID,
fileIds: this.fileIds || [],
}
}
}
module.exports = exports = FileBoxModel

View File

@ -1,4 +1,5 @@
const { Middleware } = require('libflitter') const { Middleware } = require('libflitter')
const { ObjectId } = require('mongodb')
class DataInjectionMiddleware extends Middleware { class DataInjectionMiddleware extends Middleware {
static get services() { static get services() {
@ -103,6 +104,45 @@ class DataInjectionMiddleware extends Middleware {
req.form.file_group = file_group req.form.file_group = file_group
} }
// Try to load in the file box
if ( req.params.FileBoxId ) {
const FileBox = this.models.get('api:files:FileBox')
const file_box = await FileBox.findOne({
UUID: req.params.FileBoxId,
pageId: req.params.PageId,
active: true,
})
if ( !file_box ) {
return res.status(404)
.message('Invalid file box ID.')
.api()
}
req.form.file_box = file_box
if ( req.params.FileBoxFileId ) {
const File = this.models.get('upload::File')
if ( !file_box.fileIds.includes(req.params.FileBoxFileId) ) {
return res.status(400)
.message('Invalid file box file ID.')
.api()
}
const file = await File.findOne({
_id: ObjectId(req.params.FileBoxFileId),
})
if ( !file ) {
return res.status(400)
.message('Invalid file box file ID.')
.api()
}
req.form.file = file
}
}
return next() return next()
} }
} }

View File

@ -0,0 +1,56 @@
module.exports = exports = {
prefix: '/api/v1/file-box',
middleware: [],
get: {
'/:PageId/:FileBoxId': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'view' }],
'controller::api:v1:FileBox.get_box',
],
'/:PageId/:FileBoxId/files': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'view' }],
'controller::api:v1:FileBox.get_files',
],
},
post: {
'/:PageId/create': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
'controller::api:v1:FileBox.create',
],
'/:PageId/:FileBoxId': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
'controller::api:v1:FileBox.update',
],
'/:PageId/:FileBoxId/files': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
['middleware::upload:UploadFile', { tag: 'file_box_file' }],
'controller::api:v1:FileBox.upload_files',
],
'/:PageId/:FileBoxId/files/:FileBoxFileId': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
'controller::api:v1:FileBox.update_file',
],
},
delete: {
'/:PageId/:FileBoxId': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
'controller::api:v1:FileBox.delete_box',
],
'/:PageId/:FileBoxId/files/:FileBoxFileId': [
'middleware::auth:ApiRoute',
['middleware::api:DataInjection', { access_level: 'update' }],
'controller::api:v1:FileBox.delete_file',
],
},
}