From 71b5ffd79c27879af8f883c9cff2af7ba3d98ce4 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi <fme@odoo.com>
Date: Mon, 12 Jun 2023 15:43:35 +0200
Subject: [PATCH] [ADD] base: add support for custom functions in imbus &
 cron_trigger notify

This patch provides the possibility to implement a custom security layer on top
of Odoo's bus notification system (and cron live triggering system) which both
use postgresql's NOTIFY command.

The key addition is the `ODOO_NOTIFY_FUNCTION` environment variable (opt-in),
which can now define a postgresql function to be called instead of the NOTIFY
command. This allows for greater flexibility and control over the notification
and triggering mechanisms within Odoo.

closes odoo/odoo#130370

Signed-off-by: Fabien Meghazi (fme) <fme@odoo.com>
---
 addons/bus/models/bus.py           | 12 ++++++++++--
 odoo/addons/base/models/ir_cron.py | 11 ++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/addons/bus/models/bus.py b/addons/bus/models/bus.py
index e94c8f37969a..31f5d91a7096 100644
--- a/addons/bus/models/bus.py
+++ b/addons/bus/models/bus.py
@@ -2,11 +2,12 @@
 import datetime
 import json
 import logging
+import os
 import random
 import select
 import threading
 import time
-from psycopg2 import InterfaceError
+from psycopg2 import InterfaceError, sql
 
 import odoo
 import odoo.service.server as servermod
@@ -19,6 +20,9 @@ _logger = logging.getLogger(__name__)
 # longpolling timeout connection
 TIMEOUT = 50
 
+# custom function to call instead of NOTIFY postgresql command (opt-in)
+ODOO_NOTIFY_FUNCTION = os.environ.get('ODOO_NOTIFY_FUNCTION')
+
 #----------------------------------------------------------
 # Bus
 #----------------------------------------------------------
@@ -77,7 +81,11 @@ class ImBus(models.Model):
             @self.env.cr.postcommit.add
             def notify():
                 with odoo.sql_db.db_connect('postgres').cursor() as cr:
-                    cr.execute("notify imbus, %s", (json_dump(list(channels)),))
+                    if ODOO_NOTIFY_FUNCTION:
+                        query = sql.SQL("SELECT {}('imbus', %s)").format(sql.Identifier(ODOO_NOTIFY_FUNCTION))
+                    else:
+                        query = "NOTIFY imbus, %s"
+                    cr.execute(query, (json_dump(list(channels)), ))
 
     @api.model
     def _sendone(self, channel, notification_type, message):
diff --git a/odoo/addons/base/models/ir_cron.py b/odoo/addons/base/models/ir_cron.py
index 1345021fc211..46d6f0451f17 100644
--- a/odoo/addons/base/models/ir_cron.py
+++ b/odoo/addons/base/models/ir_cron.py
@@ -12,11 +12,16 @@ import odoo
 from odoo import api, fields, models, _
 from odoo.exceptions import UserError
 
+from psycopg2 import sql
+
 _logger = logging.getLogger(__name__)
 
 BASE_VERSION = odoo.modules.load_information_from_description_file('base')['version']
 MAX_FAIL_TIME = timedelta(hours=5)  # chosen with a fair roll of the dice
 
+# custom function to call instead of NOTIFY postgresql command (opt-in)
+ODOO_NOTIFY_FUNCTION = os.environ.get('ODOO_NOTIFY_FUNCTION')
+
 
 class BadVersion(Exception):
     pass
@@ -504,7 +509,11 @@ class ir_cron(models.Model):
         ir_cron modification and on trigger creation (regardless of call_at)
         """
         with odoo.sql_db.db_connect('postgres').cursor() as cr:
-            cr.execute('NOTIFY cron_trigger, %s', [self.env.cr.dbname])
+            if ODOO_NOTIFY_FUNCTION:
+                query = sql.SQL("SELECT {}('cron_trigger', %s)").format(sql.Identifier(ODOO_NOTIFY_FUNCTION))
+            else:
+                query = "NOTIFY cron_trigger, %s"
+            cr.execute(query, [self.env.cr.dbname])
         _logger.debug("cron workers notified")
 
 
-- 
GitLab