Browse Source

Jun 21 [UPDT] Updated 'mail_push_notification'

pull/331/head
AjmalCybro 10 months ago
parent
commit
351e85acb2
  1. 2
      mail_push_notification/README.rst
  2. 8
      mail_push_notification/__manifest__.py
  3. 5
      mail_push_notification/doc/RELEASE_NOTES.md
  4. 1
      mail_push_notification/models/__init__.py
  5. 101
      mail_push_notification/models/mail_thread.py
  6. 22
      mail_push_notification/models/res_company.py
  7. 119
      mail_push_notification/models/res_config_settings.py
  8. 29
      mail_push_notification/models/res_users.py
  9. BIN
      mail_push_notification/static/description/assets/screenshots/12.png
  10. BIN
      mail_push_notification/static/description/assets/screenshots/13.png
  11. BIN
      mail_push_notification/static/description/assets/screenshots/14.png
  12. BIN
      mail_push_notification/static/description/assets/screenshots/15.png
  13. BIN
      mail_push_notification/static/description/assets/screenshots/17.png
  14. BIN
      mail_push_notification/static/description/assets/screenshots/2.png
  15. BIN
      mail_push_notification/static/description/assets/screenshots/22.png
  16. 425
      mail_push_notification/static/description/index.html
  17. 162
      mail_push_notification/static/src/js/firebase.js
  18. 57
      mail_push_notification/views/res_config_settings_views.xml

2
mail_push_notification/README.rst

@ -8,7 +8,7 @@ Push Notification From ChatBox
Configuration Configuration
============= =============
* Install the pyfcm python package * Install the firebase_admin python package
* Install our module and make sure that your instance served over https.Firebase is intent on being a highly secure solution, so they have chosen to require the use of a https for all communication and http is not working. * Install our module and make sure that your instance served over https.Firebase is intent on being a highly secure solution, so they have chosen to require the use of a https for all communication and http is not working.
* After installation of module its important that allow the notification access in the webpage * After installation of module its important that allow the notification access in the webpage

8
mail_push_notification/__manifest__.py

@ -21,10 +21,10 @@
############################################################################# #############################################################################
{ {
"name": "Push Notification From ChatBox", "name": "Push Notification From ChatBox",
'version': '17.0.1.0.0', 'version': '17.0.2.0.0',
'category': 'Discuss,Extra Tools', 'category': 'Discuss,Extra Tools',
'summary': 'With Push Notification From ChatBox, users can respond promptly' 'summary': """With Push Notification From ChatBox, users can respond
' to important messages, improving communication efficiency.', promptly to important messages, improving communication efficiency.""",
'description': 'Push Notification From ChatBox is valuable for teams ' 'description': 'Push Notification From ChatBox is valuable for teams '
'looking to streamline communication and enhance ' 'looking to streamline communication and enhance '
'productivity within the Odoo platform.', 'productivity within the Odoo platform.',
@ -44,7 +44,7 @@
"mail_push_notification/static/src/js/firebase.js", "mail_push_notification/static/src/js/firebase.js",
], ],
}, },
"external_dependencies": {"python": ["pyfcm"]}, "external_dependencies": {"python": ["firebase_admin"]},
'images': ['static/description/banner.jpg'], 'images': ['static/description/banner.jpg'],
'license': 'LGPL-3', 'license': 'LGPL-3',
'installable': True, 'installable': True,

5
mail_push_notification/doc/RELEASE_NOTES.md

@ -4,3 +4,8 @@
#### Version 17.0.1.0.0 #### Version 17.0.1.0.0
#### ADD #### ADD
- Initial commit for Push Notification From ChatBox - Initial commit for Push Notification From ChatBox
#### 01.06.2024
#### Version 17.0.2.0.0
#### UPDT
- Migrated from legacy FCM APIs to HTTP v1

1
mail_push_notification/models/__init__.py

@ -23,3 +23,4 @@ from . import mail_thread
from . import push_notification from . import push_notification
from . import res_company from . import res_company
from . import res_config_settings from . import res_config_settings
from . import res_users

101
mail_push_notification/models/mail_thread.py

@ -19,7 +19,7 @@
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################# #############################################################################
from pyfcm import FCMNotification from firebase_admin import messaging, initialize_app, credentials, _apps
from odoo import models from odoo import models
@ -28,39 +28,74 @@ class MailThread(models.AbstractModel):
_inherit = 'mail.thread' _inherit = 'mail.thread'
def _notify_thread(self, message, msg_vals=False, **kwargs): def _notify_thread(self, message, msg_vals=False, **kwargs):
"""Supering the _notify_thread() function to fetch the details of the """Override the _notify_thread() function to fetch chat message details
chat message and push that message as a notification """ and push that message as a notification."""
res = super(MailThread, self)._notify_thread(message, res = super()._notify_thread(message, msg_vals=msg_vals, **kwargs)
msg_vals=msg_vals,
**kwargs)
msg = message.read() msg = message.read()
if self.env.company.push_notification and self.env.user.has_group( if (self.env.company.push_notification and
'base.group_user'): self.env.user.has_group('base.group_user')):
try: try:
push_service = FCMNotification(
api_key=self.env.company.server_key)
receiver_id = False
domain = [] domain = []
if self.channel_type != 'channel': receiver_ids = self._get_receiver_ids(msg)
for partner in self.channel_partner_ids: user_list = [rec.id for rec in receiver_ids]
if partner.id != msg[0]['author_id'][0]: if receiver_ids:
receiver_id = self.env['res.users'].search([( domain = [('user_id', 'in', user_list)]
'partner_id', self._send_push_notification(msg, domain)
'=', except Exception as e:
partner.id)]) self.env['ir.logging'].sudo().create({
if receiver_id: 'name': 'Push Notification Error',
domain = [('user_id', '=', 'type': 'server',
receiver_id.id)] 'level': 'ERROR',
push_service.notify_multiple_devices( 'message': str(e),
registration_ids=[registration_id.register_id for 'path': 'mail.thread',
registration_id in 'func': '_notify_thread',
self.env['push.notification'].search( 'line': '45',
domain)], })
message_title='Send by ' + msg[0]['author_id'][1],
message_body=msg[0]['description'],
extra_notification_kwargs={
'click_action': '/web'
})
except Exception:
pass
return res return res
def _get_receiver_ids(self, msg):
"""Identify the receiver of the notification."""
receiver_ids = []
receiver_id = False
if self.channel_type != 'channel':
for partner in self.channel_partner_ids:
if partner.id != msg[0]['author_id'][0]:
receiver_id = self.env['res.users'].search(
[('partner_id', '=', partner.id)])
if receiver_id:
receiver_ids.append(receiver_id)
else:
for partner in self.channel_partner_ids:
receiver_id = self.env['res.users'].search(
[('partner_id', '=', partner.id)])
if receiver_id:
receiver_ids.append(receiver_id)
return receiver_ids
def _send_push_notification(self, msg, domain):
"""Send a push notification using Firebase."""
if not _apps:
cred = credentials.Certificate({
"type": "service_account",
"project_id": self.env.company.project_id_firebase,
"private_key_id": self.env.company.private_key_ref,
"private_key": self.env.company.private_key.replace('\\n',
'\n'),
"client_email": self.env.company.client_email,
"client_id": self.env.company.client_id_firebase,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": self.env.company.client_cert_url,
"universe_domain": "googleapis.com"
})
initialize_app(cred)
message = messaging.MulticastMessage(
notification=messaging.Notification(
title='Message from ' + msg[0]['author_id'][1],
body=msg[0]['body']
),
tokens=[reg_id.register_id for reg_id in
self.env['push.notification'].search(domain)]
)
messaging.send_each_for_multicast(message)

22
mail_push_notification/models/res_company.py

@ -29,8 +29,23 @@ class ResCompany(models.Model):
push_notification = fields.Boolean(string='Enable Push Notification', push_notification = fields.Boolean(string='Enable Push Notification',
help="Enable Web Push Notification") help="Enable Web Push Notification")
server_key = fields.Char(string="Server Key", private_key_ref = fields.Char(string='Private Key Id',
help="Server Key of the firebase") help="Private Key Id in the certificate")
project_id_firebase = fields.Char(string="Project Id",
help='Corresponding projectId of '
'firebase config')
private_key = fields.Char(string="Private Key",
help="Private Key value in the firebase "
"certificate"
)
client_email = fields.Char(string="Client Email",
help='Client Email in the firebase config')
client_id_firebase = fields.Char(string="Client Id",
help='Client Id in the firebase config')
client_cert_url = fields.Char(string="Client Certificate Url",
help='Value corresponding to '
'client_x509_cert_url in the '
'firebase config')
vapid = fields.Char(string="Vapid", help='VapId of the firebase', vapid = fields.Char(string="Vapid", help='VapId of the firebase',
readonly=False) readonly=False)
api_key = fields.Char(string="Api Key", api_key = fields.Char(string="Api Key",
@ -39,9 +54,6 @@ class ResCompany(models.Model):
auth_domain = fields.Char(string="Auth Domain", auth_domain = fields.Char(string="Auth Domain",
help='Corresponding authDomain of firebase ' help='Corresponding authDomain of firebase '
'config') 'config')
project_id_firebase = fields.Char(string="Project Id",
help='Corresponding projectId of '
'firebase config')
storage_bucket = fields.Char(string="Storage Bucket", storage_bucket = fields.Char(string="Storage Bucket",
help='Corresponding storageBucket of ' help='Corresponding storageBucket of '
'firebase config') 'firebase config')

119
mail_push_notification/models/res_config_settings.py

@ -19,7 +19,8 @@
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################# #############################################################################
from pyfcm import FCMNotification from firebase_admin import initialize_app, _apps
from firebase_admin import credentials
from odoo import fields, models, _ from odoo import fields, models, _
@ -32,11 +33,33 @@ class ResConfigSettings(models.TransientModel):
help="Enable Web Push Notification", help="Enable Web Push Notification",
related='company_id.push_notification', related='company_id.push_notification',
readonly=False) readonly=False)
server_key = fields.Char(string="Server Key", project_id_firebase = fields.Char(string="Project Id",
help="Server Key of the firebase", help='Corresponding projectId of '
related='company_id.server_key', readonly=False) 'firebase config',
vapid = fields.Char(string="Vapid", help='VapId of the firebase', related='company_id.project_id_firebase',
related='company_id.vapid', readonly=False) readonly=False)
private_key_ref = fields.Char(string='Private Key Id',
help="Private Key Id in the certificate",
related='company_id.private_key_ref',
readonly=False)
private_key = fields.Char(string="Private Key",
help="Private Key value in the firebase "
"certificate",
related='company_id.private_key', readonly=False)
client_email = fields.Char(string="Client Email", help='Client Email in '
'the firebase config',
related='company_id.client_email',
readonly=False)
client_id_firebase = fields.Char(string="Client Id",
help='Client Id in the firebase config',
related='company_id.client_id_firebase',
readonly=False)
client_cert_url = fields.Char(string="Client Certificate Url",
help='Value corresponding to '
'client_x509_cert_url in the firebase '
'config',
related='company_id.client_cert_url',
readonly=False)
api_key = fields.Char(string="Api Key", api_key = fields.Char(string="Api Key",
help='Corresponding apiKey of firebase config', help='Corresponding apiKey of firebase config',
related='company_id.api_key', readonly=False) related='company_id.api_key', readonly=False)
@ -44,11 +67,7 @@ class ResConfigSettings(models.TransientModel):
help='Corresponding authDomain of firebase ' help='Corresponding authDomain of firebase '
'config', 'config',
related='company_id.auth_domain', readonly=False) related='company_id.auth_domain', readonly=False)
project_id_firebase = fields.Char(string="Project Id",
help='Corresponding projectId of '
'firebase config',
related='company_id.project_id_firebase',
readonly=False)
storage_bucket = fields.Char(string="Storage Bucket", storage_bucket = fields.Char(string="Storage Bucket",
help='Corresponding storageBucket of ' help='Corresponding storageBucket of '
'firebase config', 'firebase config',
@ -58,8 +77,7 @@ class ResConfigSettings(models.TransientModel):
help='Corresponding ' help='Corresponding '
'messagingSenderId of ' 'messagingSenderId of '
'firebase config', 'firebase config',
related='company_id' related='company_id.messaging_sender_id_firebase',
'.messaging_sender_id_firebase',
readonly=False) readonly=False)
app_id_firebase = fields.Char(string="App Id", app_id_firebase = fields.Char(string="App Id",
help='Corresponding appId of firebase config', help='Corresponding appId of firebase config',
@ -71,46 +89,47 @@ class ResConfigSettings(models.TransientModel):
related='company_id' related='company_id'
'.measurement_id_firebase', '.measurement_id_firebase',
readonly=False) readonly=False)
vapid = fields.Char(string="Vapid", help='VapId of the firebase',
related='company_id.vapid', readonly=False)
def test_connection(self): def test_connection(self):
"""Test connection to firebase using the firebase credentials""" """Test connection to firebase using the firebase credentials"""
if self.env.company.push_notification: if not self.env.company.push_notification:
try: return False
push_service = FCMNotification( try:
api_key=self.env.company.server_key) # Initialize the firebase app with the credentials
registration_ids = self.env['push.notification'].sudo().search( if not _apps:
[('user_id', '=', self.env.user.id)]) cred = credentials.Certificate(
push_service.notify_multiple_devices( {
registration_ids=[registration_id.register_id for "type": "service_account",
registration_id in registration_ids], "project_id": self.project_id_firebase,
message_title='Test Connection', "private_key_id": self.private_key_ref,
message_body='Successfully', "private_key": self.private_key.replace('\\n', '\n'),
extra_notification_kwargs={ "client_email": self.client_email,
'click_action': '/web' "client_id": self.client_id_firebase,
}) "auth_uri": "https://accounts.google.com/o/oauth2/auth",
return { "token_uri": "https://oauth2.googleapis.com/token",
'type': 'ir.actions.client', "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
'tag': 'display_notification', "client_x509_cert_url": self.client_cert_url,
'params': { "universe_domain": "googleapis.com"
'type': 'success',
'message': _("Connection successfully established"),
'next': {
'type': 'ir.actions.client',
'tag': 'reload_context',
},
} }
)
initialize_app(cred)
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': _("Connection successfully established"),
} }
except: }
return { except Exception as e:
'type': 'ir.actions.client', return {
'tag': 'display_notification', 'type': 'ir.actions.client',
'params': { 'tag': 'display_notification',
'type': 'danger', 'params': {
'message': _( 'type': 'danger',
"Failed to connect with firebase"), 'message': _(
'next': { "Failed to connect with firebase:%s" % e),
'type': 'ir.actions.client',
'tag': 'reload_context',
},
}
} }
}

29
mail_push_notification/models/res_users.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Gokul PI (<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models
class ResUsers(models.Model):
_inherit = 'res.users'
def has_push_notification_permission(self):
return self.has_group('base.group_user')

BIN
mail_push_notification/static/description/assets/screenshots/12.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 118 KiB

BIN
mail_push_notification/static/description/assets/screenshots/13.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 127 KiB

BIN
mail_push_notification/static/description/assets/screenshots/14.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 126 KiB

BIN
mail_push_notification/static/description/assets/screenshots/15.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 196 KiB

BIN
mail_push_notification/static/description/assets/screenshots/17.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 69 KiB

BIN
mail_push_notification/static/description/assets/screenshots/2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 217 KiB

BIN
mail_push_notification/static/description/assets/screenshots/22.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 72 KiB

425
mail_push_notification/static/description/index.html

@ -378,8 +378,8 @@
<div class="px-3"> <div class="px-3">
<h4 class="mt-2" <h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
You can see the credentials(not server key You can see the credentials(apiKey, authDomain, projectId, storageBucket,
and vapid) we need in odoo in the General messagingSenderId, appId, measurementId) in the General
--> Your apps --> Your apps
</h4> </h4>
</div> </div>
@ -397,250 +397,233 @@
</div> </div>
</div> </div>
<div class="col-lg-12 py-2" <div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;"> style="padding: 1rem 4rem !important;">
<div <div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0"> <div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/12.png" <img src="assets/screenshots/12.png"
class="img-responsive" width="100%" class="img-responsive" width="100%"
height="auto"> height="auto">
</div> </div>
<div class="px-3"> <div class="px-3">
<h4 class="mt-2" <h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
You can create the server key we need in Now we need to create a Vapid goto the Cloud Messaging --> Web configuration -->
odoo.For that goto the Cloud Messaging --> Generate Key pair
Cloud Messaging API (Legacy) --> 3 dots </h4>
-->Manage API in Google Cloud Console --> </div>
Enable the Cloud Messaging
</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/13.png"
class="img-responsive" width="100%"
height="auto">
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/13.png"
<img src="assets/screenshots/14.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> We can see the Vapid here.
After that you can see the Server key in Cloud </h4>
Messaging API (Legacy) </div>
</h4>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/14.png"
<img src="assets/screenshots/15.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> After that navigate to Firebase Admin SDK under Service accounts, select Python and
Now we need to create a Vapid goto the Cloud Generate new private key. It will generate a json file containing all remaining
Messaging --> Web configuration --> Generate credentials.
Key pair </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/15.png"
<img src="assets/screenshots/16.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> Downloaded json file.
After that you can see the public key of the </h4>
Vap id Cloud Messaging --> Web configuration </div>
</h4>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/17.png"
<img src="assets/screenshots/17.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> Goto the General Settings --> Firebase Push Notification --> enable the 'Enable Push
Goto the General Settings --> Firebase Push Notification' then you can set the credentials.
Notification --> enable the 'Enable Push </h4>
Notification' then you can set the credential </div>
</h4>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/18.png"
<img src="assets/screenshots/18.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> <mark>Its very important that You must Allow
<mark>Its very important that You must Allow the notification in the web browser
the notification in the web browser </mark>
</mark> </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/19.png"
<img src="assets/screenshots/19.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> <mark>If you are using firefox browser you need
<mark>If you are using firefox browser you need to allow the notification from clicking top
to allow the notification from clicking top of the browser and allow like in the above
of the browser and allow like in the above image
image </mark>
</mark> </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/20.png"
<img src="assets/screenshots/20.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> <mark>If you are using Brave browser you need
<mark>If you are using Brave browser you need to enable Google Services for push
to enable Google Services for push messaging for that goto the <a
messaging for that goto the <a href="brave://settings/privacy">brave://settings/privacy</a>
href="brave://settings/privacy">brave://settings/privacy</a> in brave and enable 'Use Google services
in brave and enable 'Use Google services for push messaging' like shown in the above
for push messaging' like shown in the above image
image </mark>
</mark> </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/21.png"
<img src="assets/screenshots/21.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> After Allowing the notification access in the
After Allowing the notification access in the browser you can click the "TEST CONNECTION"
browser you can click the "TEST CONNECTION" Button
Button </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/22.png"
<img src="assets/screenshots/22.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> Then you can see a notification on the system,
Then you can see a notification on the system, and you can see a green popup
and you can see a green popup </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/23.png"
<img src="assets/screenshots/23.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> After that you can send message from the
After that you can send message from the chatBox module or in the discuss module
chatBox module or in the discuss module </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> <div class="col-lg-12 py-2"
<div class="col-lg-12 py-2" style="padding: 1rem 4rem !important;">
style="padding: 1rem 4rem !important;"> <div
<div style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> <div class="row justify-content-center p-3 w-100 m-0">
<div class="row justify-content-center p-3 w-100 m-0"> <img src="assets/screenshots/24.png"
<img src="assets/screenshots/24.png" class="img-responsive" width="100%"
class="img-responsive" width="100%" height="auto">
height="auto"> </div>
</div> <div class="px-3">
<div class="px-3"> <h4 class="mt-2"
<h4 class="mt-2" style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> Then you can see a popup notification in the
Then you can see a popup notification in the other user and when you click on that it will
other user and when you click on that it will be redirected to the odoo instance
be redirected to the odoo instance </h4>
</h4> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div id="tab2" class="tab-pane fade"> <div id="tab2" class="tab-pane fade">

162
mail_push_notification/static/src/js/firebase.js

@ -1,89 +1,81 @@
/** @odoo-module **/ /** @odoo-module **/
import { jsonrpc } from "@web/core/network/rpc_service"; import { jsonrpc } from "@web/core/network/rpc_service";
/**
* Odoo module for handling Firebase push notifications. // Initialize variables
* let vapid = '';
* This module initializes Firebase messaging and handles push notifications let firebaseConfig = {};
* for the current session's company. It also registers the service worker for let messaging = null;
* handling notifications if the company has push notifications enabled. let push_notification = false;
*
* @module mail_push_notification // Fetch push notification settings for the current company
*/ jsonrpc("/firebase_credentials", {}).then(function(data) {
var vapid = ''; if (data && data.push_notification) {
var firebaseConfig = {}; push_notification = true;
var push_notification = false; if ("serviceWorker" in navigator) {
/** navigator.serviceWorker.register("/firebase-messaging-sw.js").then(function () {
* Sends an RPC query to retrieve push notification settings for the current company. console.log('Service worker registered successfully.');
* }).catch(function (err) {
* @function console.error('Failed to register service worker:', err);
* @returns {Promise} A promise that resolves with the push notification settings.
*/
jsonrpc("/firebase_credentials", {}).then(function(data) {
if (data) {
if (data.push_notification) {
push_notification = true;
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/firebase-messaging-sw.js").then(function () {});
}
}
}
});
jsonrpc("/firebase_config_details", {}).then(function (data) {
if (data) {
var json = JSON.parse(data);
vapid = json.vapid;
firebaseConfig = json.config;
/**
* Initializes Firebase messaging and sets up event listeners for incoming messages.
*
* @function
*/
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
/**
* Handles incoming push notification messages.
*
* @function
* @param {Object} payload - The notification payload.
*/
messaging.onMessage((payload) => {
const notificationOptions = {
body: payload.notification.body,
};
let notification = payload.notification;
navigator.serviceWorker.getRegistrations().then((registration) => {
registration[0].showNotification(notification.title, notificationOptions);
});
}); });
/** }
* Requests permission for receiving push notifications and retrieves the registration token. }
* });
* @function // Fetch Firebase configuration details
*/ jsonrpc("/firebase_config_details", {}).then(function(data) {
messaging.requestPermission().then(function () { if (data) {
/** const json = JSON.parse(data);
* Retrieves the registration token and sends it to the server for subscription. vapid = json.vapid;
* firebaseConfig = json.config;
* @function // Initialize Firebase app with the retrieved configuration
* @param {string} vapidKey - The VAPID key for authentication. firebase.initializeApp(firebaseConfig);
*/ messaging = firebase.messaging();
messaging.getToken({ vapidKey: vapid }).then((currentToken) => { // Function to request notification permission and retrieve token
if (currentToken) { function requestPermissionAndRetrieveToken() {
/** console.log('not',Notification)
* Sends a POST request to the server with the registration token. Notification.requestPermission().then((permission) => {
* console.log('permission',permission)
* @function if (permission === 'granted') {
* @param {string} token - The registration token. console.log('Permission granted');
*/ // Retrieve registration token
$.post("/push_notification", { messaging.getToken({ vapidKey: vapid }).then((currentToken) => {
name: currentToken console.log('Current token:', currentToken);
}); if (currentToken) {
} else { // Send the token to the server for subscription
console.log('No registration token found'); $.post("/push_notification", { name: currentToken }).done(function(response) {
} console.log('Token sent to server:', response);
}).catch((err) => { }).fail(function(error) {
console.log('There is an error has occurred while attempting to retrieve the token.', err); console.error('Failed to send token to server:', error);
}); });
} else {
console.warn('No registration token available');
}
}).catch((err) => {
console.error('Error retrieving token:', err);
});
} else {
console.warn('Permission for notifications was denied');
}
}).catch((err) => {
console.error('Unable to get permission to notify:', err);
}); });
} }
}); // Initialize Firebase messaging and handle incoming messages
messaging.onMessage((payload) => {
// Show notification to user
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: payload.notification.icon
};
navigator.serviceWorker.getRegistrations().then((registrations) => {
registrations[0].showNotification(notificationTitle, notificationOptions);
}).catch((err) => {
console.error('Error showing notification:', err);
});
});
// Request permission and retrieve token when the DOM content is loaded
document.addEventListener('DOMContentLoaded', (event) => {
requestPermissionAndRetrieveToken();
});
}
});

57
mail_push_notification/views/res_config_settings_views.xml

@ -34,41 +34,62 @@
<div class="o_setting_left_pane"> <div class="o_setting_left_pane">
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="server_key" <label for="project_id_firebase"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="server_key" <field name="project_id_firebase"
required="push_notification==True" required="push_notification==True"
password="1"/> password="1"/>
</div> </div>
<div class="o_setting_left_pane"> <div class="o_setting_left_pane">
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="vapid" <label for="private_key_ref"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="vapid" <field name="private_key_ref"
required="push_notification == True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
<div class="o_setting_left_pane"> <div class="o_setting_left_pane">
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="api_key" <label for="private_key"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="api_key" <field name="private_key"
required="push_notification == True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="auth_domain" <label for="client_email"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="auth_domain" <field name="client_email"
required="push_notification == True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="project_id_firebase" <label for="client_id_firebase"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="project_id_firebase" <field name="client_id_firebase"
required="push_notification == True"
password="1"/>
</div>
<div class="o_setting_right_pane">
<label for="client_cert_url"
class="col-2 col-lg-2 o_light_label"/>
<field name="client_cert_url"
required="push_notification == True"
password="1"/>
</div>
<div class="o_setting_right_pane">
<label for="api_key"
class="col-2 col-lg-2 o_light_label"/>
<field name="api_key"
required="push_notification == True"
password="1"/>
</div>
<div class="o_setting_right_pane">
<label for="auth_domain"
class="col-2 col-lg-2 o_light_label"/>
<field name="auth_domain"
required="push_notification == True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
@ -83,7 +104,7 @@
<label for="messaging_sender_id_firebase" <label for="messaging_sender_id_firebase"
class="col-2 col-lg-2 o_light_label"/> class="col-2 col-lg-2 o_light_label"/>
<field name="messaging_sender_id_firebase" <field name="messaging_sender_id_firebase"
required="push_notification== True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
@ -100,11 +121,15 @@
required="push_notification == True" required="push_notification == True"
password="1"/> password="1"/>
</div> </div>
<div class="col-lg-6 col-8 d-flex flex-row-reverse <div class="o_setting_right_pane">
o_setting_box"> <label for="vapid"
<button name="test_connection" class="col-2 col-lg-2 o_light_label"/>
string="Test Connection" <field name="vapid"
type="object" class="btn-primary"/> required="push_notification == True"
password="1"/>
</div>
<div class="col-lg-6 col-8 d-flex flex-row-reverse o_setting_box">
<button name="test_connection" string="Test Connection" type="object" class="btn-primary"/>
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save