UserAffiliationsController.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. import _ from 'lodash'
  2. /* eslint-disable
  3. max-len,
  4. no-return-assign,
  5. no-useless-escape,
  6. */
  7. import App from '../../../base'
  8. import getMeta from '../../../utils/meta'
  9. export default App.controller(
  10. 'UserAffiliationsController',
  11. function ($scope, $rootScope, UserAffiliationsDataService, $q, $window) {
  12. $scope.userEmails = []
  13. $scope.linkedInstitutionIds = []
  14. $scope.hideInstitutionNotifications = {}
  15. $scope.closeInstitutionNotification = type => {
  16. $scope.hideInstitutionNotifications[type] = true
  17. }
  18. $scope.samlBetaSession = ExposedSettings.hasSamlBeta
  19. $scope.samlInitPath = ExposedSettings.samlInitPath
  20. $scope.reconfirmationRemoveEmail = getMeta('ol-reconfirmationRemoveEmail')
  21. $scope.reconfirmedViaSAML = getMeta('ol-reconfirmedViaSAML')
  22. $scope.showInstitutionalLeaversSurvey = false
  23. $scope.dismissInstitutionalLeaversSurvey = () => {
  24. try {
  25. localStorage.setItem('hideInstitutionalLeaversSurvey', true)
  26. } catch (e) {}
  27. $scope.showInstitutionalLeaversSurvey = false
  28. }
  29. function maybeShowInstitutionalLeaversSurvey() {
  30. if (localStorage.getItem('hideInstitutionalLeaversSurvey')) return
  31. if (
  32. localStorage.getItem('showInstitutionalLeaversSurveyUntil') > Date.now()
  33. ) {
  34. $scope.showInstitutionalLeaversSurvey = true
  35. }
  36. }
  37. maybeShowInstitutionalLeaversSurvey()
  38. const ONE_WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000
  39. const LOCAL_AND_DOMAIN_REGEX = /([^@]+)@(.+)/
  40. const EMAIL_REGEX =
  41. /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
  42. const _matchLocalAndDomain = function (userEmailInput) {
  43. const match = userEmailInput
  44. ? userEmailInput.match(LOCAL_AND_DOMAIN_REGEX)
  45. : undefined
  46. if (match) {
  47. return { local: match[1], domain: match[2] }
  48. } else {
  49. return { local: null, domain: null }
  50. }
  51. }
  52. const _ssoAvailableForAffiliation = affiliation => {
  53. if (!affiliation) return false
  54. const institution = affiliation.institution
  55. if (!_ssoAvailableForInstitution(institution)) return false
  56. if (!institution.confirmed) return false // domain is confirmed, not the email
  57. return true
  58. }
  59. const _ssoAvailableForDomain = domain => {
  60. if (!domain) return false
  61. if (!domain.confirmed) return false // domain is confirmed, not the email
  62. const institution = domain.university
  63. if (!_ssoAvailableForInstitution(institution)) return false
  64. return true
  65. }
  66. const _ssoAvailableForInstitution = institution => {
  67. if (!ExposedSettings.hasSamlFeature) return false
  68. if (!institution) return false
  69. if (institution.ssoEnabled) return true
  70. if ($scope.samlBetaSession && institution.ssoBeta) return true
  71. return false
  72. }
  73. $scope.getEmailSuggestion = function (userInput) {
  74. const userInputLocalAndDomain = _matchLocalAndDomain(userInput)
  75. $scope.ui.isValidEmail = EMAIL_REGEX.test(userInput)
  76. $scope.ui.isBlacklistedEmail = false
  77. $scope.ui.showManualUniversitySelectionUI = false
  78. if (userInputLocalAndDomain.domain) {
  79. $scope.ui.isBlacklistedEmail =
  80. UserAffiliationsDataService.isDomainBlacklisted(
  81. userInputLocalAndDomain.domain
  82. )
  83. return UserAffiliationsDataService.getUniversityDomainFromPartialDomainInput(
  84. userInputLocalAndDomain.domain
  85. )
  86. .then(function (universityDomain) {
  87. const currentUserInputLocalAndDomain = _matchLocalAndDomain(
  88. $scope.newAffiliation.email
  89. )
  90. if (
  91. currentUserInputLocalAndDomain.domain ===
  92. universityDomain.hostname
  93. ) {
  94. $scope.newAffiliation.university = universityDomain.university
  95. $scope.newAffiliation.department = universityDomain.department
  96. $scope.newAffiliation.ssoAvailable =
  97. _ssoAvailableForDomain(universityDomain)
  98. } else {
  99. _resetAffiliationSuggestion()
  100. }
  101. return $q.resolve(
  102. `${userInputLocalAndDomain.local}@${universityDomain.hostname}`
  103. )
  104. })
  105. .catch(function () {
  106. _resetAffiliationSuggestion()
  107. return $q.reject(null)
  108. })
  109. } else {
  110. _resetAffiliationSuggestion()
  111. return $q.reject(null)
  112. }
  113. }
  114. $scope.linkInstitutionAcct = function (email, institutionId) {
  115. _resetMakingRequestType()
  116. $scope.ui.isMakingRequest = true
  117. $scope.ui.isProcessing = true
  118. $window.location.href = `${$scope.samlInitPath}?university_id=${institutionId}&auto=/user/settings&email=${email}`
  119. }
  120. $scope.selectUniversityManually = function () {
  121. _resetAffiliationSuggestion()
  122. $scope.ui.showManualUniversitySelectionUI = true
  123. }
  124. $scope.changeAffiliation = function (userEmail) {
  125. if (_.get(userEmail, ['affiliation', 'institution', 'id'])) {
  126. UserAffiliationsDataService.getUniversityDetails(
  127. userEmail.affiliation.institution.id
  128. ).then(
  129. universityDetails =>
  130. ($scope.affiliationToChange.university = universityDetails)
  131. )
  132. }
  133. $scope.affiliationToChange.email = userEmail.email
  134. $scope.affiliationToChange.role = userEmail.affiliation.role
  135. $scope.affiliationToChange.department = userEmail.affiliation.department
  136. }
  137. $scope.saveAffiliationChange = function (userEmail) {
  138. userEmail.affiliation.role = $scope.affiliationToChange.role
  139. userEmail.affiliation.department = $scope.affiliationToChange.department
  140. _resetAffiliationToChange()
  141. return _monitorRequest(
  142. UserAffiliationsDataService.addRoleAndDepartment(
  143. userEmail.email,
  144. userEmail.affiliation.role,
  145. userEmail.affiliation.department
  146. )
  147. ).then(() => setTimeout(() => _getUserEmails()))
  148. }
  149. $scope.cancelAffiliationChange = email => _resetAffiliationToChange()
  150. $scope.isChangingAffiliation = email =>
  151. $scope.affiliationToChange.email === email
  152. $scope.showAddEmailForm = () => ($scope.ui.showAddEmailUI = true)
  153. $scope.addNewEmail = function () {
  154. let addEmailPromise
  155. if (!$scope.newAffiliation.university) {
  156. addEmailPromise = UserAffiliationsDataService.addUserEmail(
  157. $scope.newAffiliation.email
  158. )
  159. } else {
  160. if ($scope.newAffiliation.university.isUserSuggested) {
  161. addEmailPromise =
  162. UserAffiliationsDataService.addUserAffiliationWithUnknownUniversity(
  163. $scope.newAffiliation.email,
  164. $scope.newAffiliation.university.name,
  165. $scope.newAffiliation.country.code,
  166. $scope.newAffiliation.role,
  167. $scope.newAffiliation.department
  168. )
  169. } else {
  170. addEmailPromise = UserAffiliationsDataService.addUserAffiliation(
  171. $scope.newAffiliation.email,
  172. $scope.newAffiliation.university.id,
  173. $scope.newAffiliation.role,
  174. $scope.newAffiliation.department
  175. )
  176. }
  177. }
  178. $scope.ui.isAddingNewEmail = true
  179. $scope.ui.showAddEmailUI = false
  180. return _monitorRequest(addEmailPromise)
  181. .then(function () {
  182. _resetNewAffiliation()
  183. _resetAddingEmail()
  184. setTimeout(() => _getUserEmails())
  185. })
  186. .finally(() => ($scope.ui.isAddingNewEmail = false))
  187. }
  188. $scope.setDefaultUserEmail = userEmail =>
  189. _monitorRequest(
  190. UserAffiliationsDataService.setDefaultUserEmail(userEmail.email)
  191. ).then(function () {
  192. for (const email of $scope.userEmails || []) {
  193. email.default = false
  194. }
  195. userEmail.default = true
  196. window.usersEmail = userEmail.email
  197. $rootScope.usersEmail = userEmail.email
  198. })
  199. $scope.removeUserEmail = function (userEmail) {
  200. $scope.userEmails = $scope.userEmails.filter(ue => ue !== userEmail)
  201. return _monitorRequest(
  202. UserAffiliationsDataService.removeUserEmail(userEmail.email)
  203. )
  204. .then(() => {
  205. if (
  206. userEmail.emailHasInstitutionLicence ||
  207. (userEmail.affiliation && userEmail.affiliation.pastReconfirmDate)
  208. ) {
  209. const stillHasLicenseAccess = $scope.userEmails.some(
  210. ue => ue.emailHasInstitutionLicence
  211. )
  212. if (!stillHasLicenseAccess) {
  213. try {
  214. localStorage.setItem(
  215. 'showInstitutionalLeaversSurveyUntil',
  216. Date.now() + ONE_WEEK_IN_MS
  217. )
  218. maybeShowInstitutionalLeaversSurvey()
  219. } catch (e) {}
  220. }
  221. }
  222. })
  223. .catch(() => {
  224. $scope.userEmails.push(userEmail)
  225. })
  226. }
  227. $scope.resendConfirmationEmail = function (userEmail) {
  228. _resetMakingRequestType()
  229. $scope.ui.isResendingConfirmation = true
  230. return _monitorRequest(
  231. UserAffiliationsDataService.resendConfirmationEmail(userEmail.email)
  232. ).finally(() => ($scope.ui.isResendingConfirmation = false))
  233. }
  234. $scope.acknowledgeError = function () {
  235. _reset()
  236. return _getUserEmails()
  237. }
  238. const _resetAffiliationToChange = () =>
  239. ($scope.affiliationToChange = {
  240. email: '',
  241. university: null,
  242. role: null,
  243. department: null,
  244. })
  245. const _resetNewAffiliation = () =>
  246. ($scope.newAffiliation = {
  247. email: '',
  248. country: null,
  249. university: null,
  250. role: null,
  251. department: null,
  252. })
  253. function _resetAddingEmail() {
  254. $scope.ui.showAddEmailUI = false
  255. $scope.ui.isValidEmail = false
  256. $scope.ui.isBlacklistedEmail = false
  257. $scope.ui.showManualUniversitySelectionUI = false
  258. }
  259. const _resetAffiliationSuggestion = () => {
  260. $scope.newAffiliation = {
  261. email: $scope.newAffiliation.email,
  262. }
  263. }
  264. function _resetMakingRequestType() {
  265. $scope.ui.isLoadingEmails = false
  266. $scope.ui.isProcessing = false
  267. $scope.ui.isResendingConfirmation = false
  268. }
  269. function _reset() {
  270. $scope.ui = {
  271. hasError: false,
  272. errorMessage: '',
  273. showChangeAffiliationUI: false,
  274. isMakingRequest: false,
  275. isLoadingEmails: false,
  276. isAddingNewEmail: false,
  277. }
  278. _resetAffiliationToChange()
  279. _resetNewAffiliation()
  280. return _resetAddingEmail()
  281. }
  282. _reset()
  283. $scope.ui.showAddEmailUI = window.location.hash === '#add-email'
  284. function _monitorRequest(promise) {
  285. $scope.ui.hasError = false
  286. $scope.ui.isMakingRequest = true
  287. promise
  288. .catch(function (response) {
  289. $scope.ui.hasError = true
  290. $scope.ui.errorMessage = _.get(response, ['data', 'message'])
  291. })
  292. .finally(() => ($scope.ui.isMakingRequest = false))
  293. return promise
  294. }
  295. $scope.inReconfirmNotificationPeriod = function (emailData) {
  296. return _.get(emailData, ['affiliation', 'inReconfirmNotificationPeriod'])
  297. }
  298. $scope.institutionAlreadyLinked = function (emailData) {
  299. const institutionId =
  300. emailData.affiliation &&
  301. emailData.affiliation.institution &&
  302. emailData.affiliation.institution &&
  303. emailData.affiliation.institution.id
  304. ? emailData.affiliation.institution.id.toString()
  305. : undefined
  306. return $scope.linkedInstitutionIds.indexOf(institutionId) !== -1
  307. }
  308. // Populates the emails table
  309. function _getUserEmails() {
  310. _resetMakingRequestType()
  311. $scope.ui.isLoadingEmails = true
  312. _monitorRequest(
  313. UserAffiliationsDataService.getUserEmailsEnsureAffiliation()
  314. )
  315. .then(emails => {
  316. $scope.userEmails = emails.map(email => {
  317. email.ssoAvailable = _ssoAvailableForAffiliation(email.affiliation)
  318. return email
  319. })
  320. $scope.linkedInstitutionIds = emails
  321. .filter(email => {
  322. return !!email.samlProviderId
  323. })
  324. .map(email => email.samlProviderId)
  325. })
  326. .finally(() => ($scope.ui.isLoadingEmails = false))
  327. }
  328. _getUserEmails()
  329. }
  330. )