-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2fb9ea3
commit e7ea631
Showing
4 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import sys | ||
import importlib | ||
|
||
MOVED_MODULES = { | ||
"odoo.addons.sale.models.sale_order_line": "odoo.addons.sale.models.sale", | ||
"odoo.addons.sale.models.sale_order": "odoo.addons.sale.models.sale", | ||
} | ||
EXTENDED_MODULES = ["odoo.tools.float_utils", "odoo.http"] | ||
|
||
|
||
def extend(module, name): | ||
extended_module = importlib.import_module(f"odoo.addons.sixteen_in_fourteen.{name}") | ||
module.__dict__.update( | ||
{ | ||
key: value | ||
for key, value in extended_module.__dict__.items() | ||
if key not in ["__file__", "__doc__", "__package__", "__loader__"] | ||
} | ||
) | ||
|
||
|
||
class SixteenInFourteenMovedHook(object): | ||
def find_module(self, name, path=None): | ||
if name in MOVED_MODULES: | ||
return self | ||
|
||
def load_module(self, name): | ||
assert name not in sys.modules | ||
odoo_module = sys.modules.get(name) | ||
if not odoo_module: | ||
odoo_module = importlib.import_module(MOVED_MODULES[name]) | ||
sys.modules[name] = odoo_module | ||
return odoo_module | ||
|
||
|
||
class SixteenInFourteenExtendedHook(object): | ||
def find_module(self, name, path=None): | ||
if name in EXTENDED_MODULES: | ||
return self | ||
|
||
def load_module(self, name): | ||
assert name not in sys.modules | ||
odoo_module = sys.modules.get(name) | ||
if not odoo_module: | ||
odoo_module = importlib.import_module(name) | ||
extend(odoo_module, name) | ||
|
||
sys.modules[name] = odoo_module | ||
return odoo_module | ||
|
||
|
||
sys.meta_path.insert(0, SixteenInFourteenMovedHook()) | ||
sys.meta_path.insert(0, SixteenInFourteenExtendedHook()) | ||
|
||
# Also patch already imported modules | ||
for mod in EXTENDED_MODULES: | ||
if mod in sys.modules: | ||
extend(sys.modules[mod], mod) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Copyright 2024 Akretion (http://www.akretion.com). | ||
# @author Florian Mounier <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Sixteen in Fourteen", | ||
"summary": "Layer of compat to run 16.0 modules in 14.0", | ||
"version": "14.0.1.0.0", | ||
"category": "Technical", | ||
"website": "https://github.com/akretion/ak-odoo-incubator", | ||
"author": " Akretion", | ||
"license": "AGPL-3", | ||
"application": False, | ||
"installable": True, | ||
"depends": [ | ||
"base", | ||
], | ||
"data": [], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from abc import ABC, abstractmethod | ||
import werkzeug.exceptions | ||
import collections.abc | ||
|
||
_dispatchers = {} | ||
CORS_MAX_AGE = 60 * 60 * 24 | ||
|
||
|
||
class Dispatcher(ABC): | ||
routing_type: str | ||
|
||
@classmethod | ||
def __init_subclass__(cls): | ||
super().__init_subclass__() | ||
_dispatchers[cls.routing_type] = cls | ||
|
||
def __init__(self): | ||
from odoo.http import request | ||
|
||
self.request = request | ||
|
||
@classmethod | ||
@abstractmethod | ||
def is_compatible_with(cls, request): | ||
""" | ||
Determine if the current request is compatible with this | ||
dispatcher. | ||
""" | ||
|
||
def pre_dispatch(self, rule, args): | ||
""" | ||
Prepare the system before dispatching the request to its | ||
controller. This method is often overridden in ir.http to | ||
extract some info from the request query-string or headers and | ||
to save them in the session or in the context. | ||
""" | ||
routing = rule.endpoint.routing | ||
self.request.session.can_save = routing.get("save_session", True) | ||
|
||
set_header = self.request.future_response.headers.set | ||
cors = routing.get("cors") | ||
if cors: | ||
set_header("Access-Control-Allow-Origin", cors) | ||
set_header( | ||
"Access-Control-Allow-Methods", | ||
( | ||
"POST" | ||
if routing["type"] == "json" | ||
else ", ".join(routing["methods"] or ["GET", "POST"]) | ||
), | ||
) | ||
|
||
if cors and self.request.httprequest.method == "OPTIONS": | ||
set_header("Access-Control-Max-Age", CORS_MAX_AGE) | ||
set_header( | ||
"Access-Control-Allow-Headers", | ||
"Origin, X-Requested-With, Content-Type, Accept, Authorization", | ||
) | ||
werkzeug.exceptions.abort(Response(status=204)) | ||
|
||
@abstractmethod | ||
def dispatch(self, endpoint, args): | ||
""" | ||
Extract the params from the request's body and call the | ||
endpoint. While it is preferred to override ir.http._pre_dispatch | ||
and ir.http._post_dispatch, this method can be override to have | ||
a tight control over the dispatching. | ||
""" | ||
|
||
def post_dispatch(self, response): | ||
""" | ||
Manipulate the HTTP response to inject various headers, also | ||
save the session when it is dirty. | ||
""" | ||
self.request._save_session() | ||
self.request._inject_future_response(response) | ||
root.set_csp(response) | ||
|
||
@abstractmethod | ||
def handle_error(self, exc: Exception) -> collections.abc.Callable: | ||
""" | ||
Transform the exception into a valid HTTP response. Called upon | ||
any exception while serving a request. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
def json_float_round(value, precision_digits, rounding_method="HALF-UP"): | ||
"""Not suitable for float calculations! Similar to float_repr except that it | ||
returns a float suitable for json dump | ||
This may be necessary to produce "exact" representations of rounded float | ||
values during serialization, such as what is done by `json.dumps()`. | ||
Unfortunately `json.dumps` does not allow any form of custom float representation, | ||
nor any custom types, everything is serialized from the basic JSON types. | ||
:param int precision_digits: number of fractional digits to round to. | ||
:param rounding_method: the rounding method used: 'HALF-UP', 'UP' or 'DOWN', | ||
the first one rounding up to the closest number with the rule that | ||
number>=0.5 is rounded up to 1, the second always rounding up and the | ||
latest one always rounding down. | ||
:return: a rounded float value that must not be used for calculations, but | ||
is ready to be serialized in JSON with minimal chances of | ||
representation errors. | ||
""" | ||
rounded_value = float_round( | ||
value, precision_digits=precision_digits, rounding_method=rounding_method | ||
) | ||
rounded_repr = float_repr(rounded_value, precision_digits=precision_digits) | ||
# As of Python 3.1, rounded_repr should be the shortest representation for our | ||
# rounded float, so we create a new float whose repr is expected | ||
# to be the same value, or a value that is semantically identical | ||
# and will be used in the json serialization. | ||
# e.g. if rounded_repr is '3.1750', the new float repr could be 3.175 | ||
# but not 3.174999999999322452. | ||
# Cfr. bpo-1580: https://bugs.python.org/issue1580 | ||
return float(rounded_repr) |