Selaa lähdekoodia

Merge pull request #5573 from weseek/feat/add-compare-method-for-deletion-config

imprv: Validate deletion settings
Yuki Takei 4 vuotta sitten
vanhempi
sitoutus
14cc91c463

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

@@ -4,34 +4,34 @@ export const PageDeleteConfigValue = {
   AdminOnly: 'adminOnly',
   Inherit: 'inherit',
 } as const;
-export type PageDeleteConfigValue = typeof PageDeleteConfigValue[keyof typeof PageDeleteConfigValue];
+export type IPageDeleteConfigValue = typeof PageDeleteConfigValue[keyof typeof PageDeleteConfigValue];
 
-export type PageDeleteConfigValueToProcessValidation = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
+export type IPageDeleteConfigValueToProcessValidation = Exclude<IPageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
 
 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 type PageSingleDeleteConfigValue = Exclude<IPageDeleteConfigValue, 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 type PageSingleDeleteCompConfigValue = Exclude<IPageDeleteConfigValue, typeof PageDeleteConfigValue.Inherit>;
 
 export const PageRecursiveDeleteConfigValue = {
   AdminAndAuthor: 'adminAndAuthor',
   AdminOnly: 'adminOnly',
   Inherit: 'inherit',
 } as const;
-export type PageRecursiveDeleteConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;
+export type PageRecursiveDeleteConfigValue = Exclude<IPageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;
 
 export const PageRecursiveDeleteCompConfigValue = {
   AdminAndAuthor: 'adminAndAuthor',
   AdminOnly: 'adminOnly',
   Inherit: 'inherit',
 } as const;
-export type PageRecursiveDeleteCompConfigValue = Exclude<PageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;
+export type PageRecursiveDeleteCompConfigValue = Exclude<IPageDeleteConfigValue, typeof PageDeleteConfigValue.Anyone>;

+ 9 - 16
packages/app/src/server/service/page.ts

@@ -23,10 +23,11 @@ import { Ref } from '~/interfaces/common';
 import { HasObjectId } from '~/interfaces/has-object-id';
 import { SocketEventName, UpdateDescCountRawData } from '~/interfaces/websocket';
 import {
-  PageDeleteConfigValue, PageDeleteConfigValueToProcessValidation,
+  PageDeleteConfigValue, IPageDeleteConfigValueToProcessValidation,
 } from '~/interfaces/page-delete-config';
 import PageOperation, { PageActionStage, PageActionType } from '../models/page-operation';
 import ActivityDefine from '../util/activityDefine';
+import { prepareDeleteConfigValuesForCalc } from '~/utils/page-delete-config';
 
 const debug = require('debug')('growi:services:page');
 
@@ -215,34 +216,26 @@ class PageService {
     const pageCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority');
     const pageRecursiveCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority');
 
-    const recursiveAuthority = this.calcRecursiveDeleteConfigValue(pageCompleteDeletionAuthority, pageRecursiveCompleteDeletionAuthority);
+    const [singleAuthority, recursiveAuthority] = prepareDeleteConfigValuesForCalc(pageCompleteDeletionAuthority, pageRecursiveCompleteDeletionAuthority);
 
-    return this.canDeleteLogic(creatorId, operator, isRecursively, pageCompleteDeletionAuthority, recursiveAuthority);
+    return this.canDeleteLogic(creatorId, operator, isRecursively, singleAuthority, recursiveAuthority);
   }
 
   canDelete(creatorId: ObjectIdLike, operator, isRecursively: boolean): boolean {
     const pageDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageDeletionAuthority');
     const pageRecursiveDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveDeletionAuthority');
 
-    const recursiveAuthority = this.calcRecursiveDeleteConfigValue(pageDeletionAuthority, pageRecursiveDeletionAuthority);
+    const [singleAuthority, recursiveAuthority] = prepareDeleteConfigValuesForCalc(pageDeletionAuthority, pageRecursiveDeletionAuthority);
 
-    return this.canDeleteLogic(creatorId, operator, isRecursively, pageDeletionAuthority, recursiveAuthority);
-  }
-
-  private calcRecursiveDeleteConfigValue(confForSingle, confForRecursive) {
-    if (confForRecursive === PageDeleteConfigValue.Inherit) {
-      return confForSingle;
-    }
-
-    return confForRecursive;
+    return this.canDeleteLogic(creatorId, operator, isRecursively, singleAuthority, recursiveAuthority);
   }
 
   private canDeleteLogic(
       creatorId: ObjectIdLike,
       operator,
       isRecursively: boolean,
-      authority: PageDeleteConfigValueToProcessValidation | null,
-      recursiveAuthority: PageDeleteConfigValueToProcessValidation | null,
+      authority: IPageDeleteConfigValueToProcessValidation | null,
+      recursiveAuthority: IPageDeleteConfigValueToProcessValidation | null,
   ): boolean {
     const isAdmin = operator.admin;
     const isOperator = operator?._id == null ? false : operator._id.equals(creatorId);
@@ -254,7 +247,7 @@ class PageService {
     return this.compareDeleteConfig(isAdmin, isOperator, authority);
   }
 
-  private compareDeleteConfig(isAdmin: boolean, isOperator: boolean, authority: PageDeleteConfigValueToProcessValidation | null): boolean {
+  private compareDeleteConfig(isAdmin: boolean, isOperator: boolean, authority: IPageDeleteConfigValueToProcessValidation | null): boolean {
     if (isAdmin) {
       return true;
     }

+ 62 - 0
packages/app/src/utils/page-delete-config.ts

@@ -0,0 +1,62 @@
+import {
+  PageDeleteConfigValue as Value, IPageDeleteConfigValueToProcessValidation,
+  IPageDeleteConfigValue,
+} from '~/interfaces/page-delete-config';
+
+/**
+ * Return true if "configForRecursive" is stronger than "configForSingle"
+ * Strength: "Admin" > "Admin and author" > "Anyone"
+ * @param configForSingle IPageDeleteConfigValueToProcessValidation
+ * @param configForRecursive IPageDeleteConfigValueToProcessValidation
+ * @returns boolean
+ */
+export const validateDeleteConfigs = (
+    configForSingle: IPageDeleteConfigValueToProcessValidation, configForRecursive: IPageDeleteConfigValueToProcessValidation,
+): boolean => {
+  if (configForSingle === Value.Anyone) {
+    switch (configForRecursive) {
+      case Value.Anyone:
+      case Value.AdminAndAuthor:
+      case Value.AdminOnly:
+        return true;
+    }
+  }
+
+  if (configForSingle === Value.AdminAndAuthor) {
+    switch (configForRecursive) {
+      case Value.Anyone:
+        return false;
+      case Value.AdminAndAuthor:
+      case Value.AdminOnly:
+        return true;
+    }
+  }
+
+  if (configForSingle === Value.AdminOnly) {
+    switch (configForRecursive) {
+      case Value.Anyone:
+      case Value.AdminAndAuthor:
+        return false;
+      case Value.AdminOnly:
+        return true;
+    }
+  }
+
+  return false;
+};
+
+/**
+ * Convert IPageDeleteConfigValue.Inherit to the calculable value
+ * @param confForSingle IPageDeleteConfigValueToProcessValidation
+ * @param confForRecursive IPageDeleteConfigValue
+ * @returns [(value for single), (value for recursive)]
+ */
+export const prepareDeleteConfigValuesForCalc = (
+    confForSingle: IPageDeleteConfigValueToProcessValidation, confForRecursive: IPageDeleteConfigValue,
+): [IPageDeleteConfigValueToProcessValidation, IPageDeleteConfigValueToProcessValidation] => {
+  if (confForRecursive === Value.Inherit) {
+    return [confForSingle, confForSingle];
+  }
+
+  return [confForSingle, confForRecursive];
+};

+ 22 - 0
packages/app/test/unit/utils/page-delete-config.test.ts

@@ -0,0 +1,22 @@
+import { PageDeleteConfigValue } from '../../../src/interfaces/page-delete-config';
+import { validateDeleteConfigs } from '../../../src/utils/page-delete-config';
+
+describe('validateDeleteConfigs utility function', () => {
+  test('Should validate delete configs', () => {
+    const Anyone = PageDeleteConfigValue.Anyone;
+    const AdminAndAuthor = PageDeleteConfigValue.AdminAndAuthor;
+    const AdminOnly = PageDeleteConfigValue.AdminOnly;
+
+    expect(validateDeleteConfigs(Anyone, Anyone)).toBe(true);
+    expect(validateDeleteConfigs(Anyone, AdminAndAuthor)).toBe(true);
+    expect(validateDeleteConfigs(Anyone, AdminOnly)).toBe(true);
+
+    expect(validateDeleteConfigs(AdminAndAuthor, Anyone)).toBe(false);
+    expect(validateDeleteConfigs(AdminAndAuthor, AdminAndAuthor)).toBe(true);
+    expect(validateDeleteConfigs(AdminAndAuthor, AdminOnly)).toBe(true);
+
+    expect(validateDeleteConfigs(AdminOnly, Anyone)).toBe(false);
+    expect(validateDeleteConfigs(AdminOnly, AdminAndAuthor)).toBe(false);
+    expect(validateDeleteConfigs(AdminOnly, AdminOnly)).toBe(true);
+  });
+});