Taichi Masuyama 4 лет назад
Родитель
Сommit
d66ef60d0a

+ 1 - 1
packages/app/resource/locales/en_US/translation.json

@@ -393,7 +393,7 @@
     "notfound_or_forbidden": "Original page is not found or forbidden.",
     "notfound_or_forbidden": "Original page is not found or forbidden.",
     "already_exists": "New page is already exists.",
     "already_exists": "New page is already exists.",
     "outdated": "Page is updated someone and now outdated.",
     "outdated": "Page is updated someone and now outdated.",
-    "user_not_admin": "Only admin user can delete completely"
+    "user_not_admin": "Only admin user can delete"
   },
   },
   "page_history": {
   "page_history": {
     "revision_list": "Revision list",
     "revision_list": "Revision list",

+ 1 - 1
packages/app/resource/locales/ja_JP/translation.json

@@ -392,7 +392,7 @@
     "notfound_or_forbidden": "元のページが見つからないか、アクセス権がありません。",
     "notfound_or_forbidden": "元のページが見つからないか、アクセス権がありません。",
     "already_exists": "新しいページが既に存在しています。",
     "already_exists": "新しいページが既に存在しています。",
     "outdated": "ページが他のユーザーによって更新されました。",
     "outdated": "ページが他のユーザーによって更新されました。",
-    "user_not_admin": "権限のあるユーザーのみが完全削除できます"
+    "user_not_admin": "権限のあるユーザーのみが削除できます"
   },
   },
   "page_history": {
   "page_history": {
     "revision_list": "更新履歴",
     "revision_list": "更新履歴",

+ 1 - 1
packages/app/resource/locales/zh_CN/translation.json

@@ -371,7 +371,7 @@
 		"notfound_or_forbidden": "未找到或禁止原始页。",
 		"notfound_or_forbidden": "未找到或禁止原始页。",
 		"already_exists": "新建页面已存在",
 		"already_exists": "新建页面已存在",
 		"outdated": "页面已被某人更新,现在已过时。",
 		"outdated": "页面已被某人更新,现在已过时。",
-		"user_not_admin": "仅管理员用户可以完全删除"
+		"user_not_admin": "仅管理员用户可以删除"
   },
   },
   "page_history": {
   "page_history": {
     "revision_list": "修订清单",
     "revision_list": "修订清单",

+ 8 - 5
packages/app/src/client/services/AdminGeneralSecurityContainer.js

@@ -1,6 +1,9 @@
 import { Container } from 'unstated';
 import { Container } from 'unstated';
 
 
-import { PageDeleteConfigValue } from '~/interfaces/page-delete-config';
+import {
+  PageSingleDeleteConfigValue, PageSingleDeleteCompConfigValue,
+  PageRecursiveDeleteConfigValue, PageRecursiveDeleteCompConfigValue,
+} from '~/interfaces/page-delete-config';
 import { toastError } from '../util/apiNotification';
 import { toastError } from '../util/apiNotification';
 import { removeNullPropertyFromObject } from '~/utils/object-utils';
 import { removeNullPropertyFromObject } from '~/utils/object-utils';
 
 
@@ -23,10 +26,10 @@ export default class AdminGeneralSecurityContainer extends Container {
       wikiMode: '',
       wikiMode: '',
       // set dummy value tile for using suspense
       // set dummy value tile for using suspense
       currentRestrictGuestMode: this.dummyCurrentRestrictGuestMode,
       currentRestrictGuestMode: this.dummyCurrentRestrictGuestMode,
-      currentPageDeletionAuthority: PageDeleteConfigValue.AdminOnly,
-      currentPageCompleteDeletionAuthority: PageDeleteConfigValue.AdminOnly,
-      currentPageRecursiveDeletionAuthority: PageDeleteConfigValue.Inherit,
-      currentPageRecursiveCompleteDeletionAuthority: PageDeleteConfigValue.Inherit,
+      currentPageDeletionAuthority: PageSingleDeleteConfigValue.AdminOnly,
+      currentPageCompleteDeletionAuthority: PageSingleDeleteCompConfigValue.AdminOnly,
+      currentPageRecursiveDeletionAuthority: PageRecursiveDeleteConfigValue.Inherit,
+      currentPageRecursiveCompleteDeletionAuthority: PageRecursiveDeleteCompConfigValue.Inherit,
       isShowRestrictedByOwner: false,
       isShowRestrictedByOwner: false,
       isShowRestrictedByGroup: false,
       isShowRestrictedByGroup: false,
       appSiteUrl: appContainer.config.crowi.url || '',
       appSiteUrl: appContainer.config.crowi.url || '',

+ 34 - 1
packages/app/src/interfaces/page-delete-config.ts

@@ -1,7 +1,40 @@
 export const PageDeleteConfigValue = {
 export const PageDeleteConfigValue = {
-  Anyone: 'anyone',
+  Anyone: 'anyOne', // must be "anyOne" (not "anyone") for backward compatibility
   AdminAndAuthor: 'adminAndAuthor',
   AdminAndAuthor: 'adminAndAuthor',
   AdminOnly: 'adminOnly',
   AdminOnly: 'adminOnly',
   Inherit: 'inherit',
   Inherit: 'inherit',
 } as const;
 } as const;
 export type PageDeleteConfigValue = typeof PageDeleteConfigValue[keyof typeof PageDeleteConfigValue];
 export type PageDeleteConfigValue = typeof PageDeleteConfigValue[keyof typeof PageDeleteConfigValue];
+
+export type PageDeleteConfigValueToProcessValidation =
+  Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
+export type PageRecursiveDeleteConfigValueToProcessValidation =
+  Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit | typeof PageDeleteConfigValue.Anyone>;
+
+export const PageSingleDeleteConfigValue = {
+  Anyone: 'anyOne', // must be "anyOne" (not "anyone") for backward compatibility
+  AdminAndAuthor: 'adminAndAuthor',
+  AdminOnly: 'adminOnly',
+} as const;
+export type PageSingleDeleteConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
+
+export const PageSingleDeleteCompConfigValue = {
+  Anyone: 'anyOne', // must be "anyOne" (not "anyone") for backward compatibility
+  AdminAndAuthor: 'adminAndAuthor',
+  AdminOnly: 'adminOnly',
+} as const;
+export type PageSingleDeleteCompConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
+
+export const PageRecursiveDeleteConfigValue = {
+  AdminAndAuthor: 'adminAndAuthor',
+  AdminOnly: 'adminOnly',
+  Inherit: 'inherit',
+} as const;
+export type PageRecursiveDeleteConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;
+
+export const PageRecursiveDeleteCompConfigValue = {
+  AdminAndAuthor: 'adminAndAuthor',
+  AdminOnly: 'adminOnly',
+  Inherit: 'inherit',
+} as const;
+export type PageRecursiveDeleteCompConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;

+ 7 - 35
packages/app/src/migrations/20220311011114-convert-page-delete-config.js

@@ -2,7 +2,9 @@ import mongoose from 'mongoose';
 import { getModelSafely, getMongoUri, mongoOptions } from '@growi/core';
 import { getModelSafely, getMongoUri, mongoOptions } from '@growi/core';
 
 
 import ConfigModel from '~/server/models/config';
 import ConfigModel from '~/server/models/config';
-import { PageDeleteConfigValue } from '~/interfaces/page-delete-config';
+import {
+  PageRecursiveDeleteConfigValue, PageRecursiveDeleteCompConfigValue,
+} from '~/interfaces/page-delete-config';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -19,34 +21,26 @@ module.exports = {
       key: 'security:pageCompleteDeletionAuthority',
       key: 'security:pageCompleteDeletionAuthority',
     });
     });
 
 
-    const oldValue = oldConfig?.value || '"anyOne"';
-    const newValue = oldValue === '"anyOne"' ? `"${PageDeleteConfigValue.Anyone}"` : oldConfig.value;
+    const oldValue = oldConfig?.value ?? '"anyOne"';
 
 
     try {
     try {
-      await Config.updateOne(
-        {
-          ns: 'crowi',
-          key: 'security:pageCompleteDeletionAuthority',
-        },
-        { value: newValue },
-      );
 
 
       await Config.insertMany(
       await Config.insertMany(
         [
         [
           {
           {
             ns: 'crowi',
             ns: 'crowi',
             key: 'security:pageDeletionAuthority',
             key: 'security:pageDeletionAuthority',
-            value: newValue,
+            value: oldValue,
           },
           },
           {
           {
             ns: 'crowi',
             ns: 'crowi',
             key: 'security:pageRecursiveDeletionAuthority',
             key: 'security:pageRecursiveDeletionAuthority',
-            value: `"${PageDeleteConfigValue.Inherit}"`,
+            value: `"${PageRecursiveDeleteConfigValue.Inherit}"`,
           },
           },
           {
           {
             ns: 'crowi',
             ns: 'crowi',
             key: 'security:pageRecursiveCompleteDeletionAuthority',
             key: 'security:pageRecursiveCompleteDeletionAuthority',
-            value: `"${PageDeleteConfigValue.Inherit}"`,
+            value: `"${PageRecursiveDeleteCompConfigValue.Inherit}"`,
           },
           },
         ],
         ],
       );
       );
@@ -60,28 +54,6 @@ module.exports = {
   },
   },
 
 
   async down(db, client) {
   async down(db, client) {
-    mongoose.connect(getMongoUri(), mongoOptions);
-    const Config = getModelSafely('Config') || ConfigModel;
-
-    await Config.deleteMany({
-      ns: 'crowi',
-      key: { $in: ['security:pageDeletionAuthority', 'security:pageRecursiveDeletionAuthority', 'security:pageRecursiveCompleteDeletionAuthority'] },
-    });
-
-    const beforeVersionConfig = await Config.findOne({
-      ns: 'crowi',
-      key: 'security:pageCompleteDeletionAuthority',
-    });
-
-    if (beforeVersionConfig?.value === `"${PageDeleteConfigValue.Anyone}"`) {
-      await Config.updateOne({
-        ns: 'crowi',
-        key: 'security:pageCompleteDeletionAuthority',
-      }, {
-        value: '"anyOne"', // 'anyone' to 'anyOne'
-      });
-    }
-
     logger.info('Migration down has successfully applied');
     logger.info('Migration down has successfully applied');
   },
   },
 };
 };

+ 25 - 8
packages/app/src/server/service/page.ts

@@ -22,7 +22,9 @@ import { IUserHasId } from '~/interfaces/user';
 import { Ref } from '~/interfaces/common';
 import { Ref } from '~/interfaces/common';
 import { HasObjectId } from '~/interfaces/has-object-id';
 import { HasObjectId } from '~/interfaces/has-object-id';
 import { SocketEventName, UpdateDescCountRawData } from '~/interfaces/websocket';
 import { SocketEventName, UpdateDescCountRawData } from '~/interfaces/websocket';
-import { PageDeleteConfigValue } from '~/interfaces/page-delete-config';
+import {
+  PageDeleteConfigValue, PageDeleteConfigValueToProcessValidation, PageRecursiveDeleteConfigValueToProcessValidation,
+} from '~/interfaces/page-delete-config';
 import PageOperation, { PageActionStage, PageActionType } from '../models/page-operation';
 import PageOperation, { PageActionStage, PageActionType } from '../models/page-operation';
 import ActivityDefine from '../util/activityDefine';
 import ActivityDefine from '../util/activityDefine';
 
 
@@ -213,17 +215,35 @@ class PageService {
     const pageCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority');
     const pageCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority');
     const pageRecursiveCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority');
     const pageRecursiveCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority');
 
 
-    return this.canDeleteLogic(creatorId, operator, isRecursively, pageCompleteDeletionAuthority, pageRecursiveCompleteDeletionAuthority);
+    const recursiveAuthority = this.calcRecursiveDeleteConfigValue(pageCompleteDeletionAuthority, pageRecursiveCompleteDeletionAuthority);
+
+    return this.canDeleteLogic(creatorId, operator, isRecursively, pageCompleteDeletionAuthority, recursiveAuthority);
   }
   }
 
 
   canDelete(creatorId: ObjectIdLike, operator, isRecursively: boolean): boolean {
   canDelete(creatorId: ObjectIdLike, operator, isRecursively: boolean): boolean {
     const pageDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageDeletionAuthority');
     const pageDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageDeletionAuthority');
     const pageRecursiveDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveDeletionAuthority');
     const pageRecursiveDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveDeletionAuthority');
 
 
-    return this.canDeleteLogic(creatorId, operator, isRecursively, pageDeletionAuthority, pageRecursiveDeletionAuthority);
+    const recursiveAuthority = this.calcRecursiveDeleteConfigValue(pageDeletionAuthority, pageRecursiveDeletionAuthority);
+
+    return this.canDeleteLogic(creatorId, operator, isRecursively, pageDeletionAuthority, recursiveAuthority);
+  }
+
+  private calcRecursiveDeleteConfigValue(confForSingle, confForRecursive) {
+    if (confForRecursive === PageDeleteConfigValue.Inherit) {
+      return confForSingle;
+    }
+
+    return confForRecursive;
   }
   }
 
 
-  private canDeleteLogic(creatorId: ObjectIdLike, operator, isRecursively: boolean, authority, recursiveAuthority): boolean {
+  private canDeleteLogic(
+      creatorId: ObjectIdLike,
+      operator,
+      isRecursively: boolean,
+      authority: PageDeleteConfigValueToProcessValidation,
+      recursiveAuthority: PageRecursiveDeleteConfigValueToProcessValidation,
+  ): boolean {
     const isAdmin = operator.admin;
     const isAdmin = operator.admin;
     const isOperator = operator?._id == null ? false : operator._id.equals(creatorId);
     const isOperator = operator?._id == null ? false : operator._id.equals(creatorId);
 
 
@@ -232,10 +252,7 @@ class PageService {
     }
     }
 
 
     if (isRecursively) {
     if (isRecursively) {
-      if (recursiveAuthority === PageDeleteConfigValue.Inherit || recursiveAuthority == null) {
-        // Do nothing
-      }
-      else if (recursiveAuthority === PageDeleteConfigValue.AdminAndAuthor && isOperator) {
+      if (recursiveAuthority === PageDeleteConfigValue.AdminAndAuthor && isOperator) {
         return true;
         return true;
       }
       }
     }
     }