Enable file uploader component

This commit is contained in:
garrettmills 2020-02-09 04:37:21 -06:00
parent 8714ab79f1
commit f629e6f3bd
7 changed files with 224 additions and 3 deletions

2
.gitignore vendored
View File

@ -4,7 +4,7 @@
.idea .idea
.idea/* .idea/*
uploads/*
### Node ### ### Node ###
# Logs # Logs
logs logs

View File

@ -0,0 +1,137 @@
const Controller = require('libflitter/controller/Controller')
const Page = require('../../../models/api/Page.model')
const Node = require('../../../models/api/Node.model')
const FileGroup = require('../../../models/api/FileGroup.model')
const { ObjectId } = require('mongodb')
/*
* File Controller
* -------------------------------------------------------------
* Put some description here!
*/
class File extends Controller {
static get services() {
return [...super.services, 'models']
}
async create_config(req, res) {
const PageId = req.params.PageId
let page = await Page.findOne({UUID: PageId})
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
if ( !page.accessible_by(req.user) ) return req.security.deny()
const NodeId = req.params.NodeId
let node = await Node.findOne({UUID: NodeId})
if ( !node ) return res.status(404).message('Node not found with that ID.').api({})
const group = new FileGroup({
NodeId: node.UUID,
PageId: page.UUID,
FileIds: [],
})
await group.save()
req.user.allow(`files:${group.UUID}`)
await req.user.save()
return res.api(group)
}
async get_config(req, res) {
const PageId = req.params.PageId
let page = await Page.findOne({UUID: PageId})
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
if ( !page.accessible_by(req.user) ) return req.security.deny()
const NodeId = req.params.NodeId
let node = await Node.findOne({UUID: NodeId})
if ( !node ) return res.status(404).message('Node not found with that ID.').api({})
const group = await FileGroup.findOne({UUID: req.params.FilesId})
if ( !group ) return res.status(404).message('Invalid file group.').api({})
if ( !group.accessible_by(req.user) ) return req.security.deny()
const File = this.models.get('upload::File')
const files = await File.find({_id: {$in: group.FileIds.map(x => ObjectId(x))}})
group.files = files
return res.api(group)
}
async save_upload(req, res) {
const PageId = req.params.PageId
let page = await Page.findOne({UUID: PageId})
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
if ( !page.accessible_by(req.user) ) return req.security.deny()
const NodeId = req.params.NodeId
let node = await Node.findOne({UUID: NodeId})
if ( !node ) return res.status(404).message('Node not found with that ID.').api({})
const group = await FileGroup.findOne({UUID: req.params.FilesId})
if ( !group ) return res.status(404).message('Invalid file group.').api({})
if ( !group.accessible_by(req.user) ) return req.security.deny()
if ( req.uploads.uploaded_file ) {
group.FileIds.push(req.uploads.uploaded_file.id)
}
await group.save()
return res.redirect('/')
}
async download(req, res) {
const PageId = req.params.PageId
let page = await Page.findOne({UUID: PageId})
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
if ( !page.accessible_by(req.user) ) return req.security.deny()
const NodeId = req.params.NodeId
let node = await Node.findOne({UUID: NodeId})
if ( !node ) return res.status(404).message('Node not found with that ID.').api({})
const group = await FileGroup.findOne({UUID: req.params.FilesId})
if ( !group ) return res.status(404).message('Invalid file group.').api({})
if ( !group.accessible_by(req.user) ) return req.security.deny()
if ( !group.FileIds.includes(req.params.FileId) ) {
return req.security.deny()
}
const File = this.models.get('upload::File')
const file = await File.findOne({_id: ObjectId(req.params.FileId)})
if ( !file ) return res.status(404).api({})
return file.send(res)
}
async delete_group(req, res) {
const PageId = req.params.PageId
let page = await Page.findOne({UUID: PageId})
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
if ( !page.accessible_by(req.user) ) return req.security.deny()
const NodeId = req.params.NodeId
let node = await Node.findOne({UUID: NodeId})
if ( !node ) return res.status(404).message('Node not found with that ID.').api({})
const group = await FileGroup.findOne({UUID: req.params.FilesId})
if ( !group ) return res.status(404).message('Invalid file group.').api({})
if ( !group.accessible_by(req.user) ) return req.security.deny()
await group.delete()
return res.api({})
}
}
module.exports = exports = File

View File

@ -0,0 +1,27 @@
const Model = require('flitter-orm/src/model/Model')
const uuid = require('uuid/v4')
/*
* FileGroup Model
* -------------------------------------------------------------
* Put some description here!
*/
class FileGroup extends Model {
static get schema() {
// Return a flitter-orm schema here.
return {
NodeId: String,
PageId: String,
FileIds: [String],
UUID: {type: String, default: () => uuid()}
}
}
accessible_by(user, mode = 'view') {
return user.can(`files:${this.UUID}:${mode}`)
}
// Static and instance methods can go here
}
module.exports = exports = FileGroup

View File

@ -0,0 +1,12 @@
const Middleware = require('flitter-upload/middleware/UploadFile')
/*
* Middleware to upload the files included in the request
* to the default file store backend. Stores instances of
* the "upload::File" model in "request.uploads".
*/
class UploadFile extends Middleware {
}
module.exports = exports = UploadFile

View File

@ -36,6 +36,9 @@ const index = {
* or middleware that are applied in order. * or middleware that are applied in order.
*/ */
get: { get: {
'/files/:PageId/:NodeId/get/:FilesId': ['controller::api:v1:File.get_config'],
'/files/:PageId/:NodeId/get/:FilesId/:FileId': ['controller::api:v1:File.download'],
'/hello_world': ['controller::api:v1:Misc.hello_world'], '/hello_world': ['controller::api:v1:Misc.hello_world'],
'/page/:PageId': ['controller::api:v1:Page.get_page'], '/page/:PageId': ['controller::api:v1:Page.get_page'],
'/page/:PageId/nodes': ['controller::api:v1:Page.get_nodes'], '/page/:PageId/nodes': ['controller::api:v1:Page.get_nodes'],
@ -49,6 +52,11 @@ const index = {
}, },
post: { post: {
'/file/upload/:PageId/:NodeId/:FilesId': ['middleware::upload:UploadFile', 'controller::api:v1:File.save_upload'],
'/files/:PageId/:NodeId/create': ['controller::api:v1:File.create_config'],
'/files/:PageId/:NodeId/delete/:FilesId': ['controller::api:v1:File.delete_group'],
'/page/:PageId/save': ['controller::api:v1:Page.save_page'], '/page/:PageId/save': ['controller::api:v1:Page.save_page'],
'/page/:PageId/nodes/save': ['controller::api:v1:Page.save_nodes'], '/page/:PageId/nodes/save': ['controller::api:v1:Page.save_nodes'],
'/page/create': ['controller::api:v1:Page.create_top_level'], '/page/create': ['controller::api:v1:Page.create_top_level'],

View File

@ -34,6 +34,7 @@ const server_config = {
uploads: { uploads: {
enable: true,
/* /*
* Used by flitter-upload. Path for uploaded files. * Used by flitter-upload. Path for uploaded files.
* Should be relative to the application root. * Should be relative to the application root.

36
config/upload.config.js Normal file
View File

@ -0,0 +1,36 @@
/*
* flitter-upload configuration
* ---------------------------------------------------------------
* Specifies the configuration for various uploader aspects. Mainly,
* contains the configuration for the different file upload backends.
*/
const upload_config = {
/*
* The name of the upload backend to use by default.
*/
default_store: 'flitter',
enabled: true,
/*
* Stores available to the uploader.
*/
stores: {
/*
* Example of the basic, filesystem-backed uploader.
* The name of the store is arbitrary. Here, it's called 'flitter'.
*/
flitter: {
enabled: true,
// This is a filesystem backed 'FlitterStore'
type: 'FlitterStore',
// Destination for uploaded files. Will be relative to the root
// path of the application.
destination: './uploads',
},
},
}
module.exports = exports = upload_config