From a0efe6f6371429ceccd87c8bcbfd1f6c9594fc5f Mon Sep 17 00:00:00 2001 From: vibsin9322 Date: Tue, 19 Aug 2025 14:08:28 +0900 Subject: [PATCH] Fix file upload errors and improve error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix uploadAttachments method to use proper SupabaseHelper methods - Add addFileAttachment method for proper database insertion - Improve error handling with detailed logging and user feedback - Add file upload progress tracking and cleanup on failure - Fix direct supabase variable access issues - Better error messages for users and developers Bug fixes: โ€ข File upload now works properly with Supabase Storage โ€ข Database insertion errors are properly handled โ€ข Failed uploads are cleaned up automatically โ€ข More informative error messages displayed to users ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- script.js | 99 ++++++++++++++++++++++++++++++++++++++-------- supabase-config.js | 17 ++++++++ 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/script.js b/script.js index c565c39..0c82b6e 100644 --- a/script.js +++ b/script.js @@ -358,20 +358,42 @@ class FileManager { try { this.updateSyncStatus('syncing'); + console.log('ํŒŒ์ผ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ์ค‘...', fileData); + const result = await SupabaseHelper.addFile(fileData, this.currentUser.id); + console.log('ํŒŒ์ผ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ์„ฑ๊ณต:', result); // ์ฒจ๋ถ€ํŒŒ์ผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํŒŒ์ผ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ if (fileData.files && fileData.files.length > 0) { + console.log(`${fileData.files.length}๊ฐœ์˜ ์ฒจ๋ถ€ํŒŒ์ผ ์—…๋กœ๋“œ ์‹œ์ž‘...`); await this.uploadAttachments(result.id, fileData.files); + console.log('๋ชจ๋“  ์ฒจ๋ถ€ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ'); } this.showNotification('์ƒˆ ์ž๋ฃŒ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค!', 'success'); await this.loadUserFiles(); // ๋ชฉ๋ก ์ƒˆ๋กœ๊ณ ์นจ this.updateSyncStatus('online'); + this.clearForm(); // ํผ ์ดˆ๊ธฐํ™” + } catch (error) { console.error('ํŒŒ์ผ ์ถ”๊ฐ€ ์˜ค๋ฅ˜:', error); - this.showNotification('ํŒŒ์ผ ์ถ”๊ฐ€ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.', 'error'); + + // ๋” ๊ตฌ์ฒด์ ์ธ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ œ๊ณต + let errorMessage = 'ํŒŒ์ผ ์ถ”๊ฐ€ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'; + if (error.message) { + errorMessage += ` (${error.message})`; + } + + this.showNotification(errorMessage, 'error'); this.updateSyncStatus('error'); + + // ์ฝ˜์†”์— ์ƒ์„ธ ์˜ค๋ฅ˜ ์ •๋ณด ์ถœ๋ ฅ + if (error.details) { + console.error('์˜ค๋ฅ˜ ์ƒ์„ธ:', error.details); + } + if (error.hint) { + console.error('์˜ค๋ฅ˜ ํžŒํŠธ:', error.hint); + } } } @@ -463,35 +485,80 @@ class FileManager { // ํŒŒ์ผ ์—…๋กœ๋“œ ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋“ค async uploadAttachments(fileId, attachments) { if (!isSupabaseConfigured() || !this.currentUser) { + console.log('์˜คํ”„๋ผ์ธ ๋ชจ๋“œ: ์ฒจ๋ถ€ํŒŒ์ผ์„ base64๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.'); return; // ์˜คํ”„๋ผ์ธ ๋ชจ๋“œ์—์„œ๋Š” base64๋กœ ์ €์žฅ๋œ ์ƒํƒœ ์œ ์ง€ } + const uploadedFiles = []; + try { - for (const attachment of attachments) { - // base64 ๋ฐ์ดํ„ฐ๋ฅผ Blob์œผ๋กœ ๋ณ€ํ™˜ - const response = await fetch(attachment.data); - const blob = await response.blob(); + for (let i = 0; i < attachments.length; i++) { + const attachment = attachments[i]; - // ํŒŒ์ผ ๊ฒฝ๋กœ ์ƒ์„ฑ (์‚ฌ์šฉ์ž๋ณ„/ํŒŒ์ผID๋ณ„ ํด๋” ๊ตฌ์กฐ) - const fileName = `${Date.now()}_${attachment.name}`; - const filePath = `${this.currentUser.id}/${fileId}/${fileName}`; - - // Supabase Storage์— ์—…๋กœ๋“œ - await SupabaseHelper.uploadFile(blob, filePath); - - // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ €์žฅ - if (supabase) { - await supabase.from('file_attachments').insert({ - file_id: fileId, + try { + console.log(`ํŒŒ์ผ ์—…๋กœ๋“œ ์ค‘... (${i + 1}/${attachments.length}): ${attachment.name}`); + + // base64 ๋ฐ์ดํ„ฐ๋ฅผ Blob์œผ๋กœ ๋ณ€ํ™˜ + const response = await fetch(attachment.data); + const blob = await response.blob(); + + // ํŒŒ์ผ ๊ฒฝ๋กœ ์ƒ์„ฑ (์‚ฌ์šฉ์ž๋ณ„/ํŒŒ์ผID๋ณ„ ํด๋” ๊ตฌ์กฐ) + const fileName = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}_${attachment.name}`; + const filePath = `${this.currentUser.id}/${fileId}/${fileName}`; + + // Supabase Storage์— ์—…๋กœ๋“œ + const uploadResult = await SupabaseHelper.uploadFile(blob, filePath); + console.log('Storage ์—…๋กœ๋“œ ์„ฑ๊ณต:', uploadResult); + + // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ €์žฅ + const attachmentResult = await this.addFileAttachment(fileId, { original_name: attachment.name, storage_path: filePath, file_size: attachment.size || blob.size, mime_type: attachment.type || blob.type }); + + uploadedFiles.push(attachmentResult); + console.log('์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ €์žฅ ์„ฑ๊ณต:', attachmentResult); + + } catch (fileError) { + console.error(`ํŒŒ์ผ "${attachment.name}" ์—…๋กœ๋“œ ์‹คํŒจ:`, fileError); + throw new Error(`ํŒŒ์ผ "${attachment.name}" ์—…๋กœ๋“œ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${fileError.message}`); } } + + console.log('๋ชจ๋“  ์ฒจ๋ถ€ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ:', uploadedFiles); + return uploadedFiles; + } catch (error) { console.error('ํŒŒ์ผ ์—…๋กœ๋“œ ์˜ค๋ฅ˜:', error); + + // ๋ถ€๋ถ„์ ์œผ๋กœ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ๋“ค ์ •๋ฆฌ (์„ ํƒ์‚ฌํ•ญ) + try { + for (const uploadedFile of uploadedFiles) { + if (uploadedFile.storage_path) { + await SupabaseHelper.deleteStorageFile(uploadedFile.storage_path); + } + } + } catch (cleanupError) { + console.error('์—…๋กœ๋“œ ์‹คํŒจ ํŒŒ์ผ ์ •๋ฆฌ ์ค‘ ์˜ค๋ฅ˜:', cleanupError); + } + + throw error; + } + } + + async addFileAttachment(fileId, attachmentData) { + if (!isSupabaseConfigured()) { + return; // ์˜คํ”„๋ผ์ธ ๋ชจ๋“œ์—์„œ๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Œ + } + + try { + // SupabaseHelper๋ฅผ ํ†ตํ•ด ์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ €์žฅ + const result = await SupabaseHelper.addFileAttachment(fileId, attachmentData); + return result; + } catch (error) { + console.error('์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ €์žฅ ์˜ค๋ฅ˜:', error); throw error; } } diff --git a/supabase-config.js b/supabase-config.js index 69bfc06..5fb5000 100644 --- a/supabase-config.js +++ b/supabase-config.js @@ -214,6 +214,23 @@ const SupabaseHelper = { .remove([filePath]); if (error) throw error; + }, + + // ์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด ์ถ”๊ฐ€ + async addFileAttachment(fileId, attachmentData) { + if (!supabase) throw new Error('Supabase๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.'); + + const { data, error } = await supabase + .from('file_attachments') + .insert([{ + file_id: fileId, + ...attachmentData + }]) + .select() + .single(); + + if (error) throw error; + return data; } };