210 lines
7.2 KiB
PHP
210 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Commands;
|
|
|
|
use CodeIgniter\CLI\BaseCommand;
|
|
use CodeIgniter\CLI\CLI;
|
|
use App\Models\ActivityLogModel;
|
|
use App\Models\UserModel;
|
|
|
|
class SendActivityDigest extends BaseCommand
|
|
{
|
|
protected $group = 'Activity';
|
|
protected $name = 'activity:digest';
|
|
protected $description = 'Send activity log digest email to admin users (daily/weekly/monthly)';
|
|
protected $usage = 'activity:digest [daily|weekly|monthly]';
|
|
protected $arguments = [
|
|
'period' => 'Digest period: daily, weekly, or monthly (default: daily)',
|
|
];
|
|
|
|
public function run(array $params = [])
|
|
{
|
|
$period = $params[0] ?? 'daily';
|
|
|
|
if (!in_array($period, ['daily', 'weekly', 'monthly'])) {
|
|
CLI::error('Invalid period. Use: daily, weekly, or monthly');
|
|
return;
|
|
}
|
|
|
|
$activityModel = new ActivityLogModel();
|
|
$userModel = new UserModel();
|
|
|
|
// Determine date range
|
|
$startDate = match($period) {
|
|
'daily' => date('Y-m-d H:i:s', strtotime('-1 day')),
|
|
'weekly' => date('Y-m-d H:i:s', strtotime('-7 days')),
|
|
'monthly' => date('Y-m-d H:i:s', strtotime('-30 days')),
|
|
default => date('Y-m-d H:i:s', strtotime('-1 day')),
|
|
};
|
|
|
|
// Get activity summary for the period
|
|
$db = \Config\Database::connect();
|
|
$logs = $db->table('activity_logs')
|
|
->where('activity_at >=', $startDate)
|
|
->orderBy('activity_at', 'DESC')
|
|
->get()
|
|
->getResultArray();
|
|
|
|
if (empty($logs)) {
|
|
CLI::write('No activity found for ' . $period . ' digest', 'yellow');
|
|
return;
|
|
}
|
|
|
|
// Get admin users
|
|
$admins = $userModel->where('role', 'admin')->findAll();
|
|
|
|
if (empty($admins)) {
|
|
CLI::error('No admin users found to send digest to');
|
|
return;
|
|
}
|
|
|
|
// Send email to each admin
|
|
$email = service('email');
|
|
$emailConfig = config('Email');
|
|
|
|
$successCount = 0;
|
|
$failCount = 0;
|
|
|
|
foreach ($admins as $admin) {
|
|
$html = $this->generateDigestHTML($logs, $period, $admin);
|
|
|
|
$email->setFrom($emailConfig->fromEmail, $emailConfig->fromName)
|
|
->setTo($admin['email'])
|
|
->setSubject(ucfirst($period) . ' Activity Digest - ' . date('Y-m-d'))
|
|
->setMessage($html);
|
|
|
|
if ($email->send(false)) {
|
|
$successCount++;
|
|
CLI::write('Email sent to: ' . $admin['email'], 'green');
|
|
} else {
|
|
$failCount++;
|
|
CLI::error('Failed to send email to: ' . $admin['email']);
|
|
}
|
|
|
|
$email->clear();
|
|
}
|
|
|
|
CLI::write("\nDigest email summary:", 'cyan');
|
|
CLI::write('Sent: ' . $successCount, 'green');
|
|
CLI::write('Failed: ' . $failCount, 'red');
|
|
}
|
|
|
|
protected function generateDigestHTML($logs, $period, $admin)
|
|
{
|
|
$totalActions = count($logs);
|
|
|
|
// Group by action
|
|
$byAction = [];
|
|
foreach ($logs as $log) {
|
|
$action = $log['action'];
|
|
$byAction[$action] = ($byAction[$action] ?? 0) + 1;
|
|
}
|
|
|
|
// Get critical actions
|
|
$criticalActions = array_filter($logs, function($log) {
|
|
return stripos($log['action'], 'delete') !== false;
|
|
});
|
|
|
|
$actionTypeCount = count($byAction);
|
|
$criticalActionCount = count($criticalActions);
|
|
|
|
$html = <<<HTML
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<style>
|
|
body { font-family: Arial, sans-serif; color: #333; }
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
.header { background: #667eea; color: white; padding: 20px; border-radius: 8px 8px 0 0; }
|
|
.content { background: #f9fafb; padding: 20px; border-radius: 0 0 8px 8px; }
|
|
.summary-cards { display: flex; gap: 10px; margin: 20px 0; }
|
|
.card { background: white; padding: 15px; border-radius: 5px; flex: 1; border-left: 4px solid #667eea; }
|
|
.card-value { font-size: 24px; font-weight: bold; }
|
|
.card-label { font-size: 12px; color: #666; }
|
|
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
|
|
th { background: #e5e7eb; padding: 10px; text-align: left; }
|
|
td { border-bottom: 1px solid #e5e7eb; padding: 10px; }
|
|
.critical { color: #dc2626; font-weight: bold; }
|
|
.footer { font-size: 12px; color: #999; margin-top: 20px; text-align: center; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>Activity Digest Report</h1>
|
|
<p>Dear {$admin['first_name']}, here is your {$period} activity summary</p>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="summary-cards">
|
|
<div class="card">
|
|
<div class="card-value">{$totalActions}</div>
|
|
<div class="card-label">Total Actions</div>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-value">{$actionTypeCount}</div>
|
|
<div class="card-label">Action Types</div>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-value">{$criticalActionCount}</div>
|
|
<div class="card-label">Critical Actions</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Top Actions</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Action</th>
|
|
<th>Count</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
HTML;
|
|
|
|
arsort($byAction);
|
|
foreach (array_slice($byAction, 0, 10) as $action => $count) {
|
|
$isCritical = stripos($action, 'delete') !== false ? 'class="critical"' : '';
|
|
$html .= "<tr {$isCritical}><td>{$action}</td><td>{$count}</td></tr>";
|
|
}
|
|
|
|
$html .= <<<HTML
|
|
</tbody>
|
|
</table>
|
|
|
|
<h2>Critical Actions (Deletions)</h2>
|
|
HTML;
|
|
|
|
if (!empty($criticalActions)) {
|
|
$html .= '<table><thead><tr><th>Time</th><th>User</th><th>Action</th><th>Target</th></tr></thead><tbody>';
|
|
foreach (array_slice($criticalActions, 0, 20) as $log) {
|
|
$userId = $log['activity_user_id'] ?? 'System';
|
|
$targetType = $log['target_user_type'] ?? '-';
|
|
$html .= "<tr>";
|
|
$html .= "<td>" . date('Y-m-d H:i', strtotime($log['activity_at'])) . "</td>";
|
|
$html .= "<td>{$userId}</td>";
|
|
$html .= "<td class='critical'>{$log['action']}</td>";
|
|
$html .= "<td>{$targetType}</td>";
|
|
$html .= "</tr>";
|
|
}
|
|
$html .= '</tbody></table>';
|
|
} else {
|
|
$html .= '<p style="color: #22c55e;">No critical actions detected.</p>';
|
|
}
|
|
|
|
$html .= <<<HTML
|
|
<div class="footer">
|
|
<p>This is an automated email. Please do not reply to this message.</p>
|
|
<p>Generated on {date('Y-m-d H:i:s')}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
|
|
return $html;
|
|
}
|
|
}
|