From 525348b1f3c24148a79bd85154a65be52df91ce5 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Mon, 18 May 2026 19:52:46 +0700 Subject: [PATCH] fix: make forwardToStorage fully dynamic based on fileType - Replace forceDocument boolean with fileType string in forwardToStorage - Dynamically call matching sendPhoto, sendAudio, sendVideo, sendVoice, sendAnimation, sendSticker, or sendDocument Telegraf API method - Correctly extract uploaded file details based on what Telegram returned - Fixes IMAGE_PROCESS_FAILED 500 error when uploading ogg audio, video, sticker, or voice notes via HTTP - Update upload.ts, bot.ts, and test suites to match the new dynamic signature Co-Authored-By: Claude Opus 4.7 --- src/bot.ts | 2 +- src/routes/upload.ts | 12 ++--------- src/utils/telegram.ts | 47 +++++++++++++++++++++++++++++++++++++------ test/bot.test.ts | 6 +++--- test/telegram.test.ts | 6 +++--- 5 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index f959ad8..1565ff7 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -96,7 +96,7 @@ export const startBot = async (): Promise> => { return; } - const result = await forwardToStorage(file_id, fileName); + const result = await forwardToStorage(file_id, fileName, fileType); const publicId = nanoid(); const uploaded = { diff --git a/src/routes/upload.ts b/src/routes/upload.ts index 0d4a5a2..8c618a6 100644 --- a/src/routes/upload.ts +++ b/src/routes/upload.ts @@ -88,11 +88,7 @@ const handleMultipartUpload = async (req: Request): Promise => { return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 }); } - const isDocument = - finalFileName.endsWith('.pdf') || - finalFileName.endsWith('.txt') || - !['photo', 'video', 'audio', 'voice', 'animation'].includes(fileType); - const result = await forwardToStorage(fileBuffer, finalFileName, isDocument); + const result = await forwardToStorage(fileBuffer, finalFileName, fileType); const bot = getBot(); const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any; @@ -199,11 +195,7 @@ const handleJSONUpload = async (req: Request): Promise => { return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 }); } - const isDocument = - finalFileName.endsWith('.pdf') || - finalFileName.endsWith('.txt') || - !['photo', 'video', 'audio', 'voice', 'animation'].includes(fileType); - const result = await forwardToStorage(fileBytes, finalFileName, isDocument); + const result = await forwardToStorage(fileBytes, finalFileName, fileType); const bot = getBot(); const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any; diff --git a/src/utils/telegram.ts b/src/utils/telegram.ts index 3380f30..eb3a696 100644 --- a/src/utils/telegram.ts +++ b/src/utils/telegram.ts @@ -20,15 +20,50 @@ interface TelegramFileInfo { export const forwardToStorage = async ( fileChunk: any, fileName: string, - forceDocument = false, + fileType: string, ): Promise => { try { - const caption = forceDocument ? `📁 ${fileName}` : fileName; const filePayload = { source: fileChunk, filename: fileName }; - const result: any = forceDocument - ? await bot.telegram.sendDocument(config.storageChatId, filePayload, { caption }) - : await bot.telegram.sendPhoto(config.storageChatId, filePayload, { caption }); - const uploadedFile = forceDocument ? result.document : result.photo?.slice(-1)[0]; + let result: any; + + if (fileType === 'photo') { + result = await bot.telegram.sendPhoto(config.storageChatId, filePayload, { + caption: fileName, + }); + } else if (fileType === 'audio') { + result = await bot.telegram.sendAudio(config.storageChatId, filePayload, { + caption: fileName, + }); + } else if (fileType === 'video') { + result = await bot.telegram.sendVideo(config.storageChatId, filePayload, { + caption: fileName, + }); + } else if (fileType === 'voice') { + result = await bot.telegram.sendVoice(config.storageChatId, filePayload, { + caption: fileName, + }); + } else if (fileType === 'animation') { + result = await bot.telegram.sendAnimation(config.storageChatId, filePayload, { + caption: fileName, + }); + } else if (fileType === 'sticker') { + result = await bot.telegram.sendSticker(config.storageChatId, filePayload); + } else { + result = await bot.telegram.sendDocument(config.storageChatId, filePayload, { + caption: `📁 ${fileName}`, + }); + } + + let uploadedFile: any; + if (result.document) uploadedFile = result.document; + else if (result.photo) uploadedFile = result.photo?.slice(-1)[0]; + else if (result.video) uploadedFile = result.video; + else if (result.audio) uploadedFile = result.audio; + else if (result.voice) uploadedFile = result.voice; + else if (result.animation) uploadedFile = result.animation; + else if (result.sticker) uploadedFile = result.sticker; + else if (result.video_note) uploadedFile = result.video_note; + else uploadedFile = result[fileType]; logger.info('File forwarded to storage', { fileName, message: result.message_id }); diff --git a/test/bot.test.ts b/test/bot.test.ts index 00059a6..1cacc6c 100644 --- a/test/bot.test.ts +++ b/test/bot.test.ts @@ -132,7 +132,7 @@ describe('Telegram Bot Handler', () => { }; await fileHandler(ctx); - expect(mockForwardToStorage).toHaveBeenCalledWith('doc_123', 'cv.pdf'); + expect(mockForwardToStorage).toHaveBeenCalledWith('doc_123', 'cv.pdf', 'document'); expect(mockInsert).toHaveBeenCalled(); expect(replyMock).toHaveBeenCalledWith( expect.stringContaining('File berhasil diupload'), @@ -233,7 +233,7 @@ describe('Telegram Bot Handler', () => { }; await fileHandler(ctx); - expect(mockForwardToStorage).toHaveBeenCalledWith('sticker_123', 'file'); + expect(mockForwardToStorage).toHaveBeenCalledWith('sticker_123', 'file', 'sticker'); expect(mockInsert).toHaveBeenCalled(); expect(replyMock).toHaveBeenCalledWith( expect.stringContaining('File berhasil diupload'), @@ -263,7 +263,7 @@ describe('Telegram Bot Handler', () => { }; await fileHandler(ctx); - expect(mockForwardToStorage).toHaveBeenCalledWith('video_note_123', 'file'); + expect(mockForwardToStorage).toHaveBeenCalledWith('video_note_123', 'file', 'video_note'); expect(mockInsert).toHaveBeenCalled(); expect(replyMock).toHaveBeenCalledWith( expect.stringContaining('File berhasil diupload'), diff --git a/test/telegram.test.ts b/test/telegram.test.ts index 4310f7b..bda8669 100644 --- a/test/telegram.test.ts +++ b/test/telegram.test.ts @@ -68,7 +68,7 @@ describe('Telegram API Utilities', () => { it('should forward photo to storage chat and return file details', async () => { const chunk = Buffer.from('fake photo data'); const fileName = 'test_photo.jpg'; - const result = await forwardToStorage(chunk, fileName, false); + const result = await forwardToStorage(chunk, fileName, 'photo'); expect(result).toEqual({ telegramFileId: 'photo_id_high', @@ -86,7 +86,7 @@ describe('Telegram API Utilities', () => { const chunk = Buffer.from('fake document data'); const fileName = 'document.pdf'; - const result = await forwardToStorage(chunk, fileName, true); + const result = await forwardToStorage(chunk, fileName, 'document'); expect(bot.telegram.sendDocument).toHaveBeenCalledWith( config.storageChatId, @@ -107,7 +107,7 @@ describe('Telegram API Utilities', () => { const chunk = Buffer.from('fake photo data'); const fileName = 'test_photo.jpg'; - await expect(forwardToStorage(chunk, fileName, false)).rejects.toThrow( + await expect(forwardToStorage(chunk, fileName, 'photo')).rejects.toThrow( 'Telegram send failed', ); expect(errorSpy).toHaveBeenCalledWith('Failed to forward file to storage', {