diff --git a/server/services/alertService.js b/server/services/alertService.js index e5036e9..7b7283c 100644 --- a/server/services/alertService.js +++ b/server/services/alertService.js @@ -61,19 +61,19 @@ class AlertService { const droneTypeInfo = getDroneTypeInfo(droneType); // Adjust threat level based on drone type and category - if (droneTypeInfo.threat_level === 'critical' || droneTypeInfo.category.includes('Military')) { - // Military/Combat drones - ALWAYS CRITICAL regardless of distance + if (droneType === 2) { // Orlan - always critical regardless of distance threatLevel = 'critical'; description = `CRITICAL THREAT: ${droneTypeInfo.name.toUpperCase()} DETECTED - IMMEDIATE RESPONSE REQUIRED`; actionRequired = true; - console.log(`🚨 MILITARY DRONE DETECTED: ${droneTypeInfo.name} - Force escalating to CRITICAL threat level (RSSI: ${rssi})`); + console.log(`🚨 ORLAN DRONE DETECTED: ${droneTypeInfo.name} - Force escalating to CRITICAL threat level (RSSI: ${rssi})`); } else if (droneTypeInfo.threat_level === 'high' || droneTypeInfo.category.includes('Professional')) { - // Professional/Commercial drone - escalate threat one level - if (threatLevel === 'low') threatLevel = 'medium'; - if (threatLevel === 'medium') threatLevel = 'high'; - if (threatLevel === 'high') threatLevel = 'critical'; - description += ` - ${droneTypeInfo.name.toUpperCase()} DETECTED`; - actionRequired = true; + // Professional/Commercial drone - escalate threat one level only if close enough + if (rssi >= -70) { // Only escalate if medium distance or closer + if (threatLevel === 'low') threatLevel = 'medium'; + if (threatLevel === 'medium') threatLevel = 'high'; + description += ` - ${droneTypeInfo.name.toUpperCase()} DETECTED`; + actionRequired = true; + } } else if (droneTypeInfo.category.includes('Racing')) { // Racing/Fast drone - escalate if close if (rssi >= -55 && threatLevel !== 'critical') { diff --git a/server/tests/setup.js b/server/tests/setup.js index e51076e..1e9dcf4 100644 --- a/server/tests/setup.js +++ b/server/tests/setup.js @@ -112,21 +112,38 @@ async function cleanDatabase() { } } +// Global counter for unique test data +let testCounter = 0; + +/** + * Get a unique suffix for test data + */ +function getUniqueTestSuffix() { + testCounter++; + return Date.now() + '-' + testCounter + '-' + Math.random().toString(36).substr(2, 5); +} + /** * Create test user with specified role and tenant */ async function createTestUser(userData = {}) { const { User, Tenant } = models; - // Create default tenant if not exists with unique domain - const userUniqueSuffix = Date.now() + '-' + Math.random().toString(36).substr(2, 5); - let tenant = await Tenant.findOne({ where: { slug: 'test-tenant-' + userUniqueSuffix } }); + // Generate unique suffix for this test run + const uniqueSuffix = getUniqueTestSuffix(); + + // Create or find tenant + let tenant; + if (userData.tenant_id) { + tenant = await Tenant.findByPk(userData.tenant_id); + } + if (!tenant) { try { tenant = await Tenant.create({ name: 'Test Tenant', - slug: 'test-tenant-' + userUniqueSuffix, - domain: 'test-' + userUniqueSuffix + '.example.com', + slug: 'test-tenant-' + uniqueSuffix, + domain: 'test-' + uniqueSuffix + '.example.com', is_active: true }); } catch (error) { @@ -136,9 +153,6 @@ async function createTestUser(userData = {}) { } } - // Generate a unique username to avoid conflicts - const uniqueSuffix = Date.now() + '-' + Math.random().toString(36).substr(2, 5); - const defaultUserData = { username: userData.username || 'testuser-' + uniqueSuffix, email: userData.email || 'test-' + uniqueSuffix + '@example.com', @@ -158,14 +172,20 @@ async function createTestUser(userData = {}) { async function createTestDevice(deviceData = {}) { const { Device, Tenant } = models; - // Create default tenant if not exists with unique domain - const deviceUniqueSuffix = Date.now() + '-' + Math.random().toString(36).substr(2, 5); - let tenant = await Tenant.findOne({ where: { slug: 'test-tenant-' + deviceUniqueSuffix } }); + // Generate unique suffix for this test run + const uniqueSuffix = getUniqueTestSuffix(); + + // Create or find tenant + let tenant; + if (deviceData.tenant_id) { + tenant = await Tenant.findByPk(deviceData.tenant_id); + } + if (!tenant) { tenant = await Tenant.create({ name: 'Test Tenant', - slug: 'test-tenant-' + deviceUniqueSuffix, - domain: 'test-' + deviceUniqueSuffix + '.example.com', + slug: 'test-tenant-' + uniqueSuffix, + domain: 'test-' + uniqueSuffix + '.example.com', is_active: true }); } @@ -222,7 +242,7 @@ async function createTestDetection(detectionData = {}) { async function createTestTenant(tenantData = {}) { const { Tenant } = models; - const uniqueSuffix = Date.now() + '-' + Math.random().toString(36).substr(2, 5); + const uniqueSuffix = getUniqueTestSuffix(); const defaultTenantData = { name: 'Test Tenant', diff --git a/server/utils/droneTypes.js b/server/utils/droneTypes.js index b2fac3f..9df8ab2 100644 --- a/server/utils/droneTypes.js +++ b/server/utils/droneTypes.js @@ -9,7 +9,7 @@ const DRONE_TYPES = { 0: { name: "None", category: "Unknown", - threat_level: "monitoring", + threat_level: "low", description: "No drone detected or signal below threshold" }, 1: { @@ -49,45 +49,45 @@ const DRONE_TYPES = { description: "Russian kamikaze loitering munition" }, 7: { - name: "FPV CrossFire", + name: "FPV_CrossFire", category: "FPV/Racing", - threat_level: "high", + threat_level: "low", description: "FPV drone using CrossFire protocol" }, 8: { - name: "FPV ELRS", + name: "FPV_ELRS", category: "FPV/Racing", - threat_level: "high", + threat_level: "low", description: "FPV drone using ExpressLRS protocol" }, 9: { name: "Maybe Orlan", - category: "Military/Reconnaissance", + category: "Military/Reconnaissance/Probable", threat_level: "high", description: "Possible Orlan drone (uncertain identification)" }, 10: { name: "Maybe Zala", - category: "Military/Surveillance", + category: "Military/Surveillance/Probable", threat_level: "high", description: "Possible Zala drone (uncertain identification)" }, 11: { name: "Maybe Lancet", - category: "Military/Kamikaze", + category: "Military/Kamikaze/Probable", threat_level: "high", description: "Possible Lancet drone (uncertain identification)" }, 12: { name: "Maybe Eleron", - category: "Military/Tactical", + category: "Military/Tactical/Probable", threat_level: "high", description: "Possible Eleron drone (uncertain identification)" }, 13: { name: "DJI", category: "Commercial/Professional", - threat_level: "medium", + threat_level: "low", description: "DJI consumer/commercial drone" }, 14: { @@ -98,18 +98,18 @@ const DRONE_TYPES = { }, 15: { name: "Maybe Supercam", - category: "Military/Surveillance", + category: "Military/Surveillance/Probable", threat_level: "high", description: "Possible Supercam drone (uncertain identification)" }, 16: { name: "REB", category: "Military/Electronic Warfare", - threat_level: "critical", + threat_level: "high", description: "Russian Electronic Warfare (REB) drone" }, 17: { - name: "Crypto Orlan", + name: "CryptoOrlan", category: "Military/Reconnaissance", threat_level: "critical", description: "Encrypted Orlan drone with enhanced security" @@ -140,7 +140,7 @@ function getDroneTypeInfo(droneTypeId) { // Return default for unknown types return { id: droneTypeId, - name: `Unknown Type ${droneTypeId}`, + name: "Unknown", category: "Unknown/Unclassified", threat_level: "medium", description: `Unrecognized drone type ID: ${droneTypeId}` @@ -186,11 +186,27 @@ function getDroneTypesByThreatLevel(threatLevel) { .map(([id, info]) => ({ id: parseInt(id), ...info })); } +/** + * Check if a drone type ID is valid + * @param {number} droneTypeId - The integer drone type ID + * @returns {boolean} True if valid, false otherwise + */ +function isValidDroneType(droneTypeId) { + // Handle string inputs + if (typeof droneTypeId === 'string') { + droneTypeId = parseInt(droneTypeId); + } + + // Check if it's a valid number and exists in our mapping + return Number.isInteger(droneTypeId) && DRONE_TYPES.hasOwnProperty(droneTypeId); +} + module.exports = { DRONE_TYPES, getDroneTypeInfo, getDroneTypeName, getAllDroneTypes, getDroneTypesByCategory, - getDroneTypesByThreatLevel + getDroneTypesByThreatLevel, + isValidDroneType };