Просмотр исходного кода

Merge pull request #7437 from weseek/imprv/customize-user-page-deleteable

imprv: User home page deleteable if needed
Yuki Takei 3 лет назад
Родитель
Сommit
2b595e1ff7

+ 1 - 0
packages/app/src/client/services/AdminGeneralSecurityContainer.js

@@ -218,6 +218,7 @@ export default class AdminGeneralSecurityContainer extends Container {
       pageRecursiveCompleteDeletionAuthority: this.state.currentPageRecursiveCompleteDeletionAuthority,
       hideRestrictedByGroup: !this.state.isShowRestrictedByGroup,
       hideRestrictedByOwner: !this.state.isShowRestrictedByOwner,
+      isUserPageDeletionEnabled: this.state.isUserPageDeletionEnabled,
     };
 
     requestParams = await removeNullPropertyFromObject(requestParams);

+ 1 - 0
packages/app/src/server/models/config.ts

@@ -67,6 +67,7 @@ export const defaultCrowiConfigs: { [key: string]: any } = {
   'security:pageRecursiveDeletionAuthority' : undefined,
   'security:pageRecursiveCompleteDeletionAuthority' : undefined,
   'security:disableLinkSharing' : false,
+  'security:isUserPageDeletionEnabled': false,
 
   'security:passport-local:isEnabled' : true,
   'security:passport-ldap:isEnabled' : false,

+ 0 - 7
packages/app/src/server/models/obsolete-page.js

@@ -672,13 +672,6 @@ export const getPageSchema = (crowi) => {
 
   };
 
-  pageSchema.statics.removeByPath = function(path) {
-    if (path == null) {
-      throw new Error('path is required');
-    }
-    return this.findOneAndRemove({ path }).exec();
-  };
-
   pageSchema.statics.findListByPathsArray = async function(paths, includeEmpty = false) {
     const queryBuilder = new this.PageQueryBuilder(this.find(), includeEmpty);
     queryBuilder.addConditionToListByPathsArray(paths);

+ 17 - 0
packages/app/src/server/models/page.ts

@@ -4,6 +4,7 @@ import nodePath from 'path';
 
 import { HasObjectId, pagePathUtils, pathUtils } from '@growi/core';
 import escapeStringRegexp from 'escape-string-regexp';
+import { DeleteResult } from 'mongodb';
 import mongoose, {
   Schema, Model, Document, AnyObject,
 } from 'mongoose';
@@ -954,6 +955,22 @@ schema.statics.findNonEmptyClosestAncestor = async function(path: string): Promi
   return ancestors[0];
 };
 
+schema.statics.removeUserHome = async function(
+    username: string,
+): Promise<{ deleteManyResult: DeleteResult, findOneAndRemoveResult: PageDocument & HasObjectId | null }> {
+  const userHomePagePath = `/user/${username}`;
+
+  // https://regex101.com/r/PY1tI5/1
+  const regex = new RegExp(`^${userHomePagePath}/.+`);
+
+  const [deleteManyResult, findOneAndRemoveResult] = await Promise.all([
+    this.deleteMany({ path: regex }),
+    this.findOneAndRemove({ path: userHomePagePath }),
+  ]);
+
+  return { deleteManyResult, findOneAndRemoveResult };
+};
+
 
 export type PageCreateOptions = {
   format?: string

+ 4 - 0
packages/app/src/server/routes/apiv3/security-setting.js

@@ -27,6 +27,7 @@ const validator = {
     body('pageCompleteDeletionAuthority').if(value => value != null).isString().isIn(Object.values(PageDeleteConfigValue)),
     body('hideRestrictedByOwner').if(value => value != null).isBoolean(),
     body('hideRestrictedByGroup').if(value => value != null).isBoolean(),
+    body('isUserPageDeletionEnabled').if(value => value != null).isBoolean(),
   ],
   shareLinkSetting: [
     body('disableLinkSharing').if(value => value != null).isBoolean(),
@@ -354,6 +355,7 @@ module.exports = (crowi) => {
         pageRecursiveCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority'),
         hideRestrictedByOwner: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByOwner'),
         hideRestrictedByGroup: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByGroup'),
+        isUserPageDeletionEnabled: await crowi.configManager.getConfig('crowi', 'security:isUserPageDeletionEnabled'),
         wikiMode: await crowi.configManager.getConfig('crowi', 'security:wikiMode'),
         sessionMaxAge: await crowi.configManager.getConfig('crowi', 'security:sessionMaxAge'),
       },
@@ -612,6 +614,7 @@ module.exports = (crowi) => {
       'security:pageRecursiveCompleteDeletionAuthority': req.body.pageRecursiveCompleteDeletionAuthority,
       'security:list-policy:hideRestrictedByOwner': req.body.hideRestrictedByOwner,
       'security:list-policy:hideRestrictedByGroup': req.body.hideRestrictedByGroup,
+      'security:isUserPageDeletionEnabled': req.body.isUserPageDeletionEnabled,
     };
 
     // Validate delete config
@@ -640,6 +643,7 @@ module.exports = (crowi) => {
         pageRecursiveCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority'),
         hideRestrictedByOwner: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByOwner'),
         hideRestrictedByGroup: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByGroup'),
+        isUserPageDeletionEnabled: await crowi.configManager.getConfig('crowi', 'security:isUserPageDeletionEnabled'),
       };
 
       const parameters = { action: SupportedAction.ACTION_ADMIN_SECURITY_SETTINGS_UPDATE };

+ 3 - 1
packages/app/src/server/routes/apiv3/users.js

@@ -672,13 +672,15 @@ module.exports = (crowi) => {
    */
   router.delete('/:id/remove', loginRequiredStrictly, adminRequired, certifyUserOperationOtherThenYourOwn, addActivity, async(req, res) => {
     const { id } = req.params;
+    const isUserPageDeletionEnabled = crowi.configManager.getConfig('crowi', 'security:isUserPageDeletionEnabled');
 
     try {
       const userData = await User.findById(id);
+      const username = userData.username;
       await UserGroupRelation.remove({ relatedUser: userData });
       await userData.statusDelete();
       await ExternalAccount.remove({ user: userData });
-      await Page.removeByPath(`/user/${userData.username}`);
+      if (isUserPageDeletionEnabled) await Page.removeUserHome(username);
 
       const serializedUserData = serializeUserSecurely(userData);