backend/app/controllers/api/v1/Menu.controller.js
garrettmills 97b4bf662c
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Add ability to fetch menu items for a virtual root
2020-11-23 10:57:32 -06:00

165 lines
5.7 KiB
JavaScript

const Controller = require('libflitter/controller/Controller')
const { PageType } = require('../../../enum')
/*
* Menu Controller
* -------------------------------------------------------------
* Put some description here!
*/
class Menu extends Controller {
static get services() {
return [...super.services, 'models']
}
async get_items(req, res) {
const virtual_root = req.query.virtualRootPageId
const Page = this.models.get('api:Page')
const page_only = req.query.type === 'page'
if ( !virtual_root ) {
return this.get_top_level_menu(req, res);
} else {
const root_page = await Page.findOne({ UUID: virtual_root })
if ( !root_page || !(await root_page.is_accessible_by(req.user, 'view')) ) {
return res.status(404)
.message('Invalid virtual root page ID.')
.api()
}
const nodes = await this._build_menu_object(root_page, [], page_only)
const menu = []
const virtual_page = {
id: root_page.UUID,
children: [...(await root_page.get_menu_items(page_only)), ...nodes],
name: root_page.is_shared() ? root_page.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : root_page.Name,
shared: root_page.is_shared(),
type: PageType.Note,
};
menu.push({
id: 0,
name: 'Virtual Tree Root',
children: [virtual_page],
noDelete: true,
noChildren: true,
virtual: true,
type: PageType.Branch,
})
return res.api(menu)
}
}
async get_top_level_menu(req, res) {
const Page = this.models.get('api:Page')
const page_only = req.query.type === 'page'
// Build the "My Tree" option
const root_page = await req.user.get_root_page()
const nodes = await this._build_menu_object(root_page, [], page_only)
const menu = []
menu.push({
id: 0,
name: 'My Info Tree',
children: nodes,
noDelete: true,
noChildren: true,
virtual: true,
type: PageType.Branch,
})
// 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),
type: tree.PageType || PageType.Note,
})
}
// 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),
type: tree.PageType || PageType.Note,
})
}
// 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),
type: tree.PageType || PageType.Note,
})
}
menu.push({
id: 0,
name: 'Trees Shared With Me',
children: [...view_only_nodes, ...update_nodes, ...manage_nodes],
noDelete: true,
noChildren: true,
virtual: true,
type: PageType.Branch,
})
return res.api(menu)
}
async _build_menu_object(parent_node, arr= [], page_only = false) {
const children = await this.models.get('api:Page').find({UUID: {$in: parent_node.ChildPageIds}})
if ( children ) {
for ( const child of children ) {
arr.push({
id: child.UUID,
name: child.is_shared() ? child.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : child.Name,
shared: child.is_shared(),
children: [...(await child.get_menu_items(page_only)), ...(await this._build_menu_object(child, [], page_only))],
type: child.PageType || PageType.Note,
})
}
}
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),
type: child.PageType || PageType.Note,
})
}
}
return arr
}
}
module.exports = exports = Menu