From 046449d4bdbd2e800a049c8d00d521c976ac2982 Mon Sep 17 00:00:00 2001 From: Jessica Lawshe <5312836+lawshe@users.noreply.github.com> Date: Thu, 16 Oct 2025 09:52:56 -0500 Subject: [PATCH] Merge pull request #28710 from overleaf/jel-no-sso-notifications-when-domain-capture [web] Do not show notification to link to Commons SSO when domain is also for group with domain capture GitOrigin-RevId: 6779e2db02d5d9cc4e7a60789a620403a4e4aa11 --- .../Project/ProjectListController.mjs | 5 +++ .../settings/components/emails/row.tsx | 9 +++++ .../components/emails/emails-row.test.tsx | 40 +++++++++++++++++++ .../Project/ProjectListController.test.mjs | 23 +++++++++++ services/web/types/affiliation.ts | 5 +++ 5 files changed, 82 insertions(+) diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 6c4742d6b3..7f12181dff 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -53,6 +53,11 @@ const _ssoAvailable = (affiliation, session, linkedInstitutionIds) => { // Do not show SSO UI for unconfirmed domains if (!affiliation.institution.confirmed) return false + // If ssoEnabled = true and group.domainCaptureEnabled = true + // then Commons is migrating to group subscription and we do not want to prompt + // linking through Commons SSO + if (affiliation?.group?.domainCaptureEnabled) return false + // Could have multiple emails at the same institution, and if any are // linked to the institution then do not show notification for others if ( diff --git a/services/web/frontend/js/features/settings/components/emails/row.tsx b/services/web/frontend/js/features/settings/components/emails/row.tsx index 93cec80588..167f9f6b66 100644 --- a/services/web/frontend/js/features/settings/components/emails/row.tsx +++ b/services/web/frontend/js/features/settings/components/emails/row.tsx @@ -110,6 +110,15 @@ function SSOAffiliationInfo({ userEmailData }: SSOAffiliationInfoProps) { ) } + const domainAlsoForGroupWithDomainCapture = + userEmailData?.affiliation?.group?.domainCaptureEnabled + + if (domainAlsoForGroupWithDomainCapture) { + // user is not linked via Commons and should link via groups + // do not show UI to link to Commons + return null + } + return ( diff --git a/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx index f0d105d3e9..3d47a4ddc7 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx @@ -117,5 +117,45 @@ describe('', function () { .null }) }) + + describe('and domain capture is also on for group and Commons SSO also enabled', function () { + // scenario of a Commons account migrating to a group account + let affiliatedEmailWithDomainCaptureAndCommons: UserEmailData & { + affiliation: Affiliation + } + beforeEach(async function () { + fetchMock.removeRoutes().clearHistory() + + affiliatedEmailWithDomainCaptureAndCommons = cloneDeep(affiliatedEmail) + affiliatedEmailWithDomainCaptureAndCommons.affiliation.group = { + _id: 'grou123', + domainCaptureEnabled: true, + managedUsersEnabled: true, + } + + await fetchMock.callHistory.flush(true) + }) + + it('does not prompt the user to link to their institutional account', function () { + renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons) + expect(() => + getByTextContent( + 'You can now link your Overleaf account to your Overleaf institutional account.' + ) + ).to.throw('Unable to find an element with the text') + expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be + .null + }) + + it('still shows users can log in via Commons SSO if already linked', function () { + affiliatedEmailWithDomainCaptureAndCommons.samlProviderId = '1' + renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons) + getByTextContent( + 'You can log in to Overleaf through your Overleaf institutional login.' + ) + expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be + .null + }) + }) }) }) diff --git a/services/web/test/unit/src/Project/ProjectListController.test.mjs b/services/web/test/unit/src/Project/ProjectListController.test.mjs index d970fcf8b0..6d58da5836 100644 --- a/services/web/test/unit/src/Project/ProjectListController.test.mjs +++ b/services/web/test/unit/src/Project/ProjectListController.test.mjs @@ -799,6 +799,29 @@ describe('ProjectListController', function () { ctx.ProjectListController.projectListPage(ctx.req, ctx.res) }) }) + describe('group domain capture enabled for domain', function () { + it('does not show institution SSO available notification', function (ctx) { + ctx.UserGetter.promises.getUserFullEmails.resolves([ + { + email: 'test@overleaf.com', + affiliation: { + group: { domainCaptureEnabled: true }, + institution: { + id: 1, + confirmed: true, + name: 'Overleaf', + ssoBeta: false, + ssoEnabled: true, + }, + }, + }, + ]) + ctx.res.render = (pageName, opts) => { + expect(opts.notificationsInstitution).to.deep.equal([]) + ctx.ProjectListController.projectListPage(ctx.req, ctx.res) + } + }) + }) }) describe('Without Institution SSO feature', function () { diff --git a/services/web/types/affiliation.ts b/services/web/types/affiliation.ts index d60aa25ba1..c2e51fe6a2 100644 --- a/services/web/types/affiliation.ts +++ b/services/web/types/affiliation.ts @@ -16,4 +16,9 @@ export type Affiliation = { pastReconfirmDate: boolean portal: Portal role: Nullable + group?: { + domainCaptureEnabled: boolean + managedUsersEnabled: boolean + _id: string + } }