Merge pull request #51 from the-luap/claude/fix-issues-49-50-01Rqwe1uhvLpbZ64tA5eiB2H

Fix issues #49 and #50: Migration errors and missing worker manager
This commit is contained in:
Paul Nothaft
2025-11-19 23:05:48 +01:00
committed by GitHub
2 changed files with 122 additions and 17 deletions
@@ -1,23 +1,56 @@
exports.up = async function(knex) {
// Add user upload settings to events table
await knex.schema.alterTable('events', function(table) {
table.boolean('allow_user_uploads').defaultTo(false);
table.integer('upload_category_id').references('id').inTable('photo_categories').onDelete('SET NULL');
});
// Add user upload settings to events table (check if columns exist first)
const hasAllowUserUploads = await knex.schema.hasColumn('events', 'allow_user_uploads');
if (!hasAllowUserUploads) {
console.log('Adding allow_user_uploads column to events table...');
await knex.schema.alterTable('events', function(table) {
table.boolean('allow_user_uploads').defaultTo(false);
});
} else {
console.log('Column allow_user_uploads already exists in events table, skipping...');
}
const hasUploadCategoryId = await knex.schema.hasColumn('events', 'upload_category_id');
if (!hasUploadCategoryId) {
console.log('Adding upload_category_id column to events table...');
await knex.schema.alterTable('events', function(table) {
table.integer('upload_category_id').references('id').inTable('photo_categories').onDelete('SET NULL');
});
} else {
console.log('Column upload_category_id already exists in events table, skipping...');
}
// Add uploaded_by field to photos table to track who uploaded
await knex.schema.alterTable('photos', function(table) {
table.string('uploaded_by').defaultTo('admin'); // 'admin' or guest identifier
});
const hasUploadedBy = await knex.schema.hasColumn('photos', 'uploaded_by');
if (!hasUploadedBy) {
console.log('Adding uploaded_by column to photos table...');
await knex.schema.alterTable('photos', function(table) {
table.string('uploaded_by').defaultTo('admin'); // 'admin' or guest identifier
});
} else {
console.log('Column uploaded_by already exists in photos table, skipping...');
}
};
exports.down = async function(knex) {
await knex.schema.alterTable('events', function(table) {
table.dropColumn('allow_user_uploads');
table.dropColumn('upload_category_id');
});
await knex.schema.alterTable('photos', function(table) {
table.dropColumn('uploaded_by');
});
const hasAllowUserUploads = await knex.schema.hasColumn('events', 'allow_user_uploads');
if (hasAllowUserUploads) {
await knex.schema.alterTable('events', function(table) {
table.dropColumn('allow_user_uploads');
});
}
const hasUploadCategoryId = await knex.schema.hasColumn('events', 'upload_category_id');
if (hasUploadCategoryId) {
await knex.schema.alterTable('events', function(table) {
table.dropColumn('upload_category_id');
});
}
const hasUploadedBy = await knex.schema.hasColumn('photos', 'uploaded_by');
if (hasUploadedBy) {
await knex.schema.alterTable('photos', function(table) {
table.dropColumn('uploaded_by');
});
}
};
+72
View File
@@ -0,0 +1,72 @@
/**
* Worker Manager - Background service for PicPeak
*
* This service runs as a separate process to handle:
* - File watching for new photos
* - Expiration checking for events
* - Other background tasks
*/
const path = require('path');
const logger = require('../utils/logger');
// Load environment variables
require('dotenv').config({ path: path.join(__dirname, '../../.env') });
// Import services
const { startFileWatcher } = require('./fileWatcher');
const { startExpirationChecker } = require('./expirationChecker');
let isShuttingDown = false;
async function startWorkers() {
logger.info('Starting PicPeak background workers...');
try {
// Start file watcher for automatic photo processing
startFileWatcher();
logger.info('File watcher started successfully');
// Start expiration checker for event lifecycle management
startExpirationChecker();
logger.info('Expiration checker started successfully');
logger.info('All background workers started successfully');
} catch (error) {
logger.error('Failed to start background workers:', error);
process.exit(1);
}
}
function handleShutdown(signal) {
if (isShuttingDown) {
logger.info('Shutdown already in progress...');
return;
}
isShuttingDown = true;
logger.info(`Received ${signal}. Shutting down gracefully...`);
// Give time for cleanup
setTimeout(() => {
logger.info('Worker manager shutdown complete');
process.exit(0);
}, 1000);
}
// Handle shutdown signals
process.on('SIGTERM', () => handleShutdown('SIGTERM'));
process.on('SIGINT', () => handleShutdown('SIGINT'));
// Handle uncaught errors
process.on('uncaughtException', (error) => {
logger.error('Uncaught exception in worker manager:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled rejection in worker manager:', reason);
});
// Start workers
startWorkers();