فهرست منبع

Merge pull request #5977 from weseek/feat/96900-activity-event-emitter

feat: Activity Event Emitter
Yuki Takei 3 سال پیش
والد
کامیت
ccff19b5c1

+ 1 - 0
packages/app/src/server/crowi/index.js

@@ -91,6 +91,7 @@ function Crowi() {
   this.events = {
     user: new (require('../events/user'))(this),
     page: new (require('../events/page'))(this),
+    activity: new (require('../events/activity'))(this),
     bookmark: new (require('../events/bookmark'))(this),
     comment: new (require('../events/comment'))(this),
     tag: new (require('../events/tag'))(this),

+ 17 - 0
packages/app/src/server/events/activity.ts

@@ -0,0 +1,17 @@
+import loggerFactory from '~/utils/logger';
+
+import Crowi from '../crowi';
+
+const logger = loggerFactory('growi:events:activity');
+
+const events = require('events');
+const util = require('util');
+
+function ActivityEvent(crowi: Crowi) {
+  this.crowi = crowi;
+
+  events.EventEmitter.call(this);
+}
+util.inherits(ActivityEvent, events.EventEmitter);
+
+module.exports = ActivityEvent;

+ 6 - 12
packages/app/src/server/routes/apiv3/logout.js

@@ -10,23 +10,17 @@ const express = require('express');
 const router = express.Router();
 
 module.exports = (crowi) => {
-  const activityService = crowi.activityService;
+  const activityEvent = crowi.event('activity');
   const addActivity = generateAddActivityMiddleware(crowi);
 
   router.post('/', addActivity, async(req, res) => {
     req.session.destroy();
 
-    // return response first
-    res.send();
-
-    try {
-      const activityId = res.locals.activity._id;
-      const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGOUT };
-      await activityService.updateByParameters(activityId, parameters);
-    }
-    catch (err) {
-      logger.error('Update activity failed', err);
-    }
+    const activityId = res.locals.activity._id;
+    const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGOUT };
+    activityEvent.emit('update', activityId, parameters);
+
+    return res.send();
   });
 
   return router;

+ 10 - 24
packages/app/src/server/routes/apiv3/pages.js

@@ -151,6 +151,8 @@ module.exports = (crowi) => {
   const PageTagRelation = crowi.model('PageTagRelation');
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
 
+  const activityEvent = crowi.event('activity');
+
   const globalNotificationService = crowi.getGlobalNotificationService();
   const userNotificationService = crowi.getUserNotificationService();
 
@@ -554,31 +556,15 @@ module.exports = (crowi) => {
       logger.error('Move notification failed', err);
     }
 
-    // return response first
-    res.apiv3(result);
-
-    let activity;
-    try {
-      const activityId = res.locals.activity._id;
-      const parameters = {
-        targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
-        target: page,
-        action: SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME,
-      };
-      activity = await crowi.activityService.updateByParameters(activityId, parameters);
-    }
-    catch (err) {
-      logger.error('Update activity failed', err);
-      return res.apiv3Err(err);
-    }
+    const activityId = res.locals.activity._id;
+    const parameters = {
+      targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
+      target: page,
+      action: SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME,
+    };
+    activityEvent.emit('update', activityId, parameters, page);
 
-    try {
-      await crowi.inAppNotificationService.createInAppNotification(activity, page);
-    }
-    catch (err) {
-      logger.error('Create InAppNotification failed', err);
-      return res.apiv3Err(err);
-    }
+    return res.apiv3(result);
   });
 
   /**

+ 9 - 21
packages/app/src/server/routes/login-passport.js

@@ -9,7 +9,9 @@ module.exports = function(crowi, app) {
   const passport = require('passport');
   const ExternalAccount = crowi.model('ExternalAccount');
   const passportService = crowi.passportService;
-  const activityService = crowi.activityService;
+
+  const activityEvent = crowi.event('activity');
+
   const ApiResponse = require('../util/apiResponse');
 
   /**
@@ -30,17 +32,10 @@ module.exports = function(crowi, app) {
     // remove session.redirectTo
     delete req.session.redirectTo;
 
-    // return response first
-    res.safeRedirect(redirectTo);
+    const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGIN_SUCCESS };
+    activityEvent.emit('update', res.locals.activity._id, parameters);
 
-    try {
-      const activityId = res.locals.activity._id;
-      const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGIN_SUCCESS };
-      await activityService.updateByParameters(activityId, parameters);
-    }
-    catch (err) {
-      logger.error('Update activity failed', err);
-    }
+    return res.safeRedirect(redirectTo);
   };
 
   /**
@@ -51,17 +46,10 @@ module.exports = function(crowi, app) {
   const loginFailureHandler = async(req, res, message) => {
     req.flash('errorMessage', message || req.t('message.sign_in_failure'));
 
-    // return response first
-    res.redirect('/login');
+    const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGIN_FAILURE };
+    activityEvent.emit('update', res.locals.activity._id, parameters);
 
-    try {
-      const activityId = res.locals.activity._id;
-      const parameters = { action: SUPPORTED_ACTION_TYPE.ACTION_LOGIN_FAILURE };
-      await activityService.updateByParameters(activityId, parameters);
-    }
-    catch (err) {
-      logger.error('Update activity failed', err);
-    }
+    return res.redirect('/login');
   };
 
   /**

+ 27 - 2
packages/app/src/server/service/activity.ts

@@ -1,22 +1,47 @@
 import { getModelSafely } from '@growi/core';
 
 import { IActivity } from '~/interfaces/activity';
+import { IPage } from '~/interfaces/page';
 import Activity from '~/server/models/activity';
 
+import loggerFactory from '../../utils/logger';
 import Crowi from '../crowi';
 
 
+const logger = loggerFactory('growi:service:ActivityService');
+
 type ParameterType = Omit<IActivity, 'createdAt'>
 
 class ActivityService {
 
   crowi!: Crowi;
 
-  inAppNotificationService!: any;
+  activityEvent: any;
 
   constructor(crowi: Crowi) {
     this.crowi = crowi;
-    this.inAppNotificationService = crowi.inAppNotificationService;
+    this.activityEvent = crowi.event('activity');
+
+    this.updateByParameters = this.updateByParameters.bind(this);
+
+    this.initActivityEventListeners();
+  }
+
+  initActivityEventListeners(): void {
+    this.activityEvent.on('update', async(activityId: string, parameters: ParameterType, target?: IPage) => {
+
+      // update activity
+      let activity: IActivity;
+      try {
+        activity = await this.updateByParameters(activityId, parameters);
+      }
+      catch (err) {
+        logger.error('Update activity failed', err);
+        return;
+      }
+
+      this.activityEvent.emit('updated', activity, target);
+    });
   }
 
 

+ 14 - 0
packages/app/src/server/service/in-app-notification.ts

@@ -32,18 +32,32 @@ export default class InAppNotificationService {
 
   socketIoService!: any;
 
+  activityEvent!: any;
+
   commentEvent!: any;
 
 
   constructor(crowi: Crowi) {
     this.crowi = crowi;
+    this.activityEvent = crowi.event('activity');
     this.socketIoService = crowi.socketIoService;
 
     this.emitSocketIo = this.emitSocketIo.bind(this);
     this.upsertByActivity = this.upsertByActivity.bind(this);
     this.getUnreadCountByUser = this.getUnreadCountByUser.bind(this);
+    this.createInAppNotification = this.createInAppNotification.bind(this);
   }
 
+  initActivityEventListeners(): void {
+    this.activityEvent.on('updated', async(activity: ActivityDocument, target: IPage) => {
+      try {
+        await this.createInAppNotification(activity, target);
+      }
+      catch (err) {
+        logger.error('Create InAppNotification failed', err);
+      }
+    });
+  }
 
   emitSocketIo = async(targetUsers) => {
     if (this.socketIoService.isInitialized) {