V1SubscriptionManager.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  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. * DS103: Rewrite code to no longer use __guard__
  11. * DS207: Consider shorter variations of null checks
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. let V1SubscriptionManager
  15. const UserGetter = require('../User/UserGetter')
  16. const request = require('request')
  17. const settings = require('settings-sharelatex')
  18. const logger = require('logger-sharelatex')
  19. const { V1ConnectionError, NotFoundError } = require('../Errors/Errors')
  20. module.exports = V1SubscriptionManager = {
  21. // Returned planCode = 'v1_pro' | 'v1_pro_plus' | 'v1_student' | 'v1_free' | null
  22. // For this to work, we need plans in settings with plan-codes:
  23. // - 'v1_pro'
  24. // - 'v1_pro_plus'
  25. // - 'v1_student'
  26. // - 'v1_free'
  27. getPlanCodeFromV1(userId, callback) {
  28. if (callback == null) {
  29. callback = function(err, planCode, v1Id) {}
  30. }
  31. logger.log({ userId }, '[V1SubscriptionManager] fetching v1 plan for user')
  32. return V1SubscriptionManager._v1Request(
  33. userId,
  34. {
  35. method: 'GET',
  36. url(v1Id) {
  37. return `/api/v1/sharelatex/users/${v1Id}/plan_code`
  38. }
  39. },
  40. function(error, body, v1Id) {
  41. if (error != null) {
  42. return callback(error)
  43. }
  44. let planName = body != null ? body.plan_name : undefined
  45. logger.log(
  46. { userId, planName, body },
  47. '[V1SubscriptionManager] fetched v1 plan for user'
  48. )
  49. if (['pro', 'pro_plus', 'student', 'free'].includes(planName)) {
  50. planName = `v1_${planName}`
  51. } else {
  52. // Throw away 'anonymous', etc as being equivalent to null
  53. planName = null
  54. }
  55. return callback(null, planName, v1Id)
  56. }
  57. )
  58. },
  59. getSubscriptionsFromV1(userId, callback) {
  60. if (callback == null) {
  61. callback = function(err, subscriptions, v1Id) {}
  62. }
  63. return V1SubscriptionManager._v1Request(
  64. userId,
  65. {
  66. method: 'GET',
  67. url(v1Id) {
  68. return `/api/v1/sharelatex/users/${v1Id}/subscriptions`
  69. }
  70. },
  71. callback
  72. )
  73. },
  74. getSubscriptionStatusFromV1(userId, callback) {
  75. if (callback == null) {
  76. callback = function(err, status) {}
  77. }
  78. return V1SubscriptionManager._v1Request(
  79. userId,
  80. {
  81. method: 'GET',
  82. url(v1Id) {
  83. return `/api/v1/sharelatex/users/${v1Id}/subscription_status`
  84. }
  85. },
  86. callback
  87. )
  88. },
  89. cancelV1Subscription(userId, callback) {
  90. if (callback == null) {
  91. callback = function(err) {}
  92. }
  93. return V1SubscriptionManager._v1Request(
  94. userId,
  95. {
  96. method: 'DELETE',
  97. url(v1Id) {
  98. return `/api/v1/sharelatex/users/${v1Id}/subscription`
  99. }
  100. },
  101. callback
  102. )
  103. },
  104. v1IdForUser(userId, callback) {
  105. if (callback == null) {
  106. callback = function(err, v1Id) {}
  107. }
  108. return UserGetter.getUser(userId, { 'overleaf.id': 1 }, function(
  109. err,
  110. user
  111. ) {
  112. if (err != null) {
  113. return callback(err)
  114. }
  115. const v1Id = __guard__(
  116. user != null ? user.overleaf : undefined,
  117. x => x.id
  118. )
  119. if (v1Id == null) {
  120. logger.log(
  121. { userId },
  122. '[V1SubscriptionManager] no v1 id found for user'
  123. )
  124. }
  125. return callback(null, v1Id)
  126. })
  127. },
  128. // v1 accounts created before migration to v2 had github and mendeley for free
  129. // but these are now paid-for features for new accounts (v1id > cutoff)
  130. getGrandfatheredFeaturesForV1User(v1Id) {
  131. const cutoff = settings.v1GrandfatheredFeaturesUidCutoff
  132. if (cutoff == null) {
  133. return {}
  134. }
  135. if (v1Id == null) {
  136. return {}
  137. }
  138. if (v1Id < cutoff) {
  139. return settings.v1GrandfatheredFeatures || {}
  140. } else {
  141. return {}
  142. }
  143. },
  144. _v1Request(userId, options, callback) {
  145. if (callback == null) {
  146. callback = function(err, body, v1Id) {}
  147. }
  148. if (!settings.apis.v1.url) {
  149. return callback(null, null)
  150. }
  151. return V1SubscriptionManager.v1IdForUser(userId, function(err, v1Id) {
  152. if (err != null) {
  153. return callback(err)
  154. }
  155. if (v1Id == null) {
  156. return callback(null, null, null)
  157. }
  158. return request(
  159. {
  160. baseUrl: settings.apis.v1.url,
  161. url: options.url(v1Id),
  162. method: options.method,
  163. auth: {
  164. user: settings.apis.v1.user,
  165. pass: settings.apis.v1.pass,
  166. sendImmediately: true
  167. },
  168. json: true,
  169. timeout: 15 * 1000
  170. },
  171. function(error, response, body) {
  172. if (error != null) {
  173. // Specially handle no connection err, so warning can be shown
  174. if (error.code === 'ECONNREFUSED') {
  175. error = new V1ConnectionError('No V1 connection')
  176. }
  177. return callback(error)
  178. }
  179. if (response.statusCode >= 200 && response.statusCode < 300) {
  180. return callback(null, body, v1Id)
  181. } else {
  182. if (response.statusCode === 404) {
  183. return callback(new NotFoundError(`v1 user not found: ${userId}`))
  184. } else {
  185. return callback(
  186. new Error(
  187. `non-success code from v1: ${response.statusCode} ${
  188. options.method
  189. } ${options.url(v1Id)}`
  190. )
  191. )
  192. }
  193. }
  194. }
  195. )
  196. })
  197. }
  198. }
  199. function __guard__(value, transform) {
  200. return typeof value !== 'undefined' && value !== null
  201. ? transform(value)
  202. : undefined
  203. }