UserPagesController.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. const UserGetter = require('./UserGetter')
  2. const OError = require('@overleaf/o-error')
  3. const UserSessionsManager = require('./UserSessionsManager')
  4. const logger = require('@overleaf/logger')
  5. const Settings = require('@overleaf/settings')
  6. const AuthenticationController = require('../Authentication/AuthenticationController')
  7. const SessionManager = require('../Authentication/SessionManager')
  8. const NewsletterManager = require('../Newsletter/NewsletterManager')
  9. const _ = require('lodash')
  10. const { expressify } = require('../../util/promises')
  11. async function settingsPage(req, res) {
  12. const userId = SessionManager.getLoggedInUserId(req.session)
  13. const reconfirmationRemoveEmail = req.query.remove
  14. // SSO
  15. const ssoError = req.session.ssoError
  16. if (ssoError) {
  17. delete req.session.ssoError
  18. }
  19. const ssoErrorMessage = req.session.ssoErrorMessage
  20. if (ssoErrorMessage) {
  21. delete req.session.ssoErrorMessage
  22. }
  23. const projectSyncSuccessMessage = req.session.projectSyncSuccessMessage
  24. if (projectSyncSuccessMessage) {
  25. delete req.session.projectSyncSuccessMessage
  26. }
  27. // Institution SSO
  28. let institutionLinked = _.get(req.session, ['saml', 'linked'])
  29. if (institutionLinked) {
  30. // copy object if exists because _.get does not
  31. institutionLinked = Object.assign(
  32. {
  33. hasEntitlement: _.get(req.session, ['saml', 'hasEntitlement']),
  34. },
  35. institutionLinked
  36. )
  37. }
  38. const samlError = _.get(req.session, ['saml', 'error'])
  39. const institutionEmailNonCanonical = _.get(req.session, [
  40. 'saml',
  41. 'emailNonCanonical',
  42. ])
  43. const institutionRequestedEmail = _.get(req.session, [
  44. 'saml',
  45. 'requestedEmail',
  46. ])
  47. const reconfirmedViaSAML = _.get(req.session, ['saml', 'reconfirmed'])
  48. delete req.session.saml
  49. let shouldAllowEditingDetails = true
  50. if (Settings.ldap && Settings.ldap.updateUserDetailsOnLogin) {
  51. shouldAllowEditingDetails = false
  52. }
  53. if (Settings.saml && Settings.saml.updateUserDetailsOnLogin) {
  54. shouldAllowEditingDetails = false
  55. }
  56. const oauthProviders = Settings.oauthProviders || {}
  57. const user = await UserGetter.promises.getUser(userId)
  58. if (!user) {
  59. // The user has just deleted their account.
  60. return res.redirect('/logout')
  61. }
  62. res.render('user/settings', {
  63. title: 'account_settings',
  64. user: {
  65. id: user._id,
  66. isAdmin: user.isAdmin,
  67. email: user.email,
  68. allowedFreeTrial: user.allowedFreeTrial,
  69. first_name: user.first_name,
  70. last_name: user.last_name,
  71. alphaProgram: user.alphaProgram,
  72. betaProgram: user.betaProgram,
  73. labsProgram: user.labsProgram,
  74. features: {
  75. dropbox: user.features.dropbox,
  76. github: user.features.github,
  77. mendeley: user.features.mendeley,
  78. zotero: user.features.zotero,
  79. references: user.features.references,
  80. },
  81. refProviders: {
  82. mendeley: user.refProviders?.mendeley,
  83. zotero: user.refProviders?.zotero,
  84. },
  85. },
  86. hasPassword: !!user.hashedPassword,
  87. shouldAllowEditingDetails,
  88. oauthProviders: UserPagesController._translateProviderDescriptions(
  89. oauthProviders,
  90. req
  91. ),
  92. institutionLinked,
  93. samlError,
  94. institutionEmailNonCanonical:
  95. institutionEmailNonCanonical && institutionRequestedEmail
  96. ? institutionEmailNonCanonical
  97. : undefined,
  98. reconfirmedViaSAML,
  99. reconfirmationRemoveEmail,
  100. samlBeta: req.session.samlBeta,
  101. ssoErrorMessage,
  102. thirdPartyIds: UserPagesController._restructureThirdPartyIds(user),
  103. projectSyncSuccessMessage,
  104. })
  105. }
  106. const UserPagesController = {
  107. registerPage(req, res) {
  108. const sharedProjectData = {
  109. project_name: req.query.project_name,
  110. user_first_name: req.query.user_first_name,
  111. }
  112. const newTemplateData = {}
  113. if (req.session.templateData != null) {
  114. newTemplateData.templateName = req.session.templateData.templateName
  115. }
  116. res.render('user/register', {
  117. title: 'register',
  118. sharedProjectData,
  119. newTemplateData,
  120. samlBeta: req.session.samlBeta,
  121. })
  122. },
  123. loginPage(req, res) {
  124. // if user is being sent to /login with explicit redirect (redir=/foo),
  125. // such as being sent from the editor to /login, then set the redirect explicitly
  126. if (
  127. req.query.redir != null &&
  128. AuthenticationController._getRedirectFromSession(req) == null
  129. ) {
  130. AuthenticationController.setRedirectInSession(req, req.query.redir)
  131. }
  132. res.render('user/login', {
  133. title: 'login',
  134. })
  135. },
  136. /**
  137. * Landing page for users who may have received one-time login
  138. * tokens from the read-only maintenance site.
  139. *
  140. * We tell them that Overleaf is back up and that they can login normally.
  141. */
  142. oneTimeLoginPage(req, res, next) {
  143. res.render('user/one_time_login')
  144. },
  145. logoutPage(req, res) {
  146. res.render('user/logout')
  147. },
  148. renderReconfirmAccountPage(req, res) {
  149. const pageData = {
  150. reconfirm_email: req.session.reconfirm_email,
  151. }
  152. // when a user must reconfirm their account
  153. res.render('user/reconfirm', pageData)
  154. },
  155. settingsPage: expressify(settingsPage),
  156. sessionsPage(req, res, next) {
  157. const user = SessionManager.getSessionUser(req.session)
  158. logger.debug({ userId: user._id }, 'loading sessions page')
  159. const currentSession = {
  160. ip_address: user.ip_address,
  161. session_created: user.session_created,
  162. }
  163. UserSessionsManager.getAllUserSessions(
  164. user,
  165. [req.sessionID],
  166. (err, sessions) => {
  167. if (err != null) {
  168. OError.tag(err, 'error getting all user sessions', {
  169. userId: user._id,
  170. })
  171. return next(err)
  172. }
  173. res.render('user/sessions', {
  174. title: 'sessions',
  175. currentSession,
  176. sessions,
  177. })
  178. }
  179. )
  180. },
  181. emailPreferencesPage(req, res, next) {
  182. const userId = SessionManager.getLoggedInUserId(req.session)
  183. UserGetter.getUser(userId, (err, user) => {
  184. if (err != null) {
  185. return next(err)
  186. }
  187. NewsletterManager.subscribed(user, (err, subscribed) => {
  188. if (err != null) {
  189. OError.tag(err, 'error getting newsletter subscription status')
  190. return next(err)
  191. }
  192. res.render('user/email-preferences', {
  193. title: 'newsletter_info_title',
  194. subscribed,
  195. })
  196. })
  197. })
  198. },
  199. _restructureThirdPartyIds(user) {
  200. // 3rd party identifiers are an array of objects
  201. // this turn them into a single object, which
  202. // makes data easier to use in template
  203. if (
  204. !user.thirdPartyIdentifiers ||
  205. user.thirdPartyIdentifiers.length === 0
  206. ) {
  207. return null
  208. }
  209. return user.thirdPartyIdentifiers.reduce((obj, identifier) => {
  210. obj[identifier.providerId] = identifier.externalUserId
  211. return obj
  212. }, {})
  213. },
  214. _translateProviderDescriptions(providers, req) {
  215. const result = {}
  216. if (providers) {
  217. for (const provider in providers) {
  218. const data = providers[provider]
  219. data.description = req.i18n.translate(
  220. data.descriptionKey,
  221. Object.assign({}, data.descriptionOptions)
  222. )
  223. result[provider] = data
  224. }
  225. }
  226. return result
  227. },
  228. }
  229. module.exports = UserPagesController