- Remove non-existent src/Core/Service/ from CLAUDE.md L1 packages list - Fix LifecycleEventsTest: remove dependency on McpToolHandler interface (lives in core-mcp, not needed since McpToolsRegistering stores class name strings) - Run Laravel Pint to fix PSR-12 violations across all source and test files - Add missing declare(strict_types=1) to 18 PHP files (tests, seeders, Layout.php, GenerateServiceOgImages.php) Co-Authored-By: Virgil <virgil@lethean.io>
148 lines
4.5 KiB
PHP
148 lines
4.5 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Core PHP Framework
|
|
*
|
|
* Licensed under the European Union Public Licence (EUPL) v1.2.
|
|
* See LICENSE file for details.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Core\Console\Commands;
|
|
|
|
use Core\Mail\EmailShieldStat;
|
|
use Illuminate\Console\Command;
|
|
use Symfony\Component\Console\Completion\CompletionInput;
|
|
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
|
|
|
/**
|
|
* Prune old Email Shield statistics records.
|
|
*
|
|
* Removes records older than the specified retention period to prevent
|
|
* unbounded table growth. Should be scheduled to run daily.
|
|
*
|
|
* Usage:
|
|
* php artisan email-shield:prune
|
|
* php artisan email-shield:prune --days=30
|
|
*
|
|
* Scheduling (in app/Console/Kernel.php):
|
|
* $schedule->command('email-shield:prune')->daily();
|
|
*/
|
|
class PruneEmailShieldStatsCommand extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*/
|
|
protected $signature = 'email-shield:prune
|
|
{--days= : Number of days to retain (default: from config or 90)}
|
|
{--dry-run : Show what would be deleted without actually deleting}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*/
|
|
protected $description = 'Prune old Email Shield statistics records';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle(): int
|
|
{
|
|
$days = $this->getRetentionDays();
|
|
$dryRun = $this->option('dry-run');
|
|
|
|
$this->newLine();
|
|
$this->components->info('Email Shield Stats Cleanup');
|
|
$this->newLine();
|
|
|
|
// Get count of records that would be deleted
|
|
$cutoffDate = now()->subDays($days)->format('Y-m-d');
|
|
$recordsToDelete = EmailShieldStat::query()
|
|
->where('date', '<', $cutoffDate)
|
|
->count();
|
|
|
|
// Show current state table
|
|
$this->components->twoColumnDetail('<fg=gray;options=bold>Configuration</>', '');
|
|
$this->components->twoColumnDetail('Retention period', "<fg=cyan>{$days} days</>");
|
|
$this->components->twoColumnDetail('Cutoff date', "<fg=cyan>{$cutoffDate}</>");
|
|
$this->components->twoColumnDetail('Records to delete', $recordsToDelete > 0
|
|
? "<fg=yellow>{$recordsToDelete}</>"
|
|
: '<fg=green>0</>');
|
|
$this->newLine();
|
|
|
|
if ($recordsToDelete === 0) {
|
|
$this->components->info('No records older than the retention period found.');
|
|
$this->newLine();
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
if ($dryRun) {
|
|
$this->components->warn('Dry run mode - no records were deleted.');
|
|
$this->newLine();
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
// Show progress for deletion
|
|
$this->components->task(
|
|
"Deleting {$recordsToDelete} old records",
|
|
function () use ($days) {
|
|
EmailShieldStat::pruneOldRecords($days);
|
|
|
|
return true;
|
|
}
|
|
);
|
|
|
|
$this->newLine();
|
|
$this->components->info("Successfully deleted {$recordsToDelete} records older than {$days} days.");
|
|
$this->newLine();
|
|
|
|
// Show remaining stats
|
|
$remaining = EmailShieldStat::getRecordCount();
|
|
$oldest = EmailShieldStat::getOldestRecordDate();
|
|
|
|
$this->components->twoColumnDetail('<fg=gray;options=bold>Current State</>', '');
|
|
$this->components->twoColumnDetail('Remaining records', "<fg=cyan>{$remaining}</>");
|
|
if ($oldest) {
|
|
$this->components->twoColumnDetail('Oldest record', "<fg=cyan>{$oldest->format('Y-m-d')}</>");
|
|
}
|
|
$this->newLine();
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Get the retention period in days from option, config, or default.
|
|
*/
|
|
protected function getRetentionDays(): int
|
|
{
|
|
// First check command option
|
|
$days = $this->option('days');
|
|
if ($days !== null) {
|
|
return (int) $days;
|
|
}
|
|
|
|
// Then check config
|
|
$configDays = config('core.email_shield.retention_days');
|
|
if ($configDays !== null) {
|
|
return (int) $configDays;
|
|
}
|
|
|
|
// Default to 90 days
|
|
return 90;
|
|
}
|
|
|
|
/**
|
|
* Get shell completion suggestions for options.
|
|
*/
|
|
public function complete(
|
|
CompletionInput $input,
|
|
CompletionSuggestions $suggestions
|
|
): void {
|
|
if ($input->mustSuggestOptionValuesFor('days')) {
|
|
// Suggest common retention periods
|
|
$suggestions->suggestValues(['7', '14', '30', '60', '90', '180', '365']);
|
|
}
|
|
}
|
|
}
|