V1SubscriptionManager.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. let V1SubscriptionManager
  2. const UserGetter = require('../User/UserGetter')
  3. const request = require('requestretry')
  4. const settings = require('@overleaf/settings')
  5. const { V1ConnectionError, NotFoundError } = require('../Errors/Errors')
  6. const { promisifyAll } = require('@overleaf/promise-utils')
  7. module.exports = V1SubscriptionManager = {
  8. getSubscriptionsFromV1(userId, callback) {
  9. V1SubscriptionManager._v1Request(
  10. userId,
  11. {
  12. method: 'GET',
  13. url(v1Id) {
  14. return `/api/v1/overleaf/users/${v1Id}/subscriptions`
  15. },
  16. },
  17. callback
  18. )
  19. },
  20. cancelV1Subscription(userId, callback) {
  21. V1SubscriptionManager._v1Request(
  22. userId,
  23. {
  24. method: 'DELETE',
  25. url(v1Id) {
  26. return `/api/v1/overleaf/users/${v1Id}/subscription`
  27. },
  28. },
  29. callback
  30. )
  31. },
  32. v1IdForUser(userId, callback) {
  33. UserGetter.getUser(userId, { 'overleaf.id': 1 }, function (err, user) {
  34. if (err) {
  35. return callback(err)
  36. }
  37. const v1Id = user?.overleaf?.id
  38. callback(null, v1Id)
  39. })
  40. },
  41. // v1 accounts created before migration to v2 had github and mendeley for free
  42. // but these are now paid-for features for new accounts (v1id > cutoff)
  43. getGrandfatheredFeaturesForV1User(v1Id) {
  44. const cutoff = settings.v1GrandfatheredFeaturesUidCutoff
  45. if (!cutoff) {
  46. return {}
  47. }
  48. if (!v1Id) {
  49. return {}
  50. }
  51. if (v1Id < cutoff) {
  52. return settings.v1GrandfatheredFeatures || {}
  53. } else {
  54. return {}
  55. }
  56. },
  57. _v1Request(userId, options, callback) {
  58. if (!settings.apis.v1.url) {
  59. return callback(null, null)
  60. }
  61. V1SubscriptionManager.v1IdForUser(userId, function (err, v1Id) {
  62. if (err) {
  63. return callback(err)
  64. }
  65. if (!v1Id) {
  66. return callback(null, null, null)
  67. }
  68. const url = options.url(v1Id)
  69. const requestOptions = {
  70. baseUrl: settings.apis.v1.url,
  71. url,
  72. method: options.method,
  73. auth: {
  74. user: settings.apis.v1.user,
  75. pass: settings.apis.v1.pass,
  76. sendImmediately: true,
  77. },
  78. json: true,
  79. timeout: settings.apis.v1.timeout,
  80. }
  81. if (options.method === 'GET') {
  82. requestOptions.maxAttempts = 3
  83. requestOptions.retryDelay = 500
  84. } else {
  85. requestOptions.maxAttempts = 0
  86. }
  87. request(requestOptions, function (error, response, body) {
  88. if (error) {
  89. return callback(
  90. new V1ConnectionError({
  91. message: 'no v1 connection',
  92. info: { url },
  93. }).withCause(error)
  94. )
  95. }
  96. if (response && response.statusCode >= 500) {
  97. return callback(
  98. new V1ConnectionError({
  99. message: 'error from v1',
  100. info: {
  101. status: response.statusCode,
  102. body,
  103. },
  104. })
  105. )
  106. }
  107. if (response.statusCode >= 200 && response.statusCode < 300) {
  108. return callback(null, body, v1Id)
  109. } else {
  110. if (response.statusCode === 404) {
  111. return callback(new NotFoundError(`v1 user not found: ${userId}`))
  112. } else {
  113. return callback(
  114. new Error(
  115. `non-success code from v1: ${response.statusCode} ${
  116. options.method
  117. } ${options.url(v1Id)}`
  118. )
  119. )
  120. }
  121. }
  122. })
  123. })
  124. },
  125. }
  126. module.exports.promises = promisifyAll(module.exports, {
  127. without: ['getGrandfatheredFeaturesForV1User'],
  128. })