Procházet zdrojové kódy

Implemented validation logic & improved dropdowns

Taichi Masuyama před 4 roky
rodič
revize
a258055190

+ 13 - 8
packages/app/src/components/Admin/Security/SecuritySetting.jsx

@@ -38,6 +38,7 @@ class SecuritySetting extends React.Component {
   }
 
   renderPageDeletePermissionDropdown(currentState, setState, deletionType, t) {
+    const isRecursiveDeletion = deletionType === DeletionType.RecursiveDeletion || deletionType === DeletionType.RecursiveCompleteDeletion;
     return (
       <div className="row mb-4">
         <div className="col-md-3 text-md-right mb-2">
@@ -63,7 +64,7 @@ class SecuritySetting extends React.Component {
             </button>
             <div className="dropdown-menu" aria-labelledby="dropdownMenuButton">
               {
-                (deletionType === DeletionType.RecursiveDeletion || deletionType === DeletionType.RecursiveCompleteDeletion)
+                isRecursiveDeletion
                 && (
                   <button
                     className="dropdown-item"
@@ -74,13 +75,17 @@ class SecuritySetting extends React.Component {
                   </button>
                 )
               }
-              <button
-                className="dropdown-item"
-                type="button"
-                onClick={() => { setState(PageDeleteConfigValue.Anyone) }}
-              >
-                {t('security_setting.anyone')}
-              </button>
+              {
+                !isRecursiveDeletion && (
+                  <button
+                    className="dropdown-item"
+                    type="button"
+                    onClick={() => { setState(PageDeleteConfigValue.Anyone) }}
+                  >
+                    {t('security_setting.anyone')}
+                  </button>
+                )
+              }
               <button
                 className="dropdown-item"
                 type="button"

+ 1 - 1
packages/app/src/server/routes/apiv3/page-listing.ts

@@ -139,7 +139,7 @@ export default (crowi: Crowi): Router => {
           // create IPageInfoForListing
           : {
             ...basicPageInfo,
-            isAbleToDeleteCompletely: pageService.canDeleteCompletely((page.creator as IUserHasId)?._id, req.user, false), // TODOT: consider
+            isAbleToDeleteCompletely: pageService.canDeleteCompletely((page.creator as IUserHasId)?._id, req.user, false), // use normal delete config
             bookmarkCount: bookmarkCountMap != null ? bookmarkCountMap[page._id] : undefined,
             revisionShortBody: shortBodiesMap != null ? shortBodiesMap[page._id] : undefined,
           } as IPageInfoForListing;

+ 0 - 1
packages/app/src/server/routes/apiv3/pages.js

@@ -760,7 +760,6 @@ module.exports = (crowi) => {
      * Delete Completely
      */
     if (isCompletely) {
-      // TODOT: pass isRecursively as well
       pagesCanBeDeleted = crowi.pageService.filterPagesByCanDeleteCompletely(pagesToDelete, req.user, isRecursively);
     }
     /*

+ 32 - 12
packages/app/src/server/service/page.ts

@@ -22,6 +22,7 @@ import { IUserHasId } from '~/interfaces/user';
 import { Ref } from '~/interfaces/common';
 import { HasObjectId } from '~/interfaces/has-object-id';
 import { SocketEventName, UpdateDescCountRawData } from '~/interfaces/websocket';
+import { PageDeleteConfigValue } from '~/interfaces/page-delete-config';
 import PageOperation, { PageActionStage, PageActionType } from '../models/page-operation';
 import ActivityDefine from '../util/activityDefine';
 
@@ -208,28 +209,47 @@ class PageService {
     });
   }
 
-  // TODOT: implement
   canDeleteCompletely(creatorId: ObjectIdLike, operator, isRecursively: boolean): boolean {
     const pageCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority');
-    if (operator.admin) {
+    const pageRecursiveCompleteDeletionAuthority = this.crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority');
+
+    return this.canDeleteLogic(creatorId, operator, isRecursively, pageCompleteDeletionAuthority, pageRecursiveCompleteDeletionAuthority);
+  }
+
+  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');
+
+    return this.canDeleteLogic(creatorId, operator, isRecursively, pageDeletionAuthority, pageRecursiveDeletionAuthority);
+  }
+
+  private canDeleteLogic(creatorId: ObjectIdLike, operator, isRecursively: boolean, authority, recursiveAuthority): boolean {
+    const isAdmin = operator.admin;
+    const isOperator = operator?._id == null ? false : operator._id.equals(creatorId);
+
+    if (isAdmin) {
       return true;
     }
-    if (pageCompleteDeletionAuthority === 'anyOne' || pageCompleteDeletionAuthority == null) {
+
+    if (isRecursively) {
+      if (recursiveAuthority === PageDeleteConfigValue.Inherit || recursiveAuthority == null) {
+        // Do nothing
+      }
+      else if (recursiveAuthority === PageDeleteConfigValue.AdminAndAuthor && isOperator) {
+        return true;
+      }
+    }
+
+    if (authority === PageDeleteConfigValue.Anyone || authority == null) {
       return true;
     }
-    if (pageCompleteDeletionAuthority === 'adminAndAuthor') {
-      const operatorId = operator?._id;
-      return (operatorId != null && operatorId.equals(creatorId));
+    if (authority === PageDeleteConfigValue.AdminAndAuthor && isOperator) {
+      return true;
     }
 
     return false;
   }
 
-  // TODOT: implement
-  canDelete(creatorId: ObjectIdLike, operator, isRecursively: boolean): boolean {
-    return false;
-  }
-
   filterPagesByCanDeleteCompletely(pages, user, isRecursively: boolean) {
     return pages.filter(p => p.isEmpty || this.canDeleteCompletely(p.creator, user, isRecursively));
   }
@@ -289,7 +309,7 @@ class PageService {
 
     const isBookmarked: boolean = (await Bookmark.findByPageIdAndUserId(pageId, user._id)) != null;
     const isLiked: boolean = page.isLiked(user);
-    const isAbleToDeleteCompletely: boolean = this.canDeleteCompletely((page.creator as IUserHasId)?._id, user, false); // TODOT: consider
+    const isAbleToDeleteCompletely: boolean = this.canDeleteCompletely((page.creator as IUserHasId)?._id, user, false); // use normal delete config
 
     const subscription = await Subscription.findByUserIdAndTargetId(user._id, pageId);