Notifications.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /* eslint-disable
  2. no-unused-vars,
  3. */
  4. // TODO: This file was created by bulk-decaffeinate.
  5. // Fix any style issues and re-enable lint.
  6. /*
  7. * decaffeinate suggestions:
  8. * DS102: Remove unnecessary code created because of implicit returns
  9. * DS207: Consider shorter variations of null checks
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. let Notifications
  13. const logger = require('@overleaf/logger')
  14. const { db, ObjectId } = require('./mongodb')
  15. const metrics = require('@overleaf/metrics')
  16. module.exports = Notifications = {
  17. getUserNotifications(userId, callback) {
  18. if (callback == null) {
  19. callback = function () {}
  20. }
  21. const query = {
  22. user_id: new ObjectId(userId),
  23. templateKey: { $exists: true },
  24. }
  25. db.notifications.find(query).toArray(callback)
  26. },
  27. _countExistingNotifications(userId, notification, callback) {
  28. if (callback == null) {
  29. callback = function () {}
  30. }
  31. const query = {
  32. user_id: new ObjectId(userId),
  33. key: notification.key,
  34. }
  35. return db.notifications.count(query, function (err, count) {
  36. if (err != null) {
  37. return callback(err)
  38. }
  39. return callback(null, count)
  40. })
  41. },
  42. addNotification(userId, notification, callback) {
  43. return this._countExistingNotifications(
  44. userId,
  45. notification,
  46. function (err, count) {
  47. if (err != null) {
  48. return callback(err)
  49. }
  50. if (count !== 0 && !notification.forceCreate) {
  51. return callback()
  52. }
  53. const doc = {
  54. user_id: new ObjectId(userId),
  55. key: notification.key,
  56. messageOpts: notification.messageOpts,
  57. templateKey: notification.templateKey,
  58. }
  59. // TTL index on the optional `expires` field, which should arrive as an iso date-string, corresponding to
  60. // a datetime in the future when the document should be automatically removed.
  61. // in Mongo, TTL indexes only work on date fields, and ignore the document when that field is missing
  62. // see `README.md` for instruction on creating TTL index
  63. if (notification.expires != null) {
  64. try {
  65. doc.expires = new Date(notification.expires)
  66. const _testValue = doc.expires.toISOString()
  67. } catch (error) {
  68. err = error
  69. logger.error(
  70. { userId, expires: notification.expires },
  71. 'error converting `expires` field to Date'
  72. )
  73. return callback(err)
  74. }
  75. }
  76. db.notifications.updateOne(
  77. { user_id: doc.user_id, key: notification.key },
  78. { $set: doc },
  79. { upsert: true },
  80. callback
  81. )
  82. }
  83. )
  84. },
  85. removeNotificationId(userId, notificationId, callback) {
  86. const searchOps = {
  87. user_id: new ObjectId(userId),
  88. _id: new ObjectId(notificationId),
  89. }
  90. const updateOperation = { $unset: { templateKey: true, messageOpts: true } }
  91. db.notifications.updateOne(searchOps, updateOperation, callback)
  92. },
  93. removeNotificationKey(userId, notificationKey, callback) {
  94. const searchOps = {
  95. user_id: new ObjectId(userId),
  96. key: notificationKey,
  97. }
  98. const updateOperation = { $unset: { templateKey: true } }
  99. db.notifications.updateOne(searchOps, updateOperation, callback)
  100. },
  101. removeNotificationByKeyOnly(notificationKey, callback) {
  102. const searchOps = { key: notificationKey }
  103. const updateOperation = { $unset: { templateKey: true } }
  104. db.notifications.updateOne(searchOps, updateOperation, callback)
  105. },
  106. countNotificationsByKeyOnly(notificationKey, callback) {
  107. const searchOps = { key: notificationKey, templateKey: { $exists: true } }
  108. db.notifications.count(searchOps, callback)
  109. },
  110. deleteUnreadNotificationsByKeyOnlyBulk(notificationKey, callback) {
  111. if (typeof notificationKey !== 'string') {
  112. throw new Error('refusing to bulk delete arbitrary notifications')
  113. }
  114. const searchOps = { key: notificationKey, templateKey: { $exists: true } }
  115. db.notifications.deleteMany(searchOps, (err, result) => {
  116. if (err) return callback(err)
  117. callback(null, result.deletedCount)
  118. })
  119. },
  120. // hard delete of doc, rather than removing the templateKey
  121. deleteNotificationByKeyOnly(notificationKey, callback) {
  122. const searchOps = { key: notificationKey }
  123. db.notifications.deleteOne(searchOps, callback)
  124. },
  125. }
  126. ;['getUserNotifications', 'addNotification'].map(method =>
  127. metrics.timeAsyncMethod(Notifications, method, 'mongo.Notifications', logger)
  128. )