diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js
index 50d49f23f2..884a604d33 100644
--- a/services/web/app/src/Features/Project/ProjectController.js
+++ b/services/web/app/src/Features/Project/ProjectController.js
@@ -429,6 +429,7 @@ const ProjectController = {
(results.v1Projects != null ? results.v1Projects.tags : undefined) ||
[]
const tags = results.tags.concat(v1Tags)
+ const notificationsInstitution = []
for (const notification of notifications) {
notification.html = req.i18n.translate(
notification.templateKey,
@@ -460,7 +461,7 @@ const ProjectController = {
affiliation.institution.id.toString()
) === -1
) {
- notifications.push({
+ notificationsInstitution.push({
email: affiliation.email,
institutionId: affiliation.institution.id,
institutionName: affiliation.institution.name,
@@ -473,7 +474,7 @@ const ProjectController = {
if (samlSession) {
// Notification: After SSO Linked
if (samlSession.linked) {
- notifications.push({
+ notificationsInstitution.push({
email: samlSession.institutionEmail,
institutionName: samlSession.linked.universityName,
templateKey: 'notification_institution_sso_linked'
@@ -484,7 +485,7 @@ const ProjectController = {
// The requested email does not match primary email returned from
// the institution
if (samlSession.emailNonCanonical) {
- notifications.push({
+ notificationsInstitution.push({
institutionEmail: samlSession.emailNonCanonical,
requestedEmail: samlSession.requestedEmail,
templateKey: 'notification_institution_sso_non_canonical'
@@ -493,7 +494,7 @@ const ProjectController = {
// Notification: Tried to register, but account already existed
if (samlSession.registerIntercept) {
- notifications.push({
+ notificationsInstitution.push({
email: samlSession.institutionEmail,
templateKey: 'notification_institution_sso_already_registered'
})
@@ -529,6 +530,7 @@ const ProjectController = {
projects,
tags,
notifications: notifications || [],
+ notificationsInstitution,
portalTemplates,
user,
userAffiliations,
diff --git a/services/web/app/views/project/list.pug b/services/web/app/views/project/list.pug
index 555f534c5c..409b094404 100644
--- a/services/web/app/views/project/list.pug
+++ b/services/web/app/views/project/list.pug
@@ -5,7 +5,7 @@ block vars
block content
script#data(type="application/json").
- !{StringHelper.stringifyJsonForScript({ projects, tags, notifications })}
+ !{StringHelper.stringifyJsonForScript({ projects, tags, notifications, notificationsInstitution })}
script(type="text/javascript").
window.data = JSON.parse($("#data").text());
diff --git a/services/web/app/views/project/list/notifications.pug b/services/web/app/views/project/list/notifications.pug
index cb3d9abbf6..f7092f01aa 100644
--- a/services/web/app/views/project/list/notifications.pug
+++ b/services/web/app/views/project/list/notifications.pug
@@ -1,29 +1,43 @@
.user-notifications(ng-controller="NotificationsController")
ul.list-unstyled(
- ng-if="notifications.length > 0",
+ ng-if="notifications.length > 0 && projects.length > 0",
ng-cloak
)
li.notification-entry(
- ng-repeat="notification in notifications",
+ ng-repeat="notification in notifications"
)
div(ng-switch="notification.templateKey" ng-hide="notification.hide")
- .alert.alert-info(ng-switch-when="notification_project_invite", ng-controller="ProjectInviteNotificationController")
- .notification-body(ng-show="!notification.accepted")
- | !{translate("notification_project_invite_message", { userName: "{{ userName }}", projectName: "{{ projectName }}" })}
- a.pull-right.btn.btn-sm.btn-info(href, ng-click="accept()", ng-disabled="notification.inflight")
+ .alert.alert-info(
+ ng-switch-when="notification_project_invite",
+ ng-controller="ProjectInviteNotificationController"
+ )
+ .notification-body
+ span(ng-show="!notification.accepted") !{translate("notification_project_invite_message", { userName: "{{ userName }}", projectName: "{{ projectName }}" })}
+ span(ng-show="notification.accepted") !{translate("notification_project_invite_accepted_message", { projectName: "{{ projectName }}" })}
+ .notification-action
+ a.pull-right.btn.btn-sm.btn-info(
+ ng-show="notification.accepted",
+ href="/project/{{ notification.messageOpts.projectId }}"
+ ) #{translate("open_project")}
+ a.pull-right.btn.btn-sm.btn-info(
+ href,
+ ng-click="accept()",
+ ng-disabled="notification.inflight",
+ ng-show="!notification.accepted"
+ )
span(ng-show="!notification.inflight") #{translate("join_project")}
span(ng-show="notification.inflight")
i.fa.fa-fw.fa-spinner.fa-spin(aria-hidden="true")
|
| #{translate("joining")}...
- .notification-body(ng-show="notification.accepted")
- | !{translate("notification_project_invite_accepted_message", { projectName: "{{ projectName }}" })}
- a.pull-right.btn.btn-sm.btn-info(href="/project/{{ notification.messageOpts.projectId }}") #{translate("open_project")}
.notification-close
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-info(ng-switch-when="notification_ip_matched_affiliation")
+
+ .alert.alert-info(
+ ng-switch-when="notification_ip_matched_affiliation"
+ )
.notification-body
| It looks like you're at
strong {{ notification.messageOpts.university_name }}!
@@ -31,31 +45,41 @@
strong free Overleaf Professional accounts
| to everyone at {{notification.messageOpts.university_name}}?
| Add an institutional email address to claim your account.
+ .notification-action
a.pull-right.btn.btn-sm.btn-info(href="/user/settings")
| Add Affiliation
.notification-close
- button(ng-click="dismiss(notification)").close.pull-right
+ button.btn-sm(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-info(ng-switch-when="notification_institution_sso_available")
+
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_available"
+ )
.notification-body
p !{translate("can_link_institution_email_acct_to_institution_acct", {appName: settings.appName, email: "{{notification.email}}", institutionName: "{{notification.institutionName}}"})}
div !{translate("doing_this_allow_log_in_through_institution", {appName: settings.appName})}
.notification-action
- a.btn.btn-info(href="{{samlInitPath}}?university_id={{notification.institutionId}}&auto=project&email={{notification.email}}")
+ a.btn.btn-sm.btn-info(href="{{samlInitPath}}?university_id={{notification.institutionId}}&auto=project&email={{notification.email}}")
| #{translate('link_account')}
.notification-close
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-info(ng-switch-when="notification_institution_sso_linked")
+
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_linked"
+ )
.notification-body
div !{translate("account_has_been_link_to_institution_account", {appName: settings.appName, email: "{{notification.email}}", institutionName: "{{notification.institutionName}}"})}
.notification-close
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-warning(ng-switch-when="notification_institution_sso_non_canonical")
+
+ .alert.alert-warning(
+ ng-switch-when="notification_institution_sso_non_canonical"
+ )
.notification-body
div
i.fa.fa-fw.fa-exclamation-triangle(aria-hidden="true")
@@ -64,24 +88,88 @@
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-info(ng-switch-when="notification_institution_sso_already_registered")
+
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_already_registered"
+ )
.notification-body
| !{translate("tried_to_register_with_email", {appName: settings.appName, email: "{{notification.email}}"})}
| #{translate("we_logged_you_in")}
.notification-action
- a.btn.btn-info(href="/")
+ a.btn.btn-sm.btn-info(href="/")
| #{translate("find_out_more")}
.notification-close
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
- .alert.alert-info(ng-switch-default)
+
+ .alert.alert-info(
+ ng-switch-default
+ )
span(ng-bind-html="notification.html").notification-body
.notification-close
button(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
span.sr-only #{translate("close")}
+ ul.list-unstyled(
+ ng-if="notificationsInstitution.length > 0",
+ ng-cloak
+ )
+ li.notification-entry(
+ ng-repeat="notification in notificationsInstitution"
+ )
+ div(ng-switch="notification.templateKey" ng-hide="notification.hide")
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_available"
+ )
+ .notification-body
+ p !{translate("can_link_institution_email_acct_to_institution_acct", {appName: settings.appName, email: "{{notification.email}}", institutionName: "{{notification.institutionName}}"})}
+ div !{translate("doing_this_allow_log_in_through_institution", {appName: settings.appName})}
+ .notification-action
+ a.btn.btn-sm.btn-info(href="{{samlInitPath}}?university_id={{notification.institutionId}}&auto=project&email={{notification.email}}")
+ | #{translate('link_account')}
+ .notification-close
+ button(ng-click="dismiss(notification)").close.pull-right
+ span(aria-hidden="true") ×
+ span.sr-only #{translate("close")}
+
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_linked"
+ )
+ .notification-body
+ div !{translate("account_has_been_link_to_institution_account", {appName: settings.appName, email: "{{notification.email}}", institutionName: "{{notification.institutionName}}"})}
+ .notification-close
+ button(ng-click="dismiss(notification)").close.pull-right
+ span(aria-hidden="true") ×
+ span.sr-only #{translate("close")}
+
+ .alert.alert-warning(
+ ng-switch-when="notification_institution_sso_non_canonical"
+ )
+ .notification-body
+ div
+ i.fa.fa-fw.fa-exclamation-triangle(aria-hidden="true")
+ | !{translate("tried_to_log_in_with_email", {email: "{{notification.requestedEmail}}"})} !{translate("in_order_to_match_institutional_metadata_associated", {email: "{{notification.institutionEmail}}"})}
+ .notification-close
+ button(ng-click="dismiss(notification)").close.pull-right
+ span(aria-hidden="true") ×
+ span.sr-only #{translate("close")}
+
+ .alert.alert-info(
+ ng-switch-when="notification_institution_sso_already_registered"
+ )
+ .notification-body
+ | !{translate("tried_to_register_with_email", {appName: settings.appName, email: "{{notification.email}}"})}
+ | #{translate("we_logged_you_in")}
+ .notification-action
+ a.btn.btn-sm.btn-info(href="/")
+ | #{translate("find_out_more")}
+ .notification-close
+ button(ng-click="dismiss(notification)").close.pull-right
+ span(aria-hidden="true") ×
+ span.sr-only #{translate("close")}
+
ul.list-unstyled(
ng-controller="EmailNotificationController",
@@ -89,7 +177,7 @@
)
li.notification-entry(
ng-repeat="userEmail in userEmails",
- ng-if="showConfirmEmail(userEmail)"
+ ng-if="showConfirmEmail(userEmail) && projects.length > 0"
)
.alert.alert-warning(ng-if="!userEmail.confirmationInflight")
.notification-body
diff --git a/services/web/public/src/main/project-list/project-list.js b/services/web/public/src/main/project-list/project-list.js
index 0434d2ae3b..3cf8c395ac 100644
--- a/services/web/public/src/main/project-list/project-list.js
+++ b/services/web/public/src/main/project-list/project-list.js
@@ -12,6 +12,7 @@ define(['base', 'main/project-list/services/project-list'], function(App) {
$scope.projects = window.data.projects
$scope.tags = window.data.tags
$scope.notifications = window.data.notifications
+ $scope.notificationsInstitution = window.data.notificationsInstitution
$scope.allSelected = false
$scope.selectedProjects = []
$scope.isArchiveableProjectSelected = false
diff --git a/services/web/test/unit/src/Project/ProjectControllerTests.js b/services/web/test/unit/src/Project/ProjectControllerTests.js
index 09daec1e54..e16c903de8 100644
--- a/services/web/test/unit/src/Project/ProjectControllerTests.js
+++ b/services/web/test/unit/src/Project/ProjectControllerTests.js
@@ -645,7 +645,7 @@ describe('ProjectController', function() {
})
it('should show institution SSO available notification', function() {
this.res.render = (pageName, opts) => {
- expect(opts.notifications).to.deep.include({
+ expect(opts.notificationsInstitution).to.deep.include({
email: 'test@overleaf.com',
institutionId: 1,
institutionName: 'Overleaf',
@@ -663,7 +663,7 @@ describe('ProjectController', function() {
}
}
this.res.render = (pageName, opts) => {
- expect(opts.notifications).to.deep.include({
+ expect(opts.notificationsInstitution).to.deep.include({
email: this.institutionEmail,
institutionName: this.institutionName,
templateKey: 'notification_institution_sso_linked'
@@ -675,7 +675,7 @@ describe('ProjectController', function() {
// when they request to link an email but the institution returns
// a different email
this.res.render = (pageName, opts) => {
- expect(opts.notifications).to.deep.include({
+ expect(opts.notificationsInstitution).to.deep.include({
institutionEmail: this.institutionEmail,
requestedEmail: 'requested@overleaf.com',
templateKey: 'notification_institution_sso_non_canonical'
@@ -694,7 +694,7 @@ describe('ProjectController', function() {
})
it('should show a notification when intent was to register via SSO but account existed', function() {
this.res.render = (pageName, opts) => {
- expect(opts.notifications).to.deep.include({
+ expect(opts.notificationsInstitution).to.deep.include({
email: this.institutionEmail,
templateKey: 'notification_institution_sso_already_registered'
})
@@ -718,7 +718,7 @@ describe('ProjectController', function() {
})
it('should not show institution sso available notification', function() {
this.res.render = (pageName, opts) => {
- expect(opts.notifications).to.deep.not.include({
+ expect(opts.notificationsInstitution).to.deep.not.include({
email: 'test@overleaf.com',
institutionId: 1,
institutionName: 'Overleaf',