Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions base_exception_compat/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
.. |company| replace:: ADHOC SA

.. |company_logo| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-logo.png
:alt: ADHOC SA
:target: https://www.adhoc.com.ar

.. |icon| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-icon.png

.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: https://www.gnu.org/licenses/agpl
:alt: License: AGPL-3

=====================
Base Exception Compat
=====================

Keeps the exception flow that `base_exception` had before OCA/server-tools#3590,
where `detect_exceptions()` writes in the ongoing transaction and returns the
rules instead of writing through a second cursor and raising.

The upstream mechanism opens a second database connection to store the
exceptions. That connection writes the same rows the ongoing transaction is
about to write, so the operation either fails with a serialization error or
blocks until the worker is killed. It also turns the exception into an error
for any caller outside the backend web client (portal, e-commerce, API, cron),
because the handler that translates it into a popup is only registered in
`web.assets_backend`.

The replacement belongs here and not in a module of a specific application:
`detect_exceptions()` is defined on `base.exception.method`, the abstract model
every exception module inherits from, so `sale_exception`, `stock_exception`
and any other one are all affected. Keeping it in `sale_exception_compat` left
stock covered only as long as a sale module happened to be installed, with
nothing declaring that dependency.

Installation
============

To install this module, you need to:

#. Only need to install the module. It is auto installed with `base_exception`.

Configuration
=============

To configure this module, you need to:

#. Nothing to configure.

Usage
=====

To use this module, you need to:

#. Confirm or validate a record that matches an exception rule: the exception
popup shows up instead of an error.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: http://runbot.adhoc.com.ar/

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/ingadhoc/miscellaneous/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* |company| |icon|

Contributors
------------

Maintainer
----------

|company_logo|

This module is maintained by the |company|.

To contribute to this module, please visit https://www.adhoc.com.ar.
1 change: 1 addition & 0 deletions base_exception_compat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
12 changes: 12 additions & 0 deletions base_exception_compat/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "Base Exception Compat",
"version": "18.0.1.1.0",
"category": "Tools",
"author": "ADHOC SA",
"website": "www.adhoc.com.ar",
"license": "AGPL-3",
"summary": "Keeps the pre-3590 exception flow while OCA fixes the second cursor",
"depends": ["base_exception"],
"installable": True,
"auto_install": True,
}
1 change: 1 addition & 0 deletions base_exception_compat/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import base_exception_method
24 changes: 24 additions & 0 deletions base_exception_compat/models/base_exception_method.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from odoo import models
from odoo.fields import Command


class BaseExceptionMethod(models.AbstractModel):
_inherit = "base.exception.method"

def detect_exceptions(self):
# Full replacement of the upstream method: it writes the exceptions
# through a second cursor that commits on the same rows the ongoing
# transaction is about to write, which breaks with a serialization
# failure (or blocks until the worker dies). Write in the current
# transaction and return the rules, as before OCA/server-tools#3590.
if self.env.context.get("test_base_exception"):
# Upstream sets this key to exercise the second cursor on purpose.
# Nothing sets it outside its own tests, so keeping that path alive
# leaves them meaningful instead of red.
return super().detect_exceptions()
all_exception_ids, rules_to_remove, rules_to_add = self._get_exceptions()
for rule_id, records in rules_to_remove.items():
records.write({"exception_ids": [Command.unlink(rule_id)]})
for rule_id, records in rules_to_add.items():
records.write({"exception_ids": [Command.link(rule_id)]})
return all_exception_ids
2 changes: 1 addition & 1 deletion portal_backend/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
##############################################################################
{
"name": "Portal Backend",
"version": "18.0.1.1.0",
"version": "18.0.1.2.0",
"category": "Base",
"sequence": 14,
"summary": "",
Expand Down
1 change: 1 addition & 0 deletions portal_backend/controllers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

from . import patch_web_controller_utils
from . import discuss
from . import thread
18 changes: 18 additions & 0 deletions portal_backend/controllers/thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import http
from odoo.addons.mail.controllers.thread import ThreadController
from odoo.http import request


class PortalBackendThreadController(ThreadController):
@http.route("/mail/thread/data", methods=["POST"], type="json", auth="user")
def mail_thread_data(self, thread_model, thread_id, request_list, **kwargs):
"""Core empties request_list for non internal users, so the chatter never gets
followersCount nor attachments and its counters spin forever. Let portal backend users
through: core still checks read access on the record before answering."""
if request.env.user.has_group("portal_backend.group_portal_backend"):
request.update_context(portal_bypass=True)
return super().mail_thread_data(thread_model, thread_id, request_list, **kwargs)
6 changes: 0 additions & 6 deletions portal_backend/models/mail_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,3 @@ class MailThread(models.AbstractModel):

message_attachment_count = fields.Integer(groups="base.group_user, portal_backend.group_portal_backend")
message_follower_ids = fields.One2many(groups="base.group_user, portal_backend.group_portal_backend")

def _get_mail_thread_data(self, request_list):
"""This avoids to get an error when an internal user is follower of a record that a portal_backend has access"""
if "followers" in request_list and self.env.user.has_group("portal_backend.group_portal_backend"):
request_list.remove("followers")
return super()._get_mail_thread_data(request_list)
Loading