backend/app/controllers/api/v1/FormDatabase.controller.js
garrettmills 14babd5b8b
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Track database column versions and include in database version data
2020-11-02 16:04:45 -06:00

314 lines
12 KiB
JavaScript

const Controller = require('libflitter/controller/Controller')
const Page = require('../../../models/api/Page.model')
const Node = require('../../../models/api/Node.model')
const Database = require('../../../models/api/db/Database.model')
const ColumnDef = require('../../../models/api/db/ColumnDef.model')
const DBEntry = require('../../../models/api/db/DBEntry.model')
/*
* Database Controller
* -------------------------------------------------------------
* Put some description here!
*/
class FormDatabase extends Controller {
async create_new(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 ( !(await page.is_accessible_by(req.user, 'update')) ) 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 db = new Database({
Name: req.body.name || req.body.Name || 'New Database',
NodeId: node.UUID,
PageId: page.UUID,
})
if ( req.body.UUID ) {
const existingUUID = await Database.findOne({ UUID: req.body.UUID })
if ( !existingUUID ) {
db.UUID = req.body.UUID
}
}
await db.version_save(`Added to page "${page.Name}"`, req.user.id)
req.user.allow(`database:${db.UUID}`);
await req.user.save()
return res.api(db)
}
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 ( !(await page.is_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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user) ) return req.security.deny()
return res.api(db)
}
async get_columns(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 ( !(await page.is_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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
const columns = []
for ( const col_id of db.ColumnIds ) {
const rec = await ColumnDef.findOne({UUID: col_id})
if ( rec ) {
rec.additionalData = rec.data()
columns.push(rec)
}
}
// Fallback for backwards compat
if ( columns.length < 1 ) {
return res.api((await ColumnDef.find({DatabaseId: db.UUID})).map(x => {
x.additionalData = x.data()
return x
}))
}
return res.api(columns)
}
async set_name(req, res) {
if ( !req.body.Name ) {
return res.status(400)
.message('Missing required field: Name')
.api()
}
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 ( !(await page.is_accessible_by(req.user, 'update')) ) 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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user, 'update') ) return req.security.deny()
if ( req.body.Name !== db.Name ) {
db.Name = req.body.Name
await db.version_save(`Changed database name to "${req.body.Name}"`, req.user.id)
} else {
await db.save()
}
return res.api(db)
}
async set_columns(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 ( !(await page.is_accessible_by(req.user, 'update')) ) 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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user, 'update') ) return req.security.deny()
const existing_columns = await ColumnDef.find({ DatabaseId: db.UUID })
const assoc_columns = []
existing_columns.forEach(col => assoc_columns[col.UUID] = col)
const update_columns = []
for ( const col of req.body.columns ) {
if ( col.UUID && assoc_columns[col.UUID] ) {
assoc_columns[col.UUID].headerName = col.headerName
assoc_columns[col.UUID].field = col.field
assoc_columns[col.UUID].DatabaseId = db.UUID
assoc_columns[col.UUID].Type = col.Type
assoc_columns[col.UUID].additionalData = JSON.stringify(col.additionalData)
await assoc_columns[col.UUID].version_save(`Updated in page "${page.Name}"`, req.user.id)
update_columns.push(assoc_columns[col.UUID])
} else {
const new_col = new ColumnDef({
headerName: col.headerName,
field: col.field,
DatabaseId: db.UUID,
Type: col.Type,
additionalData: JSON.stringify(col.additionalData),
})
if ( col.UUID ) {
const existingUUID = await ColumnDef.findOne({ UUID: col.UUID })
if ( !existingUUID ) {
new_col.UUID = col.UUID
}
}
await new_col.version_save(`Added to database`, req.user.id)
update_columns.push(new_col)
}
}
for ( const col of existing_columns ) {
if ( !update_columns.includes(col) ) {
await col.delete()
}
}
const new_cols = update_columns.map(x => x.UUID)
const no_updates = (new_cols.length === db.ColumnIds.length) && (new_cols.every(val => db.ColumnIds.includes(val)));
if ( !no_updates ) {
db.ColumnIds = new_cols
await db.version_save('Updated columns', req.user.id)
} else {
await db.save()
}
return res.api(update_columns)
}
async get_data(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 ( !(await page.is_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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user) ) return req.security.deny()
const entries = await DBEntry.find({DatabaseId: db.UUID})
entries.forEach(entry => entry.RowData.UUID = entry.UUID)
return res.api(entries)
}
async set_data(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 ( !(await page.is_accessible_by(req.user, 'update')) ) 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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user) ) return req.security.deny()
await DBEntry.deleteMany({DatabaseId: db.UUID})
const new_recs = []
for ( const rec of req.body ) {
const data = {DatabaseId: db.UUID}
if ( rec.UUID ) data.UUID = rec.UUID
delete rec.UUID
data.RowData = rec
const dbe = new DBEntry(data)
await dbe.save()
dbe.RowData.UUID = dbe.UUID
new_recs.push(dbe)
}
await db.version_save('Updated data', req.user.id)
return res.api(await this._set_indices(db, new_recs))
}
async drop_database(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 ( !(await page.is_accessible_by(req.user, 'update')) ) 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 DatabaseId = req.params.DatabaseId
const db = await Database.findOne({UUID: DatabaseId})
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
// if ( !db.accessible_by(req.user) ) return req.security.deny()
await DBEntry.deleteMany({DatabaseId: db.UUID})
await db.version_save('Deleted', req.user.id)
await db.delete()
return res.api({})
}
async _set_indices(db, data) {
const index_columns = await ColumnDef.find({DatabaseId: db.UUID, Type: 'index'})
for ( const col of index_columns ) {
let max_val = 0
data.forEach(row => {
const val = row.RowData[col.field]
if ( val && val > max_val ) max_val = val
});
let next_val = max_val + 1
for ( const row of data ) {
if ( !row.RowData[col.field] ) {
row.RowData[col.field] = next_val
next_val += 1
await row.save()
}
}
}
return data
}
}
module.exports = exports = FormDatabase