persistNotifications(); $this->sendWebPush(); } private function persistNotifications(): void { $userIds = $this->resolveUserIds(); foreach ($userIds as $uid) { Notification::create([ 'user_id' => $uid, 'title' => $this->title, 'body' => $this->body, 'url' => $this->url, ]); } } private function sendWebPush(): 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->isSubscriptionExpired()) { $expiredEndpoints[] = $report->getEndpoint(); } } 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 (Builder $userQuery): void { $userQuery->whereHas('roles', fn (Builder $roleQuery) => $roleQuery->whereIn('name', $this->roles)); }); } return $query->get(); } /** * @return list */ private function resolveUserIds(): array { if ($this->userId !== null) { return [$this->userId]; } if (! empty($this->roles)) { return User::query() ->whereHas('roles', fn (Builder $q) => $q->whereIn('name', $this->roles)) ->pluck('id') ->all(); } return User::query()->pluck('id')->all(); } }