19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:34 +01:00
parent 5faf7397c5
commit 2696f14ed7
721 changed files with 220375 additions and 91221 deletions

View file

@ -1,39 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import contextlib
import logging
import json
import requests
import uuid
from unittest.mock import patch
from odoo import exceptions, _
from odoo.tests.common import BaseCase
from odoo.tools import email_normalize, exception_to_unicode, pycompat
from odoo import exceptions, modules, _
from odoo.tools import email_normalize, exception_to_unicode
_logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap.odoo.com'
# We need to mock iap_jsonrpc during tests as we don't want to perform real calls to RPC endpoints
def iap_jsonrpc_mocked(*args, **kwargs):
raise exceptions.AccessError("Unavailable during tests.")
iap_patch = patch('odoo.addons.iap.tools.iap_tools.iap_jsonrpc', iap_jsonrpc_mocked)
def setUp(self):
old_setup_func(self)
iap_patch.start()
self.addCleanup(iap_patch.stop)
old_setup_func = BaseCase.setUp
BaseCase.setUp = setUp
#----------------------------------------------------------
# Tools globals
#----------------------------------------------------------
@ -62,7 +41,7 @@ _MAIL_PROVIDERS = {
'asterisk-tech.mn', 'in.com', 'aliceadsl.fr', 'lycos.com', 'topnet.tn', 'teleworm.us', 'kedgebs.com', 'supinfo.com', 'posteo.de',
'yahoo.com ', 'op.pl', 'gmail.fr', 'grr.la', 'oci.fr', 'aselcis.com', 'optusnet.com.au', 'mailcatch.com', 'rambler.ru', 'protonmail.ch',
'prisme.ch', 'bbox.fr', 'orbitalu.com', 'netcourrier.com', 'iinet.net.au', 'cegetel.net', 'proton.me', 'dbmail.com', 'club-internet.fr', 'outlook.jp',
'pm.me',
'eim.ae', 'pm.me',
# Dummy entries
'example.com',
}
@ -107,17 +86,10 @@ def mail_prepare_for_domain_search(email, min_email_length=0):
return email_tocheck
#----------------------------------------------------------
# Helpers for both clients and proxy
#----------------------------------------------------------
def iap_get_endpoint(env):
url = env['ir.config_parameter'].sudo().get_param('iap.endpoint', DEFAULT_ENDPOINT)
return url
#----------------------------------------------------------
# Helpers for clients
#----------------------------------------------------------
class InsufficientCreditError(Exception):
pass
@ -132,6 +104,9 @@ def iap_jsonrpc(url, method='call', params=None, timeout=15):
Calls the provided JSON-RPC endpoint, unwraps the result and
returns JSON-RPC errors as exceptions.
"""
if modules.module.current_test:
raise exceptions.AccessError("Unavailable during tests.") # pylint: disable=missing-gettext
payload = {
'jsonrpc': '2.0',
'method': method,
@ -144,6 +119,7 @@ def iap_jsonrpc(url, method='call', params=None, timeout=15):
req = requests.post(url, json=payload, timeout=timeout)
req.raise_for_status()
response = req.json()
_logger.info("iap jsonrpc %s responded in %.3f seconds", url, req.elapsed.total_seconds())
if 'error' in response:
name = response['error']['data'].get('name').rpartition('.')[-1]
if name == 'InsufficientCreditError':
@ -161,91 +137,5 @@ def iap_jsonrpc(url, method='call', params=None, timeout=15):
except (requests.exceptions.RequestException, IAPServerError) as e:
_logger.warning("iap jsonrpc %s failed, %s: %s", url, e.__class__.__name__, exception_to_unicode(e))
raise exceptions.AccessError(
_('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s', url)
_("An error occurred while reaching %s. Please contact Odoo support if this error persists.", url)
)
#----------------------------------------------------------
# Helpers for proxy
#----------------------------------------------------------
class IapTransaction(object):
def __init__(self):
self.credit = None
def iap_authorize(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None, ttl=4320):
endpoint = iap_get_endpoint(env)
params = {
'account_token': account_token,
'credit': credit,
'key': key,
'description': description,
'ttl': ttl,
}
if dbuuid:
params.update({'dbuuid': dbuuid})
try:
transaction_token = iap_jsonrpc(endpoint + '/iap/1/authorize', params=params)
except InsufficientCreditError as e:
if credit_template:
arguments = json.loads(e.args[0])
arguments['body'] = pycompat.to_text(env['ir.qweb']._render(credit_template))
e.args = (json.dumps(arguments),)
raise e
return transaction_token
def iap_cancel(env, transaction_token, key):
endpoint = iap_get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
}
r = iap_jsonrpc(endpoint + '/iap/1/cancel', params=params)
return r
def iap_capture(env, transaction_token, key, credit):
endpoint = iap_get_endpoint(env)
params = {
'token': transaction_token,
'key': key,
'credit_to_capture': credit,
}
r = iap_jsonrpc(endpoint + '/iap/1/capture', params=params)
return r
@contextlib.contextmanager
def iap_charge(env, key, account_token, credit, dbuuid=False, description=None, credit_template=None, ttl=4320):
"""
Account charge context manager: takes a hold for ``credit``
amount before executing the body, then captures it if there
is no error, or cancels it if the body generates an exception.
:param str key: service identifier
:param str account_token: user identifier
:param int credit: cost of the body's operation
:param description: a description of the purpose of the charge,
the user will be able to see it in their
dashboard
:type description: str
:param credit_template: a QWeb template to render and show to the
user if their account does not have enough
credits for the requested operation
:param int ttl: transaction time to live in hours.
If the credit are not captured when the transaction
expires, the transaction is canceled
:type credit_template: str
"""
transaction_token = iap_authorize(env, key, account_token, credit, dbuuid, description, credit_template, ttl)
try:
transaction = IapTransaction()
transaction.credit = credit
yield transaction
except Exception as e:
r = iap_cancel(env,transaction_token, key)
raise e
else:
r = iap_capture(env,transaction_token, key, transaction.credit)