Skip to content

Commit ecb33b5

Browse files
author
Leonid Vakulenko
committed
Updated integration with web push notifications service Firebase.
1 parent 321a900 commit ecb33b5

File tree

229 files changed

+37379
-827
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

229 files changed

+37379
-827
lines changed

wa-system/push/adapters/firebase/firebase-core.js

Lines changed: 266 additions & 610 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,43 @@
1-
importScripts('https://www.gstatic.com/firebasejs/3.7.2/firebase-app.js');
2-
importScripts('https://www.gstatic.com/firebasejs/3.7.2/firebase-messaging.js');
3-
4-
firebase.initializeApp({
5-
messagingSenderId: {$sender_id|json_encode}
6-
});
7-
1+
importScripts(
2+
"https://www.gstatic.com/firebasejs/11.6.0/firebase-app-compat.js"
3+
);
4+
importScripts(
5+
"https://www.gstatic.com/firebasejs/11.6.0/firebase-messaging-compat.js"
6+
);
7+
8+
(function (self) {
9+
10+
const firebaseConfig = {
11+
apiKey: {$api_key|json_encode},
12+
authDomain: {$project_id|json_encode} + ".firebaseapp.com",
13+
projectId: {$project_id|json_encode},
14+
storageBucket: {$project_id|json_encode} + ".firebasestorage.app",
15+
messagingSenderId: {$sender_id|json_encode},
16+
appId: {$app_id|json_encode}
17+
};
18+
19+
firebase.initializeApp(firebaseConfig);
820
const messaging = firebase.messaging();
921

10-
// Customize notification handler
11-
messaging.setBackgroundMessageHandler(function(payload) {
22+
messaging.onBackgroundMessage(function(payload) {
1223
console.log('Handling background message', payload);
13-
14-
// Copy data object to get parameters in the click handler
15-
payload.data.data = JSON.parse(JSON.stringify(payload.data));
16-
17-
return self.registration.showNotification(payload.data.title, payload.data);
24+
if (!('notification' in payload) && payload.data?.title && payload.data?.body) {
25+
self.registration.showNotification(
26+
payload.data.title, {
27+
body: payload.data.body,
28+
image: payload.data.image,
29+
icon: payload.data.image,
30+
data: payload.data
31+
}
32+
);
33+
}
1834
});
1935

2036
self.addEventListener('notificationclick', function(event) {
21-
const target = event.notification.data.click_action || '/';
37+
// Notification clicked.
38+
console.log('Handling notification click', event.notification);
39+
40+
const target = event.notification.data?.link || '/';
2241
event.notification.close();
2342

2443
// This looks to see if the current is already open and focuses if it is
@@ -37,3 +56,5 @@ self.addEventListener('notificationclick', function(event) {
3756
return clients.openWindow(target);
3857
}));
3958
});
59+
60+
})(self);

wa-system/push/adapters/firebase/firebasePush.class.php

Lines changed: 399 additions & 100 deletions
Large diffs are not rendered by default.
Lines changed: 21 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,34 @@
11
// {* This js including in smarty on all backend layout pages as part of $wa->header() call. *}
22
(function($) { "use strict";
33

4-
var firebase_core_path = {if !empty($firebase_core_path)}{$firebase_core_path|json_encode}{else}null{/if},
4+
var firebase_core_path = {if !empty($firebase_core_path)}{$firebase_core_path|json_encode}{else}null{/if};
5+
{*
56
firebase_messaging_path = {if !empty($firebase_messaging_path)}{$firebase_messaging_path|json_encode}{else}null{/if},
6-
firebase_sender_id = {if !empty($firebase_sender_id)}{$firebase_sender_id|json_encode}{else}null{/if};
7-
8-
if (!$ || !firebase_core_path || !firebase_sender_id) return;
9-
10-
var id = '#firebase-core-'+Date.now(),
11-
$script = $(id);
12-
13-
if (!$script.length) {
14-
var script = document.createElement("script");
7+
firebase_sender_id = {if !empty($sender_id)}{$sender_id|json_encode}{else}null{/if};
8+
*}
9+
if (!$ || !firebase_core_path /* || !firebase_sender_id */) return;
10+
11+
const id = '#firebase-core-{$update_ts}';
12+
if (!$(id).length) {
13+
const script = document.createElement("script");
14+
script.type = "module";
1515
script.async = true;
1616

1717
document.getElementsByTagName("head")[0].appendChild(script);
1818

19-
$script = $(script)
20-
.attr("id", id)
21-
.on("load", function() {
22-
initFirebase();
23-
});
24-
25-
$script.attr("src", firebase_core_path);
19+
$(script).attr("id", id)
20+
.attr("src", firebase_core_path + "?ts={$update_ts}");
2621
}
2722

28-
function initFirebase() {
29-
// Browser supports notifications?
30-
// In general, this check should be done by the Firebase library, but it does not.
31-
if (
32-
'Notification' in window &&
33-
'serviceWorker' in navigator
34-
) {
35-
36-
// firebase_subscribe.js
37-
firebase.initializeApp({
38-
messagingSenderId: firebase_sender_id
39-
});
40-
41-
var messaging = firebase.messaging();
42-
43-
// Handle catch the notification on current page
44-
messaging.onMessage(function(payload) {
45-
console.log('Message received', payload);
46-
47-
// Register fake ServiceWorker for show notification on mobile devices
48-
navigator.serviceWorker.register(firebase_messaging_path, { scope: '/' });
49-
50-
Notification.requestPermission(function(permission) {
51-
52-
if (permission === 'granted') {
53-
54-
navigator.serviceWorker.ready.then(function(registration) {
55-
// Copy data object to get parameters in the click handler
56-
payload.data.data = JSON.parse(JSON.stringify(payload.data));
57-
58-
registration.showNotification(payload.data.title, payload.data);
59-
}).catch(function(error) {
60-
// Registration failed :(
61-
console.log('ServiceWorker registration failed', error);
62-
});
63-
64-
}
65-
});
66-
});
67-
68-
// Callback fired if Instance ID token is updated.
69-
messaging.onTokenRefresh(function() {
70-
messaging.getToken()
71-
.then(function(refreshed_subscriber_token) {
72-
console.log('Token refreshed');
73-
74-
if (refreshed_subscriber_token) {
75-
saveSubscriber(refreshed_subscriber_token);
76-
}
77-
})
78-
.catch(function(error) {
79-
console.log('Unable to retrieve refreshed token', error);
80-
});
81-
});
82-
83-
// Requested permission to receive notifications
84-
messaging.requestPermission()
85-
.then(function () {
86-
// Get device token
87-
messaging.getToken()
88-
.then(function (subscriber_token) {
89-
if (subscriber_token) {
90-
saveSubscriber(subscriber_token);
91-
}
92-
});
93-
})
94-
.catch(function (err) {
95-
console.log('Failed to get permission to show notifications.', err);
96-
});
97-
}
98-
}
99-
100-
// Send subscriber token to the server
101-
function saveSubscriber(subscriber_token) {
102-
console.log('Sending a token to the server...');
103-
var href = {$webasyst_app_url|json_encode}+"?module=push&action=addSubscriber",
104-
data = {
105-
provider_id: 'firebase',
106-
data: {
107-
sender_id: firebase_sender_id,
108-
token: subscriber_token
109-
}
110-
};
23+
$(window).on('wa_push_settings_reload', () => {
24+
const script = document.createElement("script");
25+
script.type = "module";
26+
script.async = true;
11127

112-
$.post(href, data);
113-
}
28+
document.getElementsByTagName("head")[0].appendChild(script);
29+
const ts = Date.now();
30+
$(script).attr("id", "#firebase-core-" + ts)
31+
.attr("src", firebase_core_path + "?ts=" + ts);
32+
});
11433

11534
}(window.jQuery));
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{if !empty($validator_path)}
2+
<span class="js-json-key-file custom-mr-8">
3+
<span class="upload">
4+
<label class="button outlined js-add-json-key">
5+
<i class="fas fa-key"></i>
6+
<span>[s`Upload JSON key file`]</span>
7+
<input type="file" autocomplete="off" class="js-json-key-file-input">
8+
</label>
9+
</span>
10+
</span>
11+
12+
<a href="javascript:void(0);" class="js-show-json-key hidden">[s`Show JSON key`]</a>
13+
<pre class="js-json-key-container" style="display: none; overflow-x: auto; width: 100%;
14+
min-height: 50px;
15+
-webkit-box-sizing: border-box;
16+
-moz-box-sizing: border-box;
17+
box-sizing: border-box;
18+
border-radius: 5px;
19+
background: var(--background-color-blockquote);
20+
color: var(--text-color);
21+
font-size: .9rem;
22+
line-height: 1.25em;
23+
resize: vertical;
24+
border: 0 none !important;
25+
padding: 1rem !important;"></pre>
26+
<div class="state-caution js-json-key-error"></div>
27+
<script>
28+
(function($) { "use strict";
29+
30+
const validator_path = {$validator_path|json_encode};
31+
32+
if (!$ || !validator_path) return;
33+
34+
const id = '#firebase-validator-' + Date.now();
35+
36+
if ($(id).length == 0) {
37+
const script = document.createElement("script");
38+
script.type = "module";
39+
script.async = true;
40+
41+
document.getElementsByTagName("head")[0].appendChild(script);
42+
43+
const $script = $(script)
44+
.attr("id", id)
45+
.attr("src", validator_path);
46+
}
47+
48+
if (window.location.protocol === 'http:') {
49+
$('div.js-push-adapter-settings[data-adapter-id="firebase"]').prepend($('<p class="state-caution">[s`Full settings validation not available: missing HTTPS connection.`]</p>'));
50+
} else if (window.Notification.permission === "denied") {
51+
$('div.js-push-adapter-settings[data-adapter-id="firebase"]').prepend($('<p class="state-caution">[s`Full settings validation not available: notifications are blocked by user settings.`]</p>'));
52+
}
53+
54+
$('input[name="push_settings[firebase][project_id]"]').on('input', function() {
55+
const value = $(this).val();
56+
const href = 'https://console.firebase.google.com/project/' + (value || '_') + '/settings/';
57+
$('.js-firebase-api_key-link').attr('href', 'https://console.cloud.google.com/apis/credentials?project=' + value);
58+
$('.js-firebase-json_key-link').attr('href', href + 'serviceaccounts/adminsdk');
59+
$('.js-firebase-app_id-link').attr('href', href + 'general');
60+
$('.js-firebase-sender_id-link').attr('href', href + 'cloudmessaging');
61+
$('.js-firebase-vapid_key-link').attr('href', href + 'cloudmessaging');
62+
});
63+
$('input[name="push_settings[firebase][app_id]"]').addClass('long');
64+
//$('input[name="push_settings[firebase][sender_id]"]').addClass('long');
65+
$('input[name="push_settings[firebase][api_key]"]').addClass('long');
66+
$('input[name="push_settings[firebase][vapid_key]"]').addClass('long');
67+
const $json_key_textarea = $('textarea[name="push_settings[firebase][json_key]"]');
68+
const $json_key_show_link = $('.js-show-json-key');
69+
const $json_key_error = $('.js-json-key-error');
70+
const $json_key_container = $('.js-json-key-container');
71+
72+
$(".js-json-key-file").waUpload({
73+
show_file_name: false
74+
});
75+
76+
$json_key_textarea
77+
//.addClass('full-width')
78+
//.addClass('smaller')
79+
.addClass('hidden')
80+
//.css('height', '30em')
81+
.closest('div.field').addClass('vertical');
82+
83+
if ($json_key_textarea.val()) {
84+
try {
85+
$json_key_container.html(JSON.stringify(JSON.parse($json_key_textarea.val()), null, 2));
86+
$json_key_show_link.removeClass('hidden');
87+
} catch (e) {
88+
$json_key_textarea.val('');
89+
}
90+
}
91+
92+
$json_key_show_link.on('click', function(e) {
93+
e.preventDefault();
94+
$json_key_container.toggle();
95+
});
96+
97+
$(".js-json-key-file-input").on('change', async function(e) {
98+
const [file] = this.files;
99+
if (!file || !file.type.startsWith('application/json')) {
100+
$json_key_textarea.val('');
101+
$json_key_container.html('').hide();
102+
if (file) $json_key_error.html('[s`The selected file does not contain JSON.`]');
103+
$json_key_show_link.addClass('hidden');
104+
return;
105+
}
106+
const reader = new FileReader();
107+
reader.onload = () => {
108+
$json_key_textarea.val(reader.result);
109+
try {
110+
$json_key_container.html(JSON.stringify(JSON.parse(reader.result), null, 2));
111+
$json_key_error.html('');
112+
$json_key_show_link.removeClass('hidden');
113+
} catch (e) {
114+
$json_key_textarea.val('');
115+
$json_key_container.html('').hide();
116+
$json_key_error.html('[s`The selected file does not contain JSON.`]');
117+
$json_key_show_link.addClass('hidden');
118+
}
119+
};
120+
reader.onerror = () => {
121+
console.log("File reading error. Please try again.", reader.error);
122+
$json_key_error.html('[s`File reading error. Please try again.`]');
123+
$json_key_textarea.val('');
124+
$json_key_container.html('').hide();
125+
$json_key_show_link.addClass('hidden');
126+
};
127+
reader.readAsText(file);
128+
});
129+
130+
}(window.jQuery));
131+
</script>
132+
{/if}

0 commit comments

Comments
 (0)