|
|
@@ -3,7 +3,7 @@ import { pagePathUtils, pathUtils } from '@growi/core';
|
|
|
import escapeStringRegexp from 'escape-string-regexp';
|
|
|
|
|
|
import UserGroup from '~/server/models/user-group';
|
|
|
-import { PageModel } from '~/server/models/page';
|
|
|
+import { PageDocument, PageModel } from '~/server/models/page';
|
|
|
import { PageQueryBuilder } from '../models/obsolete-page';
|
|
|
import { isIncludesObjectId, excludeTestIdsFromTargetIds } from '~/server/util/compare-objectId';
|
|
|
|
|
|
@@ -212,7 +212,7 @@ class PageGrantService {
|
|
|
* @param targetPath string of the target path
|
|
|
* @returns Promise<ComparableAncestor>
|
|
|
*/
|
|
|
- private async generateComparableAncestor(targetPath: string): Promise<ComparableAncestor> {
|
|
|
+ private async generateComparableAncestor(targetPath: string, includeNotMigratedPages: boolean): Promise<ComparableAncestor> {
|
|
|
const Page = mongoose.model('Page') as unknown as PageModel;
|
|
|
const UserGroupRelation = mongoose.model('UserGroupRelation') as any; // TODO: Typescriptize model
|
|
|
|
|
|
@@ -223,6 +223,9 @@ class PageGrantService {
|
|
|
* make granted users list of ancestor's
|
|
|
*/
|
|
|
const builderForAncestors = new PageQueryBuilder(Page.find(), false);
|
|
|
+ if (!includeNotMigratedPages) {
|
|
|
+ builderForAncestors.addConditionAsMigrated();
|
|
|
+ }
|
|
|
const ancestors = await builderForAncestors
|
|
|
.addConditionToListOnlyAncestors(targetPath)
|
|
|
.addConditionToSortPagesByDescPath()
|
|
|
@@ -254,7 +257,7 @@ class PageGrantService {
|
|
|
* @param targetPath string of the target path
|
|
|
* @returns ComparableDescendants
|
|
|
*/
|
|
|
- private async generateComparableDescendants(targetPath: string): Promise<ComparableDescendants> {
|
|
|
+ private async generateComparableDescendants(targetPath: string, includeNotMigratedPages: boolean): Promise<ComparableDescendants> {
|
|
|
const Page = mongoose.model('Page') as unknown as PageModel;
|
|
|
|
|
|
/*
|
|
|
@@ -263,12 +266,17 @@ class PageGrantService {
|
|
|
const pathWithTrailingSlash = addTrailingSlash(targetPath);
|
|
|
const startsPattern = escapeStringRegexp(pathWithTrailingSlash);
|
|
|
|
|
|
+ const $match: any = {
|
|
|
+ path: new RegExp(`^${startsPattern}`),
|
|
|
+ isEmpty: { $ne: true },
|
|
|
+ };
|
|
|
+ if (includeNotMigratedPages) {
|
|
|
+ $match.parent = { $ne: null };
|
|
|
+ }
|
|
|
+
|
|
|
const result = await Page.aggregate([
|
|
|
{ // match to descendants excluding empty pages
|
|
|
- $match: {
|
|
|
- path: new RegExp(`^${startsPattern}`),
|
|
|
- isEmpty: { $ne: true },
|
|
|
- },
|
|
|
+ $match,
|
|
|
},
|
|
|
{
|
|
|
$project: {
|
|
|
@@ -310,16 +318,18 @@ class PageGrantService {
|
|
|
|
|
|
/**
|
|
|
* About the rule of validation, see: https://dev.growi.org/61b2cdabaa330ce7d8152844
|
|
|
+ * Only v5 schema pages will be used to compare.
|
|
|
* @returns Promise<boolean>
|
|
|
*/
|
|
|
async isGrantNormalized(
|
|
|
- targetPath: string, grant, grantedUserIds?: ObjectIdLike[], grantedGroupId?: ObjectIdLike, shouldCheckDescendants = false,
|
|
|
+ // eslint-disable-next-line max-len
|
|
|
+ targetPath: string, grant, grantedUserIds?: ObjectIdLike[], grantedGroupId?: ObjectIdLike, shouldCheckDescendants = false, includeNotMigratedPages = false,
|
|
|
): Promise<boolean> {
|
|
|
if (isTopPage(targetPath)) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- const comparableAncestor = await this.generateComparableAncestor(targetPath);
|
|
|
+ const comparableAncestor = await this.generateComparableAncestor(targetPath, includeNotMigratedPages);
|
|
|
|
|
|
if (!shouldCheckDescendants) { // checking the parent is enough
|
|
|
const comparableTarget = await this.generateComparableTarget(grant, grantedUserIds, grantedGroupId, false);
|
|
|
@@ -327,11 +337,42 @@ class PageGrantService {
|
|
|
}
|
|
|
|
|
|
const comparableTarget = await this.generateComparableTarget(grant, grantedUserIds, grantedGroupId, true);
|
|
|
- const comparableDescendants = await this.generateComparableDescendants(targetPath);
|
|
|
+ const comparableDescendants = await this.generateComparableDescendants(targetPath, includeNotMigratedPages);
|
|
|
|
|
|
return this.processValidation(comparableTarget, comparableAncestor, comparableDescendants);
|
|
|
}
|
|
|
|
|
|
+ async separateNormalizedAndNonNormalizedPages(pageIds: ObjectIdLike[]): Promise<[(PageDocument & { _id: any })[], (PageDocument & { _id: any })[]]> {
|
|
|
+ const Page = mongoose.model('Page') as unknown as PageModel;
|
|
|
+ const { PageQueryBuilder } = Page;
|
|
|
+ const shouldCheckDescendants = true;
|
|
|
+ const shouldIncludeNotMigratedPages = true;
|
|
|
+
|
|
|
+ const normalizedPages: (PageDocument & { _id: any })[] = [];
|
|
|
+ const nonNormalizedPages: (PageDocument & { _id: any })[] = []; // can be used to tell user which page failed to migrate
|
|
|
+
|
|
|
+ const builder = new PageQueryBuilder(Page.find());
|
|
|
+ builder.addConditionToListByPageIdsArray(pageIds);
|
|
|
+
|
|
|
+ const pages = await builder.query.exec();
|
|
|
+
|
|
|
+ for await (const page of pages) {
|
|
|
+ const {
|
|
|
+ path, grant, grantedUsers: grantedUserIds, grantedGroup: grantedGroupId,
|
|
|
+ } = page;
|
|
|
+
|
|
|
+ const isNormalized = await this.isGrantNormalized(path, grant, grantedUserIds, grantedGroupId, shouldCheckDescendants, shouldIncludeNotMigratedPages);
|
|
|
+ if (isNormalized) {
|
|
|
+ normalizedPages.push(page);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ nonNormalizedPages.push(page);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [normalizedPages, nonNormalizedPages];
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
export default PageGrantService;
|