store/app/Jobs/SendPushNotificationJob.php

102 lines
2.8 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\PushSubscription;
use App\Models\SystemConfiguration;
use App\Support\Media\MediaPresenter;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Minishlink\WebPush\Subscription;
use Minishlink\WebPush\WebPush;
class SendPushNotificationJob implements ShouldQueue
{
use Queueable;
public function __construct(
private readonly string $title,
private readonly string $body,
private readonly string $url = '/admin/dashboard',
private readonly array $roles = [],
private readonly ?int $userId = null,
) {}
public function handle(): void
{
$subscriptions = $this->resolveSubscriptions();
if ($subscriptions->isEmpty()) {
return;
}
$icon = $this->resolveIcon();
$webPush = new WebPush([
'VAPID' => [
'subject' => config('app.url'),
'publicKey' => config('webpush.vapid.public_key'),
'privateKey' => config('webpush.vapid.private_key'),
],
]);
$payload = json_encode([
'title' => $this->title,
'body' => $this->body,
'icon' => $icon,
'url' => $this->url,
]);
foreach ($subscriptions as $subscription) {
$sub = Subscription::create([
'endpoint' => $subscription->endpoint,
'publicKey' => $subscription->public_key,
'authToken' => $subscription->auth_token,
'contentEncoding' => 'aes128gcm',
]);
$webPush->queueNotification($sub, $payload);
}
$expiredEndpoints = [];
foreach ($webPush->flush() as $report) {
if (! $report->isSuccess()) {
$expiredEndpoints[] = (string) $report->getRequest()->getUri();
}
}
if (! empty($expiredEndpoints)) {
PushSubscription::whereIn('endpoint', $expiredEndpoints)->delete();
}
}
private function resolveIcon(): string
{
try {
$configuration = SystemConfiguration::instance();
$configuration->load('media');
$logo = MediaPresenter::first($configuration, 'logo');
return $logo['url'] ?? config('app.url').'/assets/logo.png';
} catch (\Throwable) {
return config('app.url').'/assets/logo.png';
}
}
private function resolveSubscriptions()
{
$query = PushSubscription::query();
if ($this->userId !== null) {
$query->where('user_id', $this->userId);
} elseif (! empty($this->roles)) {
$query->whereHas('user', function ($q): void {
$q->whereHas('roles', fn ($r) => $r->whereIn('name', $this->roles));
});
}
return $query->get();
}
}