Open luke- opened 1 year ago
@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 Block
we want to show a Message: "You have blocked Notifcations. Click here to enable."
If a user clicked Allow
we want to show a Message: "Push Notifications are active on this device. Click here to disable."
@luke- Sorry, I didn't quite understand and thank you for the clarification. In this case, I will try to figure out if it is possible to use it somehow.
@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.
@luke- @serh-mosk maybe this is what you're looking for but displayed under the Notification Overview?
/**
* @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?
@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.
@luke- see #44
@ArchBlood Awesome thanks! Can you provide the screenshots?
@yurabakhtin Can you please test this behavior?
@ArchBlood Awesome thanks! Can you provide the screenshots?
@yurabakhtin Can you please test this behavior?
Screenshots are attached in the original comment https://github.com/humhub/fcm-push/issues/24#issuecomment-2254208838
@yurabakhtin Can you please test this behavior?
@luke- I don't see the widget with green border on my test server as displayed on the screenshots https://github.com/humhub/fcm-push/issues/24#issuecomment-2254208838, maybe I should configure the module as described here https://marketplace.humhub.com/module/fcm-push/installation ?
I think all messages like Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.
should be translatable from php side.
@yurabakhtin Can you please test this behavior?
@luke- I don't see the widget with green border on my test server as displayed on the screenshots https://github.com/humhub/fcm-push/issues/24#issuecomment-2254208838, maybe I should configure the module as described here https://marketplace.humhub.com/module/fcm-push/installation ?
I think all messages like
Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.
should be translatable from php side.
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:
I think all messages like
Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.
should be translatable from php side.
@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 module.text('status.granted')
;
@luke- I think it works as expected, you can see my tests on Windows Chrome browser:
I think all messages like
Granted: Push Notifications are active on this browser.<br>You can disable it in browser settings for this site.
should be translatable from php side.@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
module.text('status.granted')
;
Done in https://github.com/humhub/fcm-push/pull/44/commits/da92e33866b21a18136cbe88a919565daa55778d & https://github.com/humhub/fcm-push/pull/44/commits/9345b2b76567f86cd5f6e167635476cd4b1f94fe
@ArchBlood Thanks, please review the requested changes.
After we want to display the status in the notification settings. We can implement the following:
Or any other idea?
After we want to display the status in the notification settings. We can implement the following:
- In Core: Add BaseStack Widget "NotificationSettingsInfo"
- in FCM Push: Add Info Widget to this BaseStack?
Or any other idea?
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 https://github.com/humhub/fcm-push/blob/enh/24-notification-grant-status/widgets/views/push-notification-info.php
@ArchBlood Yes, we can use it for that!
@ArchBlood Do you want to implement this? Or maybe something for @yurabakhtin ?
@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.
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 /notification/user
without core editing which isn't normally recommended, another method would be creating another menu link like this which I did get working without issue;
Red: Haven't found a good method of implementing. Green: Works perfectly.
With core editing;
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 develop
branch:
If you want, we can also take over the part here?
@ArchBlood Yes, in this case I would make a change in the core
develop
branch:
- Core: We add an empty widget (BaseStack like sidebar) at this position in the core view (Notification Settings)
- FCM module: We add the status widget to the empty core widget
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;
@ArchBlood should @yurabakhtin take a look into this? Our do you have time on work on this?
@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 https://github.com/humhub/fcm-push/issues/24#issuecomment-2265901181), 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 https://github.com/humhub/humhub/pull/7155 with new core widget NotificationSettingsInfo
.
I think we don't need the new widget completely, because there we already the core widget UserInfoWidget
which can be used for the second your point "FCM module: We add the status widget to the empty core widget" from the FCM Push module side like this:
config.php
:
[UserInfoWidget::class, UserInfoWidget::EVENT_INIT, [Events::class, 'onInitUserInfoWidget']],
Events.php
:
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 UserInfoWidget
is available since 1.14 version.
@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
NotificationSettingsInfo
.I think we don't need the new widget completely, because there we already the core widget
UserInfoWidget
which can be used for the second your point "FCM module: We add the status widget to the empty core widget" from the FCM Push module side like this:
config.php
:[UserInfoWidget::class, UserInfoWidget::EVENT_INIT, [Events::class, 'onInitUserInfoWidget']],
Events.php
: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
UserInfoWidget
is available since 1.14 version.
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!
@luke- done in https://github.com/humhub/fcm-push/pull/44/commits/35a16ccaebcc25a884e568e24eac2f7e382936d2 and https://github.com/humhub/fcm-push/pull/44/commits/15f465780a7a20dc2679cec2b711ab3d70df5a01, although I'd like to note that now the module no longer works because the legacy API has been completely removed and should be completely migrated.
@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. https://github.com/humhub/fcm-push/issues/46
@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.