user-affiliations.pug 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. include ../../_mixins/reconfirm_affiliation
  2. mixin aboutInstitutionLink()
  3. a(href="/learn/how-to/Institutional_Login") #{translate("find_out_more_about_institution_login")}.
  4. mixin btnMakePrimaryDisabled(tooltip)
  5. div(
  6. tooltip=tooltip
  7. tooltip-enable="!ui.isMakingRequest"
  8. )
  9. button.btn.btn-sm.btn-success.affiliations-table-inline-action(
  10. disabled
  11. type="button"
  12. ) #{translate("make_primary")}
  13. mixin btnRemoveEmail()
  14. .affiliations-table-inline-action-disabled-wrapper(ng-if="userEmail.default")
  15. div(
  16. tooltip=translate("please_change_primary_to_remove")
  17. tooltip-enable="!ui.isMakingRequest"
  18. tooltip-placement="left"
  19. )
  20. button.btn.btn-sm.btn-danger(disabled)
  21. i.fa.fa-fw.fa-trash(aria-hidden="true")
  22. span.sr-only #{translate("please_change_primary_to_remove")}
  23. button.btn.btn-sm.btn-danger.affiliations-table-inline-action(
  24. ng-if="!userEmail.default"
  25. ng-click="removeUserEmail(userEmail)"
  26. ng-disabled="ui.isMakingRequest"
  27. tooltip=translate("remove")
  28. type="button"
  29. )
  30. i.fa.fa-fw.fa-trash(aria-hidden="true")
  31. span.sr-only #{translate("remove")}
  32. form.row(
  33. ng-controller="UserAffiliationsController"
  34. name="affiliationsForm"
  35. )
  36. .col-md-12
  37. h3 #{translate("emails_and_affiliations_title")}
  38. p.small #{translate("emails_and_affiliations_explanation")}
  39. p.small !{translate("change_primary_email_address_instructions", {}, [{name: "strong"}, { name: "a", attrs: { href: "/learn/how-to/Keeping_your_account_secure"}}])}
  40. table.table.affiliations-table
  41. thead
  42. tr
  43. th.affiliations-table-email #{translate("email")}
  44. th.affiliations-table-institution #{translate("institution_and_role")}
  45. th.affiliations-table-inline-actions
  46. tbody
  47. tr(
  48. ng-repeat-start="userEmail in userEmails"
  49. )
  50. td
  51. | {{ userEmail.email + (userEmail.default ? ' (primary)' : '') }}
  52. div(ng-if="!userEmail.confirmedAt").small
  53. strong #{translate('unconfirmed')}.
  54. span(ng-if="!userEmail.ssoAvailable")  #{translate('please_check_your_inbox')}.
  55. br
  56. a(
  57. href,
  58. ng-click="resendConfirmationEmail(userEmail)",
  59. ng-if="!userEmail.ssoAvailable"
  60. ) #{translate('resend_confirmation_email')}
  61. div(ng-if="userEmail.confirmedAt && userEmail.affiliation.institution && userEmail.affiliation.institution.confirmed && userEmail.affiliation.licence && userEmail.affiliation.licence != 'free'").small
  62. span.label.label-primary #{translate("professional")}
  63. td
  64. div(ng-if="userEmail.affiliation.institution")
  65. div {{ userEmail.affiliation.institution.name }}
  66. span.small
  67. a(
  68. href
  69. ng-if="!isChangingAffiliation(userEmail.email) && !userEmail.affiliation.role && !userEmail.affiliation.department"
  70. ng-click="changeAffiliation(userEmail);"
  71. ) #{translate("add_role_and_department")}
  72. div.small(
  73. ng-if="!isChangingAffiliation(userEmail.email) && (userEmail.affiliation.role || userEmail.affiliation.department)"
  74. )
  75. span(ng-if="userEmail.affiliation.role") {{ userEmail.affiliation.role }}
  76. span(ng-if="userEmail.affiliation.role && userEmail.affiliation.department") , 
  77. span(ng-if="userEmail.affiliation.department") {{ userEmail.affiliation.department }}
  78. br
  79. a(
  80. href
  81. ng-click="changeAffiliation(userEmail);"
  82. ) #{translate("change")}
  83. .affiliation-change-container(
  84. ng-if="isChangingAffiliation(userEmail.email)"
  85. )
  86. affiliation-form(
  87. affiliation-data="affiliationToChange"
  88. show-university-and-country="false"
  89. show-role-and-department="true"
  90. )
  91. .affiliation-change-actions.small
  92. button.btn.btn-sm.btn-success(
  93. ng-click="saveAffiliationChange(userEmail);"
  94. ng-disabled="!(affiliationToChange.role && affiliationToChange.department)"
  95. type="button"
  96. ) #{translate("save_or_cancel-save")}
  97. |  #{translate("save_or_cancel-or" )} 
  98. a(
  99. href
  100. ng-click="cancelAffiliationChange();"
  101. ) #{translate("save_or_cancel-cancel")}
  102. td.affiliations-table-inline-actions
  103. // Disabled buttons don't work with tooltips, due to pointer-events: none,
  104. // so create a wrapper for the tooltip
  105. span(ng-if="!userEmail.default && (!userEmail.confirmedAt || ui.isMakingRequest) && !institutionAlreadyLinked(userEmail) && !inReconfirmNotificationPeriod(userEmail)")
  106. .affiliations-table-inline-action-disabled-wrapper(ng-if="userEmail.ssoAvailable")
  107. +btnMakePrimaryDisabled(translate("please_link_before_making_primary"))
  108. .affiliations-table-inline-action-disabled-wrapper(ng-if="!userEmail.ssoAvailable")
  109. +btnMakePrimaryDisabled(translate("please_confirm_your_email_before_making_it_default"))
  110. .affiliations-table-inline-action-disabled-wrapper(ng-if="!userEmail.default && inReconfirmNotificationPeriod(userEmail)")
  111. +btnMakePrimaryDisabled(translate("please_reconfirm_your_affiliation_before_making_this_primary"))
  112. button.btn.btn-sm.btn-success.affiliations-table-inline-action(
  113. tooltip=translate("make_email_primary_description")
  114. ng-if="!userEmail.default && (userEmail.confirmedAt && !ui.isMakingRequest) && !inReconfirmNotificationPeriod(userEmail)"
  115. ng-click="setDefaultUserEmail(userEmail)"
  116. type="button"
  117. ) #{translate("make_primary")}
  118. |  
  119. +btnRemoveEmail()
  120. tr.affiliations-table-saml-row(ng-if="userEmail.affiliation && userEmail.affiliation && userEmail.ssoAvailable")
  121. td
  122. td(ng-attr-colspan="{{userEmail.samlProviderId ? '2' : '1'}}" ng-class="institutionAlreadyLinked(userEmail) ? '' : 'with-border'")
  123. p.small(ng-if="userEmail.samlProviderId")
  124. | !{translate("acct_linked_to_institution_acct", {institutionName: '{{userEmail.affiliation.institution.name}}'})}
  125. div(ng-if="!userEmail.samlProviderId && !institutionAlreadyLinked(userEmail)")
  126. //- this email is not linked to institution login but
  127. //- cannot have multiple emails at same institution linked for "institution login"
  128. //- so check if institution is already linked
  129. p.small
  130. | !{translate("can_link_your_institution_acct", {institutionName: '{{userEmail.affiliation.institution.name}}'})}
  131. p.small
  132. | !{translate("doing_this_allow_log_in_through_institution")} 
  133. +aboutInstitutionLink()
  134. td.with-border.affiliations-table-inline-actions(ng-if="!userEmail.samlProviderId && !institutionAlreadyLinked(userEmail)")
  135. button.btn-sm.btn.btn-info(
  136. ng-click="linkInstitutionAcct(userEmail.email, userEmail.affiliation.institution.id)"
  137. ng-disabled="ui.isMakingRequest"
  138. type="button"
  139. )
  140. | #{translate("link_accounts")}
  141. tr(
  142. class="reconfirm-row"
  143. ng-if="userEmail.samlIdentifier && userEmail.samlIdentifier.providerId === reconfirmedViaSAML"
  144. )
  145. td(colspan="3")
  146. +reconfirmedAffiliationNotification()
  147. tr(
  148. class="reconfirm-row"
  149. ng-repeat-end
  150. )
  151. td(
  152. colspan="3"
  153. ng-if="userEmail.affiliation && userEmail.affiliation.inReconfirmNotificationPeriod"
  154. )
  155. div(ng-class="{'alert alert-info': reconfirmationRemoveEmail === userEmail.email}")
  156. +reconfirmAffiliationNotification('/user/settings')
  157. tr(ng-if="showInstitutionalLeaversSurvey")
  158. td(colspan="3")
  159. div.alert.alert-info
  160. button.close.pull-right(ng-click="dismissInstitutionalLeaversSurvey()")
  161. span(aria-hidden="true") ×
  162. span.sr-only #{translate("close")}
  163. strong #{translate('limited_offer')}:
  164. |
  165. | #{translate('institutional_leavers_survey_notification')}
  166. |
  167. a.btn-inline-link(href="https://docs.google.com/forms/d/e/1FAIpQLSfYdeeoY5p1d31r5iUx1jw0O-Gd66vcsBi_Ntu3lJRMjV2EJA/viewform")
  168. strong #{translate('take_short_survey')}
  169. tr.affiliations-table-highlighted-row(
  170. ng-if="!ui.showAddEmailUI && !ui.isMakingRequest"
  171. )
  172. td(colspan="3")
  173. a(
  174. href
  175. ng-click="showAddEmailForm()"
  176. ) #{translate("add_another_email")}
  177. tr.affiliations-table-highlighted-row(
  178. ng-if="ui.showAddEmailUI && !ui.isLoadingEmails"
  179. )
  180. td
  181. .affiliations-form-group
  182. input-suggestions(
  183. ng-model="newAffiliation.email"
  184. ng-model-options="{ allowInvalid: true }"
  185. get-suggestion="getEmailSuggestion(userInput)"
  186. on-blur="handleEmailInputBlur()"
  187. input-id="affiliations-email"
  188. input-name="affiliationsEmail"
  189. input-placeholder="e.g. johndoe@mit.edu"
  190. input-type="email"
  191. input-required="true"
  192. focus-on-render="true"
  193. )
  194. td(
  195. colspan="2"
  196. ng-if="newAffiliation.ssoAvailable"
  197. )
  198. p.affiliations-table-label {{ newAffiliation.university.name }}
  199. p !{translate("to_add_email_accounts_need_to_be_linked", {institutionName: "{{newAffiliation.university.name}}"})}
  200. p !{translate("doing_this_will_verify_affiliation_and_allow_log_in", {institutionName: "{{newAffiliation.university.name}}"})} 
  201. +aboutInstitutionLink()
  202. button.btn-sm.btn.btn-primary.btn-link-accounts(
  203. ng-click="linkInstitutionAcct(newAffiliation.email, newAffiliation.university.id)"
  204. ng-disabled="ui.isMakingRequest"
  205. type="button"
  206. )
  207. | #{translate("link_accounts_and_add_email")}
  208. td(
  209. ng-if="!newAffiliation.ssoAvailable"
  210. )
  211. p.affiliations-table-label(
  212. ng-if="newAffiliation.university && !ui.showManualUniversitySelectionUI"
  213. )
  214. | {{ newAffiliation.university.name }}
  215. span.small
  216. | (
  217. a(
  218. href
  219. ng-click="selectUniversityManually();"
  220. ) #{translate("change")}
  221. | )
  222. .affiliations-table-label(
  223. ng-if="!newAffiliation.university && !ui.isValidEmail && !ui.showManualUniversitySelectionUI"
  224. ) #{translate("start_by_adding_your_email")}
  225. .affiliations-table-label(
  226. ng-if="!newAffiliation.university && ui.isValidEmail && !ui.isBlacklistedEmail && !ui.showManualUniversitySelectionUI"
  227. )
  228. | #{translate("is_email_affiliated")}
  229. br
  230. a(
  231. href
  232. ng-click="selectUniversityManually();"
  233. ) #{translate("let_us_know")}
  234. affiliation-form(
  235. affiliation-data="newAffiliation"
  236. show-university-and-country="ui.showManualUniversitySelectionUI"
  237. show-role-and-department="ui.isValidEmail && newAffiliation.university"
  238. )
  239. td(
  240. ng-if="!newAffiliation.ssoAvailable"
  241. )
  242. button.btn.btn-sm.btn-primary(
  243. ng-disabled="affiliationsForm.$invalid || ui.isMakingRequest"
  244. ng-click="addNewEmail()"
  245. )
  246. | #{translate("add_new_email")}
  247. tr.affiliations-table-highlighted-row(
  248. ng-if="ui.isMakingRequest"
  249. )
  250. td.text-center(colspan="3", ng-if="ui.isLoadingEmails")
  251. i.fa.fa-fw.fa-spin.fa-refresh(aria-hidden="true")
  252. |  #{translate("loading")}…
  253. td.text-center(colspan="3", ng-if="ui.isResendingConfirmation")
  254. i.fa.fa-fw.fa-spin.fa-refresh(aria-hidden="true")
  255. |  #{translate("sending")}…
  256. td.text-center.text-capitalize(colspan="3", ng-if="ui.isProcessing")
  257. i.fa.fa-fw.fa-spin.fa-refresh(aria-hidden="true")
  258. |  #{translate("processing")}
  259. td.text-center(colspan="3", ng-if="!ui.isLoadingEmails && !ui.isResendingConfirmation && !ui.isProcessing")
  260. i.fa.fa-fw.fa-spin.fa-refresh(aria-hidden="true")
  261. |  #{translate("saving")}
  262. tr.affiliations-table-error-row(
  263. ng-if="ui.hasError"
  264. )
  265. td.text-center(colspan="3")
  266. div
  267. i.fa.fa-fw.fa-exclamation-triangle(aria-hidden="true")
  268. span(ng-if="!ui.errorMessage")  #{translate("error_performing_request")}
  269. span(ng-if="ui.errorMessage")  {{ui.errorMessage}}
  270. if institutionLinked
  271. tr.affiliations-table-info-row(ng-if="!hideInstitutionNotifications.info")
  272. td.text-center(aria-live="assertive" colspan="3")
  273. button.close(
  274. type="button"
  275. data-dismiss="modal"
  276. ng-click="closeInstitutionNotification('info')"
  277. aria-label=translate("close")
  278. )
  279. span(aria-hidden="true") ×
  280. .small(ng-non-bindable) !{translate("institution_acct_successfully_linked", {institutionName: institutionLinked.universityName})}
  281. if institutionLinked.hasEntitlement
  282. .small !{translate("this_grants_access_to_features", {featureType: translate("professional")})}
  283. if institutionEmailNonCanonical
  284. tr.affiliations-table-warning-row(ng-if="!hideInstitutionNotifications.warning")
  285. td.text-center(aria-live="assertive" colspan="3")
  286. button.close(
  287. type="button"
  288. data-dismiss="modal"
  289. ng-click="closeInstitutionNotification('warning')"
  290. aria-label=translate("close")
  291. )
  292. span(aria-hidden="true") ×
  293. .small
  294. i.fa.fa-exclamation-triangle(aria-hidden="true")
  295. |  
  296. | !{translate("in_order_to_match_institutional_metadata", {email: institutionEmailNonCanonical})}
  297. if samlError
  298. tr.affiliations-table-error-row(ng-if="!hideInstitutionNotifications.linkError")
  299. td.text-center(aria-live="assertive" colspan="3")
  300. button.close(
  301. type="button"
  302. data-dismiss="modal"
  303. ng-click="closeInstitutionNotification('linkError')"
  304. aria-label=translate("close")
  305. )
  306. span(aria-hidden="true") ×
  307. .small
  308. i.fa.fa-fw.fa-exclamation-triangle(aria-hidden="true")
  309. |  #{translate("generic_something_went_wrong")}.
  310. br
  311. if samlError.translatedMessage
  312. span(ng-non-bindable) !{samlError.translatedMessage}
  313. else if samlError.message
  314. span(ng-non-bindable) #{samlError.message}
  315. if samlError.tryAgain
  316. br
  317. |  #{translate("try_again")}.
  318. script(type="text/ng-template", id="affiliationFormTpl")
  319. .affiliations-form-group(
  320. ng-if="$ctrl.showUniversityAndCountry"
  321. )
  322. ui-select(
  323. ng-model="$ctrl.affiliationData.country"
  324. )
  325. ui-select-match(
  326. placeholder="Country"
  327. ) {{ $select.selected.name }}
  328. ui-select-choices(
  329. repeat="country in $ctrl.countries | filter: $select.search"
  330. )
  331. span(
  332. ng-bind="country.name"
  333. )
  334. .affiliations-form-group(
  335. ng-if="$ctrl.showUniversityAndCountry"
  336. )
  337. ui-select(
  338. ng-model="$ctrl.affiliationData.university"
  339. ng-disabled="!$ctrl.affiliationData.country"
  340. tagging="$ctrl.addUniversityToSelection"
  341. tagging-label="false"
  342. )
  343. ui-select-match(
  344. placeholder="Institution"
  345. ) {{ $select.selected.name }}
  346. ui-select-choices(
  347. repeat="university in $ctrl.universities | filter: $select.search"
  348. refresh="$ctrl.handleFreeformInputChange($select, 'name');"
  349. refresh-delay="10"
  350. )
  351. span(
  352. ng-bind="university.name"
  353. )
  354. .affiliations-form-group(
  355. ng-if="$ctrl.showRoleAndDepartment"
  356. )
  357. ui-select(
  358. ng-model="$ctrl.affiliationData.role"
  359. tagging
  360. tagging-label="false"
  361. )
  362. ui-select-match(
  363. placeholder="Role"
  364. ) {{ $select.selected }}
  365. ui-select-choices(
  366. repeat="role in $ctrl.roles | filter: $select.search"
  367. refresh="$ctrl.handleFreeformInputChange($select);"
  368. refresh-delay="10"
  369. )
  370. span(
  371. ng-bind="role"
  372. )
  373. .affiliations-form-group(
  374. ng-if="$ctrl.showRoleAndDepartment"
  375. )
  376. ui-select(
  377. ng-model="$ctrl.affiliationData.department"
  378. tagging
  379. tagging-label="false"
  380. )
  381. ui-select-match(
  382. placeholder="Department"
  383. ) {{ $select.selected }}
  384. ui-select-choices(
  385. repeat="department in $ctrl.departments | filter: $select.search"
  386. refresh="$ctrl.handleFreeformInputChange($select);"
  387. refresh-delay="10"
  388. )
  389. span(
  390. ng-bind="department"
  391. )