diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 3b40977f2..8584fa88d 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1760,6 +1760,13 @@ ONEDRIVE_CLIENT_ID = PersistentConfig( os.environ.get("ONEDRIVE_CLIENT_ID", ""), ) +ONEDRIVE_SHAREPOINT_URL = PersistentConfig( + "ONEDRIVE_SHAREPOINT_URL", + "onedrive.sharepoint_url", + os.environ.get("ONEDRIVE_SHAREPOINT_URL", ""), +) + + # RAG Content Extraction CONTENT_EXTRACTION_ENGINE = PersistentConfig( "CONTENT_EXTRACTION_ENGINE", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 56ea17fa1..652e0284c 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -100,6 +100,7 @@ from open_webui.config import ( # OpenAI ENABLE_OPENAI_API, ONEDRIVE_CLIENT_ID, + ONEDRIVE_SHAREPOINT_URL, OPENAI_API_BASE_URLS, OPENAI_API_KEYS, OPENAI_API_CONFIGS, @@ -240,6 +241,7 @@ from open_webui.config import ( GOOGLE_DRIVE_CLIENT_ID, GOOGLE_DRIVE_API_KEY, ONEDRIVE_CLIENT_ID, + ONEDRIVE_SHAREPOINT_URL, ENABLE_RAG_HYBRID_SEARCH, ENABLE_RAG_LOCAL_WEB_FETCH, ENABLE_WEB_LOADER_SSL_VERIFICATION, @@ -1327,7 +1329,10 @@ async def get_app_config(request: Request): "client_id": GOOGLE_DRIVE_CLIENT_ID.value, "api_key": GOOGLE_DRIVE_API_KEY.value, }, - "onedrive": {"client_id": ONEDRIVE_CLIENT_ID.value}, + "onedrive": { + "client_id": ONEDRIVE_CLIENT_ID.value, + "sharepoint_url": ONEDRIVE_SHAREPOINT_URL.value, + }, "license_metadata": app.state.LICENSE_METADATA, **( { diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index ca6487cf5..b17cabead 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1063,9 +1063,9 @@ ); } }} - uploadOneDriveHandler={async () => { + uploadOneDriveHandler={async (authorityType) => { try { - const fileData = await pickAndDownloadFile(); + const fileData = await pickAndDownloadFile(authorityType); if (fileData) { const file = new File([fileData.blob], fileData.name, { type: fileData.blob.type || 'application/octet-stream' diff --git a/src/lib/utils/onedrive-file-picker.ts b/src/lib/utils/onedrive-file-picker.ts index e7fb80a4c..4e27b88f0 100644 --- a/src/lib/utils/onedrive-file-picker.ts +++ b/src/lib/utils/onedrive-file-picker.ts @@ -8,6 +8,7 @@ class OneDriveConfig { private authorityType: 'personal' | 'organizations' = 'personal'; private sharepointUrl: string = ''; private msalInstance: PublicClientApplication | null = null; + private currentAuthorityType: 'personal' | 'organizations' = 'personal'; private constructor() {} @@ -18,20 +19,35 @@ class OneDriveConfig { return OneDriveConfig.instance; } - public async initialize(selectedAuthorityType?: 'personal' | 'organizations'): Promise { - await this.getCredentials(selectedAuthorityType); + public async initialize(authorityType?: 'personal' | 'organizations'): Promise { + if (authorityType && this.currentAuthorityType !== authorityType) { + console.log('Authority type changed, resetting msalInstance'); + this.currentAuthorityType = authorityType; + this.msalInstance = null; + } + await this.getCredentials(); } - public async ensureInitialized(selectedAuthorityType?: 'personal' | 'organizations'): Promise { - await this.initialize(selectedAuthorityType); + public async ensureInitialized(authorityType?: 'personal' | 'organizations'): Promise { + await this.initialize(authorityType); } private async getCredentials(selectedAuthorityType?: 'personal' | 'organizations'): Promise { let response; + const headers: HeadersInit = { + 'Content-Type': 'application/json' + }; + if(window.location.hostname === 'localhost') { - response = await fetch('http://localhost:8080/api/config'); + response = await fetch('http://localhost:8080/api/config', { + headers, + credentials: 'include' + }); } else { - response = await fetch('/api/config'); + response = await fetch('/api/config', { + headers, + credentials: 'include' + }); } if (!response.ok) { @@ -46,25 +62,16 @@ class OneDriveConfig { if (!newClientId) { throw new Error('OneDrive configuration is incomplete'); } - - // Reset MSAL instance if config changes - if (this.clientId && - (this.clientId !== newClientId || - this.authorityType !== selectedAuthorityType || - this.sharepointUrl !== newSharepointUrl)) { - this.msalInstance = null; - } - + this.clientId = newClientId; - this.authorityType = selectedAuthorityType || 'personal'; this.sharepointUrl = newSharepointUrl; } - public async getMsalInstance(): Promise { - await this.ensureInitialized(); + public async getMsalInstance(authorityType?: 'personal' | 'organizations'): Promise { + await this.ensureInitialized(authorityType); if (!this.msalInstance) { - const authorityEndpoint = this.authorityType === 'organizations' ? 'common' : 'consumers'; + const authorityEndpoint = this.currentAuthorityType === 'organizations' ? 'common' : 'consumers'; const msalParams = { auth: { authority: `https://login.microsoftonline.com/${authorityEndpoint}`, @@ -82,7 +89,7 @@ class OneDriveConfig { } public getAuthorityType(): 'personal' | 'organizations' { - return this.authorityType; + return this.currentAuthorityType; } public getSharepointUrl(): string { @@ -90,7 +97,7 @@ class OneDriveConfig { } public getBaseUrl(): string { - if (this.authorityType === 'organizations') { + if (this.currentAuthorityType === 'organizations') { if (!this.sharepointUrl || this.sharepointUrl === '') { throw new Error('Sharepoint URL not configured'); } @@ -107,25 +114,27 @@ class OneDriveConfig { // Retrieve OneDrive access token -async function getToken(resource?: string): Promise { +async function getToken(resource?: string, authorityType?: 'personal' | 'organizations'): Promise { const config = OneDriveConfig.getInstance(); - await config.ensureInitialized(); + await config.ensureInitialized(authorityType); - const authorityType = config.getAuthorityType(); + const currentAuthorityType = config.getAuthorityType(); - const scopes = authorityType === 'organizations' + const scopes = currentAuthorityType === 'organizations' ? [`${resource || config.getBaseUrl()}/.default`] : ['OneDrive.ReadWrite']; + + console.log('scopes', scopes); const authParams: PopupRequest = { scopes }; let accessToken = ''; try { - const msalInstance = await config.getMsalInstance(); + const msalInstance = await config.getMsalInstance(authorityType); const resp = await msalInstance.acquireTokenSilent(authParams); accessToken = resp.accessToken; } catch (err) { - const msalInstance = await config.getMsalInstance(); + const msalInstance = await config.getMsalInstance(authorityType); try { const resp = await msalInstance.loginPopup(authParams); msalInstance.setActiveAccount(resp.account); @@ -212,8 +221,8 @@ function getPickerParams(): { } // Download file from OneDrive -async function downloadOneDriveFile(fileInfo: Record): Promise { - const accessToken = await getToken(); +async function downloadOneDriveFile(fileInfo: Record, authorityType?: 'personal' | 'organizations'): Promise { + const accessToken = await getToken(undefined, authorityType); if (!accessToken) { throw new Error('Unable to retrieve OneDrive access token.'); } @@ -409,7 +418,8 @@ export async function openOneDrivePicker(): Promise { } // Pick and download file from OneDrive -export async function pickAndDownloadFile(authorityType: 'personal' | 'organizations' = 'personal'): Promise<{ blob: Blob; name: string } | null> { +export async function pickAndDownloadFile(authorityType?: 'personal' | 'organizations'): Promise<{ blob: Blob; name: string } | null> { + // Force reinitialization with selected authority type const config = OneDriveConfig.getInstance(); await config.initialize(authorityType); @@ -420,7 +430,7 @@ export async function pickAndDownloadFile(authorityType: 'personal' | 'organizat } const selectedFile = pickerResult.items[0]; - const blob = await downloadOneDriveFile(selectedFile); + const blob = await downloadOneDriveFile(selectedFile, authorityType); return { blob, name: selectedFile.name }; }