Răsfoiți Sursa

refactor user group delete code

Futa Arai 2 ani în urmă
părinte
comite
a1f5d676c3

+ 16 - 21
apps/app/src/components/Admin/UserGroup/UserGroupDeleteModal.tsx

@@ -7,6 +7,8 @@ import {
   Modal, ModalHeader, ModalBody, ModalFooter,
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 } from 'reactstrap';
 
 
+import { PageActionOnGroupDelete } from '~/interfaces/user-group';
+
 
 
 /**
 /**
  * Delete User Group Select component
  * Delete User Group Select component
@@ -18,26 +20,19 @@ import {
 type Props = {
 type Props = {
   userGroups: IUserGroupHasId[],
   userGroups: IUserGroupHasId[],
   deleteUserGroup?: IUserGroupHasId,
   deleteUserGroup?: IUserGroupHasId,
-  onDelete?: (deleteGroupId: string, actionName: string, transferToUserGroupId: string) => Promise<void> | void,
+  onDelete?: (deleteGroupId: string, actionName: PageActionOnGroupDelete, transferToUserGroupId: string) => Promise<void> | void,
   isShow: boolean,
   isShow: boolean,
   onHide?: () => Promise<void> | void,
   onHide?: () => Promise<void> | void,
 };
 };
 
 
 type AvailableOption = {
 type AvailableOption = {
   id: number,
   id: number,
-  actionForPages: string,
+  actionForPages: PageActionOnGroupDelete,
   iconClass: string,
   iconClass: string,
   styleClass: string,
   styleClass: string,
   label: string,
   label: string,
 };
 };
 
 
-// actionName master constants
-const actionForPages = {
-  public: 'public',
-  delete: 'delete',
-  transfer: 'transfer',
-};
-
 export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
 export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
 
 
   const { t } = useTranslation();
   const { t } = useTranslation();
@@ -50,21 +45,21 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
     return [
     return [
       {
       {
         id: 1,
         id: 1,
-        actionForPages: actionForPages.public,
+        actionForPages: PageActionOnGroupDelete.publicize,
         iconClass: 'icon-people',
         iconClass: 'icon-people',
         styleClass: '',
         styleClass: '',
         label: t('admin:user_group_management.delete_modal.publish_pages'),
         label: t('admin:user_group_management.delete_modal.publish_pages'),
       },
       },
       {
       {
         id: 2,
         id: 2,
-        actionForPages: actionForPages.delete,
+        actionForPages: PageActionOnGroupDelete.delete,
         iconClass: 'icon-trash',
         iconClass: 'icon-trash',
         styleClass: 'text-danger',
         styleClass: 'text-danger',
         label: t('admin:user_group_management.delete_modal.delete_pages'),
         label: t('admin:user_group_management.delete_modal.delete_pages'),
       },
       },
       {
       {
         id: 3,
         id: 3,
-        actionForPages: actionForPages.transfer,
+        actionForPages: PageActionOnGroupDelete.transfer,
         iconClass: 'icon-options',
         iconClass: 'icon-options',
         styleClass: '',
         styleClass: '',
         label: t('admin:user_group_management.delete_modal.transfer_pages'),
         label: t('admin:user_group_management.delete_modal.transfer_pages'),
@@ -75,14 +70,14 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
   /*
   /*
    * State
    * State
    */
    */
-  const [actionName, setActionName] = useState<string>('');
+  const [actionName, setActionName] = useState<PageActionOnGroupDelete | null>(null);
   const [transferToUserGroupId, setTransferToUserGroupId] = useState<string>('');
   const [transferToUserGroupId, setTransferToUserGroupId] = useState<string>('');
 
 
   /*
   /*
    * Function
    * Function
    */
    */
   const resetStates = useCallback(() => {
   const resetStates = useCallback(() => {
-    setActionName('');
+    setActionName(null);
     setTransferToUserGroupId('');
     setTransferToUserGroupId('');
   }, []);
   }, []);
 
 
@@ -106,7 +101,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
   }, []);
   }, []);
 
 
   const handleSubmit = useCallback((e) => {
   const handleSubmit = useCallback((e) => {
-    if (onDelete == null || deleteUserGroup == null) {
+    if (onDelete == null || deleteUserGroup == null || actionName == null) {
       return;
       return;
     }
     }
 
 
@@ -129,7 +124,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
         name="actionName"
         name="actionName"
         className="form-control"
         className="form-control"
         placeholder="select"
         placeholder="select"
-        value={actionName}
+        value={actionName?.toString() ?? ''}
         onChange={handleActionChange}
         onChange={handleActionChange}
       >
       >
         <option value="" disabled>{t('admin:user_group_management.delete_modal.dropdown_desc')}</option>
         <option value="" disabled>{t('admin:user_group_management.delete_modal.dropdown_desc')}</option>
@@ -157,7 +152,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
     return (
     return (
       <select
       <select
         name="transferToUserGroupId"
         name="transferToUserGroupId"
-        className={`form-control ${actionName === actionForPages.transfer ? '' : 'd-none'}`}
+        className={`form-control ${actionName === PageActionOnGroupDelete.transfer ? '' : 'd-none'}`}
         value={transferToUserGroupId}
         value={transferToUserGroupId}
         onChange={handleGroupChange}
         onChange={handleGroupChange}
       >
       >
@@ -170,10 +165,10 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
   const validateForm = useCallback(() => {
   const validateForm = useCallback(() => {
     let isValid = true;
     let isValid = true;
 
 
-    if (actionName === '') {
+    if (actionName === null) {
       isValid = false;
       isValid = false;
     }
     }
-    else if (actionName === actionForPages.transfer) {
+    else if (actionName === PageActionOnGroupDelete.transfer) {
       isValid = transferToUserGroupId !== '';
       isValid = transferToUserGroupId !== '';
     }
     }
 
 
@@ -195,7 +190,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>
         <form className="d-flex justify-content-between w-100" onSubmit={handleSubmit}>
         <form className="d-flex justify-content-between w-100" onSubmit={handleSubmit}>
-          <div className="d-flex mb-0 me-3          ">
+          <div className="d-flex mb-0 me-3">
             {renderPageActionSelector()}
             {renderPageActionSelector()}
             {renderGroupSelector()}
             {renderGroupSelector()}
           </div>
           </div>
@@ -203,7 +198,7 @@ export const UserGroupDeleteModal: FC<Props> = (props: Props) => {
             <span className="material-symbols-outlined">delete_forever</span> {t('Delete')}
             <span className="material-symbols-outlined">delete_forever</span> {t('Delete')}
           </button>
           </button>
         </form>
         </form>
-        {actionName === 'public' && (
+        {actionName === PageActionOnGroupDelete.publicize && (
           <div className="form-text text-muted">
           <div className="form-text text-muted">
             <small>{t('admin:user_group_management.delete_modal.option_explanation')}</small>
             <small>{t('admin:user_group_management.delete_modal.option_explanation')}</small>
           </div>
           </div>

+ 2 - 1
apps/app/src/components/Admin/UserGroup/UserGroupPage.tsx

@@ -10,6 +10,7 @@ import { toastSuccess, toastError } from '~/client/util/toastr';
 import { ExternalGroupManagement } from '~/features/external-user-group/client/components/ExternalUserGroup/ExternalUserGroupManagement';
 import { ExternalGroupManagement } from '~/features/external-user-group/client/components/ExternalUserGroup/ExternalUserGroupManagement';
 import { useIsAclEnabled } from '~/stores/context';
 import { useIsAclEnabled } from '~/stores/context';
 import { useSWRxUserGroupList, useSWRxChildUserGroupList, useSWRxUserGroupRelationList } from '~/stores/user-group';
 import { useSWRxUserGroupList, useSWRxChildUserGroupList, useSWRxUserGroupRelationList } from '~/stores/user-group';
+import { PageActionOnGroupDelete } from '~/interfaces/user-group';
 
 
 
 
 const UserGroupDeleteModal = dynamic(() => import('./UserGroupDeleteModal').then(mod => mod.UserGroupDeleteModal), { ssr: false });
 const UserGroupDeleteModal = dynamic(() => import('./UserGroupDeleteModal').then(mod => mod.UserGroupDeleteModal), { ssr: false });
@@ -127,7 +128,7 @@ export const UserGroupPage: FC = () => {
     }
     }
   }, [t, mutateUserGroups, hideUpdateModal]);
   }, [t, mutateUserGroups, hideUpdateModal]);
 
 
-  const deleteUserGroupById = useCallback(async(deleteGroupId: string, actionName: string, transferToUserGroupId: string) => {
+  const deleteUserGroupById = useCallback(async(deleteGroupId: string, actionName: PageActionOnGroupDelete, transferToUserGroupId: string) => {
     try {
     try {
       await apiv3Delete(`/user-groups/${deleteGroupId}`, {
       await apiv3Delete(`/user-groups/${deleteGroupId}`, {
         actionName,
         actionName,

+ 2 - 2
apps/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.tsx

@@ -14,7 +14,7 @@ import {
 } from '~/client/util/apiv3-client';
 } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import type { IExternalUserGroupHasId } from '~/features/external-user-group/interfaces/external-user-group';
 import type { IExternalUserGroupHasId } from '~/features/external-user-group/interfaces/external-user-group';
-import type { SearchType } from '~/interfaces/user-group';
+import type { PageActionOnGroupDelete, SearchType } from '~/interfaces/user-group';
 import { SearchTypes } from '~/interfaces/user-group';
 import { SearchTypes } from '~/interfaces/user-group';
 import Xss from '~/services/xss';
 import Xss from '~/services/xss';
 import { useIsAclEnabled } from '~/stores/context';
 import { useIsAclEnabled } from '~/stores/context';
@@ -297,7 +297,7 @@ const UserGroupDetailPage = (props: Props): JSX.Element => {
     setDeleteModalShown(false);
     setDeleteModalShown(false);
   }, [setSelectedUserGroup, setDeleteModalShown]);
   }, [setSelectedUserGroup, setDeleteModalShown]);
 
 
-  const deleteChildUserGroupById = useCallback(async(deleteGroupId: string, actionName: string, transferToUserGroupId: string) => {
+  const deleteChildUserGroupById = useCallback(async(deleteGroupId: string, actionName: PageActionOnGroupDelete, transferToUserGroupId: string) => {
     const url = isExternalGroup ? `/external-user-groups/${deleteGroupId}` : `/user-groups/${deleteGroupId}`;
     const url = isExternalGroup ? `/external-user-groups/${deleteGroupId}` : `/user-groups/${deleteGroupId}`;
     try {
     try {
       const res = await apiv3Delete(url, {
       const res = await apiv3Delete(url, {

+ 2 - 1
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/ExternalUserGroupManagement.tsx

@@ -17,6 +17,7 @@ import { useSWRxChildExternalUserGroupList, useSWRxExternalUserGroupList, useSWR
 
 
 import { KeycloakGroupManagement } from './KeycloakGroupManagement';
 import { KeycloakGroupManagement } from './KeycloakGroupManagement';
 import { LdapGroupManagement } from './LdapGroupManagement';
 import { LdapGroupManagement } from './LdapGroupManagement';
+import { PageActionOnGroupDelete } from '~/interfaces/user-group';
 
 
 export const ExternalGroupManagement: FC = () => {
 export const ExternalGroupManagement: FC = () => {
   const { data: externalUserGroupList, mutate: mutateExternalUserGroups } = useSWRxExternalUserGroupList();
   const { data: externalUserGroupList, mutate: mutateExternalUserGroups } = useSWRxExternalUserGroupList();
@@ -92,7 +93,7 @@ export const ExternalGroupManagement: FC = () => {
     }
     }
   }, [t, mutateExternalUserGroups, hideUpdateModal]);
   }, [t, mutateExternalUserGroups, hideUpdateModal]);
 
 
-  const deleteExternalUserGroupById = useCallback(async(deleteGroupId: string, actionName: string, transferToUserGroupId: string) => {
+  const deleteExternalUserGroupById = useCallback(async(deleteGroupId: string, actionName: PageActionOnGroupDelete, transferToUserGroupId: string) => {
     try {
     try {
       await apiv3Delete(`/external-user-groups/${deleteGroupId}`, {
       await apiv3Delete(`/external-user-groups/${deleteGroupId}`, {
         actionName,
         actionName,

+ 3 - 1
apps/app/src/features/external-user-group/server/routes/apiv3/external-user-group.ts

@@ -9,6 +9,7 @@ import {
 import ExternalUserGroup from '~/features/external-user-group/server/models/external-user-group';
 import ExternalUserGroup from '~/features/external-user-group/server/models/external-user-group';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import { SupportedAction } from '~/interfaces/activity';
 import { SupportedAction } from '~/interfaces/activity';
+import type { PageActionOnGroupDelete } from '~/interfaces/user-group';
 import type Crowi from '~/server/crowi';
 import type Crowi from '~/server/crowi';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
 import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
@@ -149,7 +150,8 @@ module.exports = (crowi: Crowi): Router => {
   router.delete('/:id', loginRequiredStrictly, adminRequired, validators.delete, apiV3FormValidator, addActivity,
   router.delete('/:id', loginRequiredStrictly, adminRequired, validators.delete, apiV3FormValidator, addActivity,
     async(req: AuthorizedRequest, res: ApiV3Response) => {
     async(req: AuthorizedRequest, res: ApiV3Response) => {
       const { id: deleteGroupId } = req.params;
       const { id: deleteGroupId } = req.params;
-      const { actionName, transferToUserGroupId } = req.query;
+      const { transferToUserGroupId } = req.query;
+      const actionName = req.query.actionName as PageActionOnGroupDelete;
 
 
       const transferGroupInfo = transferToUserGroupId != null ? {
       const transferGroupInfo = transferToUserGroupId != null ? {
         item: transferToUserGroupId as string,
         item: transferToUserGroupId as string,

+ 3 - 0
apps/app/src/interfaces/user-group.ts

@@ -5,3 +5,6 @@ export const SearchTypes = {
 } as const;
 } as const;
 
 
 export type SearchType = typeof SearchTypes[keyof typeof SearchTypes];
 export type SearchType = typeof SearchTypes[keyof typeof SearchTypes];
+
+export const PageActionOnGroupDelete = { publicize: 'publicize', delete: 'delete', transfer: 'transfer' } as const;
+export type PageActionOnGroupDelete = typeof PageActionOnGroupDelete[keyof typeof PageActionOnGroupDelete];

+ 0 - 15
apps/app/src/server/models/obsolete-page.js

@@ -646,21 +646,6 @@ export const getPageSchema = (crowi) => {
     return await queryBuilder.query.exec();
     return await queryBuilder.query.exec();
   };
   };
 
 
-  pageSchema.statics.publicizePages = async function(pages) {
-    const operationsToPublicize = pages.map((page) => {
-      return {
-        updateOne: {
-          filter: { _id: page._id },
-          update: {
-            grantedGroups: [],
-            grant: this.GRANT_PUBLIC,
-          },
-        },
-      };
-    });
-    await this.bulkWrite(operationsToPublicize);
-  };
-
   /**
   /**
    * transfer pages grant to specified user group
    * transfer pages grant to specified user group
    * @param {Page[]} pages
    * @param {Page[]} pages

+ 38 - 1
apps/app/src/server/models/page.ts

@@ -7,7 +7,7 @@ import {
   type IPage,
   type IPage,
   GroupType, type HasObjectId,
   GroupType, type HasObjectId,
 } from '@growi/core';
 } from '@growi/core';
-import { isPopulated } from '@growi/core/dist/interfaces';
+import { getIdForRef, isPopulated } from '@growi/core/dist/interfaces';
 import { isTopPage, hasSlash, collectAncestorPaths } from '@growi/core/dist/utils/page-path-utils';
 import { isTopPage, hasSlash, collectAncestorPaths } from '@growi/core/dist/utils/page-path-utils';
 import { addTrailingSlash, normalizePath } from '@growi/core/dist/utils/path-utils';
 import { addTrailingSlash, normalizePath } from '@growi/core/dist/utils/path-utils';
 import escapeStringRegexp from 'escape-string-regexp';
 import escapeStringRegexp from 'escape-string-regexp';
@@ -18,6 +18,7 @@ import mongoose, {
 import mongoosePaginate from 'mongoose-paginate-v2';
 import mongoosePaginate from 'mongoose-paginate-v2';
 import uniqueValidator from 'mongoose-unique-validator';
 import uniqueValidator from 'mongoose-unique-validator';
 
 
+import type { ExternalUserGroupDocument } from '~/features/external-user-group/server/models/external-user-group';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import type { IOptionsForCreate } from '~/interfaces/page';
 import type { IOptionsForCreate } from '~/interfaces/page';
 import type { ObjectIdLike } from '~/server/interfaces/mongoose-utils';
 import type { ObjectIdLike } from '~/server/interfaces/mongoose-utils';
@@ -26,6 +27,7 @@ import loggerFactory from '../../utils/logger';
 import { getOrCreateModel } from '../util/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 
 
 import { getPageSchema, extractToAncestorsPaths, populateDataToShowRevision } from './obsolete-page';
 import { getPageSchema, extractToAncestorsPaths, populateDataToShowRevision } from './obsolete-page';
+import type { UserGroupDocument } from './user-group';
 import UserGroupRelation from './user-group-relation';
 import UserGroupRelation from './user-group-relation';
 
 
 const logger = loggerFactory('growi:models:page');
 const logger = loggerFactory('growi:models:page');
@@ -81,6 +83,7 @@ export interface PageModel extends Model<PageDocument> {
     templateBody?: string,
     templateBody?: string,
     templateTags?: string[],
     templateTags?: string[],
   }>
   }>
+  removeGroupsToDeleteFromPages(pages: PageDocument[], groupsToDelete: UserGroupDocument[] | ExternalUserGroupDocument[]): Promise<void>
 
 
   PageQueryBuilder: typeof PageQueryBuilder
   PageQueryBuilder: typeof PageQueryBuilder
 
 
@@ -1018,6 +1021,40 @@ schema.statics.findNonEmptyClosestAncestor = async function(path: string): Promi
   return ancestors[0];
   return ancestors[0];
 };
 };
 
 
+schema.statics.removeGroupsToDeleteFromPages = async function(pages: PageDocument[], groupsToDelete: UserGroupDocument[] | ExternalUserGroupDocument[]) {
+  const groupsToDeleteIds = groupsToDelete.map(group => group._id.toString());
+  const pageGroups = pages.reduce((acc: { canPublicize: PageDocument[], cannotPublicize: PageDocument[] }, page) => {
+    const canPublicize = page.grantedGroups.every(group => groupsToDeleteIds.includes(getIdForRef(group.item).toString()));
+    acc[canPublicize ? 'canPublicize' : 'cannotPublicize'].push(page);
+    return acc;
+  }, { canPublicize: [], cannotPublicize: [] });
+
+  // Only publicize pages that can only be accessed by the groups to be deleted
+  const publicizeQueries = pageGroups.canPublicize.map((page) => {
+    return {
+      updateOne: {
+        filter: { _id: page._id },
+        update: {
+          grantedGroups: [],
+          grant: this.GRANT_PUBLIC,
+        },
+      },
+    };
+  });
+  await this.bulkWrite(publicizeQueries);
+
+  // Remove the groups to be deleted from the grantedGroups of the pages that can be accessed by other groups
+  const removeFromGrantedGroupsQueries = pageGroups.cannotPublicize.map((page) => {
+    return {
+      updateOne: {
+        filter: { _id: page._id },
+        update: { $set: { grantedGroups: page.grantedGroups.filter(group => !groupsToDeleteIds.includes(getIdForRef(group.item).toString())) } },
+      },
+    };
+  });
+  await this.bulkWrite(removeFromGrantedGroupsQueries);
+};
+
 /*
 /*
  * get latest revision body length
  * get latest revision body length
  */
  */

+ 6 - 25
apps/app/src/server/service/page/index.ts

@@ -31,6 +31,7 @@ import type { PopulatedGrantedGroup } from '~/interfaces/page-grant';
 import {
 import {
   type IPageOperationProcessInfo, type IPageOperationProcessData, PageActionStage, PageActionType,
   type IPageOperationProcessInfo, type IPageOperationProcessData, PageActionStage, PageActionType,
 } from '~/interfaces/page-operation';
 } from '~/interfaces/page-operation';
+import { PageActionOnGroupDelete } from '~/interfaces/user-group';
 import { SocketEventName, type PageMigrationErrorData, type UpdateDescCountRawData } from '~/interfaces/websocket';
 import { SocketEventName, type PageMigrationErrorData, type UpdateDescCountRawData } from '~/interfaces/websocket';
 import type { CreateMethod } from '~/server/models/page';
 import type { CreateMethod } from '~/server/models/page';
 import {
 import {
@@ -2504,38 +2505,18 @@ class PageService implements IPageService {
 
 
 
 
   async handlePrivatePagesForGroupsToDelete(
   async handlePrivatePagesForGroupsToDelete(
-      groupsToDelete: UserGroupDocument[] | ExternalUserGroupDocument[], action: string, transferToUserGroup: IGrantedGroup, user,
+      groupsToDelete: UserGroupDocument[] | ExternalUserGroupDocument[], action: PageActionOnGroupDelete, transferToUserGroup: IGrantedGroup, user,
   ): Promise<void> {
   ): Promise<void> {
     const Page = mongoose.model<IPage, PageModel>('Page');
     const Page = mongoose.model<IPage, PageModel>('Page');
     const pages = await Page.find({ grantedGroups: { $elemMatch: { item: { $in: groupsToDelete } } } });
     const pages = await Page.find({ grantedGroups: { $elemMatch: { item: { $in: groupsToDelete } } } });
 
 
     switch (action) {
     switch (action) {
-      case 'public': {
-        const groupsToDeleteIds = groupsToDelete.map(group => group._id.toString());
-        const pageGroups = pages.reduce((acc: { canPublicize: PageDocument[], cannotPublicize: PageDocument[] }, page) => {
-          const canPublicize = page.grantedGroups.every(group => groupsToDeleteIds.includes(getIdForRef(group.item).toString()));
-          acc[canPublicize ? 'canPublicize' : 'cannotPublicize'].push(page);
-          return acc;
-        }, { canPublicize: [], cannotPublicize: [] });
-
-        // Only publicize pages that can only be accessed by the groups to be deleted
-        await Page.publicizePages(pageGroups.canPublicize);
-        // Remove the groups to be deleted from the grantedGroups of the pages that can be accessed by other groups
-        const queries = pageGroups.cannotPublicize.map((page) => {
-          return {
-            updateOne: {
-              filter: { _id: page._id },
-              update: { $set: { grantedGroups: page.grantedGroups.filter(group => !groupsToDeleteIds.includes(getIdForRef(group.item).toString())) } },
-            },
-          };
-        });
-        await Page.bulkWrite(queries);
-
+      case PageActionOnGroupDelete.publicize:
+        await Page.removeGroupsToDeleteFromPages(pages, groupsToDelete);
         break;
         break;
-      }
-      case 'delete':
+      case PageActionOnGroupDelete.delete:
         return this.deleteMultipleCompletely(pages, user);
         return this.deleteMultipleCompletely(pages, user);
-      case 'transfer':
+      case PageActionOnGroupDelete.transfer:
         await Page.transferPagesToGroup(pages, transferToUserGroup);
         await Page.transferPagesToGroup(pages, transferToUserGroup);
         break;
         break;
       default:
       default:

+ 2 - 1
apps/app/src/server/service/user-group.ts

@@ -10,6 +10,7 @@ import loggerFactory from '~/utils/logger';
 
 
 import type { UserGroupRelationDocument, UserGroupRelationModel } from '../models/user-group-relation';
 import type { UserGroupRelationDocument, UserGroupRelationModel } from '../models/user-group-relation';
 import UserGroupRelation from '../models/user-group-relation';
 import UserGroupRelation from '../models/user-group-relation';
+import { PageActionOnGroupDelete } from '~/interfaces/user-group';
 
 
 
 
 const logger = loggerFactory('growi:service:UserGroupService'); // eslint-disable-line no-unused-vars
 const logger = loggerFactory('growi:service:UserGroupService'); // eslint-disable-line no-unused-vars
@@ -124,7 +125,7 @@ class UserGroupService implements IUserGroupService {
   }
   }
 
 
   async removeCompletelyByRootGroupId(
   async removeCompletelyByRootGroupId(
-      deleteRootGroupId, action, user, transferToUserGroup?: IGrantedGroup,
+      deleteRootGroupId, action: PageActionOnGroupDelete, user, transferToUserGroup?: IGrantedGroup,
       userGroupModel: Model<UserGroupDocument> & UserGroupModel = UserGroup,
       userGroupModel: Model<UserGroupDocument> & UserGroupModel = UserGroup,
       userGroupRelationModel: Model<UserGroupRelationDocument> & UserGroupRelationModel = UserGroupRelation,
       userGroupRelationModel: Model<UserGroupRelationDocument> & UserGroupRelationModel = UserGroupRelation,
   ): Promise<DeleteResult> {
   ): Promise<DeleteResult> {