const cron = require('node-cron'); const nodemailer = require('nodemailer'); const MinIOService = require('./minio.service'); const config = require('../config'); const { logger } = require('../utils/logger'); class ReportService { constructor() { this.minioService = new MinIOService(); this.transporter = null; this.scheduledTask = null; if (config.email.host) { this.initializeMailer(); this.setupSchedule(); } else { logger.warn('Email host not configured. Report scheduling disabled.'); } } initializeMailer() { const transportConfig = { host: config.email.host, port: config.email.port, secure: config.email.secure, // For Exchange Server on port 25 without TLS tls: { rejectUnauthorized: false, // Accept self-signed certificates // If you want to disable TLS completely when secure is false: ...(config.email.port === 25 && !config.email.secure ? { enabled: false } : {}) }, // Disable STARTTLS for port 25 if not using secure requireTLS: config.email.secure, ignoreTLS: config.email.port === 25 && !config.email.secure, }; // Only add auth if username and password are provided if (config.email.auth.user && config.email.auth.pass) { transportConfig.auth = { user: config.email.auth.user, pass: config.email.auth.pass, }; logger.info('Email configured with authentication'); } else { logger.info('Email configured without authentication (open relay)'); } this.transporter = nodemailer.createTransport(transportConfig); // Verify connection this.transporter.verify((error) => { if (error) { logger.error('Email transporter verification failed:', error); } else { logger.info('Email transporter ready'); } }); } setupSchedule() { if (!cron.validate(config.reports.schedule)) { logger.error(`Invalid cron expression: ${config.reports.schedule}`); return; } this.scheduledTask = cron.schedule(config.reports.schedule, async () => { logger.info('Running scheduled storage report...'); try { await this.generateAndSendReport(); } catch (error) { logger.error('Scheduled report failed:', error); } }); logger.info(`Report scheduled with cron: ${config.reports.schedule}`); } async generateReport() { const [bucketSizes, users] = await Promise.all([ this.minioService.getBucketSizes(), this.minioService.listUsers(), ]); const totalSize = bucketSizes.reduce((sum, b) => sum + b.size, 0); const date = new Date().toISOString().split('T')[0]; const report = { date, summary: { totalBuckets: bucketSizes.length, totalUsers: users.length, totalSize, totalSizeFormatted: this.minioService.formatBytes(totalSize), }, buckets: bucketSizes, users: users.map(u => u.accessKey), }; return report; } formatReportText(report) { let text = `MinIO Speicherauswertung\n`; text += `Datum: ${report.date}\n`; text += `----------------------------------------\n\n`; text += `Zusammenfassung:\n`; text += `- Buckets: ${report.summary.totalBuckets}\n`; text += `- Benutzer: ${report.summary.totalUsers}\n`; text += `- Gesamtspeicher: ${report.summary.totalSizeFormatted}\n\n`; text += `Alle MinIO-User:\n`; report.users.forEach(user => { text += `- ${user}\n`; }); text += `\nAlle Buckets:\n`; report.buckets.forEach(bucket => { text += `\nBucket: ${bucket.name}\n`; text += ` Größe: ${bucket.sizeFormatted}\n`; text += ` Objekte: ${bucket.objects}\n`; text += ` Letzte Änderung: ${bucket.lastModified}\n`; }); text += `\n----------------------------------------\n`; text += `Gesamtspeicher: ${report.summary.totalSizeFormatted}\n`; return text; } formatReportHTML(report) { let html = `
Datum: ${report.date}
| Bucket Name | Größe | Objekte | Letzte Änderung |
|---|---|---|---|
| ${bucket.name} | ${bucket.sizeFormatted} | ${bucket.objects} | ${bucket.lastModified} |