186 lines
6.3 KiB
PHP
186 lines
6.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\DnsSetting;
|
|
use App\Models\NotificationLog;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
class AdminNotificationService
|
|
{
|
|
public static function send(string $type, string $subject, string $message, array $context = []): bool
|
|
{
|
|
$settingKey = "notify_{$type}";
|
|
if (!DnsSetting::get($settingKey, true)) {
|
|
// Log as skipped (notification type disabled)
|
|
self::logNotification($type, $subject, $message, [], 'skipped', $context, 'Notification type disabled');
|
|
return false;
|
|
}
|
|
|
|
$recipients = DnsSetting::get('admin_email_recipients', '');
|
|
if (empty($recipients)) {
|
|
Log::warning("AdminNotification: No recipients configured for {$type}");
|
|
self::logNotification($type, $subject, $message, [], 'skipped', $context, 'No recipients configured');
|
|
return false;
|
|
}
|
|
|
|
$recipientList = array_filter(array_map('trim', explode(',', $recipients)));
|
|
if (empty($recipientList)) {
|
|
self::logNotification($type, $subject, $message, [], 'skipped', $context, 'No valid recipients');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$hostname = gethostname();
|
|
$fullMessage = $message . "\n\n---\n" .
|
|
"Server: {$hostname}\n" .
|
|
"Time: " . now()->format('Y-m-d H:i:s') . "\n";
|
|
|
|
if (!empty($context)) {
|
|
$fullMessage .= "\nDetails:\n";
|
|
foreach ($context as $key => $value) {
|
|
$fullMessage .= "- {$key}: {$value}\n";
|
|
}
|
|
}
|
|
|
|
$sender = "webmaster@{$hostname}";
|
|
|
|
Mail::raw($fullMessage, function ($mail) use ($recipientList, $sender, $subject, $hostname) {
|
|
$mail->from($sender, "Jabali Panel ({$hostname})");
|
|
$mail->to($recipientList);
|
|
$mail->subject("[Jabali] {$subject}");
|
|
});
|
|
|
|
Log::info("AdminNotification sent: {$type} - {$subject}");
|
|
self::logNotification($type, $subject, $message, $recipientList, 'sent', $context);
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
Log::error("AdminNotification failed: {$e->getMessage()}");
|
|
self::logNotification($type, $subject, $message, $recipientList, 'failed', $context, $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log a notification to the database.
|
|
*/
|
|
protected static function logNotification(
|
|
string $type,
|
|
string $subject,
|
|
string $message,
|
|
array $recipients,
|
|
string $status,
|
|
?array $context = null,
|
|
?string $error = null
|
|
): void {
|
|
try {
|
|
NotificationLog::log($type, $subject, $message, $recipients, $status, $context, $error);
|
|
} catch (\Exception $e) {
|
|
// Don't let logging failures break the notification system
|
|
Log::error("Failed to log notification: {$e->getMessage()}");
|
|
}
|
|
}
|
|
|
|
public static function sslError(string $domain, string $error): bool
|
|
{
|
|
return self::send(
|
|
'ssl_errors',
|
|
"SSL Certificate Error: {$domain}",
|
|
"An SSL certificate error occurred for domain: {$domain}",
|
|
['Domain' => $domain, 'Error' => $error]
|
|
);
|
|
}
|
|
|
|
public static function sslExpiring(string $domain, int $daysUntilExpiry): bool
|
|
{
|
|
return self::send(
|
|
'ssl_errors',
|
|
"SSL Certificate Expiring: {$domain}",
|
|
"The SSL certificate for {$domain} will expire in {$daysUntilExpiry} days.",
|
|
['Domain' => $domain, 'Days Until Expiry' => $daysUntilExpiry]
|
|
);
|
|
}
|
|
|
|
public static function backupFailure(string $backupName, string $error): bool
|
|
{
|
|
return self::send(
|
|
'backup_failures',
|
|
"Backup Failed: {$backupName}",
|
|
"A scheduled backup has failed.",
|
|
['Backup Name' => $backupName, 'Error' => $error]
|
|
);
|
|
}
|
|
|
|
public static function backupSuccess(string $backupName, int $sizeBytes, ?string $destination = null): bool
|
|
{
|
|
$size = self::formatBytes($sizeBytes);
|
|
$context = [
|
|
'Backup Name' => $backupName,
|
|
'Size' => $size,
|
|
];
|
|
if ($destination) {
|
|
$context['Destination'] = $destination;
|
|
}
|
|
|
|
return self::send(
|
|
'backup_success',
|
|
"Backup Completed: {$backupName}",
|
|
"A backup has completed successfully.",
|
|
$context
|
|
);
|
|
}
|
|
|
|
protected static function formatBytes(int $bytes, int $precision = 2): string
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$bytes = max($bytes, 0);
|
|
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
|
$pow = min($pow, count($units) - 1);
|
|
$bytes /= pow(1024, $pow);
|
|
return round($bytes, $precision) . ' ' . $units[$pow];
|
|
}
|
|
|
|
public static function diskQuotaWarning(string $username, int $usagePercent): bool
|
|
{
|
|
return self::send(
|
|
'disk_quota',
|
|
"Disk Quota Warning: {$username}",
|
|
"User {$username} has reached {$usagePercent}% of their disk quota.",
|
|
['Username' => $username, 'Usage' => "{$usagePercent}%"]
|
|
);
|
|
}
|
|
|
|
public static function loginFailure(string $ip, string $service, int $attempts): bool
|
|
{
|
|
return self::send(
|
|
'login_failures',
|
|
"Login Failure Alert: {$ip}",
|
|
"Multiple failed login attempts detected.",
|
|
['IP Address' => $ip, 'Service' => $service, 'Attempts' => $attempts]
|
|
);
|
|
}
|
|
|
|
public static function systemUpdatesAvailable(int $updateCount): bool
|
|
{
|
|
return self::send(
|
|
'system_updates',
|
|
"System Updates Available",
|
|
"{$updateCount} system update(s) are available for your Jabali Panel.",
|
|
['Available Updates' => $updateCount]
|
|
);
|
|
}
|
|
|
|
public static function sshLogin(string $username, string $ip, string $method = 'password'): bool
|
|
{
|
|
return self::send(
|
|
'ssh_logins',
|
|
"SSH Login: {$username}",
|
|
"Successful SSH login detected.",
|
|
['Username' => $username, 'IP Address' => $ip, 'Auth Method' => $method]
|
|
);
|
|
}
|
|
}
|