Skip to content

Commit 0f89997

Browse files
committed
Refactor image upload and deletion utilities to improve file URL handling and streamline filename generation
1 parent 35a675e commit 0f89997

1 file changed

Lines changed: 30 additions & 21 deletions

File tree

src/utils/imageUtils.ts

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,44 @@ import { ApiError } from './apiError'
44

55
type MulterFile = Express.Multer.File
66

7+
function extractFilePathAndNameFromUrl(fileUrl: string): { filePath: string, fileName: string } {
8+
try {
9+
const url = new URL(fileUrl)
10+
const pathParts = url.pathname.split('/') // ['', 'storage', 'v1', 'object', 'public', 'images', ...filePathParts]
11+
const filePath = pathParts.slice(6).join('/') // 'images/...'
12+
if (!filePath) throw new Error('Invalid file URL')
13+
const fileName = filePath.split('/').pop() || ''
14+
return { filePath, fileName }
15+
} catch {
16+
throw new ApiError('Invalid file URL', 400)
17+
}
18+
}
19+
20+
721
export async function uploadImage(
822
supabase: SupabaseClient,
923
file: MulterFile,
10-
folder: string,
11-
fileName?: string
24+
folder: string,
25+
fileUrl?: string
1226
): Promise<string> {
13-
// 1) Determine file extension
14-
const mime = file.mimetype // e.g. 'image/jpeg'
15-
if (!mime) {
16-
throw new ApiError('File type is missing', 400)
17-
}
18-
// Validate MIME type against allowed image types
19-
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
20-
if (!allowedTypes.includes(mime)) {
21-
throw new ApiError('Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.', 400)
22-
}
23-
27+
const mime = file.mimetype
28+
if (!mime) throw new ApiError('File type is missing', 400)
29+
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
30+
if (!allowedTypes.includes(mime)) {
31+
throw new ApiError('Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.', 400)
32+
}
2433
const ext = mime.split('/')[1]
2534

26-
// 2) Create filename
27-
const filename = fileName ? fileName : `${uuidv4()}.${ext}`
35+
let filename: string
36+
if (fileUrl) {
37+
const { fileName } = extractFilePathAndNameFromUrl(fileUrl)
38+
filename = fileName
39+
} else {
40+
filename = `${uuidv4()}.${ext}`
41+
}
2842

29-
// 3) Build full path inside the bucket
3043
const filePath = `${folder}/${filename}`
3144

32-
// 4) Perform the upload (upsert: true will overwrite same path if it exists)
3345
const { error: uploadError } = await supabase
3446
.storage
3547
.from('images')
@@ -42,7 +54,6 @@ const filename = fileName ? fileName : `${uuidv4()}.${ext}`
4254
throw new ApiError(`Image upload failed: ${uploadError.message}`, 500)
4355
}
4456

45-
// 5) Generate a public URL
4657
const { data: urlData } = supabase
4758
.storage
4859
.from('images')
@@ -59,9 +70,7 @@ export async function deleteImage(
5970
supabase: SupabaseClient,
6071
fileUrl: string
6172
): Promise<void> {
62-
const url = new URL(fileUrl);
63-
const pathParts = url.pathname.split('/'); // ['', 'storage', 'v1', 'object', 'public', 'images', ...filePathParts]
64-
const filePath = pathParts.slice(6).join('/'); // 'images/...'
73+
const { filePath } = extractFilePathAndNameFromUrl(fileUrl)
6574
if (!filePath) {
6675
throw new ApiError('Invalid file URL', 400)
6776
}

0 commit comments

Comments
 (0)