-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Notification Grant Status #24
Comments
@luke- Unfortunately, it is not possible to receive the confirmation status of receiving push-notifications by the user. Above all, because one user can have several devices. Secondly, push notification technology does not provide for this at the moment. Although Google FCM provides information about the delivery status of a push-notification. When you send a push-notification using FCM, you receive feedback that contains the message delivery status. This feedback may include information such as:
|
@yuriimaz It is not about whether a user has received the push notifications. It is about whether the user has agreed to receive them in the current device/browser. E.g. If a user clicked |
@luke- Sorry, I didn't quite understand and thank you for the clarification. |
@luke- Since the Notification.permission parameter can have one of three values: 'default', 'granted', and 'denied', and at the same time, a window for changing permissions is possible show only when the 'default' value is set, so I have implemented only the basis of the solution for preliminary testing and coordination. Tested in Chrome, Firefox and Safari. Works well. It remains to add:
Let me know what you think about these changes and what should be changed. |
@yuriimaz This looks really good and promising. I would prefer: The existing widget stub https://github.com/humhub/fcm-push/blob/master/widgets/PushNotificationInfoWidget.php should have a view about all different cases (Not Supported, Denied, Granted, Default).
Per Javascript we can hide/show relevant messages. I can help you then how we can show the widget from the module (FcmPush) in the Core on the Notifications page. |
Related: #17 |
@luke- @serh-mosk maybe this is what you're looking for but displayed under the Notification Overview? Modified #28/**
* @fileoverview HumHub Firebase Module
* This module handles Firebase Cloud Messaging (FCM) integration for HumHub.
* It manages notification permissions, token handling, and message reception.
* @module firebase
*/
humhub.module('firebase', function (module, require, $) {
let messaging;
/**
* Initializes the Firebase module.
* Sets up the Firebase app if not already initialized and configures message handling.
*/
const init = function () {
if (!firebase.apps.length) {
firebase.initializeApp({messagingSenderId: this.senderId()});
this.messaging = firebase.messaging();
this.messaging.onMessage(function (payload) {
module.log.info("Received FCM Push Notification", payload);
});
// Callback fired if Instance ID token is updated.
this.messaging.onTokenRefresh(function () {
this.messaging.getToken().then(function (refreshedToken) {
this.deleteTokenLocalStore();
this.sendTokenToServer(refreshedToken);
}).catch(function (err) {
console.log('Unable to retrieve refreshed token ', err);
});
});
}
};
/**
* Generates the appropriate content for notification permission status.
* @returns {string} HTML content describing the current notification permission status.
*/
const getNotificationPermissionContent = function () {
if (!("Notification" in window)) {
return 'Not Supported: This browser does not support notifications.';
}
console.log('Notification.permission:', Notification.permission);
switch (Notification.permission) {
case "granted":
return 'Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.';
case "denied":
return 'Denied: You have blocked Push Notifications.<br>You can enable it in browser settings for this site.';
default:
return 'Default: Push Notifications are not yet enabled.<br><a href="#" id="enablePushBtn"><i class="fa fa-unlock"></i> Click here to enable</a>';
}
}
/**
* Displays the notification permission request window.
* Handles the permission request process and updates the UI accordingly.
*/
const showNotificationPermissionWindow = function () {
function handlePermission(permission) {
addPushNotificationPermissionsInfo(permission, true);
}
if (!("Notification" in window)) {
console.log("This browser does not support notifications.");
handlePermission("not-supported");
} else {
Notification.requestPermission().then((permission) => {
handlePermission(permission);
});
}
}
/**
* Adds or updates the push notification permissions information in the UI.
* @param {string} permission - The current notification permission status.
* @param {boolean} rewrite - Whether to rewrite existing content or add new content.
*/
const addPushNotificationPermissionsInfo = function (permission, rewrite = false) {
if (rewrite) {
const contentContainer = document.getElementById('notificationPermissions');
contentContainer.innerHTML = getNotificationPermissionContent()
} else {
const content = '<div class="panel panel-default panel-pn-permissions"><div class="panel-body" id="notificationPermissions">' + getNotificationPermissionContent() + '</div></div>';
$('.layout-sidebar-container').prepend($(content));
}
$('#enablePushBtn').on('click', showNotificationPermissionWindow);
}
/**
* Handles tasks after service worker registration.
* Requests notification permission and manages token retrieval and storage.
* @param {ServiceWorkerRegistration} registration - The service worker registration object.
*/
const afterServiceWorkerRegistration = function (registration) {
const that = this;
this.messaging.useServiceWorker(registration);
this.messaging.requestPermission().then(function () {
addPushNotificationPermissionsInfo('granted');
that.messaging.getToken().then(function (currentToken) {
if (currentToken) {
that.sendTokenToServer(currentToken);
} else {
module.log.info('No Instance ID token available. Request permission to generate one.');
that.deleteTokenLocalStore();
}
}).catch(function (err) {
module.log.error('An error occurred while retrieving token. ', err);
that.deleteTokenLocalStore();
});
}).catch(function (err) {
module.log.info('Could not get Push Notification permission!', err);
addPushNotificationPermissionsInfo(Notification.permission);
});
};
/**
* Sends the FCM token to the server.
* @param {string} token - The FCM token to be sent.
*/
const sendTokenToServer = function (token) {
const that = this;
if (!that.isTokenSentToServer(token)) {
module.log.info("Send FCM Push Token to Server");
$.ajax({
method: "POST",
url: that.tokenUpdateUrl(),
data: {token: token},
success: function (data) {
that.setTokenLocalStore(token);
}
});
} else {
//console.log('Token already sent to server so won\'t send it again unless it changes');
}
};
/**
* Checks if the token has been sent to the server.
* @param {string} token - The token to check.
* @returns {boolean} True if the token has been sent to the server, false otherwise.
*/
const isTokenSentToServer = function (token) {
return (this.getTokenLocalStore() === token);
};
/**
* Deletes the token from local storage.
*/
const deleteTokenLocalStore = function () {
window.localStorage.removeItem('fcmPushToken_' + this.senderId())
};
/**
* Stores the token in local storage with an expiry time.
* @param {string} token - The token to store.
*/
const setTokenLocalStore = function (token) {
const item = {
value: token,
expiry: (Date.now() / 1000) + (24 * 60 * 60),
};
window.localStorage.setItem('fcmPushToken_' + this.senderId(), JSON.stringify(item))
};
/**
* Retrieves the token from local storage.
* @returns {string|null} The stored token if valid, null otherwise.
*/
const getTokenLocalStore = function () {
const itemStr = window.localStorage.getItem('fcmPushToken_' + this.senderId())
// if the item doesn't exist, return null
if (!itemStr) {
return null
}
const item = JSON.parse(itemStr)
const now = (Date.now() / 1000)
if (now > item.expiry) {
this.deleteTokenLocalStore();
return null;
}
return item.value;
};
/**
* Returns the URL for updating the token on the server.
* @returns {string} The token update URL.
*/
const tokenUpdateUrl = function () {
return module.config.tokenUpdateUrl;
};
/**
* Returns the sender ID for FCM.
* @returns {string} The sender ID.
*/
const senderId = function () {
return module.config.senderId;
};
module.export({
init: init,
isTokenSentToServer: isTokenSentToServer,
sendTokenToServer: sendTokenToServer,
afterServiceWorkerRegistration: afterServiceWorkerRegistration,
senderId: senderId,
tokenUpdateUrl: tokenUpdateUrl,
setTokenLocalStore: setTokenLocalStore,
getTokenLocalStore: getTokenLocalStore,
deleteTokenLocalStore: deleteTokenLocalStore,
});
});
/**
* Global function to handle service worker registration for the Firebase module.
* @param {ServiceWorkerRegistration} registration - The service worker registration object.
*/
function afterServiceWorkerRegistration(registration) {
humhub.modules.firebase.afterServiceWorkerRegistration(registration);
} |
@ArchBlood Thanks, looks goods interesting. Is it also possible to re-trigger the approval request manually? Would you like to provide a PR for this? |
Yes, if the settings are reset for some reason it is very possible to re-trigger the approval request manually. I've provided a screenshot for each status that I could produce on my end of things, other than one for no support as I do not know of any browsers that are installable without support. |
@ArchBlood Awesome thanks! Can you provide the screenshots? @yurabakhtin Can you please test this behavior? |
Screenshots are attached in the original comment #24 (comment) |
@luke- I don't see the widget with green border on my test server as displayed on the screenshots #24 (comment), maybe I should configure the module as described here https://marketplace.humhub.com/module/fcm-push/installation ? I think all messages like |
The border was to highlight the widget nothing more. |
@luke- I think it works as expected, you can see my tests on Windows Chrome browser:
@ArchBlood It can be implemented with code: class FcmPushAsset extends AssetBundle
{
...
public static function register($view)
{
...
Yii::$app->view->registerJsConfig('firebase', [
'text' => [
'status.granted' => Yii::t('FcmPushModule.base', 'Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.'),
],
]);
...
}
} and replace the JS string with code |
|
@ArchBlood Thanks, please review the requested changes. |
We could convert the existing widget to do this or is there any specific use that it currently uses? https://github.com/humhub/fcm-push/blob/enh/24-notification-grant-status/widgets/PushNotificationInfoWidget.php |
@ArchBlood Yes, we can use it for that! |
@ArchBlood Do you want to implement this? Or maybe something for @yurabakhtin ? |
I don't mind doing this, is there s specific design/look that would be required or anything to make it more noticeable? |
I think @Eladnarlea will look over it again. At the moment, just a line without a lot of styling is enough. |
@luke- I wasn't able to implement within Red: Haven't found a good method of implementing. If you want a better solution then I'm open for other options |
@ArchBlood Yes, in this case I would make a change in the core
If you want, we can also take over the part here? |
Sounds fine with me, I'd also like to note that the script will also have to be updated in this case as well, as currently it creates a widget on the dashboard which would have to be refactored in this case as well. The following are the updated widget and widget view that I currently use; PushNotificationInfoWidgetDetails<?php
namespace humhub\modules\fcmPush\widgets;
use Yii;
use yii\helpers\Url;
use humhub\components\Widget;
use humhub\modules\fcmPush\Module;
use humhub\modules\fcmPush\services\DriverService;
class PushNotificationInfoWidget extends Widget
{
/**
* @inheritdoc
*/
public function run()
{
/** @var Module $module */
$module = Yii::$app->getModule('fcm-push');
$pushDriver = (new DriverService($module->getConfigureForm()))->getWebDriver();
if ($pushDriver === null) {
return '';
}
return $this->render('push-notification-info', [
'tokenUpdateUrl' => Url::to(['/fcm-push/token/update']),
'senderId' => $pushDriver->getSenderId(),
]);
}
} ViewDetails<?php
use yii\helpers\Html;
use humhub\widgets\Button;
/* @var $this \humhub\modules\ui\view\components\View */
/* @var $tokenUpdateUrl string */
/* @var $senderId string */
// Prepare the status texts and JSON encode them for use in JavaScript
$statusTexts = [
'granted' => Yii::t('FcmPushModule.base', 'Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.'),
'denied' => Yii::t('FcmPushModule.base', 'Denied: You have blocked Push Notifications.<br>You can enable it in browser settings for this site.'),
'default' => Yii::t('FcmPushModule.base', 'Default: Push Notifications are not yet enabled.') . '<br>' .
Button::primary(Yii::t('FcmPushModule.base', 'Click here to enable'))
->icon('fa-unlock')
->id('enablePushBtn')
->sm()
->loader(false),
'not-supported' => Yii::t('FcmPushModule.base', 'Not Supported: This browser does not support notifications.'),
];
$statusTextsJson = json_encode($statusTexts);
$this->registerJsConfig('firebase', [
'tokenUpdateUrl' => $tokenUpdateUrl,
'senderId' => $senderId,
]);
$js = <<<JS
var statusTexts = {$statusTextsJson};
function updatePushStatus() {
var status = 'not-supported';
if ("Notification" in window) {
status = Notification.permission;
}
$('#pushNotificationStatus').html(statusTexts[status]);
}
$(document).ready(function() {
updatePushStatus();
$(document).on('click', '#enablePushBtn', function() {
Notification.requestPermission().then(function(permission) {
updatePushStatus();
});
});
});
JS;
$this->registerJs($js);
?>
<div id="push-notification-info" class="panel panel-default">
<div class="panel-heading">
<?= Yii::t('FcmPushModule.base', 'Push Notifications') ?>
</div>
<div class="panel-body" id="pushNotificationStatus">
<!-- Status will be populated by JavaScript -->
</div>
</div> |
@ArchBlood should @yurabakhtin take a look into this? Our do you have time on work on this? |
I've provide the current widget and widget view that I currently use (see #24 (comment)), I don't have much time to rework the JavaScript sorry. |
@luke- I believe that everything is in order and complies with everything requested, all that is needed is for review of both P/Rs. |
@luke- Some help is required from me here? I just see you requested "Core: We add an empty widget (BaseStack like sidebar) at this position in the core view (Notification Settings)" and it seems @ArchBlood started it in the PR humhub/humhub#7155 with new core widget I think we don't need the new widget completely, because there we already the core widget
[UserInfoWidget::class, UserInfoWidget::EVENT_INIT, [Events::class, 'onInitUserInfoWidget']],
public static function onInitUserInfoWidget($event)
{
/* @var UserInfoWidget $widget */
$widget = $event->sender;
$widget->addWidget(PushNotificationInfoWidget::class);
} I.e. it can be done currently without touching the core, because the core widget |
I can agree to this method, if it is preferred @luke-? |
@ArchBlood Please use the widgets suggested by @yurabakhtin. I've already added them for this case, few versions ago. |
@ArchBlood Also let us know, if yura should finish this task! |
@ArchBlood Thanks, can you please rebase the PR or update the base branch. The PR contains many changes which makes it hard to review: https://github.com/humhub/fcm-push/pull/44/files#diff-2bfab3db5cc1baf4c6d3ff6b19901926e3bdf4411ec685dac973e5fcff1c723b Let's create a new issue for that. #46 |
Done. |
It would be good to have a status whether the user has agreed to the notifications or not. Ideally with a possibility to request them again.
A Widget would be cool, which we can add to Notification settings page. https://community.humhub.com/notification/user
(I can help to add the Widget from FCM Module to this page)
Options/Output could be:
I'm not sure if it's possible or exactly how it works in conjunction with the Server Worker.
The text was updated successfully, but these errors were encountered: