102 lines
2.8 KiB
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();
|
|
}
|
|
}
|