doctor-appointment-system/app/Commands/SendActivityDigest.php
2026-04-17 12:28:30 +05:30

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;
}
}