in-app-notification.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { Types } from 'mongoose';
  2. import { subDays } from 'date-fns';
  3. import Crowi from '../crowi';
  4. import {
  5. InAppNotification, InAppNotificationDocument, STATUS_UNREAD, STATUS_UNOPENED,
  6. } from '~/server/models/in-app-notification';
  7. import { ActivityDocument } from '~/server/models/activity';
  8. import loggerFactory from '~/utils/logger';
  9. import { RoomPrefix, getRoomNameWithId } from '../util/socket-io-helpers';
  10. const logger = loggerFactory('growi:service:inAppNotification');
  11. export default class InAppNotificationService {
  12. crowi!: Crowi;
  13. socketIoService!: any;
  14. commentEvent!: any;
  15. constructor(crowi: Crowi) {
  16. this.crowi = crowi;
  17. this.socketIoService = crowi.socketIoService;
  18. this.getUnreadCountByUser = this.getUnreadCountByUser.bind(this);
  19. }
  20. emitSocketIo = async(targetUsers) => {
  21. if (this.socketIoService.isInitialized) {
  22. targetUsers.forEach(async(userId) => {
  23. const count = await this.getUnreadCountByUser(userId);
  24. // emit to the room for each user
  25. await this.socketIoService.getDefaultSocket()
  26. .in(getRoomNameWithId(RoomPrefix.USER, userId))
  27. .emit('notificationUpdated', { userId, count });
  28. });
  29. }
  30. }
  31. upsertByActivity = async function(
  32. users: Types.ObjectId[], activity: ActivityDocument, createdAt?: Date | null,
  33. ): Promise<void> {
  34. const {
  35. _id: activityId, targetModel, target, action,
  36. } = activity;
  37. const now = createdAt || Date.now();
  38. const lastWeek = subDays(now, 7);
  39. const operations = users.map((user) => {
  40. const filter = {
  41. user, target, action, createdAt: { $gt: lastWeek },
  42. };
  43. const parameters = {
  44. user,
  45. targetModel,
  46. target,
  47. action,
  48. status: STATUS_UNREAD,
  49. createdAt: now,
  50. $addToSet: { activities: activityId },
  51. };
  52. return {
  53. updateOne: {
  54. filter,
  55. update: parameters,
  56. upsert: true,
  57. },
  58. };
  59. });
  60. await InAppNotification.bulkWrite(operations);
  61. logger.info('InAppNotification bulkWrite has run');
  62. return;
  63. }
  64. getLatestNotificationsByUser = async(userId, limitNum, offset) => {
  65. try {
  66. const paginationResult = await InAppNotification.paginate(
  67. { user: userId },
  68. {
  69. sort: { createdAt: -1 },
  70. offset,
  71. limit: limitNum || 10,
  72. populate: [
  73. { path: 'user' },
  74. { path: 'target' },
  75. { path: 'activities', populate: { path: 'user' } },
  76. ],
  77. },
  78. );
  79. return paginationResult;
  80. }
  81. catch (err) {
  82. logger.error('Error', err);
  83. throw new Error(err);
  84. }
  85. }
  86. read = async function(user: Types.ObjectId): Promise<void> {
  87. const query = { user, status: STATUS_UNREAD };
  88. const parameters = { status: STATUS_UNOPENED };
  89. await InAppNotification.updateMany(query, parameters);
  90. return;
  91. };
  92. getUnreadCountByUser = async function(user: Types.ObjectId): Promise<number| undefined> {
  93. const query = { user, status: STATUS_UNREAD };
  94. try {
  95. const count = await InAppNotification.countDocuments(query);
  96. return count;
  97. }
  98. catch (err) {
  99. logger.error('Error on getUnreadCountByUser', err);
  100. throw err;
  101. }
  102. };
  103. }
  104. module.exports = InAppNotificationService;