activity.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import {
  2. Types, Document, Model, Schema,
  3. } from 'mongoose';
  4. import Crowi from '../crowi';
  5. import { getOrCreateModel, getModelSafely } from '../util/mongoose-utils';
  6. import loggerFactory from '../../utils/logger';
  7. import ActivityDefine from '../util/activityDefine';
  8. import Subscription from './subscription';
  9. // import { InAppNotification } from './in-app-notification';
  10. const logger = loggerFactory('growi:models:activity');
  11. export interface ActivityDocument extends Document {
  12. _id: Types.ObjectId
  13. user: Types.ObjectId | any
  14. targetModel: string
  15. target: string
  16. action: string
  17. event: Types.ObjectId
  18. eventModel: string
  19. createdAt: Date
  20. getNotificationTargetUsers(): Promise<any[]>
  21. }
  22. export type ActivityModel = Model<ActivityDocument>
  23. module.exports = function(crowi: Crowi) {
  24. const activityEvent = crowi.event('activity');
  25. // TODO: add revision id
  26. const activitySchema = new Schema<ActivityDocument, ActivityModel>({
  27. user: {
  28. type: Schema.Types.ObjectId,
  29. ref: 'User',
  30. index: true,
  31. require: true,
  32. },
  33. targetModel: {
  34. type: String,
  35. require: true,
  36. enum: ActivityDefine.getSupportTargetModelNames(),
  37. },
  38. target: {
  39. type: Schema.Types.ObjectId,
  40. refPath: 'targetModel',
  41. require: true,
  42. },
  43. action: {
  44. type: String,
  45. require: true,
  46. enum: ActivityDefine.getSupportActionNames(),
  47. },
  48. event: {
  49. type: Schema.Types.ObjectId,
  50. refPath: 'eventModel',
  51. },
  52. eventModel: {
  53. type: String,
  54. enum: ActivityDefine.getSupportEventModelNames(),
  55. },
  56. createdAt: {
  57. type: Date,
  58. default: Date.now,
  59. },
  60. });
  61. activitySchema.index({ target: 1, action: 1 });
  62. activitySchema.index({
  63. user: 1, target: 1, action: 1, createdAt: 1,
  64. }, { unique: true });
  65. // /**
  66. // * @param {object} parameters
  67. // * @return {Promise}
  68. // */
  69. // activitySchema.statics.createByParameters = function(parameters) {
  70. // return this.create(parameters);
  71. // };
  72. // /**
  73. // * @param {Comment} comment
  74. // * @return {Promise}
  75. // */
  76. // activitySchema.statics.createByPageComment = function(comment) {
  77. // const parameters = {
  78. // user: comment.creator,
  79. // targetModel: ActivityDefine.MODEL_PAGE,
  80. // target: comment.page,
  81. // eventModel: ActivityDefine.MODEL_COMMENT,
  82. // event: comment._id,
  83. // action: ActivityDefine.ACTION_COMMENT,
  84. // };
  85. // return this.createByParameters(parameters);
  86. // };
  87. // /**
  88. // * @param {Page} page
  89. // * @param {User} user
  90. // * @return {Promise}
  91. // */
  92. // activitySchema.statics.createByPageLike = function(page, user) {
  93. // const parameters = {
  94. // user: user._id,
  95. // targetModel: ActivityDefine.MODEL_PAGE,
  96. // target: page,
  97. // action: ActivityDefine.ACTION_LIKE,
  98. // };
  99. // return this.createByParameters(parameters);
  100. // };
  101. // /**
  102. // * @param {User} user
  103. // * @return {Promise}
  104. // */
  105. // activitySchema.statics.findByUser = function(user) {
  106. // return this.find({ user }).sort({ createdAt: -1 }).exec();
  107. // };
  108. // activitySchema.statics.getActionUsersFromActivities = function(activities) {
  109. // return activities.map(({ user }) => user).filter((user, i, self) => self.indexOf(user) === i);
  110. // };
  111. activitySchema.methods.getNotificationTargetUsers = async function() {
  112. const User = getModelSafely('User') || require('~/server/models/user')();
  113. const { user: actionUser, targetModel, target } = this;
  114. const model: any = await this.model(targetModel).findById(target);
  115. const [targetUsers, watchUsers, ignoreUsers] = await Promise.all([
  116. model.getNotificationTargetUsers(),
  117. Subscription.getWatchers((target as any) as Types.ObjectId),
  118. Subscription.getUnwatchers((target as any) as Types.ObjectId),
  119. ]);
  120. const unique = array => Object.values(array.reduce((objects, object) => ({ ...objects, [object.toString()]: object }), {}));
  121. const filter = (array, pull) => {
  122. const ids = pull.map(object => object.toString());
  123. return array.filter(object => !ids.includes(object.toString()));
  124. };
  125. const notificationUsers = filter(unique([...targetUsers, ...watchUsers]), [...ignoreUsers, actionUser]);
  126. const activeNotificationUsers = await User.find({
  127. _id: { $in: notificationUsers },
  128. status: User.STATUS_ACTIVE,
  129. }).distinct('_id');
  130. return activeNotificationUsers;
  131. };
  132. activitySchema.post('save', async(savedActivity: ActivityDocument) => {
  133. let targetUsers: Types.ObjectId[] = [];
  134. try {
  135. targetUsers = await savedActivity.getNotificationTargetUsers();
  136. }
  137. catch (err) {
  138. logger.error(err);
  139. }
  140. activityEvent.emit('create', targetUsers, savedActivity);
  141. });
  142. return getOrCreateModel<ActivityDocument, ActivityModel>('Activity', activitySchema);
  143. };