Browse Source

Merge pull request #6276 from weseek/feat/100013-add-activity

feat: Add activity
Yuki Takei 3 years ago
parent
commit
c4c08e9142

+ 11 - 0
packages/app/public/static/locales/en_US/admin/admin.json

@@ -560,6 +560,8 @@
     "USER_LOGIN_WITH_BASIC": "Login with BASIC",
     "USER_LOGIN_FAILURE": "Login failure",
     "USER_LOGOUT": "Logout",
+    "USER_FOGOT_PASSWORD": "Request password reset",
+    "USER_RESET_PASSWORD": "Reset password",
     "USER_PERSONAL_SETTINGS_UPDATE": "User personal settings update",
     "USER_IMAGE_TYPE_UPDATE": "User image type update",
     "USER_LDAP_ACCOUNT_ASSOCIATE": "LDAP account associate",
@@ -647,6 +649,7 @@
     "ADMIN_MARKDOWN_XSS_UPDATE": "Update prevent XSS settings",
     "ADMIN_LAYOUT_UPDATE": "Update Layout",
     "ADMIN_THEME_UPDATE": "Update Theme",
+    "ADMIN_SIDEBAR_UPDATE": "Update Default Sidebar mode",
     "ADMIN_FUNCTION_UPDATE": "Update Function",
     "ADMIN_CODE_HIGHLIGHT_UPDATE": "Update Code Highlight",
     "ADMIN_CUSTOM_TITLE_UPDATE": "Update Custom Title",
@@ -687,10 +690,18 @@
     "ADMIN_SLACK_WITHOUT_PROXY_TEST": "Test connection to Slack bot without proxy",
     "ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE": "Update Slack Incoming Webhooks configuration",
     "ADMIN_USERS_INVITE": "User Invitation",
+    "ADMIN_USERS_PASSWORD_RESET": "Reset user password",
+    "ADMIN_USERS_ACTIVATE": "Activate user",
+    "ADMIN_USERS_DEACTIVATE": "Deactivate user",
+    "ADMIN_USERS_GIVE_ADMIN": "Give admin access",
+    "ADMIN_USERS_REMOVE_ADMIN": "Remove admin access",
+    "ADMIN_USERS_SEND_INVITATION_EMAIL": "Resend invitation email",
+    "ADMIN_USERS_REMOVE": "Remove user",
     "ADMIN_USER_GROUP_CREATE": "Create User Group",
     "ADMIN_USER_GROUP_UPDATE": "Update User Group",
     "ADMIN_USER_GROUP_DELETE": "Delete User Group",
     "ADMIN_USER_GROUP_ADD_USER": "Add User to User Group",
+    "ADMIN_SEARCH_CONNECTION": "Attempting to reconnect to Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Normalize of Elasticsearch indexes",
     "ADMIN_SEARCH_INDICES_REBUILD": "Rebuild Elasticsearch indexes"
   }

+ 11 - 0
packages/app/public/static/locales/ja_JP/admin/admin.json

@@ -559,6 +559,8 @@
     "USER_LOGIN_WITH_BASIC": "BASIC 認証でログイン",
     "USER_LOGIN_FAILURE": "ログイン失敗",
     "USER_LOGOUT": "ログアウト",
+    "USER_FOGOT_PASSWORD": "パスワードリセットのリクエスト",
+    "USER_RESET_PASSWORD": "パスワードのリセット",
     "USER_PERSONAL_SETTINGS_UPDATE": "ユーザーの基本情報の更新",
     "USER_IMAGE_TYPE_UPDATE": "プロフィール画像の変更",
     "USER_LDAP_ACCOUNT_ASSOCIATE": "LDAP アカウントの追加",
@@ -646,6 +648,7 @@
     "ADMIN_MARKDOWN_XSS_UPDATE": "XSS 対策設定の更新",
     "ADMIN_LAYOUT_UPDATE": "レイアウト設定の更新",
     "ADMIN_THEME_UPDATE": "テーマ設定の更新",
+    "ADMIN_SIDEBAR_UPDATE": "デフォルトのサイドバーモードの設定の更新",
     "ADMIN_FUNCTION_UPDATE": "機能設定の更新",
     "ADMIN_CODE_HIGHLIGHT_UPDATE": "コードハイライト設定の更新",
     "ADMIN_CUSTOM_TITLE_UPDATE": "カスタムタイトル設定の更新",
@@ -686,10 +689,18 @@
     "ADMIN_SLACK_WITHOUT_PROXY_TEST": "Slack bot without proxy の接続テスト",
     "ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE": "Slack Incoming Webhooks の設定の更新",
     "ADMIN_USERS_INVITE": "ユーザーの招待",
+    "ADMIN_USERS_PASSWORD_RESET": "ユーザーのパスワードをリセット",
+    "ADMIN_USERS_ACTIVATE": "ユーザーを承認する",
+    "ADMIN_USERS_DEACTIVATE": "ユーザーを停止する",
+    "ADMIN_USERS_GIVE_ADMIN": "管理者にする",
+    "ADMIN_USERS_REMOVE_ADMIN": "管理者から外す",
+    "ADMIN_USERS_SEND_INVITATION_EMAIL": "招待メールの再送信",
+    "ADMIN_USERS_REMOVE": "ユーザーの削除",
     "ADMIN_USER_GROUP_CREATE": "ユーザーグループの作成",
     "ADMIN_USER_GROUP_UPDATE": "ユーザーグループの更新",
     "ADMIN_USER_GROUP_DELETE": "ユーザーグループの削除",
     "ADMIN_USER_GROUP_ADD_USER": "ユーザーグループにユーザーを追加",
+    "ADMIN_SEARCH_CONNECTION": "Elasticsearch の再接続の試行",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch のインデックスの正規化",
     "ADMIN_SEARCH_INDICES_REBUILD": "Elasticsearch のインデックスのリビルド"
   }

+ 12 - 1
packages/app/public/static/locales/zh_CN/admin/admin.json

@@ -569,6 +569,8 @@
     "USER_LOGIN_WITH_BASIC": "使用 BASIC 登录",
     "USER_LOGIN_FAILURE": "登录失败",
     "USER_LOGOUT": "注销",
+    "USER_FOGOT_PASSWORD": "要求重置密码",
+    "USER_RESET_PASSWORD": "重置密码",
     "USER_PERSONAL_SETTINGS_UPDATE": "用户个人设置更新",
     "USER_IMAGE_TYPE_UPDATE": "用户图片类型更新",
     "USER_LDAP_ACCOUNT_ASSOCIATE": "LDAP 帐户关联",
@@ -656,6 +658,7 @@
     "ADMIN_MARKDOWN_XSS_UPDATE": "更新阻止 XSS 设置",
     "ADMIN_LAYOUT_UPDATE": "更新布局",
     "ADMIN_THEME_UPDATE": "更新主题",
+    "ADMIN_SIDEBAR_UPDATE": "更新默认的侧边栏模式",
     "ADMIN_FUNCTION_UPDATE": "更新函数",
     "ADMIN_CODE_HIGHLIGHT_UPDATE": "更新代码高亮",
     "ADMIN_CUSTOM_TITLE_UPDATE": "更新自定义标题",
@@ -696,11 +699,19 @@
     "ADMIN_SLACK_WITHOUT_PROXY_TEST": "在没有代理的情况下测试与 Slack 机器人的连接",
     "ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE": "更新 Slack Incoming Webhooks 配置",
     "ADMIN_USERS_INVITE": "用户邀请",
+    "ADMIN_USERS_PASSWORD_RESET": "重置用户密码",
+    "ADMIN_USERS_ACTIVATE": "激活用户",
+    "ADMIN_USERS_DEACTIVATE": "停用用户",
+    "ADMIN_USERS_GIVE_ADMIN": "授予管理员访问权限",
+    "ADMIN_USERS_REMOVE_ADMIN": "删除管理员访问权限",
+    "ADMIN_USERS_SEND_INVITATION_EMAIL": "重发邀请函",
+    "ADMIN_USERS_REMOVE": "删除用户",
     "ADMIN_USER_GROUP_CREATE": "创建用户组",
     "ADMIN_USER_GROUP_UPDATE": "更新用户组",
     "ADMIN_USER_GROUP_DELETE": "删除用户组",
     "ADMIN_USER_GROUP_ADD_USER": "添加用户到用户组",
-    "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch 索引的规范化",
+    "ADMIN_SEARCH_CONNECTION": "重试Elasticsearch连接",
+    "ADMIN_SEARCH_INDICES_NORMALIZE": "试图重新连接Elasticsearch",
     "ADMIN_SEARCH_INDICES_REBUILD": "重建 Elasticsearch 索引"
   }
 }

+ 41 - 8
packages/app/src/interfaces/activity.ts

@@ -19,6 +19,8 @@ const ACTION_USER_LOGIN_WITH_SAML = 'USER_LOGIN_WITH_SAML';
 const ACTION_USER_LOGIN_WITH_BASIC = 'USER_LOGIN_WITH_BASIC';
 const ACTION_USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE';
 const ACTION_USER_LOGOUT = 'USER_LOGOUT';
+const ACTION_USER_FOGOT_PASSWORD = 'USER_FOGOT_PASSWORD';
+const ACTION_USER_RESET_PASSWORD = 'USER_RESET_PASSWORD';
 const ACTION_USER_PERSONAL_SETTINGS_UPDATE = 'USER_PERSONAL_SETTINGS_UPDATE';
 const ACTION_USER_IMAGE_TYPE_UPDATE = 'USER_IMAGE_TYPE_UPDATE';
 const ACTION_USER_LDAP_ACCOUNT_ASSOCIATE = 'USER_LDAP_ACCOUNT_ASSOCIATE';
@@ -106,6 +108,7 @@ const ACTION_ADMIN_MARKDOWN_PRESENTATION_UPDATE = 'ADMIN_MARKDOWN_PRESENTATION_U
 const ACTION_ADMIN_MARKDOWN_XSS_UPDATE = 'ADMIN_MARKDOWN_XSS_UPDATE';
 const ACTION_ADMIN_LAYOUT_UPDATE = 'ADMIN_LAYOUT_UPDATE';
 const ACTION_ADMIN_THEME_UPDATE = 'ADMIN_THEME_UPDATE';
+const ACTION_ADMIN_SIDEBAR_UPDATE = 'ADMIN_SIDEBAR_UPDATE';
 const ACTION_ADMIN_FUNCTION_UPDATE = 'ADMIN_FUNCTION_UPDATE';
 const ACTION_ADMIN_CODE_HIGHLIGHT_UPDATE = 'ADMIN_CODE_HIGHLIGHT_UPDATE';
 const ACTION_ADMIN_CUSTOM_TITLE_UPDATE = 'ADMIN_CUSTOM_TITLE_UPDATE';
@@ -146,10 +149,18 @@ const ACTION_ADMIN_SLACK_WITHOUT_PROXY_PERMISSION_UPDATE = 'ADMIN_SLACK_WITHOUT_
 const ACTION_ADMIN_SLACK_WITHOUT_PROXY_TEST = 'ADMIN_SLACK_WITHOUT_PROXY_TEST';
 const ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE = 'ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE';
 const ACTION_ADMIN_USERS_INVITE = 'ADMIN_USERS_INVITE';
+const ACTION_ADMIN_USERS_PASSWORD_RESET = 'ADMIN_USERS_PASSWORD_RESET';
+const ACTION_ADMIN_USERS_ACTIVATE = 'ADMIN_USERS_ACTIVATE';
+const ACTION_ADMIN_USERS_GIVE_ADMIN = 'ADMIN_USERS_GIVE_ADMIN';
+const ACTION_ADMIN_USERS_REMOVE_ADMIN = 'ADMIN_USERS_REMOVE_ADMIN';
+const ACTION_ADMIN_USERS_DEACTIVATE = 'ADMIN_USERS_DEACTIVATE';
+const ACTION_ADMIN_USERS_SEND_INVITATION_EMAIL = 'ADMIN_USERS_SEND_INVITATION_EMAIL';
+const ACTION_ADMIN_USERS_REMOVE = 'ADMIN_USERS_REMOVE';
 const ACTION_ADMIN_USER_GROUP_CREATE = 'ADMIN_USER_GROUP_CREATE';
 const ACTION_ADMIN_USER_GROUP_UPDATE = 'ADMIN_USER_GROUP_UPDATE';
 const ACTION_ADMIN_USER_GROUP_DELETE = 'ADMIN_USER_GROUP_DELETE';
 const ACTION_ADMIN_USER_GROUP_ADD_USER = 'ADMIN_USER_GROUP_ADD_USER';
+const ACTION_ADMIN_SEARCH_CONNECTION = 'ADMIN_SEARCH_CONNECTION';
 const ACTION_ADMIN_SEARCH_INDICES_NORMALIZE = 'ADMIN_SEARCH_INDICES_NORMALIZE';
 const ACTION_ADMIN_SEARCH_INDICES_REBUILD = 'ADMIN_SEARCH_INDICES_REBUILD';
 
@@ -187,6 +198,8 @@ export const SupportedAction = {
   ACTION_USER_LOGIN_WITH_BASIC,
   ACTION_USER_LOGIN_FAILURE,
   ACTION_USER_LOGOUT,
+  ACTION_USER_FOGOT_PASSWORD,
+  ACTION_USER_RESET_PASSWORD,
   ACTION_USER_PERSONAL_SETTINGS_UPDATE,
   ACTION_USER_IMAGE_TYPE_UPDATE,
   ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
@@ -274,6 +287,7 @@ export const SupportedAction = {
   ACTION_ADMIN_MARKDOWN_XSS_UPDATE,
   ACTION_ADMIN_LAYOUT_UPDATE,
   ACTION_ADMIN_THEME_UPDATE,
+  ACTION_ADMIN_SIDEBAR_UPDATE,
   ACTION_ADMIN_FUNCTION_UPDATE,
   ACTION_ADMIN_CODE_HIGHLIGHT_UPDATE,
   ACTION_ADMIN_CUSTOM_TITLE_UPDATE,
@@ -314,10 +328,18 @@ export const SupportedAction = {
   ACTION_ADMIN_SLACK_WITHOUT_PROXY_TEST,
   ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE,
   ACTION_ADMIN_USERS_INVITE,
+  ACTION_ADMIN_USERS_PASSWORD_RESET,
+  ACTION_ADMIN_USERS_ACTIVATE,
+  ACTION_ADMIN_USERS_DEACTIVATE,
+  ACTION_ADMIN_USERS_GIVE_ADMIN,
+  ACTION_ADMIN_USERS_REMOVE_ADMIN,
+  ACTION_ADMIN_USERS_SEND_INVITATION_EMAIL,
+  ACTION_ADMIN_USERS_REMOVE,
   ACTION_ADMIN_USER_GROUP_CREATE,
   ACTION_ADMIN_USER_GROUP_UPDATE,
   ACTION_ADMIN_USER_GROUP_DELETE,
   ACTION_ADMIN_USER_GROUP_ADD_USER,
+  ACTION_ADMIN_SEARCH_CONNECTION,
   ACTION_ADMIN_SEARCH_INDICES_NORMALIZE,
   ACTION_ADMIN_SEARCH_INDICES_REBUILD,
 } as const;
@@ -360,6 +382,8 @@ export const SmallActionGroup = {
 export const MediumActionGroup = {
   ...SmallActionGroup,
   ACTION_USER_REGISTRATION_SUCCESS,
+  ACTION_USER_FOGOT_PASSWORD,
+  ACTION_USER_RESET_PASSWORD,
   ACTION_USER_PERSONAL_SETTINGS_UPDATE,
   ACTION_USER_IMAGE_TYPE_UPDATE,
   ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
@@ -444,6 +468,7 @@ export const LargeActionGroup = {
   ACTION_ADMIN_MARKDOWN_XSS_UPDATE,
   ACTION_ADMIN_LAYOUT_UPDATE,
   ACTION_ADMIN_THEME_UPDATE,
+  ACTION_ADMIN_SIDEBAR_UPDATE,
   ACTION_ADMIN_FUNCTION_UPDATE,
   ACTION_ADMIN_CODE_HIGHLIGHT_UPDATE,
   ACTION_ADMIN_CUSTOM_TITLE_UPDATE,
@@ -451,6 +476,14 @@ export const LargeActionGroup = {
   ACTION_ADMIN_CUSTOM_CSS_UPDATE,
   ACTION_ADMIN_CUSTOM_SCRIPT_UPDATE,
   ACTION_ADMIN_ARCHIVE_DATA_UPLOAD,
+  ACTION_ADMIN_GROWI_DATA_IMPORTED,
+  ACTION_ADMIN_ESA_DATA_IMPORTED,
+  ACTION_ADMIN_QIITA_DATA_IMPORTED,
+  ACTION_ADMIN_UPLOADED_GROWI_DATA_DISCARDED,
+  ACTION_ADMIN_ESA_DATA_UPDATED,
+  ACTION_ADMIN_CONNECTION_TEST_OF_ESA_DATA,
+  ACTION_ADMIN_QIITA_DATA_UPDATED,
+  ACTION_ADMIN_CONNECTION_TEST_OF_QIITA_DATA,
   ACTION_ADMIN_ARCHIVE_DATA_CREATE,
   ACTION_ADMIN_ARCHIVE_DATA_DOWNLOAD,
   ACTION_ADMIN_ARCHIVE_DATA_DELETE,
@@ -476,20 +509,20 @@ export const LargeActionGroup = {
   ACTION_ADMIN_SLACK_WITHOUT_PROXY_TEST,
   ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE,
   ACTION_ADMIN_USERS_INVITE,
+  ACTION_ADMIN_USERS_PASSWORD_RESET,
+  ACTION_ADMIN_USERS_ACTIVATE,
+  ACTION_ADMIN_USERS_DEACTIVATE,
+  ACTION_ADMIN_USERS_GIVE_ADMIN,
+  ACTION_ADMIN_USERS_REMOVE_ADMIN,
+  ACTION_ADMIN_USERS_SEND_INVITATION_EMAIL,
+  ACTION_ADMIN_USERS_REMOVE,
   ACTION_ADMIN_USER_GROUP_CREATE,
   ACTION_ADMIN_USER_GROUP_UPDATE,
   ACTION_ADMIN_USER_GROUP_DELETE,
   ACTION_ADMIN_USER_GROUP_ADD_USER,
+  ACTION_ADMIN_SEARCH_CONNECTION,
   ACTION_ADMIN_SEARCH_INDICES_NORMALIZE,
   ACTION_ADMIN_SEARCH_INDICES_REBUILD,
-  ACTION_ADMIN_GROWI_DATA_IMPORTED,
-  ACTION_ADMIN_ESA_DATA_IMPORTED,
-  ACTION_ADMIN_QIITA_DATA_IMPORTED,
-  ACTION_ADMIN_UPLOADED_GROWI_DATA_DISCARDED,
-  ACTION_ADMIN_ESA_DATA_UPDATED,
-  ACTION_ADMIN_CONNECTION_TEST_OF_ESA_DATA,
-  ACTION_ADMIN_QIITA_DATA_UPDATED,
-  ACTION_ADMIN_CONNECTION_TEST_OF_QIITA_DATA,
 } as const;
 
 

+ 4 - 1
packages/app/src/server/routes/apiv3/customize-setting.js

@@ -365,7 +365,7 @@ module.exports = (crowi) => {
     }
   });
 
-  router.put('/sidebar', loginRequiredStrictly, adminRequired, csrf, validator.sidebar, apiV3FormValidator, async(req, res) => {
+  router.put('/sidebar', loginRequiredStrictly, adminRequired, csrf, validator.sidebar, apiV3FormValidator, addActivity, async(req, res) => {
     const requestParams = {
       'customize:isSidebarDrawerMode': req.body.isSidebarDrawerMode,
       'customize:isSidebarClosedAtDockMode': req.body.isSidebarClosedAtDockMode,
@@ -377,6 +377,9 @@ module.exports = (crowi) => {
         isSidebarDrawerMode: await crowi.configManager.getConfig('crowi', 'customize:isSidebarDrawerMode'),
         isSidebarClosedAtDockMode: await crowi.configManager.getConfig('crowi', 'customize:isSidebarClosedAtDockMode'),
       };
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SIDEBAR_UPDATE });
+
       return res.apiv3({ customizedParams });
     }
     catch (err) {

+ 13 - 2
packages/app/src/server/routes/apiv3/forgot-password.js

@@ -1,5 +1,7 @@
 import { format, subSeconds } from 'date-fns';
 
+import { SupportedAction } from '~/interfaces/activity';
+import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import injectResetOrderByTokenMiddleware from '~/server/middlewares/inject-reset-order-by-token-middleware';
 import PasswordResetOrder from '~/server/models/password-reset-order';
 import ErrorV3 from '~/server/models/vo/error-apiv3';
@@ -24,6 +26,9 @@ module.exports = (crowi) => {
   const User = crowi.model('User');
   const path = require('path');
   const csrf = require('../../middlewares/csrf')(crowi);
+  const addActivity = generateAddActivityMiddleware(crowi);
+
+  const activityEvent = crowi.event('activity');
 
   const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
 
@@ -56,7 +61,7 @@ module.exports = (crowi) => {
     });
   }
 
-  router.post('/', checkPassportStrategyMiddleware, async(req, res) => {
+  router.post('/', checkPassportStrategyMiddleware, addActivity, async(req, res) => {
     const { email } = req.body;
     const i18n = configManager.getConfig('crowi', 'app:globalLang');
     const appUrl = appService.getSiteUrl();
@@ -77,6 +82,9 @@ module.exports = (crowi) => {
       const expiredAt = subSeconds(passwordResetOrderData.expiredAt, grwTzoffsetSec);
       const formattedExpiredAt = format(expiredAt, 'yyyy/MM/dd HH:mm');
       await sendPasswordResetEmail('passwordReset', i18n, email, oneTimeUrl, formattedExpiredAt);
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_USER_FOGOT_PASSWORD });
+
       return res.apiv3();
     }
     catch (err) {
@@ -87,7 +95,7 @@ module.exports = (crowi) => {
   });
 
   // eslint-disable-next-line max-len
-  router.put('/', checkPassportStrategyMiddleware, injectResetOrderByTokenMiddleware, csrf, validator.password, apiV3FormValidator, async(req, res) => {
+  router.put('/', checkPassportStrategyMiddleware, injectResetOrderByTokenMiddleware, csrf, validator.password, apiV3FormValidator, addActivity, async(req, res) => {
     const { passwordResetOrder } = req;
     const { email } = passwordResetOrder;
     const grobalLang = configManager.getConfig('crowi', 'app:globalLang');
@@ -106,6 +114,9 @@ module.exports = (crowi) => {
       const serializedUserData = serializeUserSecurely(userData);
       passwordResetOrder.revokeOneTimeToken();
       await sendPasswordResetEmail('passwordResetSuccessful', i18n, email);
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_USER_RESET_PASSWORD });
+
       return res.apiv3({ userData: serializedUserData });
     }
     catch (err) {

+ 4 - 1
packages/app/src/server/routes/apiv3/search.js

@@ -76,7 +76,7 @@ module.exports = (crowi) => {
    *        200:
    *          description: Successfully connected
    */
-  router.post('/connection', accessTokenParser, loginRequired, adminRequired, async(req, res) => {
+  router.post('/connection', accessTokenParser, loginRequired, adminRequired, addActivity, async(req, res) => {
     const { searchService } = crowi;
 
     if (!searchService.isConfigured) {
@@ -85,6 +85,9 @@ module.exports = (crowi) => {
 
     try {
       await searchService.reconnectClient();
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SEARCH_CONNECTION });
+
       return res.status(200).send();
     }
     catch (err) {

+ 26 - 7
packages/app/src/server/routes/apiv3/users.js

@@ -464,12 +464,15 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: data of admin user
    */
-  router.put('/:id/giveAdmin', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/giveAdmin', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.params;
 
     try {
       const userData = await User.findById(id);
       await userData.makeAdmin();
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_GIVE_ADMIN });
+
       return res.apiv3({ userData });
     }
     catch (err) {
@@ -506,12 +509,15 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: data of removed admin user
    */
-  router.put('/:id/removeAdmin', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/removeAdmin', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.params;
 
     try {
       const userData = await User.findById(id);
       await userData.removeFromAdmin();
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_REMOVE_ADMIN });
+
       return res.apiv3({ userData });
     }
     catch (err) {
@@ -547,7 +553,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: data of activate user
    */
-  router.put('/:id/activate', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/activate', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     // check user upper limit
     const isUserCountExceedsUpperLimit = await User.isUserCountExceedsUpperLimit();
     if (isUserCountExceedsUpperLimit) {
@@ -561,6 +567,9 @@ module.exports = (crowi) => {
     try {
       const userData = await User.findById(id);
       await userData.statusActivate();
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_ACTIVATE });
+
       return res.apiv3({ userData });
     }
     catch (err) {
@@ -596,12 +605,15 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: data of deactivate user
    */
-  router.put('/:id/deactivate', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/deactivate', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.params;
 
     try {
       const userData = await User.findById(id);
       await userData.statusSuspend();
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_DEACTIVATE });
+
       return res.apiv3({ userData });
     }
     catch (err) {
@@ -637,7 +649,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: data of delete user
    */
-  router.delete('/:id/remove', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.delete('/:id/remove', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.params;
 
     try {
@@ -647,6 +659,8 @@ module.exports = (crowi) => {
       await ExternalAccount.remove({ user: userData });
       await Page.removeByPath(`/user/${userData.username}`);
 
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_REMOVE });
+
       return res.apiv3({ userData });
     }
     catch (err) {
@@ -814,7 +828,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: Target user
    */
-  router.put('/reset-password', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/reset-password', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.body;
 
     try {
@@ -822,6 +836,8 @@ module.exports = (crowi) => {
         await User.resetPasswordByRandomString(id),
         await User.findById(id)]);
 
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_PASSWORD_RESET });
+
       return res.apiv3({ newPassword, user });
     }
     catch (err) {
@@ -859,7 +875,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: email and reasons for email sending failure
    */
-  router.put('/send-invitation-email', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/send-invitation-email', loginRequiredStrictly, adminRequired, csrf, addActivity, async(req, res) => {
     const { id } = req.body;
 
     try {
@@ -872,6 +888,9 @@ module.exports = (crowi) => {
       }];
       const sendEmail = await sendEmailByUserList(userList);
       // return null if absent
+
+      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_USERS_SEND_INVITATION_EMAIL });
+
       return res.apiv3({ failedToSendEmail: sendEmail.failedToSendEmailList[0] });
     }
     catch (err) {