port-nimara-client-portal/server/api/files/list.ts

95 lines
2.9 KiB
TypeScript

import { listFiles } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
try {
const query = getQuery(event);
const prefix = (query.prefix as string) || '';
const recursive = query.recursive === 'true';
const files = await listFiles(prefix, recursive);
// Format file list with additional metadata
const formattedFiles = (files as any[]).map(file => ({
...file,
sizeFormatted: file.isFolder ? '-' : formatFileSize(file.size),
extension: file.isFolder ? 'folder' : getFileExtension(file.name),
icon: file.isFolder ? 'mdi-folder' : getFileIcon(file.name),
displayName: getDisplayName(file.name),
}));
// Sort folders first, then files
formattedFiles.sort((a, b) => {
if (a.isFolder && !b.isFolder) return -1;
if (!a.isFolder && b.isFolder) return 1;
return a.displayName.localeCompare(b.displayName);
});
return {
success: true,
files: formattedFiles,
count: formattedFiles.length,
currentPath: prefix,
};
} catch (error: any) {
console.error('Failed to list files - Full error:', error);
console.error('Error message:', error.message);
console.error('Error stack:', error.stack);
throw createError({
statusCode: 500,
statusMessage: error.message || 'Failed to list files',
});
}
});
// Helper functions
function formatFileSize(bytes: number): string {
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
if (bytes === 0) return '0 Bytes';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
}
function getFileExtension(filename: string): string {
const parts = filename.split('.');
return parts.length > 1 ? parts.pop()?.toLowerCase() || '' : '';
}
function getFileIcon(filename: string): string {
const ext = getFileExtension(filename);
const iconMap: Record<string, string> = {
pdf: 'mdi-file-pdf-box',
doc: 'mdi-file-document',
docx: 'mdi-file-document',
xls: 'mdi-file-excel',
xlsx: 'mdi-file-excel',
jpg: 'mdi-file-image',
jpeg: 'mdi-file-image',
png: 'mdi-file-image',
gif: 'mdi-file-image',
svg: 'mdi-file-image',
zip: 'mdi-folder-zip',
rar: 'mdi-folder-zip',
txt: 'mdi-file-document-outline',
csv: 'mdi-file-delimited',
mp4: 'mdi-file-video',
mp3: 'mdi-file-music',
};
return iconMap[ext] || 'mdi-file';
}
function getDisplayName(filepath: string): string {
// Handle folders (ending with /)
if (filepath.endsWith('/')) {
const parts = filepath.slice(0, -1).split('/');
return parts[parts.length - 1] + '/';
}
// Get just the filename from the full path
const parts = filepath.split('/');
const filename = parts[parts.length - 1];
// Remove timestamp prefix if present (e.g., "1234567890-filename.pdf" -> "filename.pdf")
const match = filename.match(/^\d{10,}-(.+)$/);
return match ? match[1] : filename;
}