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

Merge branch 'feat/notification' into imprv/#79077-get-action-usres-with-virtual-method

# Conflicts:
#	packages/app/src/server/models/activity.ts
kaori 4 лет назад
Родитель
Сommit
c2b0f706fb

+ 16 - 7
packages/app/src/components/InAppNotification/InAppNotificationDropdown.tsx

@@ -32,6 +32,7 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
 
   useEffect(() => {
     initializeSocket(props);
+    fetchNotificationStatus();
   }, []);
 
   const initializeSocket = (props) => {
@@ -44,9 +45,9 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
     });
   };
 
-  const updateNotificationStatus = () => {
+  const updateNotificationStatus = async() => {
     try {
-      // await this.props.crowi.apiPost('/notification.read');
+      await appContainer.apiv3Post('/in-app-notification/read');
       setCount(0);
     }
     catch (err) {
@@ -54,6 +55,16 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
     }
   };
 
+  const fetchNotificationStatus = async() => {
+    try {
+      const res = await appContainer.apiv3Get('/in-app-notification/status');
+      const { count } = res.data;
+      setCount(count);
+    }
+    catch (err) {
+      logger.error(err);
+    }
+  };
 
   /**
     * TODO: Fetch notification list by GW-7473
@@ -101,9 +112,6 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
     }
   };
 
-  const badge = count > 0 ? <span className="badge badge-pill badge-danger notification-badge">{count}</span> : '';
-
-
   const RenderUnLoadedInAppNotification = (): JSX.Element => {
     return (
       <i className="fa fa-spinner"></i>
@@ -144,11 +152,12 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
     return <RenderInAppNotificationList />;
   };
 
+  const badge = count > 0 ? <span className="badge badge-pill badge-danger grw-notification-badge">{count}</span> : '';
+
   return (
     <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
       <DropdownToggle tag="a" className="nav-link">
-        <i className="icon-bell mr-2"></i>
-        {badge}
+        <i className="icon-bell mr-2" /> {badge}
       </DropdownToggle>
       <DropdownMenu right>
         <InAppNotificationContents />

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

@@ -86,7 +86,6 @@ function Crowi() {
     tag: new (require('../events/tag'))(this),
     admin: new (require('../events/admin'))(this),
     comment: new (require('../events/comment'))(this),
-    activity: new (require('../events/activity'))(),
   };
 }
 

+ 3 - 2
packages/app/src/server/events/activity.ts

@@ -4,7 +4,7 @@ import loggerFactory from '../../utils/logger';
 const logger = loggerFactory('growi:events:activity');
 
 
-export default class ActivityEvent extends EventEmitter {
+class ActivityEvent extends EventEmitter {
 
   onRemove(action: string, activity: any): void {
     logger.info('onRemove activity event fired');
@@ -16,4 +16,5 @@ export default class ActivityEvent extends EventEmitter {
 
 }
 
-module.exports = ActivityEvent;
+const instance = new ActivityEvent();
+export default instance;

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

@@ -2,12 +2,17 @@ import {
   Types, Document, Model, Schema,
 } from 'mongoose';
 
+import loggerFactory from '../../utils/logger';
+
 import { getOrCreateModel, getModelSafely } from '../util/mongoose-utils';
 
 import ActivityDefine from '../util/activityDefine';
+import activityEvent from '../events/activity';
 
 import Subscription from './subscription';
 
+const logger = loggerFactory('growi:models:activity');
+
 
 export interface ActivityDocument extends Document {
   _id: Types.ObjectId
@@ -91,9 +96,21 @@ activitySchema.methods.getNotificationTargetUsers = async function() {
   return activeNotificationUsers;
 };
 
-
 activitySchema.statics.getActionUsersFromActivities = function(activities) {
   return activities.map(({ user }) => user).filter((user, i, self) => self.indexOf(user) === i);
 };
 
+activitySchema.post('save', async(savedActivity: ActivityDocument) => {
+  let targetUsers: Types.ObjectId[] = [];
+  try {
+    targetUsers = await savedActivity.getNotificationTargetUsers();
+  }
+  catch (err) {
+    logger.error(err);
+  }
+
+  activityEvent.emit('create', targetUsers, savedActivity);
+});
+
+
 export default getOrCreateModel<ActivityDocument, ActivityModel>('Activity', activitySchema);

+ 3 - 4
packages/app/src/server/routes/apiv3/in-app-notification.ts

@@ -43,13 +43,12 @@ module.exports = (crowi) => {
     }
   });
 
-  router.post('/read', accessTokenParser, loginRequiredStrictly, csrf, (req, res) => {
+  router.post('/read', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
     const user = req.user;
 
     try {
-      const notification = InAppNotification.read(user);
-      const result = { notification };
-      return res.apiv3(result);
+      await inAppNotificationService.read(user);
+      return res.apiv3();
     }
     catch (err) {
       return res.apiv3Err(err);

+ 1 - 11
packages/app/src/server/service/activity.ts

@@ -1,14 +1,7 @@
-import {
-  Types,
-} from 'mongoose';
 import Crowi from '../crowi';
 
-
 import { getModelSafely } from '../util/mongoose-utils';
 
-import loggerFactory from '../../utils/logger';
-
-const logger = loggerFactory('growi:service:activity');
 
 class ActivityService {
 
@@ -16,12 +9,9 @@ class ActivityService {
 
   inAppNotificationService!: any;
 
-  activityEvent!: any;
-
   constructor(crowi: Crowi) {
     this.crowi = crowi;
     this.inAppNotificationService = crowi.inAppNotificationService;
-    this.activityEvent = crowi.event('activity');
   }
 
 
@@ -29,7 +19,7 @@ class ActivityService {
      * @param {object} parameters
      * @return {Promise}
      */
-  createByParameters = async function(parameters) {
+  createByParameters = function(parameters) {
     const Activity = getModelSafely('Activity') || require('../models/activity')(this.crowi);
 
     return Activity.create(parameters);

+ 0 - 5
packages/app/src/server/service/comment.ts

@@ -15,14 +15,11 @@ class CommentService {
 
   commentEvent!: any;
 
-  activityEvent!: any;
-
   constructor(crowi: Crowi) {
     this.crowi = crowi;
     this.inAppNotificationService = crowi.inAppNotificationService;
 
     this.commentEvent = crowi.event('comment');
-    this.activityEvent = crowi.event('activity');
 
     // init
     this.initCommentEventListeners();
@@ -42,8 +39,6 @@ class CommentService {
         let targetUsers: Types.ObjectId[] = [];
         targetUsers = await savedActivity.getNotificationTargetUsers();
 
-        this.activityEvent.emit('create', targetUsers, savedActivity);
-
         await this.inAppNotificationService.upsertByActivity(targetUsers, savedActivity);
       }
       catch (err) {

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

@@ -20,13 +20,10 @@ export default class InAppNotificationService {
 
   commentEvent!: any;
 
-  activityEvent!: any;
-
 
   constructor(crowi: Crowi) {
     this.crowi = crowi;
     this.socketIoService = crowi.socketIoService;
-    this.activityEvent = crowi.event('activity');
 
     this.getUnreadCountByUser = this.getUnreadCountByUser.bind(this);
   }

+ 0 - 3
packages/app/src/server/service/page.js

@@ -22,7 +22,6 @@ class PageService {
   constructor(crowi) {
     this.crowi = crowi;
     this.pageEvent = crowi.event('page');
-    this.activityEvent = crowi.event('activity');
 
     // init
     this.initPageEvent();
@@ -43,8 +42,6 @@ class PageService {
         let targetUsers = [];
         targetUsers = await savedActivity.getNotificationTargetUsers();
 
-        this.activityEvent.emit('create', targetUsers, savedActivity);
-
         await inAppNotificationService.upsertByActivity(targetUsers, savedActivity);
       }
       catch (err) {

+ 6 - 0
packages/app/src/styles/_navbar.scss

@@ -101,3 +101,9 @@
     transition: 0.3s ease-in-out;
   }
 }
+
+.grw-notification-badge {
+  position: absolute;
+  top: 6px;
+  right: 3.5px;
+}