Skip to content

Commit 33abb54

Browse files
committed
WIP
1 parent e8abb5e commit 33abb54

File tree

9 files changed

+120
-66
lines changed

9 files changed

+120
-66
lines changed

app/Http/Controllers/PushController.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22

33
namespace App\Http\Controllers;
44

5+
use Illuminate\Http\JsonResponse;
56
use Illuminate\Http\Request;
7+
use Illuminate\Database\Eloquent\Builder;
68

79
class PushController extends Controller
810
{
9-
public function store(Request $request)
11+
/**
12+
* @param \Illuminate\Http\Request $request
13+
*
14+
* @return \Illuminate\Http\JsonResponse
15+
*/
16+
public function store(Request $request): JsonResponse
1017
{
1118
$request->validate([
1219
'endpoint' => 'required',
@@ -23,12 +30,33 @@ public function store(Request $request)
2330
return response()->json(['success' => true]);
2431
}
2532

26-
public function unsubscribe(Request $request)
33+
/**
34+
* @param \Illuminate\Http\Request $request
35+
*
36+
* @return \Illuminate\Http\JsonResponse
37+
*/
38+
public function check(Request $request): JsonResponse
2739
{
2840
$request->validate([
29-
'endpoint' => 'required',
30-
//'keys.auth' => 'required',
31-
//'keys.p256dh' => 'required',
41+
'endpoint' => 'required',
42+
]);
43+
44+
$exists = $request->user()->whereHas('pushSubscriptions', fn (Builder $query) =>
45+
$query->where('endpoint', $request->input('endpoint'))
46+
)->exists();
47+
48+
return response()->json(['exists' => $exists]);
49+
}
50+
51+
/**
52+
* @param \Illuminate\Http\Request $request
53+
*
54+
* @return \Illuminate\Http\JsonResponse
55+
*/
56+
public function unsubscribe(Request $request): JsonResponse
57+
{
58+
$request->validate([
59+
'endpoint' => 'required',
3260
]);
3361

3462
$request->user()->deletePushSubscription(

app/Notifications/CommentNotification.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ public function __construct(Comment $comment)
3939
*/
4040
public function via(User $user)
4141
{
42-
if ($user->id == $this->comment->author->id)
43-
{
44-
return [];
45-
}
4642
return [
4743
SiteChannel::class,
4844
WebPushChannel::class
@@ -66,10 +62,15 @@ public function toSite(User $user)
6662
->action($url, $this->comment->post->title);
6763
}
6864

69-
70-
public function toWebPush($notifiable, $notification)
65+
/**
66+
* @param \App\Models\User $user
67+
*
68+
* @return \NotificationChannels\WebPush\WebPushMessage
69+
*/
70+
public function toWebPush(User $user)
7171
{
72-
$url = route('post.show',$this->comment->post).'#'.dom_id($this->comment);
72+
$url = route('post.show', $this->comment->post) . '#' . dom_id($this->comment);
73+
7374
return (new WebPushMessage)
7475
->title('Комментарий к ваше публикации')
7576
->icon($this->comment->author->avatar)

app/Notifications/ReplyCommentNotification.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function via(User $user)
4141
{
4242
return [
4343
SiteChannel::class,
44-
WebPushChannel::class
44+
WebPushChannel::class,
4545
];
4646
}
4747

@@ -54,21 +54,28 @@ public function via(User $user)
5454
*/
5555
public function toSite(User $user)
5656
{
57-
$url = route('post.show',$this->reply->post).'#'.dom_id($this->reply);
57+
$url = route('post.show', $this->reply->post) . '#' . dom_id($this->reply);
5858
return (new SiteMessage())
5959
->title('ответил на ваш комментарий')
6060
->setCommentAuthor($this->reply->author->name)
6161
->img($this->reply->author->avatar)
6262
->action($url, $this->reply->post->title);
6363
}
64-
public function toWebPush($notifiable, $notification)
64+
65+
/**
66+
* @param \App\Models\User $user
67+
*
68+
* @return \NotificationChannels\WebPush\WebPushMessage
69+
*/
70+
public function toWebPush(User $user)
6571
{
66-
$url = route('post.show',$this->reply->post).'#'.dom_id($this->reply);
72+
$url = route('post.show', $this->reply->post) . '#' . dom_id($this->reply);
73+
6774
return (new WebPushMessage)
68-
->title('Пользователь '.$this->reply->author->name.' ответил на ваш комментарий')
75+
->title('Пользователь ' . $this->reply->author->name . ' ответил на ваш комментарий')
6976
->icon($this->reply->author->avatar)
7077
//->body('Пользователь '.$this->author->name." ответил на ваш комментарий")
71-
->action('посмотреть',$url)
78+
->action('посмотреть', $url)
7279
->vibrate([300, 200, 300])
7380
->options([
7481
'TTL' => 86400, // in seconds - 24 hours,

public/serviceworker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ self.addEventListener("fetch", event => {
4646
*/
4747
self.addEventListener('push', function (e) {
4848
if (!(self.Notification && self.Notification.permission === 'granted')) {
49-
//notifications aren't supported or permission not granted!
49+
console.warn("Notifications aren't supported or permission not granted!");
5050
return;
5151
}
5252

resources/js/controllers/webpush_controller.js

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import { Controller } from '@hotwired/stimulus';
1+
import {Controller} from '@hotwired/stimulus';
22

33
export default class extends Controller {
44
static values = {
5+
key: {
6+
type: String,
7+
default: 'BLc3xxVvQg8Q6Hlj-tIpllTBydYs08zcFCqriRrja_0QfdUWlHvQ1I_WAQjDe3to0p8K2aF1pcs9zknZF2N1tmA',
8+
},
59
errorSupported: {
610
type: String,
711
default: 'Push messaging is not supported',
@@ -11,31 +15,49 @@ export default class extends Controller {
1115
default: 'Permission denied',
1216
},
1317
};
14-
connect() {
1518

16-
this.checkSubscription();
19+
static targets = [
20+
"status"
21+
]
1722

23+
connect() {
24+
this.checkSubscription();
1825
}
19-
switching() {
2026

21-
if(document.getElementById('native_notifiable').checked){
27+
switching() {
28+
if (this.statusTarget.checked) {
2229
this.request();
23-
}else{
30+
} else {
2431
this.disablePushNotifications();
2532
}
2633
}
2734

28-
checkSubscription()
29-
{
30-
let switcher = document.getElementById('native_notifiable');
35+
checkSubscription() {
36+
let switcher = this.statusTarget;
3137
navigator.serviceWorker.ready.then(registration => {
3238
registration.pushManager.getSubscription().then(subscription => {
33-
console.log(subscription);
34-
if ( subscription === null) {
35-
switcher.checked=false;
39+
if (!subscription) {
40+
switcher.checked = false;
3641
return;
3742
}
38-
switcher.checked=true;
43+
44+
fetch('/push/check', {
45+
method: 'POST',
46+
headers: {
47+
'Content-Type': 'application/json',
48+
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').getAttribute('content')
49+
},
50+
body: JSON.stringify({
51+
endpoint: subscription.endpoint
52+
})
53+
})
54+
.then(response => response.json())
55+
.then(data => {
56+
switcher.checked = data.exists;
57+
})
58+
.catch((error) => {
59+
switcher.checked = false;
60+
});
3961
})
4062
});
4163

@@ -97,9 +119,7 @@ export default class extends Controller {
97119
subscribeUser(register) {
98120
const options = {
99121
userVisibleOnly: true,
100-
applicationServerKey: this.urlBase64ToUint8Array(
101-
'BE3lWGN-j0tamAkNA2Q-6DYCILTnZj5Q2kQaIByqdgDf0P9zZEhvCvZ0l-i1Z8LcIiDHUmX8RPdVEc1cos6wD50'
102-
),
122+
applicationServerKey: this.urlBase64ToUint8Array(this.keyValue),
103123
};
104124

105125
register.pushManager
@@ -112,6 +132,21 @@ export default class extends Controller {
112132
});
113133
}
114134

135+
// Convert a base64 string to a Uint8Array
136+
urlBase64ToUint8Array(base64String) {
137+
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
138+
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
139+
140+
const rawData = window.atob(base64);
141+
const outputArray = new Uint8Array(rawData.length);
142+
143+
for (let i = 0; i < rawData.length; ++i) {
144+
outputArray[i] = rawData.charCodeAt(i);
145+
}
146+
147+
return outputArray;
148+
}
149+
115150
// Subscribe the user
116151
disablePushNotifications() {
117152
navigator.serviceWorker.ready.then(registration => {
@@ -121,12 +156,11 @@ export default class extends Controller {
121156
}
122157

123158
subscription.unsubscribe().then(() => {
124-
const token = document.querySelector('meta[name=csrf-token]').getAttribute('content');
125159
fetch('/push/unsubscribe', {
126160
method: 'POST',
127161
headers: {
128162
'Content-Type': 'application/json',
129-
'X-CSRF-TOKEN': token
163+
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').getAttribute('content')
130164
},
131165
body: JSON.stringify({
132166
endpoint: subscription.endpoint
@@ -144,32 +178,15 @@ export default class extends Controller {
144178
});
145179
}
146180

147-
// Convert a base64 string to a Uint8Array
148-
urlBase64ToUint8Array(base64String) {
149-
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
150-
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
151-
152-
const rawData = window.atob(base64);
153-
const outputArray = new Uint8Array(rawData.length);
154-
155-
for (let i = 0; i < rawData.length; ++i) {
156-
outputArray[i] = rawData.charCodeAt(i);
157-
}
158-
159-
return outputArray;
160-
}
161-
162181
// Store the push subscription in the backend
163182
storePushSubscription(subscription) {
164-
const token = document.querySelector('meta[name=csrf-token]').getAttribute('content');
165-
166183
fetch('/push', {
167184
method: 'POST',
168185
body: JSON.stringify(subscription),
169186
headers: {
170187
Accept: 'application/json',
171188
'Content-Type': 'application/json',
172-
'X-CSRF-Token': token,
189+
'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').getAttribute('content'),
173190
},
174191
})
175192
.then((response) => {

resources/js/initializers/service-worker.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
if ('serviceWorker' in navigator) {
55
navigator.serviceWorker.register('/serviceworker.js').then(
66
(registration) => {
7-
window.EmotioServiceWorker = registration;
8-
console.log('ET: ServiceWorker registration successful with scope: ', registration.scope);
7+
window.LaravelServiceWorker = registration;
8+
console.log('Laravel.su: ServiceWorker registration successful with scope: ', registration.scope);
99
},
10-
(err) => console.log('ET: ServiceWorker registration failed: ', err)
10+
(err) => console.log('Laravel.su: ServiceWorker registration failed: ', err)
1111
);
1212

1313
navigator.serviceWorker.getRegistrations().then((registrations) => {

resources/views/components/header.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<x-container>
2-
<div class="row g-4 g-md-5 py-lg-5 justify-content-center {{ $attributes->get('align', 'align-items-center') }}">
2+
<div class="row g-md-4 g-md-5 px-4 px-lg-0 py-lg-5 justify-content-center {{ $attributes->get('align', 'align-items-center') }}">
33
<div class="col-lg-6">
44
@isset($sup)
55
<span class="text-primary mb-3 d-block text-uppercase fw-semibold ls-xl">{{ $sup }}</span>

resources/views/profile/edit.blade.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,19 @@ class="btn-group mb-3" role="group" aria-label="Тема оформления" i
9090
</div>
9191
<div class="mb-4 "
9292
data-controller="webpush"
93-
data-webpush-error-supported-value="{{ __('app.common.webpush.error.supported') }}"
94-
data-webpush-error-permission-value="{{ __('app.common.webpush.error.permission') }}">
95-
<label class="form-label d-block">Уведомления</label>
93+
data-webpush-error-supported-value="Push-сообщения не поддерживаются на этом устройстве"
94+
data-webpush-error-permission-value="Доступ запрещён">
95+
<label class="form-label d-block">Push-уведомления</label>
9696
<div class="form-check form-switch">
97-
<input class="form-check-input me-3" type="checkbox"
98-
data-controller="control-native-reminder"
97+
<input class="form-check-input me-3"
98+
type="checkbox"
9999
data-action="change->webpush#switching"
100+
data-webpush-target="status"
100101
role="switch"
101102
value="0"
102-
id="native_notifiable"
103103
name="native_notifiable"
104104
checked>
105-
<label for="native_notifiable" class="form-check-label small">Push</label>
105+
<label for="native_notifiable" class="form-check-label small">Включить на этом устройстве</label>
106106

107107
</div>
108108

routes/web.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@
350350

351351
Route::post('/push', [\App\Http\Controllers\PushController::class, 'store'])->name('push.store');
352352
Route::post('/push/unsubscribe', [\App\Http\Controllers\PushController::class, 'unsubscribe'])->name('push.unsubscribe');
353+
Route::post('/push/check', [\App\Http\Controllers\PushController::class, 'check'])->name('push.check');
353354

354355
/*
355356
|--------------------------------------------------------------------------

0 commit comments

Comments
 (0)