Fix file upload
Browse files- data/knowledgebridge.db +0 -0
- server/document-routes.ts +88 -21
- server/file-upload.ts +16 -2
- server/vite.ts +2 -2
data/knowledgebridge.db
CHANGED
|
Binary files a/data/knowledgebridge.db and b/data/knowledgebridge.db differ
|
|
|
server/document-routes.ts
CHANGED
|
@@ -10,12 +10,73 @@ const router = Router();
|
|
| 10 |
/**
|
| 11 |
* Upload documents (multiple files supported)
|
| 12 |
*/
|
| 13 |
-
router.post('/upload',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
try {
|
| 15 |
const files = req.files as Express.Multer.File[];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
const uploadedDocuments = [];
|
| 17 |
|
| 18 |
for (const file of files) {
|
|
|
|
|
|
|
| 19 |
// Extract title from filename or use provided title
|
| 20 |
const title = req.body.title || path.basename(file.originalname, path.extname(file.originalname));
|
| 21 |
const source = req.body.source || `Uploaded file: ${file.originalname}`;
|
|
@@ -42,27 +103,33 @@ router.post('/upload', upload.array('files', 10), validateUpload, async (req, re
|
|
| 42 |
}
|
| 43 |
|
| 44 |
// Create document record
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
mimeType: file.mimetype,
|
| 55 |
-
|
| 56 |
-
}
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
uploadedDocuments.push(document);
|
| 66 |
}
|
| 67 |
|
| 68 |
res.status(201).json({
|
|
|
|
| 10 |
/**
|
| 11 |
* Upload documents (multiple files supported)
|
| 12 |
*/
|
| 13 |
+
router.post('/upload', (req, res, next) => {
|
| 14 |
+
upload.array('files', 10)(req, res, (err) => {
|
| 15 |
+
if (err) {
|
| 16 |
+
console.error('Multer upload error:', err);
|
| 17 |
+
|
| 18 |
+
// Handle specific multer errors
|
| 19 |
+
if (err.code === 'LIMIT_FILE_SIZE') {
|
| 20 |
+
return res.status(400).json({
|
| 21 |
+
success: false,
|
| 22 |
+
error: 'File too large',
|
| 23 |
+
message: `File size exceeds the maximum limit of 50MB. File: ${err.field}`
|
| 24 |
+
});
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
if (err.code === 'LIMIT_FILE_COUNT') {
|
| 28 |
+
return res.status(400).json({
|
| 29 |
+
success: false,
|
| 30 |
+
error: 'Too many files',
|
| 31 |
+
message: 'Maximum 10 files allowed per upload'
|
| 32 |
+
});
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
if (err.code === 'LIMIT_UNEXPECTED_FILE') {
|
| 36 |
+
return res.status(400).json({
|
| 37 |
+
success: false,
|
| 38 |
+
error: 'Unexpected file field',
|
| 39 |
+
message: `Unexpected file field: ${err.field}`
|
| 40 |
+
});
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// Handle file type errors
|
| 44 |
+
if (err.message && err.message.includes('Unsupported file type')) {
|
| 45 |
+
return res.status(400).json({
|
| 46 |
+
success: false,
|
| 47 |
+
error: 'Unsupported file type',
|
| 48 |
+
message: err.message
|
| 49 |
+
});
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
// Generic multer error
|
| 53 |
+
return res.status(400).json({
|
| 54 |
+
success: false,
|
| 55 |
+
error: 'File upload error',
|
| 56 |
+
message: err.message || 'Unknown upload error'
|
| 57 |
+
});
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
next();
|
| 61 |
+
});
|
| 62 |
+
}, validateUpload, async (req, res) => {
|
| 63 |
try {
|
| 64 |
const files = req.files as Express.Multer.File[];
|
| 65 |
+
|
| 66 |
+
if (!files || files.length === 0) {
|
| 67 |
+
return res.status(400).json({
|
| 68 |
+
success: false,
|
| 69 |
+
error: 'No files received',
|
| 70 |
+
message: 'No files were received by the server'
|
| 71 |
+
});
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
console.log(`Processing ${files.length} uploaded files`);
|
| 75 |
const uploadedDocuments = [];
|
| 76 |
|
| 77 |
for (const file of files) {
|
| 78 |
+
console.log(`Processing file: ${file.originalname}, size: ${file.size} bytes, type: ${file.mimetype}`);
|
| 79 |
+
|
| 80 |
// Extract title from filename or use provided title
|
| 81 |
const title = req.body.title || path.basename(file.originalname, path.extname(file.originalname));
|
| 82 |
const source = req.body.source || `Uploaded file: ${file.originalname}`;
|
|
|
|
| 103 |
}
|
| 104 |
|
| 105 |
// Create document record
|
| 106 |
+
try {
|
| 107 |
+
const document = await storage.createDocument({
|
| 108 |
+
title,
|
| 109 |
+
content,
|
| 110 |
+
source,
|
| 111 |
+
sourceType,
|
| 112 |
+
url: null,
|
| 113 |
+
metadata: {
|
| 114 |
+
originalName: file.originalname,
|
| 115 |
+
uploadedAt: new Date().toISOString(),
|
| 116 |
+
mimeType: file.mimetype,
|
| 117 |
+
size: file.size
|
| 118 |
+
},
|
| 119 |
+
embedding: null,
|
| 120 |
+
filePath: file.path,
|
| 121 |
+
fileName: file.originalname,
|
| 122 |
+
fileSize: file.size,
|
| 123 |
mimeType: file.mimetype,
|
| 124 |
+
processingStatus: FileProcessor.requiresOCR(file.mimetype) ? 'pending' : 'completed'
|
| 125 |
+
} as any);
|
| 126 |
+
|
| 127 |
+
console.log(`Successfully created document record for ${file.originalname} with ID ${document.id}`);
|
| 128 |
+
uploadedDocuments.push(document);
|
| 129 |
+
} catch (dbError) {
|
| 130 |
+
console.error(`Failed to create document record for ${file.originalname}:`, dbError);
|
| 131 |
+
throw new Error(`Database error while saving ${file.originalname}: ${dbError instanceof Error ? dbError.message : 'Unknown database error'}`);
|
| 132 |
+
}
|
|
|
|
|
|
|
| 133 |
}
|
| 134 |
|
| 135 |
res.status(201).json({
|
server/file-upload.ts
CHANGED
|
@@ -14,10 +14,20 @@ const uploadsDir = process.env.NODE_ENV === 'production'
|
|
| 14 |
try {
|
| 15 |
if (!fs.existsSync(uploadsDir)) {
|
| 16 |
fs.mkdirSync(uploadsDir, { recursive: true });
|
|
|
|
|
|
|
|
|
|
| 17 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
} catch (error) {
|
| 19 |
-
console.warn(
|
| 20 |
-
console.log('File uploads
|
| 21 |
}
|
| 22 |
|
| 23 |
// Configure multer for file uploads
|
|
@@ -28,13 +38,17 @@ const storage = multer.diskStorage({
|
|
| 28 |
const dateDir = new Date().toISOString().split('T')[0];
|
| 29 |
const fullPath = path.join(uploadsDir, dateDir);
|
| 30 |
|
|
|
|
|
|
|
| 31 |
if (!fs.existsSync(fullPath)) {
|
| 32 |
fs.mkdirSync(fullPath, { recursive: true });
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
cb(null, fullPath);
|
| 36 |
} catch (error) {
|
| 37 |
console.error('Failed to create upload directory:', error);
|
|
|
|
| 38 |
// Fallback to base uploads directory
|
| 39 |
cb(null, uploadsDir);
|
| 40 |
}
|
|
|
|
| 14 |
try {
|
| 15 |
if (!fs.existsSync(uploadsDir)) {
|
| 16 |
fs.mkdirSync(uploadsDir, { recursive: true });
|
| 17 |
+
console.log(`β
Created uploads directory: ${uploadsDir}`);
|
| 18 |
+
} else {
|
| 19 |
+
console.log(`β
Uploads directory exists: ${uploadsDir}`);
|
| 20 |
}
|
| 21 |
+
|
| 22 |
+
// Test write permissions
|
| 23 |
+
const testFile = path.join(uploadsDir, 'test-permissions.txt');
|
| 24 |
+
fs.writeFileSync(testFile, 'test');
|
| 25 |
+
fs.unlinkSync(testFile);
|
| 26 |
+
console.log(`β
Upload directory is writable: ${uploadsDir}`);
|
| 27 |
+
|
| 28 |
} catch (error) {
|
| 29 |
+
console.warn(`β Failed to create or write to uploads directory at ${uploadsDir}:`, error);
|
| 30 |
+
console.log('File uploads may not work properly');
|
| 31 |
}
|
| 32 |
|
| 33 |
// Configure multer for file uploads
|
|
|
|
| 38 |
const dateDir = new Date().toISOString().split('T')[0];
|
| 39 |
const fullPath = path.join(uploadsDir, dateDir);
|
| 40 |
|
| 41 |
+
console.log(`Creating upload destination: ${fullPath} for file: ${file.originalname}`);
|
| 42 |
+
|
| 43 |
if (!fs.existsSync(fullPath)) {
|
| 44 |
fs.mkdirSync(fullPath, { recursive: true });
|
| 45 |
+
console.log(`Created upload subdirectory: ${fullPath}`);
|
| 46 |
}
|
| 47 |
|
| 48 |
cb(null, fullPath);
|
| 49 |
} catch (error) {
|
| 50 |
console.error('Failed to create upload directory:', error);
|
| 51 |
+
console.log(`Falling back to base directory: ${uploadsDir}`);
|
| 52 |
// Fallback to base uploads directory
|
| 53 |
cb(null, uploadsDir);
|
| 54 |
}
|
server/vite.ts
CHANGED
|
@@ -35,8 +35,8 @@ export async function setupVite(app: Express, server: Server) {
|
|
| 35 |
customLogger: {
|
| 36 |
...viteLogger,
|
| 37 |
error: (msg, options) => {
|
| 38 |
-
|
| 39 |
-
|
| 40 |
},
|
| 41 |
},
|
| 42 |
server: serverOptions,
|
|
|
|
| 35 |
customLogger: {
|
| 36 |
...viteLogger,
|
| 37 |
error: (msg, options) => {
|
| 38 |
+
console.warn('Vite error (non-fatal):', msg);
|
| 39 |
+
// Don't exit on Vite errors - they're often non-critical
|
| 40 |
},
|
| 41 |
},
|
| 42 |
server: serverOptions,
|