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. 93
      mail_push_notification/models/mail_thread.py
  6. 22
      mail_push_notification/models/res_company.py
  7. 91
      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. 43
      mail_push_notification/static/description/index.html
  17. 124
      mail_push_notification/static/src/js/firebase.js
  18. 55
      mail_push_notification/views/res_config_settings_views.xml

2
mail_push_notification/README.rst

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

5
mail_push_notification/doc/RELEASE_NOTES.md

@ -4,3 +4,8 @@
#### Version 17.0.1.0.0
#### ADD
- 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 res_company
from . import res_config_settings
from . import res_users

93
mail_push_notification/models/mail_thread.py

@ -19,7 +19,7 @@
# 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
@ -28,39 +28,74 @@ class MailThread(models.AbstractModel):
_inherit = 'mail.thread'
def _notify_thread(self, message, msg_vals=False, **kwargs):
"""Supering the _notify_thread() function to fetch the details of the
chat message and push that message as a notification """
res = super(MailThread, self)._notify_thread(message,
msg_vals=msg_vals,
**kwargs)
"""Override the _notify_thread() function to fetch chat message details
and push that message as a notification."""
res = super()._notify_thread(message, msg_vals=msg_vals, **kwargs)
msg = message.read()
if self.env.company.push_notification and self.env.user.has_group(
'base.group_user'):
if (self.env.company.push_notification and
self.env.user.has_group('base.group_user')):
try:
push_service = FCMNotification(
api_key=self.env.company.server_key)
receiver_id = False
domain = []
receiver_ids = self._get_receiver_ids(msg)
user_list = [rec.id for rec in receiver_ids]
if receiver_ids:
domain = [('user_id', 'in', user_list)]
self._send_push_notification(msg, domain)
except Exception as e:
self.env['ir.logging'].sudo().create({
'name': 'Push Notification Error',
'type': 'server',
'level': 'ERROR',
'message': str(e),
'path': 'mail.thread',
'func': '_notify_thread',
'line': '45',
})
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)])
receiver_id = self.env['res.users'].search(
[('partner_id', '=', partner.id)])
if receiver_id:
domain = [('user_id', '=',
receiver_id.id)]
push_service.notify_multiple_devices(
registration_ids=[registration_id.register_id for
registration_id in
self.env['push.notification'].search(
domain)],
message_title='Send by ' + msg[0]['author_id'][1],
message_body=msg[0]['description'],
extra_notification_kwargs={
'click_action': '/web'
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"
})
except Exception:
pass
return res
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',
help="Enable Web Push Notification")
server_key = fields.Char(string="Server Key",
help="Server Key of the firebase")
private_key_ref = fields.Char(string='Private Key Id',
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',
readonly=False)
api_key = fields.Char(string="Api Key",
@ -39,9 +54,6 @@ class ResCompany(models.Model):
auth_domain = fields.Char(string="Auth Domain",
help='Corresponding authDomain of firebase '
'config')
project_id_firebase = fields.Char(string="Project Id",
help='Corresponding projectId of '
'firebase config')
storage_bucket = fields.Char(string="Storage Bucket",
help='Corresponding storageBucket of '
'firebase config')

91
mail_push_notification/models/res_config_settings.py

@ -19,7 +19,8 @@
# 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, _
@ -32,11 +33,33 @@ class ResConfigSettings(models.TransientModel):
help="Enable Web Push Notification",
related='company_id.push_notification',
readonly=False)
server_key = fields.Char(string="Server Key",
help="Server Key of the firebase",
related='company_id.server_key', readonly=False)
vapid = fields.Char(string="Vapid", help='VapId of the firebase',
related='company_id.vapid', readonly=False)
project_id_firebase = fields.Char(string="Project Id",
help='Corresponding projectId of '
'firebase config',
related='company_id.project_id_firebase',
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",
help='Corresponding apiKey of firebase config',
related='company_id.api_key', readonly=False)
@ -44,11 +67,7 @@ class ResConfigSettings(models.TransientModel):
help='Corresponding authDomain of firebase '
'config',
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",
help='Corresponding storageBucket of '
'firebase config',
@ -58,8 +77,7 @@ class ResConfigSettings(models.TransientModel):
help='Corresponding '
'messagingSenderId of '
'firebase config',
related='company_id'
'.messaging_sender_id_firebase',
related='company_id.messaging_sender_id_firebase',
readonly=False)
app_id_firebase = fields.Char(string="App Id",
help='Corresponding appId of firebase config',
@ -71,46 +89,47 @@ class ResConfigSettings(models.TransientModel):
related='company_id'
'.measurement_id_firebase',
readonly=False)
vapid = fields.Char(string="Vapid", help='VapId of the firebase',
related='company_id.vapid', readonly=False)
def test_connection(self):
"""Test connection to firebase using the firebase credentials"""
if self.env.company.push_notification:
if not self.env.company.push_notification:
return False
try:
push_service = FCMNotification(
api_key=self.env.company.server_key)
registration_ids = self.env['push.notification'].sudo().search(
[('user_id', '=', self.env.user.id)])
push_service.notify_multiple_devices(
registration_ids=[registration_id.register_id for
registration_id in registration_ids],
message_title='Test Connection',
message_body='Successfully',
extra_notification_kwargs={
'click_action': '/web'
})
# Initialize the firebase app with the credentials
if not _apps:
cred = credentials.Certificate(
{
"type": "service_account",
"project_id": self.project_id_firebase,
"private_key_id": self.private_key_ref,
"private_key": self.private_key.replace('\\n', '\n'),
"client_email": self.client_email,
"client_id": self.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.client_cert_url,
"universe_domain": "googleapis.com"
}
)
initialize_app(cred)
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': _("Connection successfully established"),
'next': {
'type': 'ir.actions.client',
'tag': 'reload_context',
},
}
}
except:
except Exception as e:
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'danger',
'message': _(
"Failed to connect with firebase"),
'next': {
'type': 'ir.actions.client',
'tag': 'reload_context',
},
"Failed to connect with firebase:%s" % e),
}
}

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

43
mail_push_notification/static/description/index.html

@ -378,8 +378,8 @@
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
You can see the credentials(not server key
and vapid) we need in odoo in the General
You can see the credentials(apiKey, authDomain, projectId, storageBucket,
messagingSenderId, appId, measurementId) in the General
--> Your apps
</h4>
</div>
@ -408,11 +408,8 @@
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
You can create the server key we need in
odoo.For that goto the Cloud Messaging -->
Cloud Messaging API (Legacy) --> 3 dots
-->Manage API in Google Cloud Console -->
Enable the Cloud Messaging
Now we need to create a Vapid goto the Cloud Messaging --> Web configuration -->
Generate Key pair
</h4>
</div>
</div>
@ -426,22 +423,10 @@
class="img-responsive" width="100%"
height="auto">
</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/14.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
After that you can see the Server key in Cloud
Messaging API (Legacy)
We can see the Vapid here.
</h4>
</div>
</div>
@ -451,16 +436,16 @@
<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/15.png"
<img src="assets/screenshots/14.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Now we need to create a Vapid goto the Cloud
Messaging --> Web configuration --> Generate
Key pair
After that navigate to Firebase Admin SDK under Service accounts, select Python and
Generate new private key. It will generate a json file containing all remaining
credentials.
</h4>
</div>
</div>
@ -470,15 +455,14 @@
<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/16.png"
<img src="assets/screenshots/15.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
After that you can see the public key of the
Vap id Cloud Messaging --> Web configuration
Downloaded json file.
</h4>
</div>
</div>
@ -495,9 +479,8 @@
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Goto the General Settings --> Firebase Push
Notification --> enable the 'Enable Push
Notification' then you can set the credential
Goto the General Settings --> Firebase Push Notification --> enable the 'Enable Push
Notification' then you can set the credentials.
</h4>
</div>
</div>

124
mail_push_notification/static/src/js/firebase.js

@ -1,89 +1,81 @@
/** @odoo-module **/
import { jsonrpc } from "@web/core/network/rpc_service";
/**
* Odoo module for handling Firebase push notifications.
*
* This module initializes Firebase messaging and handles push notifications
* for the current session's company. It also registers the service worker for
* handling notifications if the company has push notifications enabled.
*
* @module mail_push_notification
*/
var vapid = '';
var firebaseConfig = {};
var push_notification = false;
/**
* Sends an RPC query to retrieve push notification settings for the current company.
*
* @function
* @returns {Promise} A promise that resolves with the push notification settings.
*/
// Initialize variables
let vapid = '';
let firebaseConfig = {};
let messaging = null;
let push_notification = false;
// Fetch push notification settings for the current company
jsonrpc("/firebase_credentials", {}).then(function(data) {
if (data) {
if (data.push_notification) {
if (data && data.push_notification) {
push_notification = true;
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/firebase-messaging-sw.js").then(function () {});
}
navigator.serviceWorker.register("/firebase-messaging-sw.js").then(function () {
console.log('Service worker registered successfully.');
}).catch(function (err) {
console.error('Failed to register service worker:', err);
});
}
}
});
// Fetch Firebase configuration details
jsonrpc("/firebase_config_details", {}).then(function(data) {
if (data) {
var json = JSON.parse(data);
const json = JSON.parse(data);
vapid = json.vapid;
firebaseConfig = json.config;
/**
* Initializes Firebase messaging and sets up event listeners for incoming messages.
*
* @function
*/
// Initialize Firebase app with the retrieved configuration
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
*/
messaging.requestPermission().then(function () {
/**
* Retrieves the registration token and sends it to the server for subscription.
*
* @function
* @param {string} vapidKey - The VAPID key for authentication.
*/
messaging = firebase.messaging();
// Function to request notification permission and retrieve token
function requestPermissionAndRetrieveToken() {
console.log('not',Notification)
Notification.requestPermission().then((permission) => {
console.log('permission',permission)
if (permission === 'granted') {
console.log('Permission granted');
// Retrieve registration token
messaging.getToken({ vapidKey: vapid }).then((currentToken) => {
console.log('Current token:', currentToken);
if (currentToken) {
/**
* Sends a POST request to the server with the registration token.
*
* @function
* @param {string} token - The registration token.
*/
$.post("/push_notification", {
name: currentToken
// Send the token to the server for subscription
$.post("/push_notification", { name: currentToken }).done(function(response) {
console.log('Token sent to server:', response);
}).fail(function(error) {
console.error('Failed to send token to server:', error);
});
} else {
console.log('No registration token found');
console.warn('No registration token available');
}
}).catch((err) => {
console.log('There is an error has occurred while attempting to retrieve the token.', 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();
});
}
});

55
mail_push_notification/views/res_config_settings_views.xml

@ -34,41 +34,62 @@
<div class="o_setting_left_pane">
</div>
<div class="o_setting_right_pane">
<label for="server_key"
<label for="project_id_firebase"
class="col-2 col-lg-2 o_light_label"/>
<field name="server_key"
<field name="project_id_firebase"
required="push_notification==True"
password="1"/>
</div>
<div class="o_setting_left_pane">
</div>
<div class="o_setting_right_pane">
<label for="vapid"
<label for="private_key_ref"
class="col-2 col-lg-2 o_light_label"/>
<field name="vapid"
<field name="private_key_ref"
required="push_notification == True"
password="1"/>
</div>
<div class="o_setting_left_pane">
</div>
<div class="o_setting_right_pane">
<label for="api_key"
<label for="private_key"
class="col-2 col-lg-2 o_light_label"/>
<field name="api_key"
<field name="private_key"
required="push_notification == True"
password="1"/>
</div>
<div class="o_setting_right_pane">
<label for="auth_domain"
<label for="client_email"
class="col-2 col-lg-2 o_light_label"/>
<field name="auth_domain"
<field name="client_email"
required="push_notification == True"
password="1"/>
</div>
<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"/>
<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"
password="1"/>
</div>
@ -100,11 +121,15 @@
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 class="o_setting_right_pane">
<label for="vapid"
class="col-2 col-lg-2 o_light_label"/>
<field name="vapid"
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>

Loading…
Cancel
Save