From 5fd794612e2c9627e46386843786c02b691f1cad Mon Sep 17 00:00:00 2001 From: hurxxxx Date: Mon, 14 Apr 2025 22:57:32 +0900 Subject: [PATCH 1/4] add onedrive sub menu --- .../chat/MessageInput/InputMenu.svelte | 146 ++++----- src/lib/utils/onedrive-file-picker.ts | 284 +++++++++++++----- 2 files changed, 273 insertions(+), 157 deletions(-) diff --git a/src/lib/components/chat/MessageInput/InputMenu.svelte b/src/lib/components/chat/MessageInput/InputMenu.svelte index 27fe2cde2..ab455ddeb 100644 --- a/src/lib/components/chat/MessageInput/InputMenu.svelte +++ b/src/lib/components/chat/MessageInput/InputMenu.svelte @@ -229,94 +229,66 @@ {/if} {#if $config?.features?.enable_onedrive_integration} - { - uploadOneDriveHandler(); - }} - > - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$i18n.t('Microsoft OneDrive')}
+ + + { + uploadOneDriveHandler('personal'); + }} > - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{$i18n.t('OneDrive')}
-
+
{$i18n.t('Microsoft OneDrive (personal)')}
+
+ { + uploadOneDriveHandler('organizations'); + }} + > +
+
{$i18n.t('Microsoft OneDrive (work/school)')}
+
Includes SharePoint
+
+
+ + {/if} diff --git a/src/lib/utils/onedrive-file-picker.ts b/src/lib/utils/onedrive-file-picker.ts index 60d2bb13c..e7fb80a4c 100644 --- a/src/lib/utils/onedrive-file-picker.ts +++ b/src/lib/utils/onedrive-file-picker.ts @@ -2,70 +2,130 @@ import { PublicClientApplication } from '@azure/msal-browser'; import type { PopupRequest } from '@azure/msal-browser'; import { v4 as uuidv4 } from 'uuid'; -let CLIENT_ID = ''; +class OneDriveConfig { + private static instance: OneDriveConfig; + private clientId: string = ''; + private authorityType: 'personal' | 'organizations' = 'personal'; + private sharepointUrl: string = ''; + private msalInstance: PublicClientApplication | null = null; -async function getCredentials() { - if (CLIENT_ID) return; + private constructor() {} - const response = await fetch('/api/config'); - if (!response.ok) { - throw new Error('Failed to fetch OneDrive credentials'); + public static getInstance(): OneDriveConfig { + if (!OneDriveConfig.instance) { + OneDriveConfig.instance = new OneDriveConfig(); + } + return OneDriveConfig.instance; } - const config = await response.json(); - CLIENT_ID = config.onedrive?.client_id; - if (!CLIENT_ID) { - throw new Error('OneDrive client ID not configured'); + + public async initialize(selectedAuthorityType?: 'personal' | 'organizations'): Promise { + await this.getCredentials(selectedAuthorityType); } -} -let msalInstance: PublicClientApplication | null = null; + public async ensureInitialized(selectedAuthorityType?: 'personal' | 'organizations'): Promise { + await this.initialize(selectedAuthorityType); + } -// Initialize MSAL authentication -async function initializeMsal() { - try { - if (!CLIENT_ID) { - await getCredentials(); + private async getCredentials(selectedAuthorityType?: 'personal' | 'organizations'): Promise { + let response; + if(window.location.hostname === 'localhost') { + response = await fetch('http://localhost:8080/api/config'); + } else { + response = await fetch('/api/config'); + } + + if (!response.ok) { + throw new Error('Failed to fetch OneDrive credentials'); + } + + const config = await response.json(); + + const newClientId = config.onedrive?.client_id; + const newSharepointUrl = config.onedrive?.sharepoint_url; + + if (!newClientId) { + throw new Error('OneDrive configuration is incomplete'); } - const msalParams = { - auth: { - authority: 'https://login.microsoftonline.com/consumers', - clientId: CLIENT_ID - } - }; + // Reset MSAL instance if config changes + if (this.clientId && + (this.clientId !== newClientId || + this.authorityType !== selectedAuthorityType || + this.sharepointUrl !== newSharepointUrl)) { + this.msalInstance = null; + } - if (!msalInstance) { - msalInstance = new PublicClientApplication(msalParams); - if (msalInstance.initialize) { - await msalInstance.initialize(); + this.clientId = newClientId; + this.authorityType = selectedAuthorityType || 'personal'; + this.sharepointUrl = newSharepointUrl; + } + + public async getMsalInstance(): Promise { + await this.ensureInitialized(); + + if (!this.msalInstance) { + const authorityEndpoint = this.authorityType === 'organizations' ? 'common' : 'consumers'; + const msalParams = { + auth: { + authority: `https://login.microsoftonline.com/${authorityEndpoint}`, + clientId: this.clientId + } + }; + + this.msalInstance = new PublicClientApplication(msalParams); + if (this.msalInstance.initialize) { + await this.msalInstance.initialize(); } } - return msalInstance; - } catch (error) { - throw new Error( - 'MSAL initialization failed: ' + (error instanceof Error ? error.message : String(error)) - ); + return this.msalInstance; + } + + public getAuthorityType(): 'personal' | 'organizations' { + return this.authorityType; + } + + public getSharepointUrl(): string { + return this.sharepointUrl; + } + + public getBaseUrl(): string { + if (this.authorityType === 'organizations') { + if (!this.sharepointUrl || this.sharepointUrl === '') { + throw new Error('Sharepoint URL not configured'); + } + + let sharePointBaseUrl = this.sharepointUrl.replace(/^https?:\/\//, ''); + sharePointBaseUrl = sharePointBaseUrl.replace(/\/$/, ''); + + return `https://${sharePointBaseUrl}`; + } else { + return 'https://onedrive.live.com/picker'; + } } } + // Retrieve OneDrive access token -async function getToken(): Promise { - const authParams: PopupRequest = { scopes: ['OneDrive.ReadWrite'] }; - let accessToken = ''; - try { - msalInstance = await initializeMsal(); - if (!msalInstance) { - throw new Error('MSAL not initialized'); - } +async function getToken(resource?: string): Promise { + const config = OneDriveConfig.getInstance(); + await config.ensureInitialized(); + + const authorityType = config.getAuthorityType(); + const scopes = authorityType === 'organizations' + ? [`${resource || config.getBaseUrl()}/.default`] + : ['OneDrive.ReadWrite']; + + const authParams: PopupRequest = { scopes }; + let accessToken = ''; + + try { + const msalInstance = await config.getMsalInstance(); const resp = await msalInstance.acquireTokenSilent(authParams); accessToken = resp.accessToken; } catch (err) { - if (!msalInstance) { - throw new Error('MSAL not initialized'); - } - + const msalInstance = await config.getMsalInstance(); try { const resp = await msalInstance.loginPopup(authParams); msalInstance.setActiveAccount(resp.account); @@ -88,60 +148,129 @@ async function getToken(): Promise { return accessToken; } -const baseUrl = 'https://onedrive.live.com/picker'; -const params = { - sdk: '8.0', +// Get picker parameters based on account type +function getPickerParams(): { + sdk: string; entry: { - oneDrive: { - files: {} - } - }, - authentication: {}, + oneDrive: Record; + }; + authentication: Record; messaging: { - origin: window?.location?.origin, - channelId: uuidv4() - }, + origin: string; + channelId: string; + }; typesAndSources: { - mode: 'files', - pivots: { - oneDrive: true, - recent: true - } + mode: string; + pivots: Record; + }; +} { + const channelId = uuidv4(); + + if (OneDriveConfig.getInstance().getAuthorityType() === 'organizations') { + // Parameters for OneDrive for Business + return { + sdk: '8.0', + entry: { + oneDrive: {} + }, + authentication: {}, + messaging: { + origin: window?.location?.origin || '', + channelId + }, + typesAndSources: { + mode: 'files', + pivots: { + oneDrive: true, + recent: true + } + } + }; + } else { + // Parameters for personal OneDrive + return { + sdk: '8.0', + entry: { + oneDrive: { + files: {} + } + }, + authentication: {}, + messaging: { + origin: window?.location?.origin || '', + channelId + }, + typesAndSources: { + mode: 'files', + pivots: { + oneDrive: true, + recent: true + } + } + }; } -}; +} // Download file from OneDrive -async function downloadOneDriveFile(fileInfo: any): Promise { +async function downloadOneDriveFile(fileInfo: Record): Promise { const accessToken = await getToken(); if (!accessToken) { throw new Error('Unable to retrieve OneDrive access token.'); } + + // The endpoint URL is provided in the file info const fileInfoUrl = `${fileInfo['@sharePoint.endpoint']}/drives/${fileInfo.parentReference.driveId}/items/${fileInfo.id}`; + const response = await fetch(fileInfoUrl, { headers: { Authorization: `Bearer ${accessToken}` } }); + if (!response.ok) { throw new Error('Failed to fetch file information.'); } + const fileData = await response.json(); const downloadUrl = fileData['@content.downloadUrl']; const downloadResponse = await fetch(downloadUrl); + if (!downloadResponse.ok) { throw new Error('Failed to download file.'); } + return await downloadResponse.blob(); } +interface PickerResult { + items?: Array<{ + id: string; + name: string; + parentReference: { + driveId: string; + }; + '@sharePoint.endpoint': string; + [key: string]: any; + }>; + command?: string; + [key: string]: any; +} + // Open OneDrive file picker and return selected file metadata -export async function openOneDrivePicker(): Promise { +export async function openOneDrivePicker(): Promise { if (typeof window === 'undefined') { throw new Error('Not in browser environment'); } + + // Force reinitialization of OneDrive config + const config = OneDriveConfig.getInstance(); + await config.initialize(); + return new Promise((resolve, reject) => { let pickerWindow: Window | null = null; let channelPort: MessagePort | null = null; + const params = getPickerParams(); + const baseUrl = config.getBaseUrl(); const handleWindowMessage = (event: MessageEvent) => { if (event.source !== pickerWindow) return; @@ -166,7 +295,9 @@ export async function openOneDrivePicker(): Promise { switch (command.command) { case 'authenticate': { try { - const newToken = await getToken(); + // Pass the resource from the command for org accounts + const resource = OneDriveConfig.getInstance().getAuthorityType() === 'organizations' ? command.resource : undefined; + const newToken = await getToken(resource); if (newToken) { channelPort?.postMessage({ type: 'result', @@ -178,9 +309,12 @@ export async function openOneDrivePicker(): Promise { } } catch (err) { channelPort?.postMessage({ - result: 'error', - error: { code: 'tokenError', message: 'Failed to get token' }, - isExpected: true + type: 'result', + id: portData.id, + data: { + result: 'error', + error: { code: 'tokenError', message: 'Failed to get token' } + } }); } break; @@ -240,7 +374,14 @@ export async function openOneDrivePicker(): Promise { const queryString = new URLSearchParams({ filePicker: JSON.stringify(params) }); - const url = `${baseUrl}?${queryString.toString()}`; + + let url = ''; + if(OneDriveConfig.getInstance().getAuthorityType() === 'organizations') { + url = baseUrl + `/_layouts/15/FilePicker.aspx?${queryString}`; + }else{ + url = baseUrl + `?${queryString}`; + } + const form = pickerWindow.document.createElement('form'); form.setAttribute('action', url); @@ -268,7 +409,10 @@ export async function openOneDrivePicker(): Promise { } // Pick and download file from OneDrive -export async function pickAndDownloadFile(): Promise<{ blob: Blob; name: string } | null> { +export async function pickAndDownloadFile(authorityType: 'personal' | 'organizations' = 'personal'): Promise<{ blob: Blob; name: string } | null> { + const config = OneDriveConfig.getInstance(); + await config.initialize(authorityType); + const pickerResult = await openOneDrivePicker(); if (!pickerResult || !pickerResult.items || pickerResult.items.length === 0) { @@ -281,4 +425,4 @@ export async function pickAndDownloadFile(): Promise<{ blob: Blob; name: string return { blob, name: selectedFile.name }; } -export { downloadOneDriveFile }; +export { downloadOneDriveFile }; \ No newline at end of file From 2d7062fc993f4d8b06a2356bdeabbe1119da9d97 Mon Sep 17 00:00:00 2001 From: hurxxxx Date: Tue, 15 Apr 2025 00:27:59 +0900 Subject: [PATCH 2/4] fix: onedrive orgs selection --- backend/open_webui/config.py | 7 ++ backend/open_webui/main.py | 7 +- src/lib/components/chat/MessageInput.svelte | 4 +- src/lib/utils/onedrive-file-picker.ts | 72 ++++++++++++--------- 4 files changed, 56 insertions(+), 34 deletions(-) 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 }; } From 55d077b52a69862321d16e9b190d1191043c9d4d Mon Sep 17 00:00:00 2001 From: hurxxxx Date: Tue, 15 Apr 2025 00:35:18 +0900 Subject: [PATCH 3/4] refactor --- src/lib/utils/onedrive-file-picker.ts | 145 ++++++++++++-------------- 1 file changed, 64 insertions(+), 81 deletions(-) diff --git a/src/lib/utils/onedrive-file-picker.ts b/src/lib/utils/onedrive-file-picker.ts index 4e27b88f0..2771119ae 100644 --- a/src/lib/utils/onedrive-file-picker.ts +++ b/src/lib/utils/onedrive-file-picker.ts @@ -5,7 +5,6 @@ import { v4 as uuidv4 } from 'uuid'; class OneDriveConfig { private static instance: OneDriveConfig; private clientId: string = ''; - private authorityType: 'personal' | 'organizations' = 'personal'; private sharepointUrl: string = ''; private msalInstance: PublicClientApplication | null = null; private currentAuthorityType: 'personal' | 'organizations' = 'personal'; @@ -21,7 +20,6 @@ class OneDriveConfig { 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; } @@ -32,7 +30,7 @@ class OneDriveConfig { await this.initialize(authorityType); } - private async getCredentials(selectedAuthorityType?: 'personal' | 'organizations'): Promise { + private async getCredentials(): Promise { let response; const headers: HeadersInit = { 'Content-Type': 'application/json' @@ -62,7 +60,7 @@ class OneDriveConfig { if (!newClientId) { throw new Error('OneDrive configuration is incomplete'); } - + this.clientId = newClientId; this.sharepointUrl = newSharepointUrl; } @@ -123,8 +121,6 @@ async function getToken(resource?: string, authorityType?: 'personal' | 'organiz const scopes = currentAuthorityType === 'organizations' ? [`${resource || config.getBaseUrl()}/.default`] : ['OneDrive.ReadWrite']; - - console.log('scopes', scopes); const authParams: PopupRequest = { scopes }; let accessToken = ''; @@ -157,8 +153,7 @@ async function getToken(resource?: string, authorityType?: 'personal' | 'organiz return accessToken; } -// Get picker parameters based on account type -function getPickerParams(): { +interface PickerParams { sdk: string; entry: { oneDrive: Record; @@ -172,56 +167,58 @@ function getPickerParams(): { mode: string; pivots: Record; }; -} { +} + +interface PickerResult { + command?: string; + items?: OneDriveFileInfo[]; + [key: string]: any; +} + +// Get picker parameters based on account type +function getPickerParams(): PickerParams { const channelId = uuidv4(); + const config = OneDriveConfig.getInstance(); - if (OneDriveConfig.getInstance().getAuthorityType() === 'organizations') { - // Parameters for OneDrive for Business - return { - sdk: '8.0', - entry: { - oneDrive: {} - }, - authentication: {}, - messaging: { - origin: window?.location?.origin || '', - channelId - }, - typesAndSources: { - mode: 'files', - pivots: { - oneDrive: true, - recent: true - } + const params: PickerParams = { + sdk: '8.0', + entry: { + oneDrive: {} + }, + authentication: {}, + messaging: { + origin: window?.location?.origin || '', + channelId + }, + typesAndSources: { + mode: 'files', + pivots: { + oneDrive: true, + recent: true } - }; - } else { - // Parameters for personal OneDrive - return { - sdk: '8.0', - entry: { - oneDrive: { - files: {} - } - }, - authentication: {}, - messaging: { - origin: window?.location?.origin || '', - channelId - }, - typesAndSources: { - mode: 'files', - pivots: { - oneDrive: true, - recent: true - } - } - }; + } + }; + + // For personal accounts, set files object in oneDrive + if (config.getAuthorityType() !== 'organizations') { + params.entry.oneDrive = { files: {} }; } + + return params; +} + +interface OneDriveFileInfo { + id: string; + name: string; + parentReference: { + driveId: string; + }; + '@sharePoint.endpoint': string; + [key: string]: any; } // Download file from OneDrive -async function downloadOneDriveFile(fileInfo: Record, authorityType?: 'personal' | 'organizations'): Promise { +async function downloadOneDriveFile(fileInfo: OneDriveFileInfo, authorityType?: 'personal' | 'organizations'): Promise { const accessToken = await getToken(undefined, authorityType); if (!accessToken) { throw new Error('Unable to retrieve OneDrive access token.'); @@ -237,43 +234,34 @@ async function downloadOneDriveFile(fileInfo: Record, authorityType }); if (!response.ok) { - throw new Error('Failed to fetch file information.'); + throw new Error(`Failed to fetch file information: ${response.status} ${response.statusText}`); } const fileData = await response.json(); const downloadUrl = fileData['@content.downloadUrl']; + + if (!downloadUrl) { + throw new Error('Download URL not found in file data'); + } + const downloadResponse = await fetch(downloadUrl); if (!downloadResponse.ok) { - throw new Error('Failed to download file.'); + throw new Error(`Failed to download file: ${downloadResponse.status} ${downloadResponse.statusText}`); } return await downloadResponse.blob(); } -interface PickerResult { - items?: Array<{ - id: string; - name: string; - parentReference: { - driveId: string; - }; - '@sharePoint.endpoint': string; - [key: string]: any; - }>; - command?: string; - [key: string]: any; -} - // Open OneDrive file picker and return selected file metadata -export async function openOneDrivePicker(): Promise { +export async function openOneDrivePicker(authorityType?: 'personal' | 'organizations'): Promise { if (typeof window === 'undefined') { throw new Error('Not in browser environment'); } - // Force reinitialization of OneDrive config + // Initialize OneDrive config with the specified authority type const config = OneDriveConfig.getInstance(); - await config.initialize(); + await config.initialize(authorityType); return new Promise((resolve, reject) => { let pickerWindow: Window | null = null; @@ -305,8 +293,8 @@ export async function openOneDrivePicker(): Promise { case 'authenticate': { try { // Pass the resource from the command for org accounts - const resource = OneDriveConfig.getInstance().getAuthorityType() === 'organizations' ? command.resource : undefined; - const newToken = await getToken(resource); + const resource = config.getAuthorityType() === 'organizations' ? command.resource : undefined; + const newToken = await getToken(resource, authorityType); if (newToken) { channelPort?.postMessage({ type: 'result', @@ -370,7 +358,7 @@ export async function openOneDrivePicker(): Promise { const initializePicker = async () => { try { - const authToken = await getToken(); + const authToken = await getToken(undefined, authorityType); if (!authToken) { return reject(new Error('Failed to acquire access token')); } @@ -385,13 +373,12 @@ export async function openOneDrivePicker(): Promise { }); let url = ''; - if(OneDriveConfig.getInstance().getAuthorityType() === 'organizations') { + if(config.getAuthorityType() === 'organizations') { url = baseUrl + `/_layouts/15/FilePicker.aspx?${queryString}`; - }else{ + } else { url = baseUrl + `?${queryString}`; } - const form = pickerWindow.document.createElement('form'); form.setAttribute('action', url); form.setAttribute('method', 'POST'); @@ -419,11 +406,7 @@ export async function openOneDrivePicker(): Promise { // Pick and download file from OneDrive 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); - - const pickerResult = await openOneDrivePicker(); + const pickerResult = await openOneDrivePicker(authorityType); if (!pickerResult || !pickerResult.items || pickerResult.items.length === 0) { return null; From 84f5a529236e662f9ddb6135d24853b06813cf21 Mon Sep 17 00:00:00 2001 From: hurxxxx Date: Wed, 16 Apr 2025 02:38:20 +0900 Subject: [PATCH 4/4] chore: clean up unnecessary code --- src/lib/utils/onedrive-file-picker.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/lib/utils/onedrive-file-picker.ts b/src/lib/utils/onedrive-file-picker.ts index 2771119ae..47b4e9627 100644 --- a/src/lib/utils/onedrive-file-picker.ts +++ b/src/lib/utils/onedrive-file-picker.ts @@ -31,22 +31,15 @@ class OneDriveConfig { } private async getCredentials(): Promise { - let response; + const headers: HeadersInit = { 'Content-Type': 'application/json' }; - if(window.location.hostname === 'localhost') { - response = await fetch('http://localhost:8080/api/config', { - headers, - credentials: 'include' - }); - } else { - response = await fetch('/api/config', { - headers, - credentials: 'include' - }); - } + const response = await fetch('/api/config', { + headers, + credentials: 'include' + }); if (!response.ok) { throw new Error('Failed to fetch OneDrive credentials');