فهرست منبع

Merge pull request #26070 from overleaf/msm-disable-dropbox

[web] Disable Dropbox Capability

GitOrigin-RevId: 5f91d2918bf3b88e52f4d27c828a4715f9b88629
Miguel Serrano 1 سال پیش
والد
کامیت
04fa5366ce

+ 0 - 1
services/web/.storybook/preview.tsx

@@ -13,7 +13,6 @@ import en from '../../../services/web/locales/en.json'
 function resetMeta() {
 function resetMeta() {
   window.metaAttributesCache = new Map()
   window.metaAttributesCache = new Map()
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
-  window.metaAttributesCache.set('ol-chatEnabled', true)
   window.metaAttributesCache.set('ol-ExposedSettings', {
   window.metaAttributesCache.set('ol-ExposedSettings', {
     adminEmail: 'placeholder@example.com',
     adminEmail: 'placeholder@example.com',
     appName: 'Overleaf',
     appName: 'Overleaf',

+ 1 - 9
services/web/app/src/Features/Project/ProjectController.js

@@ -728,14 +728,6 @@ const _ProjectController = {
           ? 'project/ide-react-detached'
           ? 'project/ide-react-detached'
           : 'project/ide-react'
           : 'project/ide-react'
 
 
-      let chatEnabled
-      if (Features.hasFeature('saas')) {
-        chatEnabled =
-          Features.hasFeature('chat') && req.capabilitySet.has('chat')
-      } else {
-        chatEnabled = Features.hasFeature('chat')
-      }
-
       const isOverleafAssistBundleEnabled =
       const isOverleafAssistBundleEnabled =
         splitTestAssignments['overleaf-assist-bundle']?.variant === 'enabled'
         splitTestAssignments['overleaf-assist-bundle']?.variant === 'enabled'
 
 
@@ -841,7 +833,7 @@ const _ProjectController = {
           isTokenMember,
           isTokenMember,
           isInvitedMember
           isInvitedMember
         ),
         ),
-        chatEnabled,
+        capabilities: [...req.capabilitySet],
         projectHistoryBlobsEnabled: Features.hasFeature(
         projectHistoryBlobsEnabled: Features.hasFeature(
           'project-history-blobs'
           'project-history-blobs'
         ),
         ),

+ 1 - 0
services/web/app/src/Features/User/UserAuditLogHandler.js

@@ -8,6 +8,7 @@ function _canHaveNoIpAddressId(operation, info) {
   if (operation === 'must-reset-password-set') return true
   if (operation === 'must-reset-password-set') return true
   if (operation === 'remove-email' && info.script) return true
   if (operation === 'remove-email' && info.script) return true
   if (operation === 'release-managed-user' && info.script) return true
   if (operation === 'release-managed-user' && info.script) return true
+  if (operation === 'unlink-dropbox' && info.batch) return true
   return false
   return false
 }
 }
 
 

+ 1 - 0
services/web/app/src/Features/User/UserPagesController.mjs

@@ -176,6 +176,7 @@ async function settingsPage(req, res) {
     gitBridgeEnabled: Settings.enableGitBridge,
     gitBridgeEnabled: Settings.enableGitBridge,
     isSaas: Features.hasFeature('saas'),
     isSaas: Features.hasFeature('saas'),
     memberOfSSOEnabledGroups,
     memberOfSSOEnabledGroups,
+    capabilities: [...req.capabilitySet],
   })
   })
 }
 }
 
 

+ 3 - 0
services/web/app/src/models/GroupPolicy.js

@@ -27,6 +27,9 @@ const GroupPolicySchema = new Schema(
 
 
     // User can't use the chat feature
     // User can't use the chat feature
     userCannotUseChat: Boolean,
     userCannotUseChat: Boolean,
+
+    // User can't use the Dropbox feature
+    userCannotUseDropbox: Boolean,
   },
   },
   { minimize: false }
   { minimize: false }
 )
 )

+ 1 - 1
services/web/app/views/project/editor/_meta.pug

@@ -12,7 +12,7 @@ meta(name="ol-isRestrictedTokenMember" data-type="boolean" content=isRestrictedT
 meta(name="ol-maxDocLength" data-type="json" content=maxDocLength)
 meta(name="ol-maxDocLength" data-type="json" content=maxDocLength)
 meta(name="ol-maxReconnectGracefullyIntervalMs" data-type="json" content=maxReconnectGracefullyIntervalMs)
 meta(name="ol-maxReconnectGracefullyIntervalMs" data-type="json" content=maxReconnectGracefullyIntervalMs)
 meta(name="ol-wikiEnabled" data-type="boolean" content=settings.proxyLearn)
 meta(name="ol-wikiEnabled" data-type="boolean" content=settings.proxyLearn)
-meta(name="ol-chatEnabled" data-type="boolean" content=chatEnabled)
+meta(name="ol-capabilities" data-type="json" content=capabilities)
 meta(name="ol-projectHistoryBlobsEnabled" data-type="boolean" content=projectHistoryBlobsEnabled)
 meta(name="ol-projectHistoryBlobsEnabled" data-type="boolean" content=projectHistoryBlobsEnabled)
 meta(name="ol-gitBridgePublicBaseUrl" content=gitBridgePublicBaseUrl)
 meta(name="ol-gitBridgePublicBaseUrl" content=gitBridgePublicBaseUrl)
 meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)
 meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)

+ 1 - 0
services/web/app/views/user/settings.pug

@@ -32,6 +32,7 @@ block append meta
 	meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)
 	meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)
 	meta(name="ol-isSaas" data-type="boolean" content=isSaas)
 	meta(name="ol-isSaas" data-type="boolean" content=isSaas)
 	meta(name="ol-memberOfSSOEnabledGroups" data-type="json" content=memberOfSSOEnabledGroups)
 	meta(name="ol-memberOfSSOEnabledGroups" data-type="json" content=memberOfSSOEnabledGroups)
+	meta(name="ol-capabilities" data-type="json" content=capabilities)
 
 
 block content
 block content
 	main.content.content-alt#main-content
 	main.content.content-alt#main-content

+ 1 - 1
services/web/frontend/js/features/chat/context/chat-context.tsx

@@ -193,7 +193,7 @@ export const ChatContext = createContext<
 >(undefined)
 >(undefined)
 
 
 export const ChatProvider: FC<React.PropsWithChildren> = ({ children }) => {
 export const ChatProvider: FC<React.PropsWithChildren> = ({ children }) => {
-  const chatEnabled = getMeta('ol-chatEnabled')
+  const chatEnabled = getMeta('ol-capabilities')?.includes('chat')
 
 
   const clientId = useRef<string>()
   const clientId = useRef<string>()
   if (clientId.current === undefined) {
   if (clientId.current === undefined) {

+ 1 - 1
services/web/frontend/js/features/editor-navigation-toolbar/components/toolbar-header.tsx

@@ -80,7 +80,7 @@ const ToolbarHeader = React.memo(function ToolbarHeader({
   openShareModal: () => void
   openShareModal: () => void
   trackChangesVisible: boolean | undefined
   trackChangesVisible: boolean | undefined
 }) {
 }) {
-  const chatEnabled = getMeta('ol-chatEnabled')
+  const chatEnabled = getMeta('ol-capabilities')?.includes('chat')
 
 
   const { t } = useTranslation()
   const { t } = useTranslation()
   const shouldDisplayPublishButton = hasPublishPermissions && PublishButton
   const shouldDisplayPublishButton = hasPublishPermissions && PublishButton

+ 2 - 1
services/web/frontend/js/features/ide-react/components/layout/main-layout.tsx

@@ -47,7 +47,8 @@ export const MainLayout: FC = () => {
     handlePaneExpand: handleChatExpand,
     handlePaneExpand: handleChatExpand,
   } = useChatPane()
   } = useChatPane()
 
 
-  const chatEnabled = getMeta('ol-chatEnabled') && !isRestrictedTokenMember
+  const chatEnabled =
+    getMeta('ol-capabilities')?.includes('chat') && !isRestrictedTokenMember
 
 
   const { t } = useTranslation()
   const { t } = useTranslation()
 
 

+ 1 - 1
services/web/frontend/js/features/ide-redesign/components/rail.tsx

@@ -156,7 +156,7 @@ export const RailLayout = () => {
         component: <ChatPane />,
         component: <ChatPane />,
         indicator: <ChatIndicator />,
         indicator: <ChatIndicator />,
         title: t('chat'),
         title: t('chat'),
-        hide: !getMeta('ol-chatEnabled'),
+        hide: !getMeta('ol-capabilities')?.includes('chat'),
       },
       },
       {
       {
         key: 'errors',
         key: 'errors',

+ 1 - 1
services/web/frontend/js/utils/meta.ts

@@ -85,7 +85,7 @@ export interface Meta {
   'ol-cannot-link-other-third-party-sso': boolean
   'ol-cannot-link-other-third-party-sso': boolean
   'ol-cannot-reactivate-subscription': boolean
   'ol-cannot-reactivate-subscription': boolean
   'ol-cannot-use-ai': boolean
   'ol-cannot-use-ai': boolean
-  'ol-chatEnabled': boolean
+  'ol-capabilities': Array<'dropbox' | 'chat'>
   'ol-compileSettings': {
   'ol-compileSettings': {
     reducedTimeoutWarning: string
     reducedTimeoutWarning: string
     compileTimeout: number
     compileTimeout: number

+ 23 - 0
services/web/migrations/20250604112908_add_dropbox_policy_to_group_policy.mjs

@@ -0,0 +1,23 @@
+const tags = ['saas']
+
+const migrate = async client => {
+  const { db } = client
+  await db.grouppolicies.updateMany(
+    {},
+    { $set: { userCannotUseDropbox: false } }
+  )
+}
+
+const rollback = async client => {
+  const { db } = client
+  await db.grouppolicies.updateMany(
+    {},
+    { $unset: { userCannotUseDropbox: '' } }
+  )
+}
+
+export default {
+  tags,
+  migrate,
+  rollback,
+}

+ 0 - 1
services/web/test/frontend/features/chat/components/chat-pane.test.jsx

@@ -19,7 +19,6 @@ describe('<ChatPane />', function () {
 
 
   beforeEach(function () {
   beforeEach(function () {
     window.metaAttributesCache.set('ol-user', user)
     window.metaAttributesCache.set('ol-user', user)
-    window.metaAttributesCache.set('ol-chatEnabled', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
   })
   })
 
 

+ 0 - 1
services/web/test/frontend/features/chat/context/chat-context.test.jsx

@@ -27,7 +27,6 @@ describe('ChatContext', function () {
     stubMathJax()
     stubMathJax()
 
 
     window.metaAttributesCache.set('ol-user', user)
     window.metaAttributesCache.set('ol-user', user)
-    window.metaAttributesCache.set('ol-chatEnabled', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
 
 
     this.stub = sinon.stub(chatClientIdGenerator, 'generate').returns(uuidValue)
     this.stub = sinon.stub(chatClientIdGenerator, 'generate').returns(uuidValue)

+ 0 - 1
services/web/test/frontend/features/editor-navigation-toolbar/components/toolbar-header.test.jsx

@@ -27,7 +27,6 @@ describe('<ToolbarHeader />', function () {
   }
   }
 
 
   beforeEach(function () {
   beforeEach(function () {
-    window.metaAttributesCache.set('ol-chatEnabled', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
   })
   })
 
 

+ 2 - 0
services/web/test/frontend/helpers/editor-providers.jsx

@@ -85,6 +85,8 @@ export function EditorProviders({
     merge({}, defaultUserSettings, userSettings)
     merge({}, defaultUserSettings, userSettings)
   )
   )
 
 
+  window.metaAttributesCache.set('ol-capabilities', ['chat', 'dropbox'])
+
   const scope = merge(
   const scope = merge(
     {
     {
       user,
       user,

+ 1 - 0
services/web/test/frontend/helpers/reset-meta.ts

@@ -2,6 +2,7 @@ export function resetMeta() {
   window.metaAttributesCache = new Map()
   window.metaAttributesCache = new Map()
   window.metaAttributesCache.set('ol-projectHistoryBlobsEnabled', true)
   window.metaAttributesCache.set('ol-projectHistoryBlobsEnabled', true)
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
+  window.metaAttributesCache.set('ol-capabilities', ['chat', 'dropbox'])
   window.metaAttributesCache.set('ol-ExposedSettings', {
   window.metaAttributesCache.set('ol-ExposedSettings', {
     appName: 'Overleaf',
     appName: 'Overleaf',
     maxEntitiesPerProject: 10,
     maxEntitiesPerProject: 10,

+ 4 - 25
services/web/test/unit/src/Project/ProjectControllerTests.js

@@ -300,6 +300,7 @@ describe('ProjectController', function () {
         translate() {},
         translate() {},
       },
       },
       ip: '192.170.18.1',
       ip: '192.170.18.1',
+      capabilitySet: new Set(['chat']),
     }
     }
     this.res = {
     this.res = {
       locals: {
       locals: {
@@ -1085,34 +1086,12 @@ describe('ProjectController', function () {
       this.ProjectController.loadEditor(this.req, this.res)
       this.ProjectController.loadEditor(this.req, this.res)
     })
     })
 
 
-    describe('chatEnabled flag', function () {
-      it('should be set to false when the feature is disabled', function (done) {
+    describe('capabilitySet', function () {
+      it('should be passed as an array when loading the editor', function (done) {
         this.Features.hasFeature = sinon.stub().withArgs('chat').returns(false)
         this.Features.hasFeature = sinon.stub().withArgs('chat').returns(false)
 
 
         this.res.render = (pageName, opts) => {
         this.res.render = (pageName, opts) => {
-          expect(opts.chatEnabled).to.be.false
-          done()
-        }
-        this.ProjectController.loadEditor(this.req, this.res)
-      })
-
-      it('should be set to false when the feature is enabled but the capability is not available', function (done) {
-        this.Features.hasFeature = sinon.stub().withArgs('chat').returns(false)
-        this.req.capabilitySet = new Set()
-
-        this.res.render = (pageName, opts) => {
-          expect(opts.chatEnabled).to.be.false
-          done()
-        }
-        this.ProjectController.loadEditor(this.req, this.res)
-      })
-
-      it('should be set to true when the feature is enabled and the capability is available', function (done) {
-        this.Features.hasFeature = sinon.stub().withArgs('chat').returns(true)
-        this.req.capabilitySet = new Set(['chat'])
-
-        this.res.render = (pageName, opts) => {
-          expect(opts.chatEnabled).to.be.true
+          expect(opts.capabilities).to.deep.equal(['chat'])
           done()
           done()
         }
         }
         this.ProjectController.loadEditor(this.req, this.res)
         this.ProjectController.loadEditor(this.req, this.res)