Notifications.js 4.5 KB

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