|
|
@@ -1,11 +1,7 @@
|
|
|
const mongoose = require('mongoose');
|
|
|
const escapeStringRegexp = require('escape-string-regexp');
|
|
|
-const logger = require('@alias/logger')('growi:models:page');
|
|
|
-const debug = require('debug')('growi:models:page');
|
|
|
const { serializePageSecurely } = require('../models/serializers/page-serializer');
|
|
|
|
|
|
-const STATUS_PUBLISHED = 'published';
|
|
|
-
|
|
|
class PageService {
|
|
|
|
|
|
constructor(crowi) {
|
|
|
@@ -46,35 +42,24 @@ class PageService {
|
|
|
return Promise.all(promises);
|
|
|
}
|
|
|
|
|
|
- async duplicate(pages, newPagePath, user) {
|
|
|
+ async duplicate(page, newPagePath, user) {
|
|
|
const Page = this.crowi.model('Page');
|
|
|
const PageTagRelation = mongoose.model('PageTagRelation');
|
|
|
// populate
|
|
|
- // await pages.populate({ path: 'revision', model: 'Revision', select: 'body' }).execPopulate();
|
|
|
- await pages.map(page => page.populate({ path: 'revision', model: 'Revision', select: 'body' }).execPopulate());
|
|
|
+ await page.populate({ path: 'revision', model: 'Revision', select: 'body' }).execPopulate();
|
|
|
|
|
|
// create option
|
|
|
- // options.grant = page.grant;
|
|
|
- // options.grantUserGroupId = page.grantedGroup;
|
|
|
- // options.grantedUsers = page.grantedUsers;
|
|
|
-
|
|
|
-
|
|
|
- // 複数にするべきか(grantUserGroupIds → ids or 一つづつ格納すべきか)
|
|
|
- const options = { pages };
|
|
|
- options.grant = pages.map(page => page.grant);
|
|
|
- options.grantUserGroupId = pages.map(page => page.grantedGroup);
|
|
|
- options.grantedUsers = pages.map(page => page.grantedUsers);
|
|
|
-
|
|
|
- console.log(`grant = ${options.grant}`);
|
|
|
- console.log(`grantUserGroupId = ${options.grantUserGroupId}`);
|
|
|
- console.log(`grantedUsers = ${options.grantedUsers}`);
|
|
|
+ const options = { page };
|
|
|
+ options.grant = page.grant;
|
|
|
+ options.grantUserGroupId = page.grantedGroup;
|
|
|
+ options.grantedUsers = page.grantedUsers;
|
|
|
|
|
|
const createdPage = await Page.create(
|
|
|
- newPagePath, pages.revision.body, user, options,
|
|
|
+ newPagePath, page.revision.body, user, options,
|
|
|
);
|
|
|
|
|
|
// take over tags
|
|
|
- const originTags = await pages.findRelatedTagsById();
|
|
|
+ const originTags = await page.findRelatedTagsById();
|
|
|
let savedTags = [];
|
|
|
if (originTags != null) {
|
|
|
await PageTagRelation.updatePageTags(createdPage.id, originTags);
|
|
|
@@ -89,22 +74,19 @@ class PageService {
|
|
|
|
|
|
async duplicateRecursively(page, newPagePath, user) {
|
|
|
const Page = this.crowi.model('Page');
|
|
|
+ const newPagePathPrefix = newPagePath;
|
|
|
const pathRegExp = new RegExp(`^${escapeStringRegexp(page.path)}`, 'i');
|
|
|
- // ここで配下のページを含むpagesを取得
|
|
|
- const pages = await Page.findManageableListWithDescendants(page, user);
|
|
|
|
|
|
+ const pages = await Page.findManageableListWithDescendants(page, user);
|
|
|
|
|
|
- // const promise = pages.map(async(page) => {
|
|
|
- // const newPagePath1 = page.path.replace(pathRegExp, newPagePath);
|
|
|
- // return this.duplicate(page, newPagePath1, user);
|
|
|
- // });
|
|
|
-
|
|
|
- const newPagePaths = pages.map(page => page.path.replace(pathRegExp, newPagePath));
|
|
|
- await this.duplicate(pages, newPagePaths, user);
|
|
|
+ const promise = pages.map(async(page) => {
|
|
|
+ const newPagePath = page.path.replace(pathRegExp, newPagePathPrefix);
|
|
|
+ return this.duplicate(page, newPagePath, user);
|
|
|
+ });
|
|
|
|
|
|
- const newPath = page.path.replace(pathRegExp, newPagePath);
|
|
|
+ const newPath = page.path.replace(pathRegExp, newPagePathPrefix);
|
|
|
|
|
|
- // await Promise.allSettled(promise);
|
|
|
+ await Promise.allSettled(promise);
|
|
|
|
|
|
const newParentpage = await Page.findByPath(newPath);
|
|
|
|
|
|
@@ -113,97 +95,6 @@ class PageService {
|
|
|
}
|
|
|
|
|
|
|
|
|
- async completelyDeletePage(pageData, user, options = {}) {
|
|
|
- this.validateCrowi();
|
|
|
- let pageEvent;
|
|
|
- // init event
|
|
|
- if (this.crowi != null) {
|
|
|
- pageEvent = this.crowi.event('page');
|
|
|
- pageEvent.on('create', pageEvent.onCreate);
|
|
|
- pageEvent.on('update', pageEvent.onUpdate);
|
|
|
- }
|
|
|
-
|
|
|
- const { _id, path } = pageData;
|
|
|
- const socketClientId = options.socketClientId || null;
|
|
|
-
|
|
|
- logger.debug('Deleting completely', path);
|
|
|
-
|
|
|
- await this.deleteCompletely(_id, path);
|
|
|
-
|
|
|
- if (socketClientId != null) {
|
|
|
- pageEvent.emit('delete', pageData, user, socketClientId); // update as renamed page
|
|
|
- }
|
|
|
- return pageData;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Delete Bookmarks, Attachments, Revisions, Pages and emit delete
|
|
|
- */
|
|
|
- async completelyDeletePageRecursively(targetPage, user, options = {}) {
|
|
|
- const findOpts = { includeTrashed: true };
|
|
|
- const Page = this.crowi.model('Page');
|
|
|
-
|
|
|
- // find manageable descendants (this array does not include GRANT_RESTRICTED)
|
|
|
- const pages = await Page.findManageableListWithDescendants(targetPage, user, findOpts);
|
|
|
-
|
|
|
- await Promise.all(pages.map((page) => {
|
|
|
- return this.completelyDeletePage(page, user, options);
|
|
|
- }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- async revertDeletedPage(page, user, options = {}) {
|
|
|
- const Page = this.crowi.model('Page');
|
|
|
- const newPath = Page.getRevertDeletedPageName(page.path);
|
|
|
- const originPage = await Page.findByPath(newPath);
|
|
|
- if (originPage != null) {
|
|
|
- // When the page is deleted, it will always be created with "redirectTo" in the path of the original page.
|
|
|
- // So, it's ok to delete the page
|
|
|
- // However, If a page exists that is not "redirectTo", something is wrong. (Data correction is needed).
|
|
|
- if (originPage.redirectTo !== page.path) {
|
|
|
- throw new Error('The new page of to revert is exists and the redirect path of the page is not the deleted page.');
|
|
|
- }
|
|
|
- await this.completelyDeletePage(originPage, options);
|
|
|
- }
|
|
|
-
|
|
|
- page.status = STATUS_PUBLISHED;
|
|
|
- page.lastUpdateUser = user;
|
|
|
- debug('Revert deleted the page', page, newPath);
|
|
|
- const updatedPage = await Page.rename(page, newPath, user, {});
|
|
|
- return updatedPage;
|
|
|
- }
|
|
|
-
|
|
|
- async handlePrivatePagesForDeletedGroup(deletedGroup, action, transferToUserGroupId) {
|
|
|
- const Page = this.crowi.model('Page');
|
|
|
- const pages = await Page.find({ grantedGroup: deletedGroup });
|
|
|
-
|
|
|
- switch (action) {
|
|
|
- case 'public':
|
|
|
- await Promise.all(pages.map((page) => {
|
|
|
- return Page.publicizePage(page);
|
|
|
- }));
|
|
|
- break;
|
|
|
- case 'delete':
|
|
|
- await Promise.all(pages.map((page) => {
|
|
|
- return this.completelyDeletePage(page);
|
|
|
- }));
|
|
|
- break;
|
|
|
- case 'transfer':
|
|
|
- await Promise.all(pages.map((page) => {
|
|
|
- return Page.transferPageToGroup(page, transferToUserGroupId);
|
|
|
- }));
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new Error('Unknown action for private pages');
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- validateCrowi() {
|
|
|
- if (this.crowi == null) {
|
|
|
- throw new Error('"crowi" is null. Init User model with "crowi" argument first.');
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
}
|
|
|
|
|
|
module.exports = PageService;
|