Taichi Masuyama 4 years ago
parent
commit
d38801a7dd

+ 5 - 6
packages/app/src/server/models/activity.ts

@@ -13,6 +13,8 @@ import Watcher from './watcher';
 
 const logger = loggerFactory('growi:models:activity');
 
+const mongoose = require('mongoose');
+
 export interface ActivityDocument extends Document {
   _id: Types.ObjectId
   user: Types.ObjectId | any
@@ -195,14 +197,11 @@ activitySchema.methods.getNotificationTargetUsers = async function() {
   return activeNotificationUsers;
 };
 
-/**
-   * saved hook   TODO: getNotificationTargetUsers by GW-7346
-   */
 activitySchema.post('save', async(savedActivity: ActivityDocument) => {
   try {
-    // const notificationUsers = await savedActivity.getNotificationTargetUsers();
-
-    // await Promise.all(notificationUsers.map(user => InAppNotification.upsertByActivity(user, savedActivity)));
+    const targetUsers = await savedActivity.getNotificationTargetUsers();
+    const InAppNotification = mongoose.model('InAppNotification');
+    await InAppNotification.upsertByActivity(targetUsers, savedActivity);
     return;
   }
   catch (err) {

+ 4 - 0
packages/app/src/server/models/comment.js

@@ -102,6 +102,10 @@ module.exports = function(crowi) {
     });
   };
 
+  commentSchema.statics.findCreatorsByPage = async function(page) {
+    return this.distinct('creator', { page }).exec();
+  };
+
   /**
    * post save hook
    */

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

@@ -5,7 +5,7 @@ import { subDays } from 'date-fns';
 import ActivityDefine from '../util/activityDefine';
 import { getOrCreateModel, getModelSafely } from '../util/mongoose-utils';
 import loggerFactory from '../../utils/logger';
-import { Activity, ActivityDocument } from '~/server/models/activity';
+import { Activity, ActivityDocument } from './activity';
 
 const logger = loggerFactory('growi:models:inAppNotification');
 const User = getModelSafely('User') || require('~/server/models/user')();
@@ -28,7 +28,7 @@ export interface InAppNotificationDocument extends Document {
 
 export interface InAppNotificationModel extends Model<InAppNotificationDocument> {
   findLatestInAppNotificationsByUser(user: Types.ObjectId, skip: number, offset: number): Promise<InAppNotificationDocument[]>
-  upsertByActivity(user: Types.ObjectId, activity: ActivityDocument, createdAt?: Date | null): Promise<InAppNotificationDocument | null>
+  upsertByActivity(userIds: Types.ObjectId[], activity: ActivityDocument, createdAt?: Date | null): Promise<InAppNotificationDocument | null>
   // commented out type 'Query' temporary to avoid ts error
   removeEmpty()/* : Query<any> */
   read(user: typeof User) /* : Promise<Query<any>> */
@@ -106,6 +106,40 @@ inAppNotificationSchema.statics.findLatestInAppNotificationsByUser = function(us
     .exec();
 };
 
+inAppNotificationSchema.statics.upsertByActivity = async function(
+    users: Types.ObjectId[], activity: ActivityDocument, createdAt: Date | null,
+): Promise<InAppNotificationDocument | null> {
+  const {
+    _id: activityId, targetModel, target, action,
+  } = activity;
+  const now = createdAt || Date.now();
+  const lastWeek = subDays(now, 7);
+  const operations = users.map((user) => {
+    const filter = {
+      user, target, action, createdAt: { $gt: lastWeek },
+    };
+    const parameters = {
+      user,
+      targetModel,
+      target,
+      action,
+      status: STATUS_UNREAD,
+      createdAt: now,
+      $addToSet: { activities: activityId },
+    };
+    return {
+      updateOne: {
+        filter,
+        update: parameters,
+        upsert: true,
+      },
+    };
+  });
+
+  const resultObject = await this.bulkWrite(operations);
+  return resultObject?.result;
+};
+
 inAppNotificationSchema.statics.removeEmpty = function() {
   return InAppNotification.deleteMany({ activities: { $size: 0 } });
 };

+ 10 - 0
packages/app/src/server/models/page.js

@@ -1149,6 +1149,16 @@ module.exports = function(crowi) {
     return pageData.save();
   };
 
+  pageSchema.methods.getNotificationTargetUsers = async function() {
+    const Comment = mongoose.model('Comment');
+    const Revision = mongoose.model('Revision');
+
+    const [commentCreators, revisionAuthors] = await Promise.all([Comment.findCreatorsByPage(this), Revision.findAuthorsByPage(this)]);
+
+    const targetUsers = new Set([this.creator].concat(commentCreators, revisionAuthors));
+    return Array.from(targetUsers);
+  };
+
   pageSchema.statics.getHistories = function() {
     // TODO
 

+ 5 - 0
packages/app/src/server/models/revision.js

@@ -90,5 +90,10 @@ module.exports = function(crowi) {
     }));
   };
 
+  revisionSchema.statics.findAuthorsByPage = async function(page) {
+    const result = await this.distinct('author', { path: page.path }).exec();
+    return result;
+  };
+
   return mongoose.model('Revision', revisionSchema);
 };