fix: prevent photo corruption during upload and add batch processing improvements
Mirror to GitHub / mirror (push) Successful in 20s
Test and Lint / backend-test (push) Successful in 1m9s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m9s
Version and Release / version-bump (push) Successful in 34s
Version and Release / trigger-drone (push) Successful in 3s

- Remove async functions from multer callbacks (primary corruption cause)
- Implement temp directory upload approach with proper cleanup
- Add comprehensive file integrity validation before processing
- Fix batch upload category assignment and photo naming
- Add automatic cleanup service for orphaned temp uploads
- Enhance error handling with better corruption detection
- Add fix-temp-photos script to repair existing temporary files
- Update file watcher to ignore temp upload files

Fixes issues with:
- Corrupted photos showing only partial images
- Photos retaining temp_ names after upload
- Category assignments lost during batch uploads
- Incomplete file uploads causing "Premature end of input" errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-17 10:02:23 +02:00
parent a896fa66c0
commit e636cf5d56
7 changed files with 498 additions and 95 deletions
+78
View File
@@ -0,0 +1,78 @@
const path = require('path');
const fs = require('fs').promises;
const logger = require('./logger');
const getStoragePath = () => process.env.STORAGE_PATH || path.join(__dirname, '../../../storage');
/**
* Clean up old temporary upload directories
* Removes temp directories older than 1 hour
*/
async function cleanupTempUploads() {
const tempPath = path.join(getStoragePath(), 'temp');
try {
// Ensure temp directory exists
await fs.mkdir(tempPath, { recursive: true });
// Read all items in temp directory
const items = await fs.readdir(tempPath);
let cleanedCount = 0;
const oneHourAgo = Date.now() - (60 * 60 * 1000); // 1 hour
for (const item of items) {
const itemPath = path.join(tempPath, item);
try {
const stats = await fs.stat(itemPath);
// Only process directories that match our upload pattern
if (stats.isDirectory() && item.startsWith('upload_')) {
// Extract timestamp from directory name
const parts = item.split('_');
if (parts.length >= 2) {
const timestamp = parseInt(parts[1]);
// Remove if older than 1 hour
if (!isNaN(timestamp) && timestamp < oneHourAgo) {
logger.info(`Cleaning up old temp upload directory: ${item}`);
await fs.rm(itemPath, { recursive: true, force: true });
cleanedCount++;
}
}
}
} catch (error) {
logger.error(`Error processing temp item ${item}:`, error.message);
}
}
if (cleanedCount > 0) {
logger.info(`Cleaned up ${cleanedCount} old temp upload directories`);
}
} catch (error) {
logger.error('Error during temp upload cleanup:', error);
}
}
/**
* Start periodic cleanup of temp uploads
* Runs every hour
*/
function startTempUploadCleanup() {
// Run immediately on startup
cleanupTempUploads();
// Then run every hour
setInterval(() => {
cleanupTempUploads();
}, 60 * 60 * 1000); // 1 hour
logger.info('Temp upload cleanup service started');
}
module.exports = {
cleanupTempUploads,
startTempUploadCleanup
};