From 9ad21bc1f502395e93b1d77f96406a942c6e313f Mon Sep 17 00:00:00 2001 From: Alexander Borg Date: Wed, 10 Sep 2025 06:24:57 +0200 Subject: [PATCH] Fix jwt-token --- server/index.js | 4 +- .../20250910-add-raw-payload-fields.js | 52 +++++--- server/scripts/migrate.js | 117 ++++++++++++++++++ 3 files changed, 153 insertions(+), 20 deletions(-) create mode 100644 server/scripts/migrate.js diff --git a/server/index.js b/server/index.js index ad6d3af..6ecf4c5 100644 --- a/server/index.js +++ b/server/index.js @@ -111,8 +111,8 @@ async function startServer() { // Always sync database in containerized environments or development // Check if tables exist before syncing try { - // Enable alter to add new columns like raw_payload - await sequelize.sync({ force: false, alter: true }); + // Use alter: false to prevent destructive changes in production + await sequelize.sync({ force: false, alter: false }); console.log('Database synchronized.'); // Seed database with initial data diff --git a/server/migrations/20250910-add-raw-payload-fields.js b/server/migrations/20250910-add-raw-payload-fields.js index 961e838..a66caf9 100644 --- a/server/migrations/20250910-add-raw-payload-fields.js +++ b/server/migrations/20250910-add-raw-payload-fields.js @@ -2,30 +2,46 @@ module.exports = { async up(queryInterface, Sequelize) { - // Add raw_payload column to drone_detections table - await queryInterface.addColumn('drone_detections', 'raw_payload', { - type: Sequelize.JSON, - allowNull: true, - comment: 'Complete raw payload received from detector (for debugging)' - }); + // Check if raw_payload column exists in drone_detections before adding + const droneDetectionsTable = await queryInterface.describeTable('drone_detections'); + if (!droneDetectionsTable.raw_payload) { + await queryInterface.addColumn('drone_detections', 'raw_payload', { + type: Sequelize.JSON, + allowNull: true, + comment: 'Complete raw payload received from detector (for debugging)' + }); + console.log('✅ Added raw_payload field to drone_detections table'); + } else { + console.log('⏭️ raw_payload field already exists in drone_detections table'); + } - // Add raw_payload column to heartbeats table - await queryInterface.addColumn('heartbeats', 'raw_payload', { - type: Sequelize.JSON, - allowNull: true, - comment: 'Complete raw payload received from detector (for debugging)' - }); - - console.log('✅ Added raw_payload fields to drone_detections and heartbeats tables'); + // Check if raw_payload column exists in heartbeats before adding + const heartbeatsTable = await queryInterface.describeTable('heartbeats'); + if (!heartbeatsTable.raw_payload) { + await queryInterface.addColumn('heartbeats', 'raw_payload', { + type: Sequelize.JSON, + allowNull: true, + comment: 'Complete raw payload received from detector (for debugging)' + }); + console.log('✅ Added raw_payload field to heartbeats table'); + } else { + console.log('⏭️ raw_payload field already exists in heartbeats table'); + } }, async down(queryInterface, Sequelize) { // Remove raw_payload column from drone_detections table - await queryInterface.removeColumn('drone_detections', 'raw_payload'); + const droneDetectionsTable = await queryInterface.describeTable('drone_detections'); + if (droneDetectionsTable.raw_payload) { + await queryInterface.removeColumn('drone_detections', 'raw_payload'); + console.log('✅ Removed raw_payload field from drone_detections table'); + } // Remove raw_payload column from heartbeats table - await queryInterface.removeColumn('heartbeats', 'raw_payload'); - - console.log('✅ Removed raw_payload fields from drone_detections and heartbeats tables'); + const heartbeatsTable = await queryInterface.describeTable('heartbeats'); + if (heartbeatsTable.raw_payload) { + await queryInterface.removeColumn('heartbeats', 'raw_payload'); + console.log('✅ Removed raw_payload field from heartbeats table'); + } } }; diff --git a/server/scripts/migrate.js b/server/scripts/migrate.js new file mode 100644 index 0000000..36e1020 --- /dev/null +++ b/server/scripts/migrate.js @@ -0,0 +1,117 @@ +const { Sequelize } = require('sequelize'); +const path = require('path'); +const fs = require('fs'); + +// Load environment variables +require('dotenv').config(); + +const runMigrations = async () => { + console.log('🔄 Starting database migrations...\n'); + + try { + // Create Sequelize instance + const sequelize = new Sequelize( + process.env.DB_NAME, + process.env.DB_USER, + process.env.DB_PASSWORD, + { + host: process.env.DB_HOST, + port: process.env.DB_PORT, + dialect: 'postgres', + logging: console.log, + } + ); + + // Test database connection + console.log('📡 Testing database connection...'); + await sequelize.authenticate(); + console.log('✅ Database connection established successfully.\n'); + + // Get migrations directory + const migrationsDir = path.join(__dirname, '../migrations'); + + if (!fs.existsSync(migrationsDir)) { + console.log('📁 No migrations directory found. Creating...'); + fs.mkdirSync(migrationsDir, { recursive: true }); + } + + // Get all migration files + const migrationFiles = fs.readdirSync(migrationsDir) + .filter(file => file.endsWith('.js')) + .sort(); // Sort to ensure proper order + + if (migrationFiles.length === 0) { + console.log('📝 No migration files found.'); + return; + } + + console.log(`📋 Found ${migrationFiles.length} migration files:`); + migrationFiles.forEach(file => console.log(` - ${file}`)); + console.log(''); + + // Create migrations table if it doesn't exist + await sequelize.getQueryInterface().createTable('SequelizeMeta', { + name: { + type: Sequelize.STRING, + primaryKey: true, + allowNull: false + } + }).catch(() => { + // Table already exists, ignore error + }); + + // Get already executed migrations + const [executedMigrations] = await sequelize.query( + 'SELECT name FROM "SequelizeMeta" ORDER BY name' + ); + const executedNames = executedMigrations.map(row => row.name); + + // Run pending migrations + for (const file of migrationFiles) { + const migrationName = file.replace('.js', ''); + + if (executedNames.includes(migrationName)) { + console.log(`⏭️ Skipping already executed migration: ${file}`); + continue; + } + + console.log(`🚀 Running migration: ${file}`); + + try { + // Load and execute migration + const migration = require(path.join(migrationsDir, file)); + await migration.up(sequelize.getQueryInterface(), Sequelize); + + // Record successful migration + await sequelize.query( + 'INSERT INTO "SequelizeMeta" (name) VALUES (?)', + { + replacements: [migrationName], + type: Sequelize.QueryTypes.INSERT + } + ); + + console.log(`✅ Migration completed: ${file}\n`); + + } catch (error) { + console.error(`❌ Migration failed: ${file}`); + console.error('Error:', error.message); + process.exit(1); + } + } + + console.log('🎉 All migrations completed successfully!'); + await sequelize.close(); + + } catch (error) { + console.error('❌ Migration process failed:', error); + process.exit(1); + } +}; + +// Run migrations if called directly +if (require.main === module) { + runMigrations(); +} + +module.exports = runMigrations;