diff --git a/services/web/app/src/Features/Notifications/NotificationsBuilder.js b/services/web/app/src/Features/Notifications/NotificationsBuilder.js
index f71d2d54ab..291f58f294 100644
--- a/services/web/app/src/Features/Notifications/NotificationsBuilder.js
+++ b/services/web/app/src/Features/Notifications/NotificationsBuilder.js
@@ -127,9 +127,15 @@ function ipMatcherAffiliation(userId) {
}
const key = `ip-matched-affiliation-${body.id}`
+ const portalPath = body.portal_slug
+ ? `/${body.is_university ? 'edu' : 'org'}/${body.portal_slug}`
+ : undefined
const messageOpts = {
university_name: body.name,
- content: body.enrolment_ad_html
+ institutionId: body.id,
+ content: body.enrolment_ad_html,
+ portalPath,
+ ssoEnabled: body.sso_enabled
}
return NotificationsHandler.createNotification(
userId,
diff --git a/services/web/app/views/project/list/notifications.pug b/services/web/app/views/project/list/notifications.pug
index ebd2e88db3..fd6a508d72 100644
--- a/services/web/app/views/project/list/notifications.pug
+++ b/services/web/app/views/project/list/notifications.pug
@@ -51,17 +51,40 @@ include ../../_mixins/saml
span.sr-only #{translate("close")}
.alert.alert-info(
ng-switch-when="notification_ip_matched_affiliation"
+ ng-if="notification.messageOpts.ssoEnabled"
)
.notification-body
- | It looks like you're at
- strong {{ notification.messageOpts.university_name }}!
- | Did you know that {{notification.messageOpts.university_name}} is providing
- strong free Overleaf Professional accounts
- | to everyone at {{notification.messageOpts.university_name}}?
- | Add an institutional email address to claim your account.
+ | !{translate("looks_like_youre_at", {institutionName: '{{notification.messageOpts.university_name}}'}, ['strong'])}
+ br
+ | !{translate("you_can_now_log_in_sso", {}, ['strong'])}
+ br
+ | #{translate("link_institutional_email_get_started", {}, ['strong'])}
+ a(
+ ng-href="{{notification.messageOpts.portalPath || 'https://www.overleaf.com/learn/how-to/Institutional_Login'}}"
+ ) #{translate("find_out_more_nt")}
.notification-action
- a.pull-right.btn.btn-sm.btn-info(href="/user/settings")
- | Add Affiliation
+ a.pull-right.btn.btn-sm.btn-info(
+ href=`{{samlInitPath}}?university_id={{notification.messageOpts.institutionId}}`
+ )
+ | #{translate("link_account")}
+ .notification-close
+ 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_ip_matched_affiliation"
+ ng-if="!notification.messageOpts.ssoEnabled"
+ )
+ .notification-body
+ | !{translate("looks_like_youre_at", {institutionName: '{{notification.messageOpts.university_name}}'}, ['strong'])}
+ br
+ | !{translate("did_you_know_institution_providing_professional", {institutionName: '{{notification.messageOpts.university_name}}'}, ['strong'])}
+ br
+ | #{translate("add_email_to_claim_features")}
+ .notification-action
+ a.pull-right.btn.btn-sm.btn-info(
+ href="/user/settings"
+ ) #{translate("add_affiliation")}
.notification-close
button.btn-sm(ng-click="dismiss(notification)").close.pull-right
span(aria-hidden="true") ×
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index 123b114b1e..a003014965 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -1330,5 +1330,11 @@
"github_is_premium": "GitHub sync is a premium feature",
"remote_service_error": "The remote service produced an error",
"linked_file": "Imported file",
- "n_items": "__count__ items"
+ "n_items": "__count__ items",
+ "you_can_now_log_in_sso": "You can now log in through your institution and may receive <0>free __appName__ Professional features0>!",
+ "link_institutional_email_get_started": "Link an institutional email address to your account to get started.",
+ "looks_like_youre_at": "It looks like you're at <0>__institutionName__0>!",
+ "add_affiliation": "Add Affiliation",
+ "did_you_know_institution_providing_professional": "Did you know that __institutionName__ is providing <0>free __appName__ Professional features0> to everyone at __institutionName__?",
+ "add_email_to_claim_features": "Add an institutional email address to claim your features."
}
diff --git a/services/web/test/unit/src/Notifications/NotificationsBuilderTests.js b/services/web/test/unit/src/Notifications/NotificationsBuilderTests.js
index 918dad2fb9..77724bf6ee 100644
--- a/services/web/test/unit/src/Notifications/NotificationsBuilderTests.js
+++ b/services/web/test/unit/src/Notifications/NotificationsBuilderTests.js
@@ -1,18 +1,4 @@
-/* eslint-disable
- camelcase,
- max-len,
- no-return-assign,
- no-unused-vars,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
const SandboxedModule = require('sandboxed-module')
-const { assert } = require('chai')
require('chai').should()
const sinon = require('sinon')
const modulePath = require('path').join(
@@ -21,53 +7,100 @@ const modulePath = require('path').join(
)
describe('NotificationsBuilder', function() {
- const user_id = '123nd3ijdks'
+ const userId = '123nd3ijdks'
- beforeEach(function() {
- this.handler = { createNotification: sinon.stub().callsArgWith(6) }
-
- this.settings = { apis: { v1: { url: 'v1.url', user: '', pass: '' } } }
- this.body = { id: 1, name: 'stanford', enrolment_ad_html: 'v1 ad content' }
- const response = { statusCode: 200 }
- this.request = sinon
- .stub()
- .returns(this.stubResponse)
- .callsArgWith(1, null, response, this.body)
- return (this.controller = SandboxedModule.require(modulePath, {
- globals: {
- console: console
- },
- requires: {
- './NotificationsHandler': this.handler,
- 'settings-sharelatex': this.settings,
- request: this.request,
- 'logger-sharelatex': {
- log() {},
- err() {}
+ describe('ipMatcherAffiliation', function() {
+ beforeEach(function() {
+ this.handler = { createNotification: sinon.stub().callsArgWith(6) }
+ this.settings = { apis: { v1: { url: 'v1.url', user: '', pass: '' } } }
+ this.request = sinon.stub()
+ this.controller = SandboxedModule.require(modulePath, {
+ globals: {
+ console: console
+ },
+ requires: {
+ './NotificationsHandler': this.handler,
+ 'settings-sharelatex': this.settings,
+ request: this.request,
+ 'logger-sharelatex': {
+ log() {},
+ err() {}
+ }
}
- }
- }))
- })
-
- it('should call v1 and create affiliation notifications', function(done) {
- const ip = '192.168.0.1'
- return this.controller
- .ipMatcherAffiliation(user_id)
- .create(ip, callback => {
- this.request.calledOnce.should.equal(true)
- const expectedOpts = {
- university_name: this.body.name,
- content: this.body.enrolment_ad_html
- }
- this.handler.createNotification
- .calledWith(
- user_id,
- `ip-matched-affiliation-${this.body.id}`,
- 'notification_ip_matched_affiliation',
- expectedOpts
- )
- .should.equal(true)
- return done()
})
+ })
+
+ describe('with portal and with SSO', function() {
+ beforeEach(function() {
+ this.body = {
+ id: 1,
+ name: 'stanford',
+ enrolment_ad_html: 'v1 ad content',
+ is_university: true,
+ portal_slug: null,
+ sso_enabled: false
+ }
+ this.request.callsArgWith(1, null, { statusCode: 200 }, this.body)
+ })
+
+ it('should call v1 and create affiliation notifications', function(done) {
+ const ip = '192.168.0.1'
+ this.controller.ipMatcherAffiliation(userId).create(ip, callback => {
+ this.request.calledOnce.should.equal(true)
+ const expectedOpts = {
+ institutionId: this.body.id,
+ university_name: this.body.name,
+ content: this.body.enrolment_ad_html,
+ ssoEnabled: false,
+ portalPath: undefined
+ }
+ this.handler.createNotification
+ .calledWith(
+ userId,
+ `ip-matched-affiliation-${this.body.id}`,
+ 'notification_ip_matched_affiliation',
+ expectedOpts
+ )
+ .should.equal(true)
+ done()
+ })
+ })
+ })
+ describe('without portal and without SSO', function() {
+ beforeEach(function() {
+ this.body = {
+ id: 1,
+ name: 'stanford',
+ enrolment_ad_html: 'v1 ad content',
+ is_university: true,
+ portal_slug: 'stanford',
+ sso_enabled: true
+ }
+ this.request.callsArgWith(1, null, { statusCode: 200 }, this.body)
+ })
+
+ it('should call v1 and create affiliation notifications', function(done) {
+ const ip = '192.168.0.1'
+ this.controller.ipMatcherAffiliation(userId).create(ip, callback => {
+ this.request.calledOnce.should.equal(true)
+ const expectedOpts = {
+ institutionId: this.body.id,
+ university_name: this.body.name,
+ content: this.body.enrolment_ad_html,
+ ssoEnabled: true,
+ portalPath: '/edu/stanford'
+ }
+ this.handler.createNotification
+ .calledWith(
+ userId,
+ `ip-matched-affiliation-${this.body.id}`,
+ 'notification_ip_matched_affiliation',
+ expectedOpts
+ )
+ .should.equal(true)
+ done()
+ })
+ })
+ })
})
})