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

Merge pull request #5794 from weseek/imprv/94090-put-snapshot-in-activity-document

imprv: Put snapshot in activity document
Shun Miyazawa 3 лет назад
Родитель
Сommit
9906d89b02

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

@@ -3,7 +3,6 @@ import { IUser } from './user';
 
 // Model
 const MODEL_PAGE = 'Page';
-const MODEL_COMMENT = 'Comment';
 
 // Action
 const ACTION_PAGE_LIKE = 'PAGE_LIKE';
@@ -21,11 +20,6 @@ const ACTION_COMMENT_UPDATE = 'COMMENT_UPDATE';
 
 export const SUPPORTED_TARGET_MODEL_TYPE = {
   MODEL_PAGE,
-  MODEL_COMMENT,
-} as const;
-
-export const SUPPORTED_EVENT_MODEL_TYPE = {
-  MODEL_COMMENT,
 } as const;
 
 export const SUPPORTED_ACTION_TYPE = {
@@ -44,10 +38,8 @@ export const SUPPORTED_ACTION_TYPE = {
 
 
 export const AllSupportedTargetModelType = Object.values(SUPPORTED_TARGET_MODEL_TYPE);
-export const AllSupportedEventModelType = Object.values(SUPPORTED_EVENT_MODEL_TYPE);
 export const AllSupportedActionType = Object.values(SUPPORTED_ACTION_TYPE);
 
-
 /*
  * For AuditLogManagement.tsx
  */
@@ -73,6 +65,7 @@ export type SupportedTargetModelType = typeof SUPPORTED_TARGET_MODEL_TYPE[keyof
 // type supportedEventModelType = typeof SUPPORTED_EVENT_MODEL_TYPE[keyof typeof SUPPORTED_EVENT_MODEL_TYPE];
 export type SupportedActionType = typeof SUPPORTED_ACTION_TYPE[keyof typeof SUPPORTED_ACTION_TYPE];
 
+
 export type IActivity = {
   user?: IUser
   targetModel: SupportedTargetModelType
@@ -82,3 +75,5 @@ export type IActivity = {
 }
 
 export type IActivityHasId = IActivity & HasObjectId;
+
+export type ISnapshot = Pick<IUser, 'username'>

+ 2 - 2
packages/app/src/server/events/comment.ts

@@ -2,9 +2,9 @@ import loggerFactory from '~/utils/logger';
 
 const logger = loggerFactory('growi:events:comment');
 
+const events = require('events');
 const util = require('util');
 
-const events = require('events');
 
 function CommentEvent(crowi) {
   this.crowi = crowi;
@@ -20,7 +20,7 @@ CommentEvent.prototype.onUpdate = function(comment) {
   logger.info('onUpdate comment event fired');
 };
 CommentEvent.prototype.onDelete = function(comment) {
-  logger.info('onRemove comment event fired');
+  logger.info('onDelete comment event fired');
 };
 
 module.exports = CommentEvent;

+ 16 - 16
packages/app/src/server/models/activity.ts

@@ -4,7 +4,7 @@ import {
 } from 'mongoose';
 import mongoosePaginate from 'mongoose-paginate-v2';
 
-import { AllSupportedTargetModelType, AllSupportedEventModelType, AllSupportedActionType } from '~/interfaces/activity';
+import { AllSupportedTargetModelType, AllSupportedActionType, ISnapshot } from '~/interfaces/activity';
 
 import loggerFactory from '../../utils/logger';
 import activityEvent from '../events/activity';
@@ -19,8 +19,7 @@ export interface ActivityDocument extends Document {
   targetModel: string
   target: Types.ObjectId
   action: string
-  event: Types.ObjectId
-  eventModel: string
+  snapshot: ISnapshot
 
   getNotificationTargetUsers(): Promise<any[]>
 }
@@ -29,39 +28,40 @@ export interface ActivityModel extends Model<ActivityDocument> {
   [x:string]: any
   getActionUsersFromActivities(activities: ActivityDocument[]): any[]
 }
+
+const snapshotSchema = new Schema<ISnapshot>({
+  username: { type: String },
+});
+
 // TODO: add revision id
 const activitySchema = new Schema<ActivityDocument, ActivityModel>({
   user: {
     type: Schema.Types.ObjectId,
     ref: 'User',
     index: true,
-    require: true,
+    required: true,
   },
   targetModel: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSupportedTargetModelType,
   },
   target: {
     type: Schema.Types.ObjectId,
     refPath: 'targetModel',
-    require: true,
+    required: true,
   },
   action: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSupportedActionType,
   },
-  event: {
-    type: Schema.Types.ObjectId,
-    refPath: 'eventModel',
-  },
-  eventModel: {
-    type: String,
-    enum: AllSupportedEventModelType,
-  },
+  snapshot: snapshotSchema,
 }, {
-  timestamps: true,
+  timestamps: {
+    createdAt: true,
+    updatedAt: false,
+  },
 });
 activitySchema.index({ target: 1, action: 1 });
 activitySchema.index({

+ 2 - 2
packages/app/src/server/models/comment.js

@@ -99,7 +99,7 @@ module.exports = function(crowi) {
    * post remove hook
    */
   commentSchema.post('reomove', async(savedComment) => {
-    await commentEvent.emit('remove', savedComment);
+    await commentEvent.emit('delete', savedComment);
   });
 
   commentSchema.methods.removeWithReplies = async function(comment) {
@@ -110,7 +110,7 @@ module.exports = function(crowi) {
         [{ replyTo: this._id }, { _id: this._id }]),
     });
 
-    await commentEvent.emit('remove', comment);
+    await commentEvent.emit('delete', comment);
     return;
   };
 

+ 2 - 2
packages/app/src/server/models/in-app-notification-settings.ts

@@ -1,5 +1,5 @@
-import { Schema, Model, Document } from 'mongoose';
 import { getOrCreateModel } from '@growi/core';
+import { Schema, Model, Document } from 'mongoose';
 
 import { IInAppNotificationSettings, subscribeRuleNames } from '~/interfaces/in-app-notification';
 
@@ -10,7 +10,7 @@ const inAppNotificationSettingsSchema = new Schema<InAppNotificationSettingsDocu
   userId: { type: Schema.Types.ObjectId },
   subscribeRules: [
     {
-      name: { type: String, require: true, enum: subscribeRuleNames },
+      name: { type: String, required: true, enum: subscribeRuleNames },
       isEnabled: { type: Boolean },
     },
   ],

+ 6 - 6
packages/app/src/server/models/in-app-notification.ts

@@ -41,21 +41,21 @@ const inAppNotificationSchema = new Schema<InAppNotificationDocument, InAppNotif
     type: Schema.Types.ObjectId,
     ref: 'User',
     index: true,
-    require: true,
+    required: true,
   },
   targetModel: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSupportedTargetModelType,
   },
   target: {
     type: Schema.Types.ObjectId,
     refPath: 'targetModel',
-    require: true,
+    required: true,
   },
   action: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSupportedActionType,
   },
   activities: [
@@ -69,7 +69,7 @@ const inAppNotificationSchema = new Schema<InAppNotificationDocument, InAppNotif
     default: STATUS_UNREAD,
     enum: InAppNotificationStatuses,
     index: true,
-    require: true,
+    required: true,
   },
   createdAt: {
     type: Date,
@@ -77,7 +77,7 @@ const inAppNotificationSchema = new Schema<InAppNotificationDocument, InAppNotif
   },
   snapshot: {
     type: String,
-    require: true,
+    required: true,
   },
 });
 inAppNotificationSchema.plugin(mongoosePaginate);

+ 3 - 3
packages/app/src/server/models/subscription.ts

@@ -37,17 +37,17 @@ const subscriptionSchema = new Schema<SubscriptionDocument, SubscriptionModel>({
   },
   targetModel: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSupportedTargetModelType,
   },
   target: {
     type: Schema.Types.ObjectId,
     refPath: 'targetModel',
-    require: true,
+    required: true,
   },
   status: {
     type: String,
-    require: true,
+    required: true,
     enum: AllSubscriptionStatusType,
   },
   createdAt: { type: Date, default: new Date() },

+ 1 - 0
packages/app/src/server/routes/apiv3/pages.js

@@ -351,6 +351,7 @@ module.exports = (crowi) => {
         targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
         target: createdPage,
         action: SUPPORTED_ACTION_TYPE.ACTION_PAGE_CREATE,
+        snapshot: { username: req.user.username },
       };
       await crowi.activityService.createByParameters(parameters);
     }

+ 2 - 2
packages/app/src/server/routes/comment.js

@@ -242,7 +242,7 @@ module.exports = function(crowi, app) {
     let createdComment;
     try {
       createdComment = await Comment.create(pageId, req.user._id, revisionId, comment, position, isMarkdown, replyTo);
-      commentEvent.emit('create', createdComment);
+      commentEvent.emit('create', req.user, createdComment);
     }
     catch (err) {
       logger.error(err);
@@ -379,7 +379,7 @@ module.exports = function(crowi, app) {
         { _id: commentId },
         { $set: { comment: commentStr, isMarkdown, revision } },
       );
-      commentEvent.emit('update', updatedComment);
+      commentEvent.emit('update', req.user, updatedComment);
     }
     catch (err) {
       logger.error(err);

+ 18 - 14
packages/app/src/server/service/comment.ts

@@ -1,7 +1,11 @@
 import { getModelSafely } from '@growi/core';
 import { Types } from 'mongoose';
 
-import { SUPPORTED_TARGET_MODEL_TYPE, SUPPORTED_EVENT_MODEL_TYPE, SUPPORTED_ACTION_TYPE } from '~/interfaces/activity';
+import {
+  SUPPORTED_TARGET_MODEL_TYPE, SUPPORTED_ACTION_TYPE, SupportedActionType, ISnapshot,
+} from '~/interfaces/activity';
+import { IPage } from '~/interfaces/page';
+import { IUserHasId } from '~/interfaces/user';
 import { stringifySnapshot } from '~/models/serializers/in-app-notification-snapshot/page';
 
 import loggerFactory from '../../utils/logger';
@@ -33,7 +37,7 @@ class CommentService {
 
   initCommentEventListeners(): void {
     // create
-    this.commentEvent.on('create', async(savedComment) => {
+    this.commentEvent.on('create', async(user, savedComment) => {
 
       try {
         const Page = getModelSafely('Page') || require('../models/page')(this.crowi);
@@ -45,7 +49,7 @@ class CommentService {
           return;
         }
 
-        const activity = await this.createActivity(savedComment, SUPPORTED_ACTION_TYPE.ACTION_COMMENT_CREATE);
+        const activity = await this.createActivity(user, savedComment.page, SUPPORTED_ACTION_TYPE.ACTION_COMMENT_CREATE);
         await this.createAndSendNotifications(activity, page);
       }
       catch (err) {
@@ -55,10 +59,10 @@ class CommentService {
     });
 
     // update
-    this.commentEvent.on('update', async(updatedComment) => {
+    this.commentEvent.on('update', async(user, updatedComment) => {
       try {
         this.commentEvent.onUpdate();
-        await this.createActivity(updatedComment, SUPPORTED_ACTION_TYPE.ACTION_COMMENT_UPDATE);
+        await this.createActivity(user, updatedComment.page, SUPPORTED_ACTION_TYPE.ACTION_COMMENT_UPDATE);
       }
       catch (err) {
         logger.error('Error occurred while handling the comment update event:\n', err);
@@ -66,8 +70,8 @@ class CommentService {
     });
 
     // remove
-    this.commentEvent.on('remove', async(comment) => {
-      this.commentEvent.onRemove();
+    this.commentEvent.on('delete', async(comment) => {
+      this.commentEvent.onDelete();
 
       try {
         const Page = getModelSafely('Page') || require('../models/page')(this.crowi);
@@ -79,27 +83,27 @@ class CommentService {
     });
   }
 
-  private createActivity = async function(comment, action) {
+  private createActivity = async function(user: IUserHasId, target: IPage, action: SupportedActionType) {
+    const snapshot: ISnapshot = { username: user.username };
     const parameters = {
-      user: comment.creator,
+      user: user._id,
       targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
-      target: comment.page,
-      eventModel: SUPPORTED_EVENT_MODEL_TYPE.MODEL_COMMENT,
-      event: comment._id,
+      target,
       action,
+      snapshot,
     };
     const activity = await this.activityService.createByParameters(parameters);
     return activity;
   };
 
-  private createAndSendNotifications = async function(activity, page) {
-    const snapshot = stringifySnapshot(page);
+  private createAndSendNotifications = async function(activity, page: IPage) {
 
     // Get user to be notified
     let targetUsers: Types.ObjectId[] = [];
     targetUsers = await activity.getNotificationTargetUsers();
 
     // Create and send notifications
+    const snapshot = stringifySnapshot(page);
     await this.inAppNotificationService.upsertByActivity(targetUsers, activity, snapshot);
     await this.inAppNotificationService.emitSocketIo(targetUsers);
   };

+ 17 - 14
packages/app/src/server/service/page.ts

@@ -6,7 +6,9 @@ import escapeStringRegexp from 'escape-string-regexp';
 import mongoose, { ObjectId, QueryCursor } from 'mongoose';
 import streamToPromise from 'stream-to-promise';
 
-import { SUPPORTED_TARGET_MODEL_TYPE, SUPPORTED_ACTION_TYPE } from '~/interfaces/activity';
+import {
+  SUPPORTED_TARGET_MODEL_TYPE, SUPPORTED_ACTION_TYPE, SupportedActionType, ISnapshot,
+} from '~/interfaces/activity';
 import { Ref } from '~/interfaces/common';
 import { V5ConversionErrCode } from '~/interfaces/errors/v5-conversion-error';
 import { HasObjectId } from '~/interfaces/has-object-id';
@@ -159,7 +161,7 @@ class PageService {
       this.pageEvent.onUpdate();
 
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_UPDATE);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_UPDATE);
       }
       catch (err) {
         logger.error(err);
@@ -169,7 +171,7 @@ class PageService {
     // rename
     this.pageEvent.on('rename', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME);
       }
       catch (err) {
         logger.error(err);
@@ -179,7 +181,7 @@ class PageService {
     // duplicate
     this.pageEvent.on('duplicate', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DUPLICATE);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DUPLICATE);
       }
       catch (err) {
         logger.error(err);
@@ -189,7 +191,7 @@ class PageService {
     // delete
     this.pageEvent.on('delete', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DELETE);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DELETE);
       }
       catch (err) {
         logger.error(err);
@@ -199,7 +201,7 @@ class PageService {
     // delete completely
     this.pageEvent.on('deleteCompletely', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DELETE_COMPLETELY);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_DELETE_COMPLETELY);
       }
       catch (err) {
         logger.error(err);
@@ -209,7 +211,7 @@ class PageService {
     // revert
     this.pageEvent.on('revert', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_REVERT);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_REVERT);
       }
       catch (err) {
         logger.error(err);
@@ -219,7 +221,7 @@ class PageService {
     // likes
     this.pageEvent.on('like', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_LIKE);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_LIKE);
       }
       catch (err) {
         logger.error(err);
@@ -229,7 +231,7 @@ class PageService {
     // bookmark
     this.pageEvent.on('bookmark', async(page, user) => {
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_BOOKMARK);
+        await this.createAndSendNotifications(user, page, SUPPORTED_ACTION_TYPE.ACTION_PAGE_BOOKMARK);
       }
       catch (err) {
         logger.error(err);
@@ -2231,17 +2233,17 @@ class PageService {
     return shortBodiesMap;
   }
 
-  private async createAndSendNotifications(page, user, action) {
+  private async createAndSendNotifications(user: IUserHasId, target: IPage, action: SupportedActionType) {
     const { activityService, inAppNotificationService } = this.crowi;
 
-    const snapshot = stringifySnapshot(page);
-
     // Create activity
+    const snapshotForActivity: ISnapshot = { username: user.username };
     const parameters = {
       user: user._id,
       targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
-      target: page,
+      target,
       action,
+      snapshot: snapshotForActivity,
     };
     const activity = await activityService.createByParameters(parameters);
 
@@ -2249,7 +2251,8 @@ class PageService {
     const targetUsers = await activity.getNotificationTargetUsers();
 
     // Create and send notifications
-    await inAppNotificationService.upsertByActivity(targetUsers, activity, snapshot);
+    const snapshotForInAppNotification = stringifySnapshot(target);
+    await inAppNotificationService.upsertByActivity(targetUsers, activity, snapshotForInAppNotification);
     await inAppNotificationService.emitSocketIo(targetUsers);
   }