feat: implement temporary file handling for uploads and update tests for dynamic ID verification
This commit is contained in:
+33
-2
@@ -1,3 +1,4 @@
|
|||||||
|
import { createReadStream, unlinkSync } from 'node:fs';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { db, files as fileSchema } from '../db';
|
import { db, files as fileSchema } from '../db';
|
||||||
@@ -33,6 +34,7 @@ export const handleUpload = async (req: Request): Promise<Response> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMultipartUpload = async (req: Request): Promise<Response> => {
|
const handleMultipartUpload = async (req: Request): Promise<Response> => {
|
||||||
|
let tempPath = '';
|
||||||
try {
|
try {
|
||||||
const formData = await req.formData();
|
const formData = await req.formData();
|
||||||
const file = formData.get('file');
|
const file = formData.get('file');
|
||||||
@@ -88,7 +90,12 @@ const handleMultipartUpload = async (req: Request): Promise<Response> => {
|
|||||||
return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 });
|
return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await forwardToStorage(fileBuffer, finalFileName, fileType);
|
// Write file to disk temporarily
|
||||||
|
tempPath = `/tmp/teleuploader-${nanoid()}`;
|
||||||
|
await Bun.write(tempPath, fileBuffer);
|
||||||
|
|
||||||
|
const fileStream = createReadStream(tempPath);
|
||||||
|
const result = await forwardToStorage(fileStream, finalFileName, fileType);
|
||||||
const bot = getBot();
|
const bot = getBot();
|
||||||
const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any;
|
const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any;
|
||||||
|
|
||||||
@@ -129,10 +136,20 @@ const handleMultipartUpload = async (req: Request): Promise<Response> => {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error('Multipart upload error', { error: error.message });
|
logger.error('Multipart upload error', { error: error.message });
|
||||||
return Response.json({ error: error.message }, { status: 500 });
|
return Response.json({ error: error.message }, { status: 500 });
|
||||||
|
} finally {
|
||||||
|
if (tempPath) {
|
||||||
|
const p = tempPath;
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
unlinkSync(p);
|
||||||
|
} catch {}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleJSONUpload = async (req: Request): Promise<Response> => {
|
const handleJSONUpload = async (req: Request): Promise<Response> => {
|
||||||
|
let tempPath = '';
|
||||||
try {
|
try {
|
||||||
const { file, fileName = 'file' } = (await req.json()) as any;
|
const { file, fileName = 'file' } = (await req.json()) as any;
|
||||||
|
|
||||||
@@ -195,7 +212,12 @@ const handleJSONUpload = async (req: Request): Promise<Response> => {
|
|||||||
return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 });
|
return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await forwardToStorage(fileBytes, finalFileName, fileType);
|
// Write file to disk temporarily
|
||||||
|
tempPath = `/tmp/teleuploader-${nanoid()}`;
|
||||||
|
await Bun.write(tempPath, fileBytes);
|
||||||
|
|
||||||
|
const fileStream = createReadStream(tempPath);
|
||||||
|
const result = await forwardToStorage(fileStream, finalFileName, fileType);
|
||||||
const bot = getBot();
|
const bot = getBot();
|
||||||
const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any;
|
const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any;
|
||||||
|
|
||||||
@@ -236,5 +258,14 @@ const handleJSONUpload = async (req: Request): Promise<Response> => {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error('JSON upload error', { error: error.message });
|
logger.error('JSON upload error', { error: error.message });
|
||||||
return Response.json({ error: error.message }, { status: 500 });
|
return Response.json({ error: error.message }, { status: 500 });
|
||||||
|
} finally {
|
||||||
|
if (tempPath) {
|
||||||
|
const p = tempPath;
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
unlinkSync(p);
|
||||||
|
} catch {}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-3
@@ -47,8 +47,9 @@ mock.module('../src/db/index', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock nanoid
|
// Mock nanoid
|
||||||
|
let nanoidCounter = 0;
|
||||||
mock.module('nanoid', () => ({
|
mock.module('nanoid', () => ({
|
||||||
nanoid: () => 'mocked-nanoid-id',
|
nanoid: () => `mocked-nanoid-id-${nanoidCounter++}`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock telegram utils
|
// Mock telegram utils
|
||||||
@@ -124,7 +125,7 @@ describe('Upload Route Handler', () => {
|
|||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
|
|
||||||
expect(body.public_id).toBe('mocked-nanoid-id');
|
expect(body.public_id).toContain('mocked-nanoid-id');
|
||||||
expect(body.telegram_file_id).toBe('tg-file-id-123');
|
expect(body.telegram_file_id).toBe('tg-file-id-123');
|
||||||
expect(body.telegram_file_unique_id).toBe('tg-unique-id-abc');
|
expect(body.telegram_file_unique_id).toBe('tg-unique-id-abc');
|
||||||
expect(body.file_name).toBe('test.png');
|
expect(body.file_name).toBe('test.png');
|
||||||
@@ -161,7 +162,7 @@ describe('Upload Route Handler', () => {
|
|||||||
const res = await handleUpload(req);
|
const res = await handleUpload(req);
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
expect(body.public_id).toBe('mocked-nanoid-id');
|
expect(body.public_id).toContain('mocked-nanoid-id');
|
||||||
expect(body.file_name).toBe('test_multi.png');
|
expect(body.file_name).toBe('test_multi.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user