Notifications.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import logger from '@overleaf/logger'
  2. import { db, ObjectId } from './mongodb.js'
  3. async function getUserNotifications(userId) {
  4. const query = {
  5. user_id: new ObjectId(userId),
  6. templateKey: { $exists: true },
  7. }
  8. return await db.notifications.find(query).toArray()
  9. }
  10. async function _countExistingNotifications(userId, notification) {
  11. const query = {
  12. user_id: new ObjectId(userId),
  13. key: notification.key,
  14. }
  15. return await db.notifications.count(query)
  16. }
  17. async function addNotification(userId, notification, callback) {
  18. const count = await _countExistingNotifications(userId, notification)
  19. if (count !== 0 && !notification.forceCreate) {
  20. return
  21. }
  22. const doc = {
  23. user_id: new ObjectId(userId),
  24. key: notification.key,
  25. messageOpts: notification.messageOpts,
  26. templateKey: notification.templateKey,
  27. }
  28. // TTL index on the optional `expires` field, which should arrive as an iso date-string, corresponding to
  29. // a datetime in the future when the document should be automatically removed.
  30. // in Mongo, TTL indexes only work on date fields, and ignore the document when that field is missing
  31. // see `README.md` for instruction on creating TTL index
  32. if (notification.expires != null) {
  33. try {
  34. doc.expires = new Date(notification.expires)
  35. // _testValue assignment will throw if `expires` is not a valid date
  36. // eslint-disable-next-line no-unused-vars
  37. const _testValue = doc.expires.toISOString()
  38. } catch (error) {
  39. logger.error(
  40. { userId, expires: notification.expires },
  41. 'error converting `expires` field to Date'
  42. )
  43. throw error
  44. }
  45. }
  46. return await db.notifications.updateOne(
  47. { user_id: doc.user_id, key: notification.key },
  48. { $set: doc },
  49. { upsert: true }
  50. )
  51. }
  52. async function removeNotificationId(userId, notificationId) {
  53. const searchOps = {
  54. user_id: new ObjectId(userId),
  55. _id: new ObjectId(notificationId),
  56. }
  57. const updateOperation = { $unset: { templateKey: true, messageOpts: true } }
  58. return await db.notifications.updateOne(searchOps, updateOperation)
  59. }
  60. async function removeNotificationKey(userId, notificationKey) {
  61. const searchOps = {
  62. user_id: new ObjectId(userId),
  63. key: notificationKey,
  64. }
  65. const updateOperation = { $unset: { templateKey: true } }
  66. return await db.notifications.updateOne(searchOps, updateOperation)
  67. }
  68. async function removeNotificationByKeyOnly(notificationKey) {
  69. const searchOps = { key: notificationKey }
  70. const updateOperation = { $unset: { templateKey: true } }
  71. return await db.notifications.updateOne(searchOps, updateOperation)
  72. }
  73. async function countNotificationsByKeyOnly(notificationKey) {
  74. const searchOps = { key: notificationKey, templateKey: { $exists: true } }
  75. return await db.notifications.countDocuments(searchOps)
  76. }
  77. async function deleteUnreadNotificationsByKeyOnlyBulk(notificationKey) {
  78. if (typeof notificationKey !== 'string') {
  79. throw new Error('refusing to bulk delete arbitrary notifications')
  80. }
  81. const searchOps = { key: notificationKey, templateKey: { $exists: true } }
  82. const result = await db.notifications.deleteMany(searchOps)
  83. return result.deletedCount
  84. }
  85. // hard delete of doc, rather than removing the templateKey
  86. async function deleteNotificationByKeyOnly(notificationKey) {
  87. const searchOps = { key: notificationKey }
  88. return await db.notifications.deleteOne(searchOps)
  89. }
  90. export default {
  91. addNotification,
  92. getUserNotifications,
  93. removeNotificationId,
  94. removeNotificationKey,
  95. removeNotificationByKeyOnly,
  96. countNotificationsByKeyOnly,
  97. deleteUnreadNotificationsByKeyOnlyBulk,
  98. deleteNotificationByKeyOnly,
  99. }