#78 - include file boxes in page children for sidebar
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
e32d38e9b6
commit
1758340a7b
@ -11,323 +11,341 @@ const { PageType } = require('../../enum');
|
||||
* Put some description here!
|
||||
*/
|
||||
class Page extends VersionedModel {
|
||||
static get services() {
|
||||
return [...super.services, 'models'];
|
||||
}
|
||||
static get schema() {
|
||||
// Return a flitter-orm schema here.
|
||||
return {
|
||||
...super.schema,
|
||||
UUID: {type: String, default: () => uuid()},
|
||||
Name: String,
|
||||
OrgUserId: ObjectId,
|
||||
IsPublic: {type: Boolean, default: true},
|
||||
IsVisibleInMenu: {type: Boolean, default: true},
|
||||
ParentId: String,
|
||||
NodeIds: [String],
|
||||
CreatedAt: {type: Date, default: () => new Date},
|
||||
UpdatedAt: {type: Date, default: () => new Date},
|
||||
DeletedAt: Date,
|
||||
Active: {type: Boolean, default: true},
|
||||
CreatedUserId: {type: String},
|
||||
UpdateUserId: {type: String},
|
||||
ChildPageIds: [String],
|
||||
PageType: {type: String, default: PageType.Note}, // PageType
|
||||
AdditionalData: Object,
|
||||
static get services() {
|
||||
return [...super.services, 'models'];
|
||||
}
|
||||
static get schema() {
|
||||
// Return a flitter-orm schema here.
|
||||
return {
|
||||
...super.schema,
|
||||
UUID: {type: String, default: () => uuid()},
|
||||
Name: String,
|
||||
OrgUserId: ObjectId,
|
||||
IsPublic: {type: Boolean, default: true},
|
||||
IsVisibleInMenu: {type: Boolean, default: true},
|
||||
ParentId: String,
|
||||
NodeIds: [String],
|
||||
CreatedAt: {type: Date, default: () => new Date},
|
||||
UpdatedAt: {type: Date, default: () => new Date},
|
||||
DeletedAt: Date,
|
||||
Active: {type: Boolean, default: true},
|
||||
CreatedUserId: {type: String},
|
||||
UpdateUserId: {type: String},
|
||||
ChildPageIds: [String],
|
||||
PageType: {type: String, default: PageType.Note}, // PageType
|
||||
AdditionalData: Object,
|
||||
|
||||
// Menu flags
|
||||
noDelete: { type: Boolean, default: false },
|
||||
virtual: { type: Boolean, default: false },
|
||||
// Menu flags
|
||||
noDelete: { type: Boolean, default: false },
|
||||
virtual: { type: Boolean, default: false },
|
||||
|
||||
// Sharing properties
|
||||
shared_users_view: [ObjectId],
|
||||
shared_users_update: [ObjectId],
|
||||
shared_users_manage: [ObjectId],
|
||||
};
|
||||
}
|
||||
// Sharing properties
|
||||
shared_users_view: [ObjectId],
|
||||
shared_users_update: [ObjectId],
|
||||
shared_users_manage: [ObjectId],
|
||||
};
|
||||
}
|
||||
|
||||
static scopes = [new ActiveScope]
|
||||
static scopes = [new ActiveScope]
|
||||
|
||||
static async visible_by_user(user) {
|
||||
const user_root = await user.get_root_page()
|
||||
const user_root_children = await user_root.visible_flat_children(user)
|
||||
static async visible_by_user(user) {
|
||||
const user_root = await user.get_root_page()
|
||||
const user_root_children = await user_root.visible_flat_children(user)
|
||||
|
||||
const view_only_trees = await this.find({ shared_users_view: user._id })
|
||||
let view_only_children = []
|
||||
for ( const tree of view_only_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
view_only_children.push(tree)
|
||||
view_only_children = [...view_only_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
const view_only_trees = await this.find({ shared_users_view: user._id })
|
||||
let view_only_children = []
|
||||
for ( const tree of view_only_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
view_only_children.push(tree)
|
||||
view_only_children = [...view_only_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const update_trees = await this.find({ shared_users_update: user._id })
|
||||
let update_children = []
|
||||
for ( const tree of update_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
update_children.push(tree)
|
||||
update_children = [...update_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
const update_trees = await this.find({ shared_users_update: user._id })
|
||||
let update_children = []
|
||||
for ( const tree of update_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
update_children.push(tree)
|
||||
update_children = [...update_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const manage_trees = await this.find({ shared_users_manage: user._id })
|
||||
let manage_children = []
|
||||
for ( const tree of manage_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
manage_children.push(tree)
|
||||
manage_children = [...manage_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
const manage_trees = await this.find({ shared_users_manage: user._id })
|
||||
let manage_children = []
|
||||
for ( const tree of manage_trees ) {
|
||||
if ( await tree.is_accessible_by(user) ) {
|
||||
manage_children.push(tree)
|
||||
manage_children = [...manage_children, await tree.visible_flat_children(user)]
|
||||
}
|
||||
}
|
||||
|
||||
const all_children = [...user_root_children, ...view_only_children, ...update_children, ...manage_children]
|
||||
const unique_children = []
|
||||
const seen_UUIDs = []
|
||||
all_children.forEach(child => {
|
||||
if ( !seen_UUIDs.includes(child.UUID) ) {
|
||||
unique_children.push(child)
|
||||
seen_UUIDs.push(child.UUID)
|
||||
}
|
||||
})
|
||||
const all_children = [...user_root_children, ...view_only_children, ...update_children, ...manage_children]
|
||||
const unique_children = []
|
||||
const seen_UUIDs = []
|
||||
all_children.forEach(child => {
|
||||
if ( !seen_UUIDs.includes(child.UUID) ) {
|
||||
unique_children.push(child)
|
||||
seen_UUIDs.push(child.UUID)
|
||||
}
|
||||
})
|
||||
|
||||
return unique_children
|
||||
}
|
||||
return unique_children
|
||||
}
|
||||
|
||||
async visible_flat_children(user) {
|
||||
const children = await this.childPages
|
||||
let visible = []
|
||||
if ( children ) {
|
||||
for ( const child of children ) {
|
||||
if ( !(await child.is_accessible_by(user)) ) continue
|
||||
visible.push(child)
|
||||
visible = [...visible, ...(await child.visible_flat_children(user))]
|
||||
}
|
||||
}
|
||||
async visible_flat_children(user) {
|
||||
const children = await this.childPages
|
||||
let visible = []
|
||||
if ( children ) {
|
||||
for ( const child of children ) {
|
||||
if ( !(await child.is_accessible_by(user)) ) continue
|
||||
visible.push(child)
|
||||
visible = [...visible, ...(await child.visible_flat_children(user))]
|
||||
}
|
||||
}
|
||||
|
||||
return visible
|
||||
}
|
||||
return visible
|
||||
}
|
||||
|
||||
is_shared() {
|
||||
return this.shared_users_view.length > 0 || this.shared_users_update.length > 0 || this.shared_users_manage.length > 0
|
||||
}
|
||||
is_shared() {
|
||||
return this.shared_users_view.length > 0 || this.shared_users_update.length > 0 || this.shared_users_manage.length > 0
|
||||
}
|
||||
|
||||
// ================= RELATIONSHIPS =================
|
||||
get user() {
|
||||
const User = this.models.get("auth:User")
|
||||
return this.belongs_to_one(User, "OrgUserId", "_id")
|
||||
}
|
||||
// ================= RELATIONSHIPS =================
|
||||
get user() {
|
||||
const User = this.models.get("auth:User")
|
||||
return this.belongs_to_one(User, "OrgUserId", "_id")
|
||||
}
|
||||
|
||||
get nodes() {
|
||||
const Node = this.models.get("api:Node")
|
||||
const node_promise = this.has_many(Node, "NodeIds", "UUID")
|
||||
if ( this.is_a_version() ) {
|
||||
// return the nodes for this version!
|
||||
return (async () => {
|
||||
const nodes = await node_promise
|
||||
const version_data = this.raw_version_data()
|
||||
const return_nodes = []
|
||||
if ( version_data?.node_version_nums ) {
|
||||
const node_x_version_num = {}
|
||||
for ( const item of version_data.node_version_nums ) {
|
||||
node_x_version_num[item.NodeId] = item.version_num
|
||||
}
|
||||
get nodes() {
|
||||
const Node = this.models.get("api:Node")
|
||||
const node_promise = this.has_many(Node, "NodeIds", "UUID")
|
||||
if ( this.is_a_version() ) {
|
||||
// return the nodes for this version!
|
||||
return (async () => {
|
||||
const nodes = await node_promise
|
||||
const version_data = this.raw_version_data()
|
||||
const return_nodes = []
|
||||
if ( version_data?.node_version_nums ) {
|
||||
const node_x_version_num = {}
|
||||
for ( const item of version_data.node_version_nums ) {
|
||||
node_x_version_num[item.NodeId] = item.version_num
|
||||
}
|
||||
|
||||
for ( const node of nodes ) {
|
||||
if ( node_x_version_num[node.UUID] ) {
|
||||
return_nodes.push(await node.as_version(node_x_version_num[node.UUID]))
|
||||
} else {
|
||||
return_nodes.push(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( const node of nodes ) {
|
||||
if ( node_x_version_num[node.UUID] ) {
|
||||
return_nodes.push(await node.as_version(node_x_version_num[node.UUID]))
|
||||
} else {
|
||||
return_nodes.push(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return return_nodes
|
||||
})()
|
||||
} else {
|
||||
return node_promise
|
||||
}
|
||||
}
|
||||
return return_nodes
|
||||
})()
|
||||
} else {
|
||||
return node_promise
|
||||
}
|
||||
}
|
||||
|
||||
get childPages() {
|
||||
const Page = this.models.get("api:Page")
|
||||
return this.has_many(Page, "ChildPageIds", "UUID")
|
||||
}
|
||||
get childPages() {
|
||||
const Page = this.models.get("api:Page")
|
||||
return this.has_many(Page, "ChildPageIds", "UUID")
|
||||
}
|
||||
|
||||
get parent() {
|
||||
const Parent = this.models.get("api:Page")
|
||||
return this.belongs_to_one(Parent, "ParentId", "UUID")
|
||||
}
|
||||
get parent() {
|
||||
const Parent = this.models.get("api:Page")
|
||||
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 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 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')
|
||||
}
|
||||
get manage_users() {
|
||||
const User = this.models.get('auth:User')
|
||||
return this.has_many(User, 'shared_users_manage', '_id')
|
||||
}
|
||||
|
||||
// ================= SECURITY =================
|
||||
// ================= SECURITY =================
|
||||
|
||||
async is_accessible_by(user, mode = 'view') {
|
||||
const can_manage = await user.can(`page:${this.UUID}:manage`)
|
||||
const can_update = await user.can(`page:${this.UUID}:update`)
|
||||
const can_view = await user.can(`page:${this.UUID}:view`)
|
||||
const can_all = await user.can(`page:${this.UUID}`)
|
||||
async is_accessible_by(user, mode = 'view') {
|
||||
const can_manage = await user.can(`page:${this.UUID}:manage`)
|
||||
const can_update = await user.can(`page:${this.UUID}:update`)
|
||||
const can_view = await user.can(`page:${this.UUID}:view`)
|
||||
const can_all = await user.can(`page:${this.UUID}`)
|
||||
|
||||
// Allow universal access
|
||||
if ( can_all ) return true
|
||||
// deny if blocked
|
||||
else if ( await 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
|
||||
if ( can_all ) return true
|
||||
// deny if blocked
|
||||
else if ( await 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
|
||||
// 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
|
||||
}
|
||||
// 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 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}`)
|
||||
}
|
||||
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)
|
||||
// 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 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)
|
||||
// Add the user to the appropriate access list
|
||||
this[`shared_users_${level}`].push(user._id)
|
||||
|
||||
// TODO replace user.uid with name of user when we support that
|
||||
await this.version_save(`Shared with ${user.uid} (${level} access)`, user.id)
|
||||
await user.save()
|
||||
}
|
||||
// TODO replace user.uid with name of user when we support that
|
||||
await this.version_save(`Shared with ${user.uid} (${level} access)`, user.id)
|
||||
await user.save()
|
||||
}
|
||||
|
||||
async unshare_with(user) {
|
||||
// Remove this page from the user's permissions
|
||||
if ( await user.can(`page:${this.UUID}`) ) user.disallow(`page:${this.UUID}`)
|
||||
for ( const level of ['view', 'update', 'manage'] ) {
|
||||
if ( await user.can(`page:${this.UUID}:${level}`) ) user.disallow(`page:${this.UUID}:${level}`)
|
||||
}
|
||||
async unshare_with(user) {
|
||||
// Remove this page from the user's permissions
|
||||
if ( await user.can(`page:${this.UUID}`) ) user.disallow(`page:${this.UUID}`)
|
||||
for ( const level of ['view', 'update', 'manage'] ) {
|
||||
if ( await 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)
|
||||
// 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.version_save(`Unshared with ${user.uid}`, user.id)
|
||||
await user.save()
|
||||
}
|
||||
await this.version_save(`Unshared with ${user.uid}`, user.id)
|
||||
await user.save()
|
||||
}
|
||||
|
||||
async get_menu_items(page_only) {
|
||||
if ( page_only ) return [];
|
||||
async get_menu_items(page_only) {
|
||||
if ( page_only ) return [];
|
||||
|
||||
// {
|
||||
// id: child.UUID,
|
||||
// name: child.is_shared() ? child.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : child.Name,
|
||||
// shared: child.is_shared(),
|
||||
// children: await this._build_menu_object(child),
|
||||
// type: 'page',
|
||||
// }
|
||||
// {
|
||||
// id: child.UUID,
|
||||
// name: child.is_shared() ? child.Name + ' ⁽ˢʰᵃʳᵉᵈ⁾' : child.Name,
|
||||
// shared: child.is_shared(),
|
||||
// children: await this._build_menu_object(child),
|
||||
// type: 'page',
|
||||
// }
|
||||
|
||||
// Databases & Code Snips
|
||||
const children = []
|
||||
// Databases & Code Snips
|
||||
const children = []
|
||||
|
||||
const Database = this.models.get('api:db:Database')
|
||||
const dbs = await Database.find({
|
||||
Active: true,
|
||||
PageId: this.UUID,
|
||||
})
|
||||
const Database = this.models.get('api:db:Database')
|
||||
const dbs = await Database.find({
|
||||
Active: true,
|
||||
PageId: this.UUID,
|
||||
})
|
||||
|
||||
for ( const db of dbs ) {
|
||||
children.push({
|
||||
id: db.PageId,
|
||||
node_id: db.NodeId,
|
||||
children: [],
|
||||
type: 'db',
|
||||
name: db.Name,
|
||||
})
|
||||
}
|
||||
for ( const db of dbs ) {
|
||||
children.push({
|
||||
id: db.PageId,
|
||||
node_id: db.NodeId,
|
||||
children: [],
|
||||
type: 'db',
|
||||
name: db.Name,
|
||||
})
|
||||
}
|
||||
|
||||
const Codium = this.models.get('api:Codium')
|
||||
const codiums = await Codium.find({
|
||||
PageId: this.UUID,
|
||||
})
|
||||
const FileBox = this.models.get('api:files:FileBox')
|
||||
const boxes = await FileBox.find({
|
||||
active: true,
|
||||
pageId: this.UUID,
|
||||
})
|
||||
|
||||
for ( const codium of codiums ) {
|
||||
children.push({
|
||||
id: codium.PageId,
|
||||
node_id: codium.NodeId,
|
||||
children: [],
|
||||
type: 'code',
|
||||
name: codium.code.slice(0, 25) + (codium.code.length > 25 ? '...' : ''),
|
||||
})
|
||||
}
|
||||
for ( const box of boxes ) {
|
||||
if ( box.parentUUID ) continue; // only show top-level
|
||||
|
||||
return children
|
||||
}
|
||||
children.push({
|
||||
id: box.pageId,
|
||||
// node_id // FIXME need to track this w/ the file boxes
|
||||
children: [],
|
||||
type: 'file_box',
|
||||
name: box.name,
|
||||
})
|
||||
}
|
||||
|
||||
async cast_to_version_data() {
|
||||
const data = await super.cast_to_version_data()
|
||||
const node_version_nums = []
|
||||
const nodes = await this.nodes
|
||||
const Codium = this.models.get('api:Codium')
|
||||
const codiums = await Codium.find({
|
||||
PageId: this.UUID,
|
||||
})
|
||||
|
||||
for ( const node of nodes ) {
|
||||
node_version_nums.push({ NodeId: node.UUID, version_num: node.version_num })
|
||||
}
|
||||
for ( const codium of codiums ) {
|
||||
children.push({
|
||||
id: codium.PageId,
|
||||
node_id: codium.NodeId,
|
||||
children: [],
|
||||
type: 'code',
|
||||
name: codium.code.slice(0, 25) + (codium.code.length > 25 ? '...' : ''),
|
||||
})
|
||||
}
|
||||
|
||||
data.node_version_nums = node_version_nums
|
||||
return data
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
async revert_to_version(version_num, user_id = undefined) {
|
||||
const Node = this.models.get('api:Node')
|
||||
const reverted = await super.revert_to_version(version_num, user_id)
|
||||
const data = await this.get_version_data(version_num)
|
||||
async cast_to_version_data() {
|
||||
const data = await super.cast_to_version_data()
|
||||
const node_version_nums = []
|
||||
const nodes = await this.nodes
|
||||
|
||||
// Revert the nodes to the given versions
|
||||
for ( const node_data of data.node_version_nums ) {
|
||||
const node = await Node.findOne({ UUID: node_data.NodeId })
|
||||
if ( node ) {
|
||||
const reverted_node = await node.revert_to_version(node_data.version_num)
|
||||
await reverted_node.save()
|
||||
}
|
||||
}
|
||||
for ( const node of nodes ) {
|
||||
node_version_nums.push({ NodeId: node.UUID, version_num: node.version_num })
|
||||
}
|
||||
|
||||
await reverted.save()
|
||||
return reverted
|
||||
}
|
||||
data.node_version_nums = node_version_nums
|
||||
return data
|
||||
}
|
||||
|
||||
async revert_to_version(version_num, user_id = undefined) {
|
||||
const Node = this.models.get('api:Node')
|
||||
const reverted = await super.revert_to_version(version_num, user_id)
|
||||
const data = await this.get_version_data(version_num)
|
||||
|
||||
// Revert the nodes to the given versions
|
||||
for ( const node_data of data.node_version_nums ) {
|
||||
const node = await Node.findOne({ UUID: node_data.NodeId })
|
||||
if ( node ) {
|
||||
const reverted_node = await node.revert_to_version(node_data.version_num)
|
||||
await reverted_node.save()
|
||||
}
|
||||
}
|
||||
|
||||
await reverted.save()
|
||||
return reverted
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = Page;
|
||||
|
Loading…
Reference in New Issue
Block a user