Fix jwt-token
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
|
||||
const cron = require('node-cron');
|
||||
const { Op } = require('sequelize');
|
||||
require('dotenv').config();
|
||||
|
||||
// Initialize database connection
|
||||
const { initializeDatabase, getModels } = require('./database');
|
||||
|
||||
@@ -135,10 +135,6 @@ app.use(errorHandler);
|
||||
// Socket.IO initialization
|
||||
initializeSocketHandlers(io);
|
||||
|
||||
// Initialize services
|
||||
const dataRetentionService = require('./services/data-retention');
|
||||
console.log('✅ Data retention service initialized');
|
||||
|
||||
const PORT = process.env.PORT || 5000;
|
||||
|
||||
// Migration runner
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
/**
|
||||
* Data Retention Cleanup Service
|
||||
* Automatically removes old data based on tenant retention policies
|
||||
*/
|
||||
|
||||
const cron = require('node-cron');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
class DataRetentionService {
|
||||
constructor() {
|
||||
this.isRunning = false;
|
||||
this.lastCleanup = null;
|
||||
|
||||
// Run cleanup daily at 2 AM
|
||||
this.scheduleCleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule automatic cleanup
|
||||
*/
|
||||
scheduleCleanup() {
|
||||
// Run at 2:00 AM every day
|
||||
cron.schedule('0 2 * * *', async () => {
|
||||
console.log('🗑️ Starting scheduled data retention cleanup...');
|
||||
await this.runCleanup();
|
||||
});
|
||||
|
||||
console.log('📅 Data retention cleanup scheduled for 2:00 AM daily');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run cleanup for all tenants
|
||||
*/
|
||||
async runCleanup() {
|
||||
if (this.isRunning) {
|
||||
console.log('⚠️ Data retention cleanup already running, skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.isRunning = true;
|
||||
const startTime = Date.now();
|
||||
console.log('🗑️ Starting data retention cleanup...');
|
||||
|
||||
const { Tenant } = require('../models');
|
||||
const tenants = await Tenant.findAll({
|
||||
where: {
|
||||
is_active: true
|
||||
}
|
||||
});
|
||||
|
||||
let totalCleaned = {
|
||||
detections: 0,
|
||||
heartbeats: 0,
|
||||
logs: 0,
|
||||
sessions: 0
|
||||
};
|
||||
|
||||
for (const tenant of tenants) {
|
||||
const retentionDays = tenant.features?.data_retention_days;
|
||||
|
||||
// Skip tenants with unlimited retention (-1)
|
||||
if (retentionDays === -1) {
|
||||
console.log(`⏭️ Skipping tenant ${tenant.slug} - unlimited retention`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`🧹 Cleaning data for tenant ${tenant.slug} (${retentionDays} days retention)`);
|
||||
|
||||
const cleanupResult = await this.cleanupTenantData(tenant.id, retentionDays);
|
||||
|
||||
totalCleaned.detections += cleanupResult.detections;
|
||||
totalCleaned.heartbeats += cleanupResult.heartbeats;
|
||||
totalCleaned.logs += cleanupResult.logs;
|
||||
totalCleaned.sessions += cleanupResult.sessions;
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
this.lastCleanup = new Date();
|
||||
|
||||
console.log(`✅ Data retention cleanup completed in ${duration}ms`);
|
||||
console.log(`📊 Cleaned up:`, totalCleaned);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error during data retention cleanup:', error);
|
||||
} finally {
|
||||
this.isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up data for a specific tenant
|
||||
*/
|
||||
async cleanupTenantData(tenantId, retentionDays) {
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
|
||||
|
||||
console.log(`🗑️ Cleaning data older than ${cutoffDate.toISOString()} for tenant ${tenantId}`);
|
||||
|
||||
const { DroneDetection, Heartbeat, ApiLog, Session } = require('../models');
|
||||
|
||||
const cleanupResults = {
|
||||
detections: 0,
|
||||
heartbeats: 0,
|
||||
logs: 0,
|
||||
sessions: 0
|
||||
};
|
||||
|
||||
try {
|
||||
// Clean up drone detections
|
||||
const deletedDetections = await DroneDetection.destroy({
|
||||
where: {
|
||||
tenant_id: tenantId,
|
||||
timestamp: {
|
||||
[Op.lt]: cutoffDate
|
||||
}
|
||||
}
|
||||
});
|
||||
cleanupResults.detections = deletedDetections;
|
||||
|
||||
// Clean up heartbeats
|
||||
const deletedHeartbeats = await Heartbeat.destroy({
|
||||
where: {
|
||||
tenant_id: tenantId,
|
||||
timestamp: {
|
||||
[Op.lt]: cutoffDate
|
||||
}
|
||||
}
|
||||
});
|
||||
cleanupResults.heartbeats = deletedHeartbeats;
|
||||
|
||||
// Clean up API logs (if exists)
|
||||
try {
|
||||
const deletedLogs = await ApiLog.destroy({
|
||||
where: {
|
||||
tenant_id: tenantId,
|
||||
created_at: {
|
||||
[Op.lt]: cutoffDate
|
||||
}
|
||||
}
|
||||
});
|
||||
cleanupResults.logs = deletedLogs;
|
||||
} catch (error) {
|
||||
// ApiLog table might not exist, skip silently
|
||||
console.log(`⏭️ Skipping API logs cleanup for tenant ${tenantId} (table might not exist)`);
|
||||
}
|
||||
|
||||
// Clean up old sessions
|
||||
try {
|
||||
const deletedSessions = await Session.destroy({
|
||||
where: {
|
||||
tenant_id: tenantId,
|
||||
updated_at: {
|
||||
[Op.lt]: cutoffDate
|
||||
}
|
||||
}
|
||||
});
|
||||
cleanupResults.sessions = deletedSessions;
|
||||
} catch (error) {
|
||||
// Session table might not exist, skip silently
|
||||
console.log(`⏭️ Skipping sessions cleanup for tenant ${tenantId} (table might not exist)`);
|
||||
}
|
||||
|
||||
console.log(`✅ Tenant ${tenantId} cleanup:`, cleanupResults);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error cleaning data for tenant ${tenantId}:`, error);
|
||||
}
|
||||
|
||||
return cleanupResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual cleanup for a specific tenant
|
||||
*/
|
||||
async manualCleanup(tenantId, retentionDays = null) {
|
||||
const { Tenant } = require('../models');
|
||||
const tenant = await Tenant.findByPk(tenantId);
|
||||
|
||||
if (!tenant) {
|
||||
throw new Error('Tenant not found');
|
||||
}
|
||||
|
||||
const days = retentionDays || tenant.features?.data_retention_days;
|
||||
|
||||
if (days === -1) {
|
||||
throw new Error('Tenant has unlimited retention, manual cleanup requires explicit retention days');
|
||||
}
|
||||
|
||||
console.log(`🧹 Manual cleanup for tenant ${tenant.slug} (${days} days retention)`);
|
||||
|
||||
return await this.cleanupTenantData(tenantId, days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cleanup statistics
|
||||
*/
|
||||
async getCleanupStats() {
|
||||
const { Tenant, DroneDetection, Heartbeat } = require('../models');
|
||||
|
||||
const tenants = await Tenant.findAll({
|
||||
where: { is_active: true }
|
||||
});
|
||||
|
||||
const stats = [];
|
||||
|
||||
for (const tenant of tenants) {
|
||||
const retentionDays = tenant.features?.data_retention_days;
|
||||
|
||||
if (retentionDays === -1) {
|
||||
stats.push({
|
||||
tenant_id: tenant.id,
|
||||
tenant_slug: tenant.slug,
|
||||
retention_days: 'unlimited',
|
||||
old_detections: 0,
|
||||
old_heartbeats: 0,
|
||||
next_cleanup: 'never'
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
|
||||
|
||||
const [oldDetections, oldHeartbeats] = await Promise.all([
|
||||
DroneDetection.count({
|
||||
where: {
|
||||
tenant_id: tenant.id,
|
||||
timestamp: { [Op.lt]: cutoffDate }
|
||||
}
|
||||
}),
|
||||
Heartbeat.count({
|
||||
where: {
|
||||
tenant_id: tenant.id,
|
||||
timestamp: { [Op.lt]: cutoffDate }
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
stats.push({
|
||||
tenant_id: tenant.id,
|
||||
tenant_slug: tenant.slug,
|
||||
retention_days: retentionDays,
|
||||
old_detections: oldDetections,
|
||||
old_heartbeats: oldHeartbeats,
|
||||
next_cleanup: this.getNextCleanupTime()
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
last_cleanup: this.lastCleanup,
|
||||
next_cleanup: this.getNextCleanupTime(),
|
||||
is_running: this.isRunning,
|
||||
tenant_stats: stats
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next scheduled cleanup time
|
||||
*/
|
||||
getNextCleanupTime() {
|
||||
const now = new Date();
|
||||
const tomorrow = new Date(now);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
tomorrow.setHours(2, 0, 0, 0);
|
||||
|
||||
return tomorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force immediate cleanup (for testing/admin use)
|
||||
*/
|
||||
async forceCleanup() {
|
||||
console.log('🚨 Force cleanup initiated');
|
||||
await this.runCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
// Create singleton instance
|
||||
const dataRetentionService = new DataRetentionService();
|
||||
|
||||
module.exports = dataRetentionService;
|
||||
Reference in New Issue
Block a user