268 lines
9.5 KiB
JavaScript
268 lines
9.5 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(req.user, root_page, [], page_only)
|
|
const menu = []
|
|
|
|
if ( req.user.preferences?.bookmark_page_ids?.length ) {
|
|
menu.push({
|
|
id: 0,
|
|
name: 'My Bookmarks',
|
|
children: await this.get_bookmarks(req.user),
|
|
noDelete: true,
|
|
noChildren: true,
|
|
virtual: true,
|
|
type: PageType.Branch,
|
|
})
|
|
}
|
|
|
|
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(req.user, root_page, [], page_only)
|
|
const menu = []
|
|
|
|
if ( req.user.preferences?.bookmark_page_ids?.length ) {
|
|
menu.push({
|
|
id: 0,
|
|
name: 'My Bookmarks',
|
|
children: await this.get_bookmarks(req.user),
|
|
noDelete: true,
|
|
noChildren: true,
|
|
virtual: true,
|
|
type: PageType.Branch,
|
|
})
|
|
}
|
|
|
|
menu.push({
|
|
id: 0,
|
|
name: 'My Info Tree',
|
|
children: nodes,
|
|
noDelete: true,
|
|
noChildren: true,
|
|
virtual: true,
|
|
type: PageType.Branch,
|
|
userRootPage: 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),
|
|
type: tree.PageType || PageType.Note,
|
|
bookmark: (req.user.preferences.bookmark_page_ids || []).includes(tree.UUID),
|
|
})
|
|
}
|
|
|
|
// 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,
|
|
bookmark: (req.user.preferences.bookmark_page_ids || []).includes(tree.UUID),
|
|
})
|
|
}
|
|
|
|
// 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,
|
|
bookmark: (req.user.preferences.bookmark_page_ids || []).includes(tree.UUID),
|
|
})
|
|
}
|
|
|
|
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 get_bookmarks(user) {
|
|
const pages = await user.get_bookmarked_pages()
|
|
const items = []
|
|
|
|
for ( const page of pages ) {
|
|
items.push({
|
|
id: page.UUID,
|
|
name: page.is_shared() ? page.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : page.Name,
|
|
shared: page.is_shared(),
|
|
bookmark: true,
|
|
type: page.PageType || PageType.Note,
|
|
children: [],
|
|
})
|
|
}
|
|
|
|
return items
|
|
}
|
|
|
|
async move_node(req, res, next) {
|
|
const Page = this.models.get('api:Page');
|
|
|
|
if ( !req.body.MovedPageId ) {
|
|
return res.status(400)
|
|
.message('Missing MovedPageId.')
|
|
.api()
|
|
}
|
|
|
|
if ( !req.body.ParentPageId && req.body.ParentPageId !== 0 ) {
|
|
return res.status(400)
|
|
.message('Missing ParentPageId.')
|
|
.api()
|
|
}
|
|
|
|
const moved_page = await Page.findOne({ UUID: req.body.MovedPageId, Active: true })
|
|
if ( !moved_page || !(await moved_page.is_accessible_by(req.user, 'manage')) ) {
|
|
return res.status(400)
|
|
.message('You do not have permission to move this page.')
|
|
.api()
|
|
}
|
|
|
|
const parent_page = req.body.ParentPageId === 0 ? await req.user.get_root_page()
|
|
: await Page.findOne({ UUID: req.body.ParentPageId, Active: true })
|
|
|
|
if ( !parent_page || !(await parent_page.is_accessible_by(req.user, 'manage')) ) {
|
|
return res.status(400)
|
|
.message('You do not have permission to move into that page.')
|
|
.api()
|
|
}
|
|
|
|
// For now, disallow moving pages between users
|
|
if ( `${moved_page.OrgUserId}` !== `${parent_page.OrgUserId}` ) {
|
|
return res.status(400)
|
|
.message('Moving pages between user accounts is not supported at this time.')
|
|
.api()
|
|
}
|
|
|
|
if ( !moved_page.ParentId || moved_page.ParentId === '0' ) {
|
|
return res.status(400)
|
|
.message('You cannot move a root page node.')
|
|
.api()
|
|
}
|
|
|
|
const old_parent = await moved_page.parent
|
|
moved_page.ParentId = parent_page.UUID;
|
|
old_parent.ChildPageIds = old_parent.ChildPageIds.filter(x => x !== moved_page.UUID);
|
|
parent_page.ChildPageIds.push(moved_page.UUID);
|
|
|
|
await parent_page.save();
|
|
await moved_page.save();
|
|
await old_parent.save();
|
|
return res.api();
|
|
}
|
|
|
|
async _build_menu_object(user, 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(user, child, [], page_only))],
|
|
type: child.PageType || PageType.Note,
|
|
bookmark: (user.preferences.bookmark_page_ids || []).includes(child.UUID),
|
|
})
|
|
}
|
|
}
|
|
|
|
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,
|
|
bookmark: (user.preferences.bookmark_page_ids || []).includes(child.UUID),
|
|
})
|
|
}
|
|
}
|
|
return arr
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = exports = Menu
|