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

Merge pull request #6063 from weseek/feat/97979-97981-do-not-create-activity-if-not-belong-to-action-group

feat: Do not create an Activity if it is an action that does not belong to the Action Group
Yuki Takei 3 лет назад
Родитель
Сommit
e7768bb7a1

+ 1 - 0
packages/app/.env.development

@@ -30,3 +30,4 @@ OGP_URI="http://ogp:8088"
 # GROWI_CLOUD_URI='http://growi.cloud'
 # GROWI_APP_ID_FOR_GROWI_CLOUD=012345
 # ACTIVITY_EXPIRATION_SECONDS=2592000
+# AUDIT_LOG_ACTION_GROUP_SIZE=SMALL

+ 62 - 0
packages/app/src/interfaces/activity.ts

@@ -101,6 +101,65 @@ export const SupportedAction = {
   ACTION_ADMIN_SEARCH_INDICES_REBUILD,
 } as const;
 
+export const ActionGroupSize = {
+  Small: 'SMALL',
+  Medium: 'MEDIUM',
+  Large: 'LARGE',
+} as const;
+
+export const SmallActionGroup = {
+  ACTION_LOGIN_SUCCESS,
+  ACTION_LOGIN_FAILURE,
+  ACTION_LOGOUT,
+  ACTION_PAGE_CREATE,
+  ACTION_PAGE_DELETE,
+} as const;
+
+// SmallActionGroup + Action by all General Users - PAGE_VIEW
+export const MediumActionGroup = {
+  ...SmallActionGroup,
+  ACTION_USER_PERSONAL_SETTINGS_UPDATE,
+  ACTION_USER_IMAGE_TYPE_UPDATE,
+  ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
+  ACTION_USER_LDAP_ACCOUNT_DISCONNECT,
+  ACTION_USER_PASSWORD_UPDATE,
+  ACTION_USER_API_TOKEN_UPDATE,
+  ACTION_USER_EDITOR_SETTINGS_UPDATE,
+  ACTION_USER_IN_APP_NOTIFICATION_SETTINGS_UPDATE,
+  ACTION_PAGE_LIKE,
+  ACTION_PAGE_UNLIKE,
+  ACTION_PAGE_BOOKMARK,
+  ACTION_PAGE_UNBOOKMARK,
+  ACTION_PAGE_CREATE,
+  ACTION_PAGE_UPDATE,
+  ACTION_PAGE_RENAME,
+  ACTION_PAGE_DUPLICATE,
+  ACTION_PAGE_DELETE,
+  ACTION_PAGE_DELETE_COMPLETELY,
+  ACTION_PAGE_REVERT,
+  ACTION_COMMENT_CREATE,
+  ACTION_COMMENT_UPDATE,
+  ACTION_COMMENT_REMOVE,
+} as const;
+
+// MediumActionGroup + All Actions by Admin Users - PAGE_VIEW
+export const LargeActionGroup = {
+  ...MediumActionGroup,
+  ACTION_ADMIN_APP_SETTINGS_UPDATE,
+  ACTION_ADMIN_SECURITY_SETTINGS_UPDATE,
+  ACTION_ADMIN_LINE_BREAK_UPDATE,
+  ACTION_ADMIN_LAYOUT_UPDATE,
+  ACTION_ADMIN_ARCHIVE_DATA_UPLOAD,
+  ACTION_ADMIN_ARCHIVE_DATA_CREATE,
+  ACTION_ADMIN_USER_NOTIFICATION_SETTINGS_ADD,
+  ACTION_ADMIN_SLACK_WORKSPACE_CREATE,
+  ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE,
+  ACTION_ADMIN_USERS_INVITE,
+  ACTION_ADMIN_USER_GROUP_CREATE,
+  ACTION_ADMIN_SEARCH_INDICES_NORMALIZE,
+  ACTION_ADMIN_SEARCH_INDICES_REBUILD,
+} as const;
+
 export const SupportedActionToNotified = {
   ACTION_PAGE_LIKE,
   ACTION_PAGE_BOOKMARK,
@@ -140,6 +199,9 @@ export const AllSupportedTargetModel = Object.values(SupportedTargetModel);
 export const AllSupportedEventModel = Object.values(SupportedEventModel);
 export const AllSupportedAction = Object.values(SupportedAction);
 export const AllSupportedActionToNotified = Object.values(SupportedActionToNotified);
+export const AllSmallGroupActions = Object.values(SmallActionGroup);
+export const AllMediumGroupActions = Object.values(MediumActionGroup);
+export const AllLargeGroupActions = Object.values(LargeActionGroup);
 
 /*
  * Type

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

@@ -119,6 +119,7 @@ activitySchema.statics.createByParameters = async function(parameters): Promise<
   return activity;
 };
 
+// When using this method, ensure that activity updates are allowed using ActivityService.shoutUpdateActivity
 activitySchema.statics.updateByParameters = async function(activityId: string, parameters): Promise<IActivity> {
   const activity = await this.findOneAndUpdate({ _id: activityId }, parameters, { new: true }) as unknown as IActivity;
 

+ 45 - 9
packages/app/src/server/service/activity.ts

@@ -1,6 +1,8 @@
 import mongoose from 'mongoose';
 
-import { IActivity } from '~/interfaces/activity';
+import {
+  IActivity, SupportedActionType, ActionGroupSize, AllSmallGroupActions, AllMediumGroupActions, AllLargeGroupActions, AllSupportedActionToNotified,
+} from '~/interfaces/activity';
 import { IPage } from '~/interfaces/page';
 import Activity from '~/server/models/activity';
 
@@ -20,24 +22,58 @@ class ActivityService {
     this.crowi = crowi;
     this.activityEvent = crowi.event('activity');
 
+    this.getAvailableActions = this.getAvailableActions.bind(this);
+    this.shoudUpdateActivity = this.shoudUpdateActivity.bind(this);
+
     this.initActivityEventListeners();
   }
 
   initActivityEventListeners(): void {
     this.activityEvent.on('update', async(activityId: string, parameters, target?: IPage) => {
       let activity: IActivity;
-      try {
-        activity = await Activity.updateByParameters(activityId, parameters);
-      }
-      catch (err) {
-        logger.error('Update activity failed', err);
-        return;
+      const shoudUpdate = this.shoudUpdateActivity(parameters.action);
+
+      if (shoudUpdate) {
+        try {
+          activity = await Activity.updateByParameters(activityId, parameters);
+        }
+        catch (err) {
+          logger.error('Update activity failed', err);
+          return;
+        }
+
+        this.activityEvent.emit('updated', activity, target);
       }
-
-      this.activityEvent.emit('updated', activity, target);
     });
   }
 
+  getAvailableActions = function(): SupportedActionType[] {
+    const auditLogActionGroupSize = this.crowi.configManager.getConfig('crowi', 'app:auditLogActionGroupSize') || ActionGroupSize.Small;
+
+    // TODO: 97982, 97986
+    // Update AvailableActions taking into account the values of "AUDIT_LOG_EXCLUDE_ACTIONS" and “AUDIT_LOG_ADDITONAL_ACTIONS"
+
+    const availableActions: SupportedActionType[] = [...AllSupportedActionToNotified];
+
+    switch (auditLogActionGroupSize) {
+      case ActionGroupSize.Small:
+        availableActions.push(...AllSmallGroupActions);
+        break;
+      case ActionGroupSize.Medium:
+        availableActions.push(...AllMediumGroupActions);
+        break;
+      case ActionGroupSize.Large:
+        availableActions.push(...AllLargeGroupActions);
+        break;
+    }
+
+    return Array.from(new Set(availableActions));
+  }
+
+  shoudUpdateActivity = function(action: SupportedActionType): boolean {
+    return this.getAvailableActions().includes(action);
+  }
+
   createTtlIndex = async function() {
     const configManager = this.crowi.configManager;
     const activityExpirationSeconds = configManager != null ? configManager.getConfig('crowi', 'app:activityExpirationSeconds') : 2592000;

+ 6 - 0
packages/app/src/server/service/config-loader.ts

@@ -628,6 +628,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type: ValueType.NUMBER,
     default: 2592000, // 30 days
   },
+  AUDIT_LOG_ACTION_GROUP_SIZE: {
+    ns: 'crowi',
+    key: 'app:auditLogActionGroupSize',
+    type: ValueType.STRING,
+    default: 'SMALL',
+  },
 };