Permissions refactor; create sharing API; update dependencies
This commit is contained in:
parent
b427a16601
commit
46f60a671a
@ -19,7 +19,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
||||||
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
||||||
if ( !group.accessible_by(req.user) ) return req.security.deny()
|
// if ( !group.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
const File = this.models.get('upload::File')
|
const File = this.models.get('upload::File')
|
||||||
const files = await File.find({_id: {$in: group.FileIds.map(x => ObjectId(x))}})
|
const files = await File.find({_id: {$in: group.FileIds.map(x => ObjectId(x))}})
|
||||||
@ -67,7 +67,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
||||||
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
||||||
if ( !group.accessible_by(req.user) ) return req.security.deny()
|
// if ( !group.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
if ( req.uploads.uploaded_file ) {
|
if ( req.uploads.uploaded_file ) {
|
||||||
group.FileIds.push(req.uploads.uploaded_file.id)
|
group.FileIds.push(req.uploads.uploaded_file.id)
|
||||||
@ -91,7 +91,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
||||||
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
||||||
if ( !group.accessible_by(req.user) ) return req.security.deny()
|
// if ( !group.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
if ( !group.FileIds.includes(req.params.FileId) ) {
|
if ( !group.FileIds.includes(req.params.FileId) ) {
|
||||||
return req.security.deny()
|
return req.security.deny()
|
||||||
@ -118,7 +118,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ class File extends Controller {
|
|||||||
|
|
||||||
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
const group = await FileGroup.findOne({UUID: req.params.FilesId})
|
||||||
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
if ( !group ) return res.status(404).message('Invalid file group.').api({})
|
||||||
if ( !group.accessible_by(req.user) ) return req.security.deny()
|
// if ( !group.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
await group.delete()
|
await group.delete()
|
||||||
return res.api({})
|
return res.api({})
|
||||||
|
@ -15,7 +15,7 @@ class FormCode extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class FormCode extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class FormCode extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ class FormCode extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
||||||
if ( !db.accessible_by(req.user) ) return req.security.deny()
|
// if ( !db.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
return res.api(db)
|
return res.api(db)
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
||||||
if ( !db.accessible_by(req.user) ) return req.security.deny()
|
// if ( !db.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
const columns = await ColumnDef.find({ DatabaseId: db.UUID })
|
const columns = await ColumnDef.find({ DatabaseId: db.UUID })
|
||||||
return res.api(columns)
|
return res.api(columns)
|
||||||
@ -84,7 +84,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
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 ( !db.accessible_by(req.user, 'update') ) return req.security.deny()
|
||||||
|
|
||||||
const existing_columns = await ColumnDef.find({ DatabaseId: db.UUID })
|
const existing_columns = await ColumnDef.find({ DatabaseId: db.UUID })
|
||||||
const assoc_columns = []
|
const assoc_columns = []
|
||||||
@ -136,7 +136,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
||||||
if ( !db.accessible_by(req.user) ) return req.security.deny()
|
// if ( !db.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
const entries = await DBEntry.find({DatabaseId: db.UUID})
|
const entries = await DBEntry.find({DatabaseId: db.UUID})
|
||||||
entries.forEach(entry => entry.RowData.UUID = entry.UUID)
|
entries.forEach(entry => entry.RowData.UUID = entry.UUID)
|
||||||
@ -159,7 +159,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
||||||
if ( !db.accessible_by(req.user) ) return req.security.deny()
|
// if ( !db.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
await DBEntry.deleteMany({DatabaseId: db.UUID})
|
await DBEntry.deleteMany({DatabaseId: db.UUID})
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ class FormDatabase extends Controller {
|
|||||||
|
|
||||||
let page = await Page.findOne({UUID: PageId})
|
let page = await Page.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
|
|
||||||
const NodeId = req.params.NodeId
|
const NodeId = req.params.NodeId
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ class FormDatabase extends Controller {
|
|||||||
const DatabaseId = req.params.DatabaseId
|
const DatabaseId = req.params.DatabaseId
|
||||||
const db = await Database.findOne({UUID: DatabaseId})
|
const db = await Database.findOne({UUID: DatabaseId})
|
||||||
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
if ( !db ) return res.status(404).message('Database not found with that ID.').api({})
|
||||||
if ( !db.accessible_by(req.user) ) return req.security.deny()
|
// if ( !db.accessible_by(req.user) ) return req.security.deny()
|
||||||
|
|
||||||
await DBEntry.deleteMany({DatabaseId: db.UUID})
|
await DBEntry.deleteMany({DatabaseId: db.UUID})
|
||||||
await db.delete()
|
await db.delete()
|
||||||
|
@ -11,6 +11,8 @@ class Menu extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async get_items(req, res) {
|
async get_items(req, res) {
|
||||||
|
const Page = this.models.get('api:Page')
|
||||||
|
|
||||||
// Build the "My Tree" option
|
// Build the "My Tree" option
|
||||||
const root_page = await req.user.get_root_page()
|
const root_page = await req.user.get_root_page()
|
||||||
const nodes = await this._build_menu_object(root_page)
|
const nodes = await this._build_menu_object(root_page)
|
||||||
@ -24,6 +26,53 @@ class Menu extends Controller {
|
|||||||
virtual: true,
|
virtual: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Get view only shared trees
|
||||||
|
const view_only_trees = await Page.find({ shared_users_view: req.user._id })
|
||||||
|
const view_only_nodes = []
|
||||||
|
for ( const tree of view_only_trees ) {
|
||||||
|
if ( !(await tree.is_accessible_by(req.user)) ) continue
|
||||||
|
view_only_nodes.push({
|
||||||
|
id: tree.UUID,
|
||||||
|
name: tree.Name,
|
||||||
|
children: await this._build_secure_menu_object(tree, req.user),
|
||||||
|
level: await tree.access_level_for(req.user),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get update, view shared trees
|
||||||
|
const update_trees = await Page.find({ shared_users_update: req.user._id })
|
||||||
|
const update_nodes = []
|
||||||
|
for ( const tree of update_trees ) {
|
||||||
|
if ( !(await tree.is_accessible_by(req.user)) ) continue
|
||||||
|
update_nodes.push({
|
||||||
|
id: tree.UUID,
|
||||||
|
name: tree.Name,
|
||||||
|
children: await this._build_secure_menu_object(tree, req.user),
|
||||||
|
level: await tree.access_level_for(req.user),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get update, view, manage shared trees
|
||||||
|
const manage_trees = await Page.find({ shared_users_manage: req.user._id })
|
||||||
|
const manage_nodes = []
|
||||||
|
for ( const tree of manage_trees ) {
|
||||||
|
if ( !(await tree.is_accessible_by(req.user)) ) continue
|
||||||
|
manage_nodes.push({
|
||||||
|
id: tree.UUID,
|
||||||
|
name: tree.Name,
|
||||||
|
children: await this._build_secure_menu_object(tree, req.user),
|
||||||
|
level: await tree.access_level_for(req.user),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.push({
|
||||||
|
id: 0,
|
||||||
|
name: 'Trees Shared With Me',
|
||||||
|
children: [...view_only_nodes, ...update_nodes, ...manage_nodes],
|
||||||
|
noDelete: true,
|
||||||
|
virtual: true,
|
||||||
|
})
|
||||||
|
|
||||||
return res.api(menu)
|
return res.api(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +82,8 @@ class Menu extends Controller {
|
|||||||
for ( const child of children ) {
|
for ( const child of children ) {
|
||||||
arr.push({
|
arr.push({
|
||||||
id: child.UUID,
|
id: child.UUID,
|
||||||
name: child.Name,
|
name: child.is_shared() ? child.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : child.Name,
|
||||||
|
shared: child.is_shared(),
|
||||||
children: await this._build_menu_object(child),
|
children: await this._build_menu_object(child),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -42,6 +92,22 @@ class Menu extends Controller {
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _build_secure_menu_object(parent_node, user, arr = []) {
|
||||||
|
const children = await parent_node.childPages
|
||||||
|
if ( children ) {
|
||||||
|
for ( const child of children ) {
|
||||||
|
if ( !(await child.is_accessible_by(user)) ) continue
|
||||||
|
arr.push({
|
||||||
|
id: child.UUID,
|
||||||
|
name: child.Name,
|
||||||
|
children: await this._build_secure_menu_object(child, user),
|
||||||
|
level: await child.access_level_for(user),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = exports = Menu
|
module.exports = exports = Menu
|
||||||
|
@ -14,7 +14,9 @@ class Page extends Controller {
|
|||||||
|
|
||||||
const page = await PageModel.findOne({UUID: PageId})
|
const page = await PageModel.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(user) ) return req.security.deny()
|
|
||||||
|
if ( !(await page.is_accessible_by(user)) ) return req.security.deny()
|
||||||
|
page.level = await page.access_level_for(req.user)
|
||||||
|
|
||||||
return res.api(page)
|
return res.api(page)
|
||||||
}
|
}
|
||||||
@ -26,7 +28,7 @@ class Page extends Controller {
|
|||||||
if ( PageId ) {
|
if ( PageId ) {
|
||||||
page = await PageModel.findOne({UUID: PageId})
|
page = await PageModel.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user, 'update') ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
} else {
|
} else {
|
||||||
page = new PageModel
|
page = new PageModel
|
||||||
page.CreatedUserId = req.user.id
|
page.CreatedUserId = req.user.id
|
||||||
@ -44,13 +46,13 @@ class Page extends Controller {
|
|||||||
page.IsVisibleInMenu = !!req.body.IsVisibleInMenu
|
page.IsVisibleInMenu = !!req.body.IsVisibleInMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent;
|
/*let parent;
|
||||||
if ( !req.body.ParentId ) return res.status(400).message('Missing required: ParentId').api({})
|
if ( !req.body.ParentId ) return res.status(400).message('Missing required: ParentId').api({})
|
||||||
else {
|
else {
|
||||||
parent = await PageModel.findOne({UUID: req.body.ParentId})
|
parent = await PageModel.findOne({UUID: req.body.ParentId})
|
||||||
if ( !parent ) return res.status(404).message('Parent page not found with that ID.').api({})
|
if ( !parent ) return res.status(404).message('Parent page not found with that ID.').api({})
|
||||||
if ( !parent.accessible_by(req.user, 'update') ) return req.security.kickout()
|
if ( !(await parent.is_accessible_by(req.user, 'update')) ) return req.security.kickout()
|
||||||
}
|
}*/ // TODO re-implement this to account for sharing
|
||||||
|
|
||||||
page.UpdatedAt = new Date
|
page.UpdatedAt = new Date
|
||||||
page.UpdateUserId = req.user._id
|
page.UpdateUserId = req.user._id
|
||||||
@ -66,7 +68,7 @@ class Page extends Controller {
|
|||||||
if ( PageId ) {
|
if ( PageId ) {
|
||||||
page = await PageModel.findOne({UUID: PageId})
|
page = await PageModel.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user) ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user)) ) return req.security.deny()
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = await Node.find({PageId: page.UUID});
|
const nodes = await Node.find({PageId: page.UUID});
|
||||||
@ -89,7 +91,7 @@ class Page extends Controller {
|
|||||||
if ( PageId ) {
|
if ( PageId ) {
|
||||||
page = await PageModel.findOne({UUID: PageId})
|
page = await PageModel.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user, 'update') ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'update')) ) return req.security.deny()
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = await Node.find({PageId: page.UUID})
|
const nodes = await Node.find({PageId: page.UUID})
|
||||||
@ -204,7 +206,7 @@ class Page extends Controller {
|
|||||||
const parent = await PageModel.findOne({UUID: req.body.parentId})
|
const parent = await PageModel.findOne({UUID: req.body.parentId})
|
||||||
if ( !parent ) {
|
if ( !parent ) {
|
||||||
return res.status(404).message('Unable to find parent with that ID.').api({})
|
return res.status(404).message('Unable to find parent with that ID.').api({})
|
||||||
} else if ( !parent.accessible_by(req.user, 'update') ) {
|
} else if ( !(await parent.is_accessible_by(req.user, 'manage')) ) {
|
||||||
return res.security.deny()
|
return res.security.deny()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +250,7 @@ class Page extends Controller {
|
|||||||
if ( PageId ) {
|
if ( PageId ) {
|
||||||
page = await PageModel.findOne({UUID: PageId})
|
page = await PageModel.findOne({UUID: PageId})
|
||||||
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
if ( !page ) return res.status(404).message('Page not found with that ID.').api({})
|
||||||
if ( !page.accessible_by(req.user, 'update') ) return req.security.deny()
|
if ( !(await page.is_accessible_by(req.user, 'manage')) ) return req.security.deny()
|
||||||
if ( page.ParentId === '0' ) return req.security.kickout()
|
if ( page.ParentId === '0' ) return req.security.kickout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
74
app/controllers/api/v1/Sharing.controller.js
Normal file
74
app/controllers/api/v1/Sharing.controller.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
const Controller = require('libflitter/controller/Controller')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sharing Controller
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* Put some description here!
|
||||||
|
*/
|
||||||
|
class Sharing extends Controller {
|
||||||
|
static get services() {
|
||||||
|
return [...super.services, 'models']
|
||||||
|
}
|
||||||
|
|
||||||
|
async share_page(req, res) {
|
||||||
|
const level = req.form.level
|
||||||
|
await req.form.page.share_with(req.form.user, level)
|
||||||
|
return res.api({})
|
||||||
|
}
|
||||||
|
|
||||||
|
async revoke_page(req, res) {
|
||||||
|
await req.form.page.unshare_with(req.form.user)
|
||||||
|
return res.api({})
|
||||||
|
}
|
||||||
|
|
||||||
|
async page_info(req, res) {
|
||||||
|
const data = {
|
||||||
|
view: (await req.form.page.view_users).map(x => {
|
||||||
|
return {username: x.uid, id: x.id, level: 'view'}
|
||||||
|
}),
|
||||||
|
update: (await req.form.page.update_users).map(x => {
|
||||||
|
return {username: x.uid, id: x.id, level: 'update'}
|
||||||
|
}),
|
||||||
|
manage: (await req.form.page.manage_users).map(x => {
|
||||||
|
return {username: x.uid, id: x.id, level: 'manage'}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.api(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_link(req, res) {
|
||||||
|
const KeyAction = this.models.get('auth:KeyAction')
|
||||||
|
const in_1_week = new Date
|
||||||
|
in_1_week.setDate(in_1_week.getDate() + 7)
|
||||||
|
|
||||||
|
const action = new KeyAction({
|
||||||
|
handler: 'controller::api:v1:Sharing.accept_link',
|
||||||
|
expires: in_1_week,
|
||||||
|
auto_login: false,
|
||||||
|
no_auto_logout: true, // THIS IS FINE. It's because the MW requires a traditional sign-in.
|
||||||
|
})
|
||||||
|
|
||||||
|
await action.save()
|
||||||
|
action.data_set('level', req.form.level)
|
||||||
|
action.data_set('PageId', req.form.page.UUID)
|
||||||
|
await action.save()
|
||||||
|
|
||||||
|
return res.api({ link: action.auth_url() })
|
||||||
|
}
|
||||||
|
|
||||||
|
async accept_link(req, res) {
|
||||||
|
if ( !req.user ) return req.security.kickout()
|
||||||
|
const Page = this.models.get('api:Page')
|
||||||
|
const PageId = req.key_action.data_get('PageId')
|
||||||
|
const level = req.key_action.data_get('level')
|
||||||
|
|
||||||
|
const page = await Page.findOne({UUID: PageId})
|
||||||
|
await page.share_with(req.user, level)
|
||||||
|
|
||||||
|
return res.redirect(`/i/editor;id=${PageId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = Sharing
|
@ -31,14 +31,24 @@ class Page extends Model {
|
|||||||
UpdateUserId: {type: String},
|
UpdateUserId: {type: String},
|
||||||
ChildPageIds: [String],
|
ChildPageIds: [String],
|
||||||
|
|
||||||
|
// Menu flags
|
||||||
noDelete: { type: Boolean, default: false },
|
noDelete: { type: Boolean, default: false },
|
||||||
virtual: { type: Boolean, default: false },
|
virtual: { type: Boolean, default: false },
|
||||||
|
|
||||||
|
// Sharing properties
|
||||||
|
shared_users_view: [ObjectId],
|
||||||
|
shared_users_update: [ObjectId],
|
||||||
|
shared_users_manage: [ObjectId],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static scopes = [new ActiveScope]
|
static scopes = [new ActiveScope]
|
||||||
|
|
||||||
// Static and instance methods can go here
|
is_shared() {
|
||||||
|
return this.shared_users_view.length > 0 || this.shared_users_update.length > 0 || this.shared_users_manage.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= RELATIONSHIPS =================
|
||||||
get user() {
|
get user() {
|
||||||
const User = this.models.get("auth:User")
|
const User = this.models.get("auth:User")
|
||||||
return this.belongs_to_one(User, "OrgUserId", "_id")
|
return this.belongs_to_one(User, "OrgUserId", "_id")
|
||||||
@ -58,8 +68,99 @@ class Page extends Model {
|
|||||||
return this.belongs_to_one(Parent, "ParentId", "UUID")
|
return this.belongs_to_one(Parent, "ParentId", "UUID")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get view_users() {
|
||||||
|
const User = this.models.get('auth:User')
|
||||||
|
return this.has_many(User, 'shared_users_view', '_id')
|
||||||
|
}
|
||||||
|
|
||||||
|
get update_users() {
|
||||||
|
const User = this.models.get('auth:User')
|
||||||
|
return this.has_many(User, 'shared_users_update', '_id')
|
||||||
|
}
|
||||||
|
|
||||||
|
get manage_users() {
|
||||||
|
const User = this.models.get('auth:User')
|
||||||
|
return this.has_many(User, 'shared_users_manage', '_id')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= SECURITY =================
|
||||||
accessible_by(user, mode = 'view') {
|
accessible_by(user, mode = 'view') {
|
||||||
return user.can(`page:${this.UUID}:${mode}`)
|
const base_access = user.can(`page:${this.UUID}:${mode}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async is_accessible_by(user, mode = 'view') {
|
||||||
|
const can_manage = user.can(`page:${this.UUID}:manage`)
|
||||||
|
const can_update = user.can(`page:${this.UUID}:update`)
|
||||||
|
const can_view = user.can(`page:${this.UUID}:view`)
|
||||||
|
const can_all = user.can(`page:${this.UUID}`)
|
||||||
|
|
||||||
|
// Allow universal access
|
||||||
|
if ( can_all ) return true
|
||||||
|
// deny if blocked
|
||||||
|
else if ( user.can(`page:${this.UUID}:block`) ) return false
|
||||||
|
// manage, update, view can view
|
||||||
|
else if ( mode === 'view' && (can_manage || can_update || can_view) ) return true
|
||||||
|
// manage, update can update
|
||||||
|
else if ( mode === 'update' ) {
|
||||||
|
if ( can_manage || can_update ) return true
|
||||||
|
// If other permissions are explicitly set for this page, use those
|
||||||
|
else if ( can_view ) return false
|
||||||
|
}
|
||||||
|
// manage can manage
|
||||||
|
else if ( mode === 'manage' ) {
|
||||||
|
if ( can_manage ) return true
|
||||||
|
// If other permissions are explicitly set for this page, use those
|
||||||
|
else if ( can_update || can_view ) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow universal access
|
||||||
|
// deny blocked users
|
||||||
|
|
||||||
|
// If there are no explicit permissions set for this node, check the parent
|
||||||
|
const parent = await this.parent
|
||||||
|
if ( parent ) return (await this.parent).is_accessible_by(user, mode)
|
||||||
|
else return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async access_level_for(user) {
|
||||||
|
if ( await this.is_accessible_by(user, 'manage') ) return 'manage'
|
||||||
|
else if ( await this.is_accessible_by(user, 'update') ) return 'update'
|
||||||
|
else if ( await this.is_accessible_by(user, 'view') ) return 'view'
|
||||||
|
else return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async share_with(user, level = 'view') {
|
||||||
|
if ( !['view', 'update', 'manage'].includes(level) ) {
|
||||||
|
throw new Error(`Invalid share level: ${level}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove existing sharing info
|
||||||
|
await this.unshare_with(user)
|
||||||
|
|
||||||
|
// Add the page to the user's permissions:
|
||||||
|
user.allow(`page:${this.UUID}:${level}`)
|
||||||
|
|
||||||
|
// Add the user to the appropriate access list
|
||||||
|
this[`shared_users_${level}`].push(user._id)
|
||||||
|
|
||||||
|
await this.save()
|
||||||
|
await user.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
async unshare_with(user) {
|
||||||
|
// Remove this page from the user's permissions
|
||||||
|
if ( user.can(`page:${this.UUID}`) ) user.disallow(`page:${this.UUID}`)
|
||||||
|
for ( const level of ['view', 'update', 'manage'] ) {
|
||||||
|
if ( user.can(`page:${this.UUID}:${level}`) ) user.disallow(`page:${this.UUID}:${level}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the user from this page's access lists
|
||||||
|
this.shared_users_view = this.shared_users_view.filter(x => String(x) !== user.id)
|
||||||
|
this.shared_users_update = this.shared_users_update.filter(x => String(x) !== user.id)
|
||||||
|
this.shared_users_manage = this.shared_users_manage.filter(x => String(x) !== user.id)
|
||||||
|
|
||||||
|
await this.save()
|
||||||
|
await user.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ const Model = require('flitter-auth/model/KeyAction')
|
|||||||
*/
|
*/
|
||||||
class KeyAction extends Model {
|
class KeyAction extends Model {
|
||||||
|
|
||||||
|
auth_url() {
|
||||||
|
return this.url().replace('auth/action/', 'auth/action/login/')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = exports = KeyAction
|
module.exports = exports = KeyAction
|
||||||
|
40
app/routing/middleware/api/PageRoute.middleware.js
Normal file
40
app/routing/middleware/api/PageRoute.middleware.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const Middleware = require('libflitter/middleware/Middleware')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PageRoute Middleware
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* Put some description here!
|
||||||
|
*/
|
||||||
|
class PageRoute extends Middleware {
|
||||||
|
static get services() {
|
||||||
|
return [...super.services, 'models']
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run the middleware test.
|
||||||
|
* This method is required by all Flitter middleware.
|
||||||
|
* It should either call the next function in the stack,
|
||||||
|
* or it should handle the response accordingly.
|
||||||
|
*/
|
||||||
|
async test(req, res, next, args = {}){
|
||||||
|
const Page = this.models.get('api:Page')
|
||||||
|
const PageId = req.form.PageId ? req.form.PageId : req.params.PageId
|
||||||
|
if ( !PageId ) return res.status(400).message(`Missing PageId.`).api({})
|
||||||
|
|
||||||
|
const level = args.level ? args.level : 'view'
|
||||||
|
const page = await Page.findOne({UUID: PageId})
|
||||||
|
|
||||||
|
if ( !page ) return res.status(404).message(`Unable to find page with that id.`).api({})
|
||||||
|
if ( !(await page.is_accessible_by(req.user, level)) ) return req.security.deny()
|
||||||
|
|
||||||
|
if ( !req.form ) req.form = {}
|
||||||
|
req.form.page = page
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the next function in the stack.
|
||||||
|
*/
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = PageRoute
|
87
app/routing/middleware/api/RequiredFields.middleware.js
Normal file
87
app/routing/middleware/api/RequiredFields.middleware.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
const Middleware = require('libflitter/middleware/Middleware')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RequiredFields Middleware
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* Put some description here!
|
||||||
|
*/
|
||||||
|
class RequiredFields extends Middleware {
|
||||||
|
static get services() {
|
||||||
|
return [...super.services, 'configs', 'output', 'utility']
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run the middleware test.
|
||||||
|
* This method is required by all Flitter middleware.
|
||||||
|
* It should either call the next function in the stack,
|
||||||
|
* or it should handle the response accordingly.
|
||||||
|
*/
|
||||||
|
async test(req, res, next, args){
|
||||||
|
// Do stuff here
|
||||||
|
const search_fields = args.search ? (Array.isArray(args.search) ? args.search : [args.search]) : ['params', 'body', 'query']
|
||||||
|
const form_config = this.configs.get('api:forms:'+args.form)
|
||||||
|
const values = {}
|
||||||
|
|
||||||
|
for ( const field in form_config.fields ) {
|
||||||
|
if ( !form_config.fields.hasOwnProperty(field) ) continue
|
||||||
|
const field_config = form_config.fields[field]
|
||||||
|
let field_value = this.get_field({ request: req, field, search_fields })
|
||||||
|
|
||||||
|
if ( !field_value ) {
|
||||||
|
if ( field_config.required ) {
|
||||||
|
return this.fail({ response: res, reason: `Missing required field: ${field}`})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( field_config.infer !== false ) {
|
||||||
|
field_value = this.utility.infer(field_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( field_config.coerce ) {
|
||||||
|
field_value = field_config.coerce(field_value)
|
||||||
|
|
||||||
|
if ( field_config.coerce === Number && isNaN(field_value) ) {
|
||||||
|
return this.fail({ response: res, reason: 'Invalid numerical value for field: '+field })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( field_config.in_set ) {
|
||||||
|
if ( Array.isArray(field_config.in_set) ) {
|
||||||
|
if ( !field_config.in_set.includes(field_value) ) {
|
||||||
|
return this.fail({ response: res, reason: `Invalid value for ${field}. Value must be one of: ${field_config.join(', ')}`})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.output.warn(`[Middleware RequiredFields] Invalid in_set for ${field} in ${args.form}. Must be array.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values[field] = field_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.form = values
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the next function in the stack.
|
||||||
|
*/
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
get_field({ request, field, search_fields }) {
|
||||||
|
for ( const search_field of search_fields ) {
|
||||||
|
if ( Object.keys(request).includes(search_field) ) {
|
||||||
|
if ( Object.keys(request[search_field]).includes(field) ) {
|
||||||
|
return request[search_field][field]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.output.warn(`[Middleware RequiredFields] Requested search of request field that does not exist: ${search_field}`)
|
||||||
|
this.output.debug(`[Middleware RequiredFields] Available request keys: ${Object.keys(request).join(', ')}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fail({ response, reason }) {
|
||||||
|
return response.status(400).message(reason).api({})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = RequiredFields
|
35
app/routing/middleware/api/UserRoute.middleware.js
Normal file
35
app/routing/middleware/api/UserRoute.middleware.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const Middleware = require('libflitter/middleware/Middleware')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UserRoute Middleware
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* Put some description here!
|
||||||
|
*/
|
||||||
|
class UserRoute extends Middleware {
|
||||||
|
static get services() {
|
||||||
|
return [...super.services, 'models']
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run the middleware test.
|
||||||
|
* This method is required by all Flitter middleware.
|
||||||
|
* It should either call the next function in the stack,
|
||||||
|
* or it should handle the response accordingly.
|
||||||
|
*/
|
||||||
|
async test(req, res, next, args = {}){
|
||||||
|
const User = this.models.get('auth:User')
|
||||||
|
const user_id = req.form.user_id ? req.form.user_id : req.params.user_id
|
||||||
|
|
||||||
|
if ( !user_id ) return res.status(400).message('Midding user_id.').api({})
|
||||||
|
|
||||||
|
const user = await User.findById(user_id)
|
||||||
|
if ( !user ) return res.status(404).message('Unable to find user with that ID.').api({})
|
||||||
|
|
||||||
|
if ( !req.form ) req.form = {}
|
||||||
|
req.form.user = user
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = UserRoute
|
@ -5,73 +5,88 @@
|
|||||||
*/
|
*/
|
||||||
const index = {
|
const index = {
|
||||||
|
|
||||||
/*
|
|
||||||
* Define the prefix applied to each of these routes.
|
|
||||||
* For example, if prefix is '/auth':
|
|
||||||
* '/' becomes '/auth'
|
|
||||||
* '/login' becomes '/auth/login'
|
|
||||||
*/
|
|
||||||
prefix: '/api/v1',
|
prefix: '/api/v1',
|
||||||
|
|
||||||
/*
|
|
||||||
* Define middleware that should be applied to all
|
|
||||||
* routes defined in this file. Middleware should be
|
|
||||||
* included using its non-prefixed canonical name.
|
|
||||||
*
|
|
||||||
* You can pass arguments along to a middleware by
|
|
||||||
* specifying it as an array where the first element
|
|
||||||
* is the canonical name of the middleware and the
|
|
||||||
* second element is the argument passed to the
|
|
||||||
* handler's exec() method.
|
|
||||||
*/
|
|
||||||
middleware: [
|
middleware: [
|
||||||
'auth:UserOnly',
|
'auth:UserOnly',
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
|
||||||
* Define GET routes.
|
|
||||||
* These routes are registered as GET methods.
|
|
||||||
* Handlers for these routes should be specified as
|
|
||||||
* an array of canonical references to controller methods
|
|
||||||
* or middleware that are applied in order.
|
|
||||||
*/
|
|
||||||
get: {
|
get: {
|
||||||
|
// Get the file ref node config for the specified file ref
|
||||||
'/files/:PageId/:NodeId/get/:FilesId': ['controller::api:v1:File.get_config'],
|
'/files/:PageId/:NodeId/get/:FilesId': ['controller::api:v1:File.get_config'],
|
||||||
|
|
||||||
|
// Download the specified file ID from the specified file ref node
|
||||||
'/files/:PageId/:NodeId/get/:FilesId/:FileId': ['controller::api:v1:File.download'],
|
'/files/:PageId/:NodeId/get/:FilesId/:FileId': ['controller::api:v1:File.download'],
|
||||||
|
|
||||||
'/hello_world': ['controller::api:v1:Misc.hello_world'],
|
// Get the data for the specified page
|
||||||
'/page/:PageId': ['controller::api:v1:Page.get_page'],
|
'/page/:PageId': ['controller::api:v1:Page.get_page'],
|
||||||
|
|
||||||
|
// Get the nodes present on the specified page
|
||||||
'/page/:PageId/nodes': ['controller::api:v1:Page.get_nodes'],
|
'/page/:PageId/nodes': ['controller::api:v1:Page.get_nodes'],
|
||||||
|
|
||||||
|
// Get the user's menu tree
|
||||||
'/menu/items': ['controller::api:v1:Menu.get_items'],
|
'/menu/items': ['controller::api:v1:Menu.get_items'],
|
||||||
|
|
||||||
|
// Get the database ref node config for the specified database
|
||||||
'/db/:PageId/:NodeId/get/:DatabaseId': ['controller::api:v1:FormDatabase.get_config'],
|
'/db/:PageId/:NodeId/get/:DatabaseId': ['controller::api:v1:FormDatabase.get_config'],
|
||||||
|
|
||||||
|
// Get the column config records for the specified database
|
||||||
'/db/:PageId/:NodeId/get/:DatabaseId/columns': [ 'controller::api:v1:FormDatabase.get_columns' ],
|
'/db/:PageId/:NodeId/get/:DatabaseId/columns': [ 'controller::api:v1:FormDatabase.get_columns' ],
|
||||||
|
|
||||||
|
// Get the row records for the specified database
|
||||||
'/db/:PageId/:NodeId/get/:DatabaseId/data': [ 'controller::api:v1:FormDatabase.get_data' ],
|
'/db/:PageId/:NodeId/get/:DatabaseId/data': [ 'controller::api:v1:FormDatabase.get_data' ],
|
||||||
|
|
||||||
|
// Get the code ref node config for the specified code editor
|
||||||
'/code/:PageId/:NodeId/get/:CodiumId': ['controller::api:v1:FormCode.get_config'],
|
'/code/:PageId/:NodeId/get/:CodiumId': ['controller::api:v1:FormCode.get_config'],
|
||||||
|
|
||||||
|
// Export the entire personal tree as HTML
|
||||||
'/data/export/html': ['controller::Export.html_export'],
|
'/data/export/html': ['controller::Export.html_export'],
|
||||||
},
|
},
|
||||||
|
|
||||||
post: {
|
post: {
|
||||||
|
// Upload the file in the 'uploaded_file' key to the specified file ref node
|
||||||
'/file/upload/:PageId/:NodeId/:FilesId': ['middleware::upload:UploadFile', 'controller::api:v1:File.save_upload'],
|
'/file/upload/:PageId/:NodeId/:FilesId': ['middleware::upload:UploadFile', 'controller::api:v1:File.save_upload'],
|
||||||
|
|
||||||
|
// Create a new file ref node
|
||||||
'/files/:PageId/:NodeId/create': ['controller::api:v1:File.create_config'],
|
'/files/:PageId/:NodeId/create': ['controller::api:v1:File.create_config'],
|
||||||
|
|
||||||
|
// Delete a file ref node and its files
|
||||||
'/files/:PageId/:NodeId/delete/:FilesId': ['controller::api:v1:File.delete_group'],
|
'/files/:PageId/:NodeId/delete/:FilesId': ['controller::api:v1:File.delete_group'],
|
||||||
|
|
||||||
|
// Save the data for the specified page
|
||||||
'/page/:PageId/save': ['controller::api:v1:Page.save_page'],
|
'/page/:PageId/save': ['controller::api:v1:Page.save_page'],
|
||||||
|
|
||||||
|
// Save the node data for the specified page
|
||||||
'/page/:PageId/nodes/save': ['controller::api:v1:Page.save_nodes'],
|
'/page/:PageId/nodes/save': ['controller::api:v1:Page.save_nodes'],
|
||||||
|
|
||||||
|
// Create a new page in the personal root
|
||||||
'/page/create': ['controller::api:v1:Page.create_top_level'],
|
'/page/create': ['controller::api:v1:Page.create_top_level'],
|
||||||
|
|
||||||
|
// Create a new page as a child of the specified page
|
||||||
'/page/create-child': ['controller::api:v1:Page.create_child'],
|
'/page/create-child': ['controller::api:v1:Page.create_child'],
|
||||||
|
|
||||||
|
// Delete the specified page
|
||||||
'/page/delete/:PageId': ['controller::api:v1:Page.delete_page'],
|
'/page/delete/:PageId': ['controller::api:v1:Page.delete_page'],
|
||||||
|
|
||||||
|
// Create a new database ref config
|
||||||
'/db/:PageId/:NodeId/create': ['controller::api:v1:FormDatabase.create_new'],
|
'/db/:PageId/:NodeId/create': ['controller::api:v1:FormDatabase.create_new'],
|
||||||
|
|
||||||
|
// Set the column configs for a database ref
|
||||||
'/db/:PageId/:NodeId/set/:DatabaseId/columns': [ 'controller::api:v1:FormDatabase.set_columns' ],
|
'/db/:PageId/:NodeId/set/:DatabaseId/columns': [ 'controller::api:v1:FormDatabase.set_columns' ],
|
||||||
|
|
||||||
|
// Delete the specified database ref
|
||||||
'/db/:PageId/:NodeId/drop/:DatabaseId': [ 'controller::api:v1:FormDatabase.drop_database' ],
|
'/db/:PageId/:NodeId/drop/:DatabaseId': [ 'controller::api:v1:FormDatabase.drop_database' ],
|
||||||
|
|
||||||
|
// Set the row data for the specified database ref
|
||||||
'/db/:PageId/:NodeId/set/:DatabaseId/data': ['controller::api:v1:FormDatabase.set_data'],
|
'/db/:PageId/:NodeId/set/:DatabaseId/data': ['controller::api:v1:FormDatabase.set_data'],
|
||||||
|
|
||||||
|
// Create a new code ref config
|
||||||
'/code/:PageId/:NodeId/create': ['controller::api:v1:FormCode.create_new'],
|
'/code/:PageId/:NodeId/create': ['controller::api:v1:FormCode.create_new'],
|
||||||
|
|
||||||
|
// Set the data for the specified code ref
|
||||||
'/code/:PageId/:NodeId/set/:CodiumId': ['controller::api:v1:FormCode.set_values'],
|
'/code/:PageId/:NodeId/set/:CodiumId': ['controller::api:v1:FormCode.set_values'],
|
||||||
|
|
||||||
|
// delete the specified code ref
|
||||||
'/code/:PageId/:NodeId/delete/:CodiumId': ['controller::api:v1:FormCode.drop_code'],
|
'/code/:PageId/:NodeId/delete/:CodiumId': ['controller::api:v1:FormCode.drop_code'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
46
app/routing/routers/api/v1/sharing.routes.js
Normal file
46
app/routing/routers/api/v1/sharing.routes.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* API v1 Routes
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* Description here
|
||||||
|
*/
|
||||||
|
const index = {
|
||||||
|
|
||||||
|
prefix: '/api/v1/share',
|
||||||
|
|
||||||
|
middleware: [
|
||||||
|
'auth:UserOnly',
|
||||||
|
],
|
||||||
|
|
||||||
|
get: {
|
||||||
|
'/page/:PageId/info': [
|
||||||
|
['middleware::api:RequiredFields', { form: 'sharing.page' }],
|
||||||
|
['middleware::api:PageRoute', {level: 'manage'}],
|
||||||
|
'controller::api:v1:Sharing.page_info',
|
||||||
|
],
|
||||||
|
'/page/:PageId/link/:level': [
|
||||||
|
['middleware::api:RequiredFields', { form: 'sharing.page_link'}],
|
||||||
|
['middleware::api:PageRoute', {level: 'manage'}],
|
||||||
|
'controller::api:v1:Sharing.get_link',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
post: {
|
||||||
|
// Share a page with the specified user.
|
||||||
|
'/page/:PageId/share': [
|
||||||
|
['middleware::api:RequiredFields', { form: 'sharing.page_level' }],
|
||||||
|
['middleware::api:PageRoute', {level: 'manage'}],
|
||||||
|
'middleware::api:UserRoute',
|
||||||
|
'controller::api:v1:Sharing.share_page',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Unshare a page with the specified user.
|
||||||
|
'/page/:PageId/revoke': [
|
||||||
|
['middleware::api:RequiredFields', { form: 'sharing.page_user' }],
|
||||||
|
['middleware::api:PageRoute', {level: 'manage'}],
|
||||||
|
'middleware::api:UserRoute',
|
||||||
|
'controller::api:v1:Sharing.revoke_page',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = index
|
@ -6,11 +6,21 @@ module.exports = exports = {
|
|||||||
'middleware::auth:KeyAction',
|
'middleware::auth:KeyAction',
|
||||||
'controller::auth:KeyAction.handle',
|
'controller::auth:KeyAction.handle',
|
||||||
],
|
],
|
||||||
|
'/login/:key': [
|
||||||
|
'middleware::auth:UserOnly',
|
||||||
|
'middleware::auth:KeyAction',
|
||||||
|
'controller::auth:KeyAction.handle',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
post: {
|
post: {
|
||||||
'/:key': [
|
'/:key': [
|
||||||
'middleware::auth:KeyAction',
|
'middleware::auth:KeyAction',
|
||||||
'controller::auth:KeyAction.handle',
|
'controller::auth:KeyAction.handle',
|
||||||
],
|
],
|
||||||
|
'/login/:key': [
|
||||||
|
'middleware::auth:UserOnly',
|
||||||
|
'middleware::auth:KeyAction',
|
||||||
|
'controller::auth:KeyAction.handle',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
55
config/api/forms/sharing.config.js
Normal file
55
config/api/forms/sharing.config.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
module.exports = exports = {
|
||||||
|
page: {
|
||||||
|
fields: {
|
||||||
|
PageId: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
page_level: {
|
||||||
|
fields: {
|
||||||
|
PageId: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
user_id: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
in_set: ['view', 'update', 'manage'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
page_link: {
|
||||||
|
fields: {
|
||||||
|
PageId: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
in_set: ['view', 'update', 'manage'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
page_user: {
|
||||||
|
fields: {
|
||||||
|
PageId: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
user_id: {
|
||||||
|
required: true,
|
||||||
|
coerce: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -22,8 +22,8 @@
|
|||||||
"flitter-di": "^0.4.1",
|
"flitter-di": "^0.4.1",
|
||||||
"flitter-flap": "^0.5.2",
|
"flitter-flap": "^0.5.2",
|
||||||
"flitter-forms": "^0.8.1",
|
"flitter-forms": "^0.8.1",
|
||||||
"flitter-orm": "^0.2.2",
|
"flitter-orm": "^0.2.4",
|
||||||
"flitter-upload": "^0.8.0",
|
"flitter-upload": "^0.8.0",
|
||||||
"libflitter": "^0.46.4"
|
"libflitter": "^0.46.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
yarn.lock
18
yarn.lock
@ -1041,10 +1041,10 @@ flitter-forms@^0.8.1:
|
|||||||
recursive-readdir "^2.2.2"
|
recursive-readdir "^2.2.2"
|
||||||
validator "^10.11.0"
|
validator "^10.11.0"
|
||||||
|
|
||||||
flitter-orm@^0.2.2:
|
flitter-orm@^0.2.4:
|
||||||
version "0.2.2"
|
version "0.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/flitter-orm/-/flitter-orm-0.2.2.tgz#b30e11c32f8467bb540a718a30824c28eb9599bd"
|
resolved "https://registry.yarnpkg.com/flitter-orm/-/flitter-orm-0.2.4.tgz#539f7631fd286955b01ce6034a0bb68142540f5d"
|
||||||
integrity sha512-zZOgbdehzYI21B6/Y0QdVlGIbFgN490TPAwB+krlCbG9Ht7ofoaokRW0WpehDiwfrNkjH+3VgexAW6gQcVhBXw==
|
integrity sha512-7yhwwzzBpPIyW4VC9nHY+Pe9pM+EFYwljYKkK1BEMy8XNk6JADhcLiwZGJmxK38vQ8D7SEdFpZiux3fB68uVnQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
flitter-di "^0.4.0"
|
flitter-di "^0.4.0"
|
||||||
json-stringify-safe "^5.0.1"
|
json-stringify-safe "^5.0.1"
|
||||||
@ -1509,10 +1509,10 @@ leven@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
|
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
|
||||||
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
|
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
|
||||||
|
|
||||||
libflitter@^0.46.4:
|
libflitter@^0.46.7:
|
||||||
version "0.46.4"
|
version "0.46.7"
|
||||||
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.46.4.tgz#ea9d59446c43eb17a4dbf14d8a13f34a1a61c8fd"
|
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.46.7.tgz#be55386a53747e1e21b2aefd356977900fd40dd1"
|
||||||
integrity sha512-rXlgH44YAkPwKWo0Qu5fKt8zrGKT4DTSQfcFhxsmJVmT+aYoQLDMXQhCk/TgpvsAL+RkGqpCP3/wIum99frraA==
|
integrity sha512-PPPEp4vR36xAvjPyxmU8K6NBv6n5ggP/bfSJU/PZ6qCChbYh0gKIN6kH88GM38imSZJxjZM1hjvzio5veIGaAw==
|
||||||
dependencies:
|
dependencies:
|
||||||
colors "^1.3.3"
|
colors "^1.3.3"
|
||||||
connect-mongodb-session "^2.2.0"
|
connect-mongodb-session "^2.2.0"
|
||||||
@ -1524,7 +1524,7 @@ libflitter@^0.46.4:
|
|||||||
express-graphql "^0.9.0"
|
express-graphql "^0.9.0"
|
||||||
express-session "^1.15.6"
|
express-session "^1.15.6"
|
||||||
flitter-di "^0.4.0"
|
flitter-di "^0.4.0"
|
||||||
flitter-orm "^0.2.2"
|
flitter-orm "^0.2.4"
|
||||||
graphql "^14.5.4"
|
graphql "^14.5.4"
|
||||||
http-status "^1.4.2"
|
http-status "^1.4.2"
|
||||||
mongo-schematic-class "^1.0.3"
|
mongo-schematic-class "^1.0.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user