UNPKG

autopv-cli

Version:

AutoPrivacy DSAR evidence-pack generator - Automated GDPR compliance for SaaS companies

153 lines (152 loc) 5.39 kB
/** * File Cleanup Utility * Manages automatic cleanup of old evidence files (>24h) on CLI startup */ import { readdirSync, statSync, unlinkSync, existsSync } from 'fs'; import { join } from 'path'; export class FileCleanup { targetDir; maxAgeHours; constructor(targetDir = '.', maxAgeHours = 24) { this.targetDir = targetDir; this.maxAgeHours = maxAgeHours; } /** * Clean up old evidence files based on age */ cleanupOldFiles() { const result = { filesScanned: 0, filesDeleted: 0, deletedFiles: [], totalSizeFreed: 0, errors: [] }; try { if (!existsSync(this.targetDir)) { return result; } const files = readdirSync(this.targetDir); const evidenceFilePatterns = [ /^evidence_.*\.pdf$/, /^mapping_.*\.csv$/, /^evidence_pack_.*\.zip$/ ]; const cutoffTime = Date.now() - (this.maxAgeHours * 60 * 60 * 1000); for (const file of files) { // Only process evidence files const isEvidenceFile = evidenceFilePatterns.some(pattern => pattern.test(file)); if (!isEvidenceFile) { continue; } result.filesScanned++; try { const filePath = join(this.targetDir, file); const stats = statSync(filePath); // Check if file is older than cutoff time if (stats.mtime.getTime() < cutoffTime) { const fileSize = stats.size; unlinkSync(filePath); result.filesDeleted++; result.deletedFiles.push(file); result.totalSizeFreed += fileSize; } } catch (error) { result.errors.push(`Failed to process ${file}: ${error.message}`); } } } catch (error) { result.errors.push(`Directory scan failed: ${error.message}`); } return result; } /** * Generate cleanup report */ generateCleanupReport(result) { let report = 'FILE CLEANUP REPORT\n'; report += '==================\n\n'; report += `Files scanned: ${result.filesScanned}\n`; report += `Files deleted: ${result.filesDeleted}\n`; report += `Space freed: ${this.formatBytes(result.totalSizeFreed)}\n`; report += `Max age threshold: ${this.maxAgeHours} hours\n\n`; if (result.deletedFiles.length > 0) { report += 'Deleted files:\n'; for (const file of result.deletedFiles) { report += ` • ${file}\n`; } report += '\n'; } if (result.errors.length > 0) { report += 'Errors encountered:\n'; for (const error of result.errors) { report += ` ⚠️ ${error}\n`; } report += '\n'; } if (result.filesDeleted === 0 && result.errors.length === 0) { report += 'No old files found to clean up.\n'; } return report; } /** * Format bytes to human readable format */ formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; } /** * List evidence files in directory with age information */ listEvidenceFiles() { const files = []; try { if (!existsSync(this.targetDir)) { return files; } const dirFiles = readdirSync(this.targetDir); const evidenceFilePatterns = [ /^evidence_.*\.pdf$/, /^mapping_.*\.csv$/, /^evidence_pack_.*\.zip$/ ]; for (const file of dirFiles) { const isEvidenceFile = evidenceFilePatterns.some(pattern => pattern.test(file)); if (!isEvidenceFile) { continue; } try { const filePath = join(this.targetDir, file); const stats = statSync(filePath); const ageHours = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60); files.push({ file, age: `${ageHours.toFixed(1)}h`, size: this.formatBytes(stats.size) }); } catch (error) { // Skip files that can't be accessed } } } catch (error) { // Return empty array if directory can't be read } return files.sort((a, b) => a.file.localeCompare(b.file)); } } /** * Convenience function for cleanup with default settings */ export function cleanupOldEvidenceFiles(targetDir = '.', maxAgeHours = 24) { const cleanup = new FileCleanup(targetDir, maxAgeHours); return cleanup.cleanupOldFiles(); }