activity.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { getOrCreateModel, getModelSafely } from '@growi/core';
  2. import {
  3. Types, Document, Model, Schema,
  4. } from 'mongoose';
  5. import mongoosePaginate from 'mongoose-paginate-v2';
  6. import { AllSupportedTargetModelType, AllSupportedActionType, ISnapshot } from '~/interfaces/activity';
  7. import loggerFactory from '../../utils/logger';
  8. import activityEvent from '../events/activity';
  9. import Subscription from './subscription';
  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: Types.ObjectId
  16. action: string
  17. snapshot: ISnapshot
  18. getNotificationTargetUsers(): Promise<any[]>
  19. }
  20. export interface ActivityModel extends Model<ActivityDocument> {
  21. [x:string]: any
  22. getActionUsersFromActivities(activities: ActivityDocument[]): any[]
  23. }
  24. const snapshotSchema = new Schema<ISnapshot>({
  25. username: { type: String },
  26. });
  27. // TODO: add revision id
  28. const activitySchema = new Schema<ActivityDocument, ActivityModel>({
  29. user: {
  30. type: Schema.Types.ObjectId,
  31. ref: 'User',
  32. index: true,
  33. required: true,
  34. },
  35. targetModel: {
  36. type: String,
  37. required: true,
  38. enum: AllSupportedTargetModelType,
  39. },
  40. target: {
  41. type: Schema.Types.ObjectId,
  42. refPath: 'targetModel',
  43. required: true,
  44. },
  45. action: {
  46. type: String,
  47. required: true,
  48. enum: AllSupportedActionType,
  49. },
  50. snapshot: snapshotSchema,
  51. }, {
  52. timestamps: {
  53. createdAt: true,
  54. updatedAt: false,
  55. },
  56. });
  57. activitySchema.index({ target: 1, action: 1 });
  58. activitySchema.index({
  59. user: 1, target: 1, action: 1, createdAt: 1,
  60. }, { unique: true });
  61. activitySchema.plugin(mongoosePaginate);
  62. activitySchema.methods.getNotificationTargetUsers = async function() {
  63. const User = getModelSafely('User') || require('~/server/models/user')();
  64. const { user: actionUser, target } = this;
  65. const [subscribeUsers, unsubscribeUsers] = await Promise.all([
  66. Subscription.getSubscription((target as any) as Types.ObjectId),
  67. Subscription.getUnsubscription((target as any) as Types.ObjectId),
  68. ]);
  69. const unique = array => Object.values(array.reduce((objects, object) => ({ ...objects, [object.toString()]: object }), {}));
  70. const filter = (array, pull) => {
  71. const ids = pull.map(object => object.toString());
  72. return array.filter(object => !ids.includes(object.toString()));
  73. };
  74. const notificationUsers = filter(unique([...subscribeUsers]), [...unsubscribeUsers, actionUser]);
  75. const activeNotificationUsers = await User.find({
  76. _id: { $in: notificationUsers },
  77. status: User.STATUS_ACTIVE,
  78. }).distinct('_id');
  79. return activeNotificationUsers;
  80. };
  81. activitySchema.post('save', async(savedActivity: ActivityDocument) => {
  82. let targetUsers: Types.ObjectId[] = [];
  83. try {
  84. targetUsers = await savedActivity.getNotificationTargetUsers();
  85. }
  86. catch (err) {
  87. logger.error(err);
  88. }
  89. activityEvent.emit('create', targetUsers, savedActivity);
  90. });
  91. activitySchema.statics.getPaginatedActivity = async function(limit: number, offset: number, query) {
  92. const paginateResult = await this.paginate(
  93. query,
  94. {
  95. limit,
  96. offset,
  97. sort: { createdAt: -1 },
  98. populate: 'user',
  99. },
  100. );
  101. return paginateResult;
  102. };
  103. export default getOrCreateModel<ActivityDocument, ActivityModel>('Activity', activitySchema);