Просмотр исходного кода

Merge pull request #15582 from overleaf/msm-sso-linking-reminders

[web] SSO Linking redirects and interstitial info

GitOrigin-RevId: fdad0290ebf2b8b8a77f12b75736c030a4c7b642
Alexandre Bourdin 2 лет назад
Родитель
Сommit
d45ca7d401

+ 7 - 0
services/web/app/src/Features/Subscription/SubscriptionLocator.js

@@ -2,6 +2,7 @@ const { promisify } = require('util')
 const { Subscription } = require('../../models/Subscription')
 const { DeletedSubscription } = require('../../models/DeletedSubscription')
 const logger = require('@overleaf/logger')
+const { SSOConfig } = require('../../models/SSOConfig')
 require('./GroupPlansData') // make sure dynamic group plans are loaded
 
 const SubscriptionLocator = {
@@ -124,6 +125,11 @@ const SubscriptionLocator = {
   },
 }
 
+async function hasSSOEnabled(subscription) {
+  const ssoConfig = await SSOConfig.findById(subscription.ssoConfig).exec()
+  return ssoConfig?.enabled
+}
+
 SubscriptionLocator.promises = {
   getUsersSubscription: promisify(SubscriptionLocator.getUsersSubscription),
   getUserIndividualSubscription: promisify(
@@ -153,5 +159,6 @@ SubscriptionLocator.promises = {
   hasRecurlyGroupSubscription: promisify(
     SubscriptionLocator.hasRecurlyGroupSubscription
   ),
+  hasSSOEnabled,
 }
 module.exports = SubscriptionLocator

+ 17 - 2
services/web/app/src/Features/Subscription/TeamInvitesController.js

@@ -84,6 +84,10 @@ async function viewInvite(req, res, next) {
       personalSubscription.recurlySubscription_id &&
       personalSubscription.recurlySubscription_id !== ''
 
+    const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled(
+      subscription
+    )
+
     if (subscription?.groupPolicy) {
       if (!subscription.populated('groupPolicy')) {
         await subscription.populate('groupPolicy')
@@ -128,6 +132,8 @@ async function viewInvite(req, res, next) {
         expired: req.query.expired,
         validationStatus: Object.fromEntries(validationStatus),
         currentManagedUserAdminEmail,
+        groupSSOActive,
+        subscriptionId: subscription._id.toString(),
       })
     } else {
       let currentManagedUserAdminEmail
@@ -146,6 +152,8 @@ async function viewInvite(req, res, next) {
         expired: req.query.expired,
         userRestrictions: Array.from(req.userRestrictions || []),
         currentManagedUserAdminEmail,
+        groupSSOActive,
+        subscriptionId: subscription._id.toString(),
       })
     }
   } else {
@@ -167,8 +175,15 @@ async function acceptInvite(req, res, next) {
   const { token } = req.params
   const userId = SessionManager.getLoggedInUserId(req.session)
 
-  await TeamInvitesHandler.promises.acceptInvite(token, userId)
-  res.sendStatus(204)
+  const subscription = await TeamInvitesHandler.promises.acceptInvite(
+    token,
+    userId
+  )
+  const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled(
+    subscription
+  )
+
+  res.status(204).json({ groupSSOActive })
 }
 
 function revokeInvite(req, res, next) {

+ 2 - 0
services/web/app/src/Features/Subscription/TeamInvitesHandler.js

@@ -95,6 +95,8 @@ async function acceptInvite(token, userId) {
   await NotificationsBuilder.promises
     .groupInvitation(userId, subscription._id, false)
     .read()
+
+  return subscription
 }
 
 async function revokeInvite(teamManagerId, subscription, email) {

+ 2 - 0
services/web/app/views/subscriptions/team/invite-managed.pug

@@ -10,6 +10,8 @@ block append meta
 	meta(name="ol-alreadyEnrolled" data-type="boolean" content=alreadyEnrolled)
 	meta(name="ol-validationStatus" data-type="json" content=validationStatus)
 	meta(name="ol-currentManagedUserAdminEmail" data-type="string" content=currentManagedUserAdminEmail)
+	meta(name="ol-groupSSOActive" data-type="boolean" content=groupSSOActive)
+	meta(name="ol-subscriptionId" data-type="string" content=subscriptionId)
 
 block content
 	main.content.content-alt.team-invite#invite-managed-root

+ 3 - 1
services/web/app/views/subscriptions/team/invite.pug

@@ -3,6 +3,8 @@ extends ../../layout
 block append meta
 	meta(name="ol-hasIndividualRecurlySubscription" data-type="boolean" content=hasIndividualRecurlySubscription)
 	meta(name="ol-inviteToken" content=inviteToken)
+	meta(name="ol-groupSSOActive" data-type="boolean" content=groupSSOActive)
+	meta(name="ol-subscriptionId" data-type="string" content=subscriptionId)
 
 block content
 	main.content.content-alt.team-invite#main-content
@@ -42,4 +44,4 @@ block content
 						div(ng-show="view =='inviteAccepted'")
 							p(ng-non-bindable) #{translate("joined_team", {inviterName: inviterName})}
 							p
-								a.btn.btn.btn-primary(href="/project") #{translate("done")}
+								a.btn.btn.btn-primary(href=doneLink) #{translate("done")}

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -1421,6 +1421,7 @@
   "you_need_to_configure_your_sso_settings": "",
   "you_will_be_able_to_reassign_subscription": "",
   "youll_get_best_results_in_visual_but_can_be_used_in_source": "",
+  "youll_no_longer_need_to_remember_credentials": "",
   "your_affiliation_is_confirmed": "",
   "your_browser_does_not_support_this_feature": "",
   "your_compile_timed_out": "",

+ 9 - 0
services/web/frontend/js/main/subscription/team-invite-controller.js

@@ -24,6 +24,15 @@ export default App.controller('TeamInviteController', [
       'ol-hasIndividualRecurlySubscription'
     )
 
+    const groupSSOActive = getMeta('ol-groupSSOActive', false)
+
+    if (groupSSOActive) {
+      const subscriptionId = getMeta('ol-subscriptionId')
+      $scope.doneLink = `/subscription/${subscriptionId}/sso_enrollment`
+    } else {
+      $scope.doneLink = '/project'
+    }
+
     if (hideJoinSubscription) {
       $scope.view = 'restrictedByManagedGroup'
     } else if (hasIndividualRecurlySubscription) {

+ 1 - 0
services/web/locales/en.json

@@ -2104,6 +2104,7 @@
   "you_will_be_able_to_contact_us_any_time_to_share_your_feedback": "<0>You will be able to contact us</0> any time to share your feedback",
   "you_will_be_able_to_reassign_subscription": "You will be able to reassign their subscription membership to another person in your organization",
   "youll_get_best_results_in_visual_but_can_be_used_in_source": "You’ll get the best results from using this tool in the <0>Visual Editor</0>, although you can still use it to insert tables in the <1>Code Editor</1>. Once you’ve selected the number of rows and columns you need, the table will appear in your document and you can double click in a cell to add contents to it.",
+  "youll_no_longer_need_to_remember_credentials": "You’ll no longer need to remember a separate email address and password. Instead, you will use single-sign on to login to Overleaf. <0>Read more about SSO</0>.",
   "your_account_is_managed_by_admin_cant_join_additional_group": "Your __appName__ account is managed by your current group admin (__admin__). This means you can’t join additional group subscriptions. <0>Read more about Managed Users.</0>",
   "your_affiliation_is_confirmed": "Your <0>__institutionName__</0> affiliation is confirmed.",
   "your_browser_does_not_support_this_feature": "Sorry, your browser doesn’t support this feature. Please update your browser to its latest version.",

+ 6 - 0
services/web/test/unit/src/Subscription/SubscriptionLocatorTests.js

@@ -15,6 +15,9 @@ describe('Subscription Locator Tests', function () {
       findOne: sinon.stub().yields(),
       find: sinon.stub().yields(),
     }
+    this.SSOConfig = {
+      findById: sinon.stub().yields(),
+    }
     this.SubscriptionLocator = SandboxedModule.require(modulePath, {
       requires: {
         './GroupPlansData': {},
@@ -24,6 +27,9 @@ describe('Subscription Locator Tests', function () {
         '../../models/DeletedSubscription': {
           DeletedSubscription: this.DeletedSubscription,
         },
+        '../../models/SSOConfig': {
+          SSOConfig: this.SSOConfig,
+        },
       },
     })
   })