|
|
@@ -14,6 +14,7 @@ import {
|
|
|
import { stringifySnapshot } from '~/models/serializers/in-app-notification-snapshot/page';
|
|
|
import ActivityDefine from '../util/activityDefine';
|
|
|
import { IPage } from '~/interfaces/page';
|
|
|
+import { PageRedirectModel } from '../models/page-redirect';
|
|
|
import { ObjectIdLike } from '../interfaces/mongoose-utils';
|
|
|
|
|
|
const debug = require('debug')('growi:services:page');
|
|
|
@@ -322,11 +323,6 @@ class PageService {
|
|
|
// update descendants first
|
|
|
await this.renameDescendantsWithStream(page, newPagePath, user, options, shouldUseV4Process);
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * bulkWrite PageRedirectDocument if createRedirectPage is true
|
|
|
- */
|
|
|
-
|
|
|
/*
|
|
|
* update target
|
|
|
*/
|
|
|
@@ -372,11 +368,6 @@ class PageService {
|
|
|
// update Rivisions
|
|
|
await Revision.updateRevisionListByPageId(renamedPage._id, { pageId: renamedPage._id });
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * bulkWrite PageRedirectDocument if createRedirectPage is true
|
|
|
- */
|
|
|
-
|
|
|
this.pageEvent.emit('rename', page, user);
|
|
|
|
|
|
return renamedPage;
|
|
|
@@ -389,27 +380,43 @@ class PageService {
|
|
|
return this.renameDescendantsV4(pages, user, options, oldPagePathPrefix, newPagePathPrefix);
|
|
|
}
|
|
|
|
|
|
- const Page = this.crowi.model('Page');
|
|
|
+ const Page = mongoose.model('Page') as unknown as PageModel;
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
- const { updateMetadata } = options;
|
|
|
+ const { updateMetadata, createRedirectPage } = options;
|
|
|
|
|
|
const updatePathOperations: any[] = [];
|
|
|
+ const insertPageRedirectOperations: any[] = [];
|
|
|
|
|
|
pages.forEach((page) => {
|
|
|
const newPagePath = page.path.replace(oldPagePathPrefix, newPagePathPrefix);
|
|
|
|
|
|
// increment updatePathOperations
|
|
|
let update;
|
|
|
- if (updateMetadata && !page.isEmpty) {
|
|
|
+ if (!page.isEmpty && updateMetadata) {
|
|
|
update = {
|
|
|
$set: { path: newPagePath, lastUpdateUser: user._id, updatedAt: new Date() },
|
|
|
};
|
|
|
+
|
|
|
}
|
|
|
else {
|
|
|
update = {
|
|
|
$set: { path: newPagePath },
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+ if (!page.isEmpty && createRedirectPage) {
|
|
|
+ // insert PageRedirect
|
|
|
+ insertPageRedirectOperations.push({
|
|
|
+ insertOne: {
|
|
|
+ document: {
|
|
|
+ fromPath: page.path,
|
|
|
+ toPath: newPagePath,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
updatePathOperations.push({
|
|
|
updateOne: {
|
|
|
filter: {
|
|
|
@@ -429,14 +436,25 @@ class PageService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ try {
|
|
|
+ await PageRedirect.bulkWrite(insertPageRedirectOperations);
|
|
|
+ }
|
|
|
+ catch (err) {
|
|
|
+ if (err.code !== 11000) {
|
|
|
+ throw Error(`Failed to create PageRedirect documents: ${err}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
this.pageEvent.emit('updateMany', pages, user);
|
|
|
}
|
|
|
|
|
|
private async renameDescendantsV4(pages, user, options, oldPagePathPrefix, newPagePathPrefix) {
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
const pageCollection = mongoose.connection.collection('pages');
|
|
|
- const { updateMetadata } = options;
|
|
|
+ const { updateMetadata, createRedirectPage } = options;
|
|
|
|
|
|
const unorderedBulkOp = pageCollection.initializeUnorderedBulkOp();
|
|
|
+ const insertPageRedirectOperations: any[] = [];
|
|
|
|
|
|
pages.forEach((page) => {
|
|
|
const newPagePath = page.path.replace(oldPagePathPrefix, newPagePathPrefix);
|
|
|
@@ -449,6 +467,17 @@ class PageService {
|
|
|
else {
|
|
|
unorderedBulkOp.find({ _id: page._id }).update({ $set: { path: newPagePath } });
|
|
|
}
|
|
|
+ // insert PageRedirect
|
|
|
+ if (!page.isEmpty && createRedirectPage) {
|
|
|
+ insertPageRedirectOperations.push({
|
|
|
+ insertOne: {
|
|
|
+ document: {
|
|
|
+ fromPath: page.path,
|
|
|
+ toPath: newPagePath,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
try {
|
|
|
@@ -460,6 +489,15 @@ class PageService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ try {
|
|
|
+ await PageRedirect.bulkWrite(insertPageRedirectOperations);
|
|
|
+ }
|
|
|
+ catch (err) {
|
|
|
+ if (err.code !== 11000) {
|
|
|
+ throw Error(`Failed to create PageRedirect documents: ${err}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
this.pageEvent.emit('updateMany', pages, user);
|
|
|
}
|
|
|
|
|
|
@@ -925,6 +963,7 @@ class PageService {
|
|
|
const Page = mongoose.model('Page') as PageModel;
|
|
|
const PageTagRelation = mongoose.model('PageTagRelation') as any; // TODO: Typescriptize model
|
|
|
const Revision = mongoose.model('Revision') as any; // TODO: Typescriptize model
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
// v4 compatible process
|
|
|
const shouldUseV4Process = this.shouldUseV4Process(page);
|
|
|
@@ -974,12 +1013,7 @@ class PageService {
|
|
|
}, { new: true });
|
|
|
await PageTagRelation.updateMany({ relatedPage: page._id }, { $set: { isPageTrashed: true } });
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * bulkWrite PageRedirect documents
|
|
|
- */
|
|
|
- // const body = `redirect ${newPath}`;
|
|
|
- // await Page.create(page.path, body, user, { redirectTo: newPath });
|
|
|
+ await PageRedirect.create({ fromPath: page.path, toPath: newPath });
|
|
|
|
|
|
this.pageEvent.emit('delete', page, user);
|
|
|
this.pageEvent.emit('create', deletedPage, user);
|
|
|
@@ -992,6 +1026,7 @@ class PageService {
|
|
|
const Page = mongoose.model('Page') as PageModel;
|
|
|
const PageTagRelation = mongoose.model('PageTagRelation') as any; // TODO: Typescriptize model
|
|
|
const Revision = mongoose.model('Revision') as any; // TODO: Typescriptize model
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
const newPath = Page.getDeletedPageName(page.path);
|
|
|
const isTrashed = isTrashPage(page.path);
|
|
|
@@ -1017,12 +1052,7 @@ class PageService {
|
|
|
}, { new: true });
|
|
|
await PageTagRelation.updateMany({ relatedPage: page._id }, { $set: { isPageTrashed: true } });
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * bulkWrite PageRedirect documents
|
|
|
- */
|
|
|
- // const body = `redirect ${newPath}`;
|
|
|
- // await Page.create(page.path, body, user, { redirectTo: newPath });
|
|
|
+ await PageRedirect.create({ fromPath: page.path, toPath: newPath });
|
|
|
|
|
|
this.pageEvent.emit('delete', page, user);
|
|
|
this.pageEvent.emit('create', deletedPage, user);
|
|
|
@@ -1031,9 +1061,11 @@ class PageService {
|
|
|
}
|
|
|
|
|
|
private async deleteDescendants(pages, user) {
|
|
|
- const Page = mongoose.model('Page') as PageModel;
|
|
|
+ const Page = mongoose.model('Page') as unknown as PageModel;
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
const deletePageOperations: any[] = [];
|
|
|
+ const insertPageRedirectOperations: any[] = [];
|
|
|
|
|
|
pages.forEach((page) => {
|
|
|
const newPath = Page.getDeletedPageName(page.path);
|
|
|
@@ -1059,6 +1091,15 @@ class PageService {
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
+
|
|
|
+ insertPageRedirectOperations.push({
|
|
|
+ insertOne: {
|
|
|
+ document: {
|
|
|
+ fromPath: page.path,
|
|
|
+ toPath: newPath,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
deletePageOperations.push(operation);
|
|
|
@@ -1075,6 +1116,15 @@ class PageService {
|
|
|
finally {
|
|
|
this.pageEvent.emit('syncDescendantsDelete', pages, user);
|
|
|
}
|
|
|
+
|
|
|
+ try {
|
|
|
+ await PageRedirect.bulkWrite(insertPageRedirectOperations);
|
|
|
+ }
|
|
|
+ catch (err) {
|
|
|
+ if (err.code !== 11000) {
|
|
|
+ throw Error(`Failed to create PageRedirect documents: ${err}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1128,25 +1178,11 @@ class PageService {
|
|
|
const ShareLink = this.crowi.model('ShareLink');
|
|
|
const Revision = this.crowi.model('Revision');
|
|
|
const Attachment = this.crowi.model('Attachment');
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
const { attachmentService } = this.crowi;
|
|
|
const attachments = await Attachment.find({ page: { $in: pageIds } });
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * deleteMany related PageRedirect documents
|
|
|
- */
|
|
|
- // const pages = await Page.find({ redirectTo: { $ne: null } });
|
|
|
- // const redirectToPagePathMapping = {};
|
|
|
- // pages.forEach((page) => {
|
|
|
- // redirectToPagePathMapping[page.redirectTo] = page.path;
|
|
|
- // });
|
|
|
-
|
|
|
- // const redirectedFromPagePaths: any[] = [];
|
|
|
- // pagePaths.forEach((pagePath) => {
|
|
|
- // redirectedFromPagePaths.push(...this.prepareShoudDeletePagesByRedirectTo(pagePath, redirectToPagePathMapping));
|
|
|
- // });
|
|
|
-
|
|
|
return Promise.all([
|
|
|
Bookmark.deleteMany({ page: { $in: pageIds } }),
|
|
|
Comment.deleteMany({ page: { $in: pageIds } }),
|
|
|
@@ -1154,8 +1190,7 @@ class PageService {
|
|
|
ShareLink.deleteMany({ relatedPage: { $in: pageIds } }),
|
|
|
Revision.deleteMany({ path: { $in: pagePaths } }),
|
|
|
Page.deleteMany({ $or: [{ path: { $in: pagePaths } }, { _id: { $in: pageIds } }] }),
|
|
|
- // TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- // Page.deleteMany({ $or: [{ path: { $in: pagePaths } }, { path: { $in: redirectedFromPagePaths } }, { _id: { $in: pageIds } }] }),
|
|
|
+ PageRedirect.deleteMany({ $or: [{ toPath: { $in: pagePaths } }] }),
|
|
|
attachmentService.removeAllAttachments(attachments),
|
|
|
]);
|
|
|
}
|
|
|
@@ -1279,8 +1314,10 @@ class PageService {
|
|
|
// use the same process in both v4 and v5
|
|
|
private async revertDeletedDescendants(pages, user) {
|
|
|
const Page = this.crowi.model('Page');
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
|
|
|
|
|
|
const revertPageOperations: any[] = [];
|
|
|
+ const fromPathsToDelete: string[] = [];
|
|
|
|
|
|
pages.forEach((page) => {
|
|
|
// e.g. page.path = /trash/test, toPath = /test
|
|
|
@@ -1295,15 +1332,13 @@ class PageService {
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
- });
|
|
|
|
|
|
- /*
|
|
|
- * TODO: https://redmine.weseek.co.jp/issues/86577
|
|
|
- * deleteMany PageRedirectDocument of paths as well
|
|
|
- */
|
|
|
+ fromPathsToDelete.push(page.path);
|
|
|
+ });
|
|
|
|
|
|
try {
|
|
|
await Page.bulkWrite(revertPageOperations);
|
|
|
+ await PageRedirect.deleteMany({ fromPath: { $in: fromPathsToDelete } });
|
|
|
}
|
|
|
catch (err) {
|
|
|
if (err.code !== 11000) {
|