diff --git a/services/web/app/src/Features/TokenAccess/TokenAccessController.js b/services/web/app/src/Features/TokenAccess/TokenAccessController.js index 8174ca797e..3735c4e6b4 100644 --- a/services/web/app/src/Features/TokenAccess/TokenAccessController.js +++ b/services/web/app/src/Features/TokenAccess/TokenAccessController.js @@ -12,6 +12,9 @@ const { handleAdminDomainRedirect, } = require('../Authorization/AuthorizationMiddleware') const ProjectAuditLogHandler = require('../Project/ProjectAuditLogHandler') +const SplitTestHandler = require('../SplitTests/SplitTestHandler') +const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler') +const EditorRealTimeController = require('../Editor/EditorRealTimeController') const orderedPrivilegeLevels = [ PrivilegeLevels.NONE, @@ -271,33 +274,77 @@ async function grantTokenAccessReadAndWrite(req, res, next) { return next(new Errors.NotFoundError()) } - if (!confirmedByUser) { - return res.json({ - requireAccept: { - projectName: project.name, - }, - }) - } + const linkSharingChanges = + await SplitTestHandler.promises.getAssignmentForUser( + project.owner_ref, + 'link-sharing-warning' + ) + + if (linkSharingChanges?.variant === 'active') { + if (!confirmedByUser) { + return res.json({ + requireAccept: { + linkSharingChanges: true, + projectName: project.name, + }, + }) + } - if (!project.tokenAccessReadAndWrite_refs.some(id => id.equals(userId))) { await ProjectAuditLogHandler.promises.addEntry( project._id, - 'join-via-token', + 'accept-via-link-sharing', userId, req.ip, { privileges: 'readAndWrite' } ) + // Currently does not enforce the collaborator limit (warning phase) + await CollaboratorsHandler.promises.addUserIdToProject( + project._id, + undefined, + userId, + PrivilegeLevels.READ_AND_WRITE + ) + // Does not remove any pending invite or the invite notification + // Should be a noop if the user is already a member, + // and would redirect transparently into the project. + EditorRealTimeController.emitToRoom( + project._id, + 'project:membership:changed', + { members: true } + ) + + return res.json({ + redirect: `/project/${project._id}`, + }) + } else { + if (!confirmedByUser) { + return res.json({ + requireAccept: { + projectName: project.name, + }, + }) + } + + if (!project.tokenAccessReadAndWrite_refs.some(id => id.equals(userId))) { + await ProjectAuditLogHandler.promises.addEntry( + project._id, + 'join-via-token', + userId, + req.ip, + { privileges: 'readAndWrite' } + ) + } + + await TokenAccessHandler.promises.addReadAndWriteUserToProject( + userId, + project._id + ) + + return res.json({ + redirect: `/project/${project._id}`, + tokenAccessGranted: tokenType, + }) } - - await TokenAccessHandler.promises.addReadAndWriteUserToProject( - userId, - project._id - ) - - return res.json({ - redirect: `/project/${project._id}`, - tokenAccessGranted: tokenType, - }) } catch (err) { return next( OError.tag( diff --git a/services/web/app/views/project/token/access-react.pug b/services/web/app/views/project/token/access-react.pug index 157d806f60..83e9f79b61 100644 --- a/services/web/app/views/project/token/access-react.pug +++ b/services/web/app/views/project/token/access-react.pug @@ -13,4 +13,5 @@ block append meta meta(name="ol-user" data-type="json" content=user) block content - div#token-access-page + .content.content-alt#main-content + div#token-access-page diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 85cdf0aace..1ef95c39e7 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -99,6 +99,7 @@ "are_you_getting_an_undefined_control_sequence_error": "", "are_you_still_at": "", "are_you_sure": "", + "as_email": "", "ask_proj_owner_to_unlink_from_current_github": "", "ask_proj_owner_to_upgrade_for_full_history": "", "ask_proj_owner_to_upgrade_for_references_search": "", @@ -873,6 +874,7 @@ "off": "", "official": "", "ok": "", + "ok_join_project": "", "on": "", "on_free_plan_upgrade_to_access_features": "", "one_step_away_from_professional_features": "", @@ -1667,6 +1669,7 @@ "your_git_access_info_bullet_5": "", "your_git_access_tokens": "", "your_message_to_collaborators": "", + "your_name_and_email_address_will_be_visible_to_the_project_owner_and_other_editors": "", "your_new_plan": "", "your_password_was_detected": "", "your_plan": "", @@ -1683,6 +1686,7 @@ "youre_about_to_enable_single_sign_on": "", "youre_about_to_enable_single_sign_on_sso_only": "", "youre_already_setup_for_sso": "", + "youre_joining": "", "youre_on_free_trial_which_ends_on": "", "youre_signed_in_as_logout": "", "youve_unlinked_all_users": "", diff --git a/services/web/frontend/js/features/token-access/components/require-accept-screen.tsx b/services/web/frontend/js/features/token-access/components/require-accept-screen.tsx index 1bcdcdcc4d..005de55c77 100644 --- a/services/web/frontend/js/features/token-access/components/require-accept-screen.tsx +++ b/services/web/frontend/js/features/token-access/components/require-accept-screen.tsx @@ -4,6 +4,7 @@ import getMeta from '@/utils/meta' export type RequireAcceptData = { projectName?: string + linkSharingChanges: boolean } export const RequireAcceptScreen: FC<{ @@ -13,6 +14,60 @@ export const RequireAcceptScreen: FC<{ const { t } = useTranslation() const user = getMeta('ol-user') + if (requireAcceptData.linkSharingChanges) { + return ( +
+ {t('youre_joining')}
+
+
+
+ {requireAcceptData.projectName || 'This project'}
+
+
+ {user && (
+ <>
+
+ {t('as_email', { email: user.email })}
+ >
+ )}
+
+ {t( + 'your_name_and_email_address_will_be_visible_to_the_project_owner_and_other_editors' + )} +
+