349 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Notifications\Server;
 | 
						|
 | 
						|
use App\Models\Server;
 | 
						|
use App\Notifications\CustomEmailNotification;
 | 
						|
use App\Notifications\Dto\DiscordMessage;
 | 
						|
use App\Notifications\Dto\PushoverMessage;
 | 
						|
use App\Notifications\Dto\SlackMessage;
 | 
						|
use Illuminate\Notifications\Messages\MailMessage;
 | 
						|
 | 
						|
class ServerPatchCheck extends CustomEmailNotification
 | 
						|
{
 | 
						|
    public string $serverUrl;
 | 
						|
 | 
						|
    public function __construct(public Server $server, public array $patchData)
 | 
						|
    {
 | 
						|
        $this->onQueue('high');
 | 
						|
        $this->serverUrl = route('server.security.patches', ['server_uuid' => $this->server->uuid]);
 | 
						|
        if (isDev()) {
 | 
						|
            $this->serverUrl = 'https://staging-but-dev.coolify.io/server/'.$this->server->uuid.'/security/patches';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function via(object $notifiable): array
 | 
						|
    {
 | 
						|
        return $notifiable->getEnabledChannels('server_patch');
 | 
						|
    }
 | 
						|
 | 
						|
    public function toMail($notifiable = null): MailMessage
 | 
						|
    {
 | 
						|
        $mail = new MailMessage;
 | 
						|
 | 
						|
        // Handle error case
 | 
						|
        if (isset($this->patchData['error'])) {
 | 
						|
            $mail->subject("Coolify: [ERROR] Failed to check patches on {$this->server->name}");
 | 
						|
            $mail->view('emails.server-patches-error', [
 | 
						|
                'name' => $this->server->name,
 | 
						|
                'error' => $this->patchData['error'],
 | 
						|
                'osId' => $this->patchData['osId'] ?? 'unknown',
 | 
						|
                'package_manager' => $this->patchData['package_manager'] ?? 'unknown',
 | 
						|
                'server_url' => $this->serverUrl,
 | 
						|
            ]);
 | 
						|
 | 
						|
            return $mail;
 | 
						|
        }
 | 
						|
 | 
						|
        $totalUpdates = $this->patchData['total_updates'] ?? 0;
 | 
						|
        $mail->subject("Coolify: [ACTION REQUIRED] {$totalUpdates} server patches available on {$this->server->name}");
 | 
						|
        $mail->view('emails.server-patches', [
 | 
						|
            'name' => $this->server->name,
 | 
						|
            'total_updates' => $totalUpdates,
 | 
						|
            'updates' => $this->patchData['updates'] ?? [],
 | 
						|
            'osId' => $this->patchData['osId'] ?? 'unknown',
 | 
						|
            'package_manager' => $this->patchData['package_manager'] ?? 'unknown',
 | 
						|
            'server_url' => $this->serverUrl,
 | 
						|
        ]);
 | 
						|
 | 
						|
        return $mail;
 | 
						|
    }
 | 
						|
 | 
						|
    public function toDiscord(): DiscordMessage
 | 
						|
    {
 | 
						|
        // Handle error case
 | 
						|
        if (isset($this->patchData['error'])) {
 | 
						|
            $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
            $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
            $error = $this->patchData['error'];
 | 
						|
 | 
						|
            $description = "**Failed to check for updates** on server {$this->server->name}\n\n";
 | 
						|
            $description .= "**Error Details:**\n";
 | 
						|
            $description .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
            $description .= "• Package Manager: {$packageManager}\n";
 | 
						|
            $description .= "• Error: {$error}\n\n";
 | 
						|
            $description .= "[Manage Server]($this->serverUrl)";
 | 
						|
 | 
						|
            return new DiscordMessage(
 | 
						|
                title: ':x: Coolify: [ERROR] Failed to check patches on '.$this->server->name,
 | 
						|
                description: $description,
 | 
						|
                color: DiscordMessage::errorColor(),
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        $totalUpdates = $this->patchData['total_updates'] ?? 0;
 | 
						|
        $updates = $this->patchData['updates'] ?? [];
 | 
						|
        $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
        $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
 | 
						|
        $description = "**{$totalUpdates} package updates** available for server {$this->server->name}\n\n";
 | 
						|
        $description .= "**Summary:**\n";
 | 
						|
        $description .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
        $description .= "• Package Manager: {$packageManager}\n";
 | 
						|
        $description .= "• Total Updates: {$totalUpdates}\n\n";
 | 
						|
 | 
						|
        // Show first few packages
 | 
						|
        if (count($updates) > 0) {
 | 
						|
            $description .= "**Sample Updates:**\n";
 | 
						|
            $sampleUpdates = array_slice($updates, 0, 5);
 | 
						|
            foreach ($sampleUpdates as $update) {
 | 
						|
                $description .= "• {$update['package']}: {$update['current_version']} → {$update['new_version']}\n";
 | 
						|
            }
 | 
						|
            if (count($updates) > 5) {
 | 
						|
                $description .= '• ... and '.(count($updates) - 5)." more packages\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // Check for critical packages
 | 
						|
            $criticalPackages = collect($updates)->filter(function ($update) {
 | 
						|
                return str_contains(strtolower($update['package']), 'docker') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'kernel') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'openssh') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'ssl');
 | 
						|
            });
 | 
						|
 | 
						|
            if ($criticalPackages->count() > 0) {
 | 
						|
                $description .= "\n **Critical packages detected** ({$criticalPackages->count()} packages may require restarts)";
 | 
						|
            }
 | 
						|
            $description .= "\n [Manage Server Patches]($this->serverUrl)";
 | 
						|
        }
 | 
						|
 | 
						|
        return new DiscordMessage(
 | 
						|
            title: ':warning: Coolify: [ACTION REQUIRED] Server patches available on '.$this->server->name,
 | 
						|
            description: $description,
 | 
						|
            color: DiscordMessage::errorColor(),
 | 
						|
        );
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public function toTelegram(): array
 | 
						|
    {
 | 
						|
        // Handle error case
 | 
						|
        if (isset($this->patchData['error'])) {
 | 
						|
            $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
            $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
            $error = $this->patchData['error'];
 | 
						|
 | 
						|
            $message = "❌ Coolify: [ERROR] Failed to check patches on {$this->server->name}!\n\n";
 | 
						|
            $message .= "📊 Error Details:\n";
 | 
						|
            $message .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
            $message .= "• Package Manager: {$packageManager}\n";
 | 
						|
            $message .= "• Error: {$error}\n\n";
 | 
						|
 | 
						|
            return [
 | 
						|
                'message' => $message,
 | 
						|
                'buttons' => [
 | 
						|
                    [
 | 
						|
                        'text' => 'Manage Server',
 | 
						|
                        'url' => $this->serverUrl,
 | 
						|
                    ],
 | 
						|
                ],
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        $totalUpdates = $this->patchData['total_updates'] ?? 0;
 | 
						|
        $updates = $this->patchData['updates'] ?? [];
 | 
						|
        $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
        $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
 | 
						|
        $message = "🔧 Coolify: [ACTION REQUIRED] {$totalUpdates} server patches available on {$this->server->name}!\n\n";
 | 
						|
        $message .= "📊 Summary:\n";
 | 
						|
        $message .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
        $message .= "• Package Manager: {$packageManager}\n";
 | 
						|
        $message .= "• Total Updates: {$totalUpdates}\n\n";
 | 
						|
 | 
						|
        if (count($updates) > 0) {
 | 
						|
            $message .= "📦 Sample Updates:\n";
 | 
						|
            $sampleUpdates = array_slice($updates, 0, 5);
 | 
						|
            foreach ($sampleUpdates as $update) {
 | 
						|
                $message .= "• {$update['package']}: {$update['current_version']} → {$update['new_version']}\n";
 | 
						|
            }
 | 
						|
            if (count($updates) > 5) {
 | 
						|
                $message .= '• ... and '.(count($updates) - 5)." more packages\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // Check for critical packages
 | 
						|
            $criticalPackages = collect($updates)->filter(function ($update) {
 | 
						|
                return str_contains(strtolower($update['package']), 'docker') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'kernel') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'openssh') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'ssl');
 | 
						|
            });
 | 
						|
 | 
						|
            if ($criticalPackages->count() > 0) {
 | 
						|
                $message .= "\n⚠️ Critical packages detected: {$criticalPackages->count()} packages may require restarts\n";
 | 
						|
                foreach ($criticalPackages->take(3) as $package) {
 | 
						|
                    $message .= "• {$package['package']}: {$package['current_version']} → {$package['new_version']}\n";
 | 
						|
                }
 | 
						|
                if ($criticalPackages->count() > 3) {
 | 
						|
                    $message .= '• ... and '.($criticalPackages->count() - 3)." more critical packages\n";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            'message' => $message,
 | 
						|
            'buttons' => [
 | 
						|
                [
 | 
						|
                    'text' => 'Manage Server Patches',
 | 
						|
                    'url' => $this->serverUrl,
 | 
						|
                ],
 | 
						|
            ],
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    public function toPushover(): PushoverMessage
 | 
						|
    {
 | 
						|
        // Handle error case
 | 
						|
        if (isset($this->patchData['error'])) {
 | 
						|
            $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
            $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
            $error = $this->patchData['error'];
 | 
						|
 | 
						|
            $message = "[ERROR] Failed to check patches on {$this->server->name}!\n\n";
 | 
						|
            $message .= "Error Details:\n";
 | 
						|
            $message .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
            $message .= "• Package Manager: {$packageManager}\n";
 | 
						|
            $message .= "• Error: {$error}\n\n";
 | 
						|
 | 
						|
            return new PushoverMessage(
 | 
						|
                title: 'Server patch check failed',
 | 
						|
                level: 'error',
 | 
						|
                message: $message,
 | 
						|
                buttons: [
 | 
						|
                    [
 | 
						|
                        'text' => 'Manage Server',
 | 
						|
                        'url' => $this->serverUrl,
 | 
						|
                    ],
 | 
						|
                ],
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        $totalUpdates = $this->patchData['total_updates'] ?? 0;
 | 
						|
        $updates = $this->patchData['updates'] ?? [];
 | 
						|
        $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
        $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
 | 
						|
        $message = "[ACTION REQUIRED] {$totalUpdates} server patches available on {$this->server->name}!\n\n";
 | 
						|
        $message .= "Summary:\n";
 | 
						|
        $message .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
        $message .= "• Package Manager: {$packageManager}\n";
 | 
						|
        $message .= "• Total Updates: {$totalUpdates}\n\n";
 | 
						|
 | 
						|
        if (count($updates) > 0) {
 | 
						|
            $message .= "Sample Updates:\n";
 | 
						|
            $sampleUpdates = array_slice($updates, 0, 3);
 | 
						|
            foreach ($sampleUpdates as $update) {
 | 
						|
                $message .= "• {$update['package']}: {$update['current_version']} → {$update['new_version']}\n";
 | 
						|
            }
 | 
						|
            if (count($updates) > 3) {
 | 
						|
                $message .= '• ... and '.(count($updates) - 3)." more packages\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // Check for critical packages
 | 
						|
            $criticalPackages = collect($updates)->filter(function ($update) {
 | 
						|
                return str_contains(strtolower($update['package']), 'docker') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'kernel') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'openssh') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'ssl');
 | 
						|
            });
 | 
						|
 | 
						|
            if ($criticalPackages->count() > 0) {
 | 
						|
                $message .= "\nCritical packages detected: {$criticalPackages->count()} may require restarts";
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return new PushoverMessage(
 | 
						|
            title: 'Server patches available',
 | 
						|
            level: 'error',
 | 
						|
            message: $message,
 | 
						|
            buttons: [
 | 
						|
                [
 | 
						|
                    'text' => 'Manage Server Patches',
 | 
						|
                    'url' => $this->serverUrl,
 | 
						|
                ],
 | 
						|
            ],
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    public function toSlack(): SlackMessage
 | 
						|
    {
 | 
						|
        // Handle error case
 | 
						|
        if (isset($this->patchData['error'])) {
 | 
						|
            $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
            $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
            $error = $this->patchData['error'];
 | 
						|
 | 
						|
            $description = "Failed to check patches on '{$this->server->name}'!\n\n";
 | 
						|
            $description .= "*Error Details:*\n";
 | 
						|
            $description .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
            $description .= "• Package Manager: {$packageManager}\n";
 | 
						|
            $description .= "• Error: `{$error}`\n\n";
 | 
						|
            $description .= "\n:link: <{$this->serverUrl}|Manage Server>";
 | 
						|
 | 
						|
            return new SlackMessage(
 | 
						|
                title: 'Coolify: [ERROR] Server patch check failed',
 | 
						|
                description: $description,
 | 
						|
                color: SlackMessage::errorColor()
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        $totalUpdates = $this->patchData['total_updates'] ?? 0;
 | 
						|
        $updates = $this->patchData['updates'] ?? [];
 | 
						|
        $osId = $this->patchData['osId'] ?? 'unknown';
 | 
						|
        $packageManager = $this->patchData['package_manager'] ?? 'unknown';
 | 
						|
 | 
						|
        $description = "{$totalUpdates} server patches available on '{$this->server->name}'!\n\n";
 | 
						|
        $description .= "*Summary:*\n";
 | 
						|
        $description .= '• OS: '.ucfirst($osId)."\n";
 | 
						|
        $description .= "• Package Manager: {$packageManager}\n";
 | 
						|
        $description .= "• Total Updates: {$totalUpdates}\n\n";
 | 
						|
 | 
						|
        if (count($updates) > 0) {
 | 
						|
            $description .= "*Sample Updates:*\n";
 | 
						|
            $sampleUpdates = array_slice($updates, 0, 5);
 | 
						|
            foreach ($sampleUpdates as $update) {
 | 
						|
                $description .= "• `{$update['package']}`: {$update['current_version']} → {$update['new_version']}\n";
 | 
						|
            }
 | 
						|
            if (count($updates) > 5) {
 | 
						|
                $description .= '• ... and '.(count($updates) - 5)." more packages\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // Check for critical packages
 | 
						|
            $criticalPackages = collect($updates)->filter(function ($update) {
 | 
						|
                return str_contains(strtolower($update['package']), 'docker') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'kernel') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'openssh') ||
 | 
						|
                    str_contains(strtolower($update['package']), 'ssl');
 | 
						|
            });
 | 
						|
 | 
						|
            if ($criticalPackages->count() > 0) {
 | 
						|
                $description .= "\n:warning: *Critical packages detected:* {$criticalPackages->count()} packages may require restarts\n";
 | 
						|
                foreach ($criticalPackages->take(3) as $package) {
 | 
						|
                    $description .= "• `{$package['package']}`: {$package['current_version']} → {$package['new_version']}\n";
 | 
						|
                }
 | 
						|
                if ($criticalPackages->count() > 3) {
 | 
						|
                    $description .= '• ... and '.($criticalPackages->count() - 3)." more critical packages\n";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $description .= "\n:link: <{$this->serverUrl}|Manage Server Patches>";
 | 
						|
 | 
						|
        return new SlackMessage(
 | 
						|
            title: 'Coolify: [ACTION REQUIRED] Server patches available',
 | 
						|
            description: $description,
 | 
						|
            color: SlackMessage::errorColor()
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 |