mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 10:52:03 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
|
|
@ -0,0 +1,4 @@
|
|||
from . import service
|
||||
from . import service_context_provider
|
||||
from . import cerberus_validator
|
||||
from . import user_component_context_provider
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# Copyright 2021 Camptocamp
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
from odoo.addons.component.core import Component
|
||||
|
||||
|
||||
class BaseRestCerberusValidator(Component):
|
||||
"""Component used to lookup the input/output validator methods
|
||||
|
||||
To modify in your services collection::
|
||||
|
||||
class MyCollectionRestCerberusValidator(Component):
|
||||
_name = "mycollection.rest.cerberus.validator"
|
||||
_inherit = "base.rest.cerberus.validator"
|
||||
_usage = "cerberus.validator"
|
||||
_collection = "mycollection"
|
||||
|
||||
def get_validator_handler(self, service, method_name, direction):
|
||||
# customize
|
||||
|
||||
def has_validator_handler(self, service, method_name, direction):
|
||||
# customize
|
||||
|
||||
"""
|
||||
|
||||
_name = "base.rest.cerberus.validator"
|
||||
_usage = "cerberus.validator"
|
||||
_is_rest_service_component = False # marker to retrieve REST components
|
||||
|
||||
def get_validator_handler(self, service, method_name, direction):
|
||||
"""Get the validator handler for a method
|
||||
|
||||
By default, it returns the method on the current service instance. It
|
||||
can be customized to delegate the validators to another component.
|
||||
|
||||
The returned method will be called without arguments, and is expected
|
||||
to return the schema.
|
||||
|
||||
direction is either "input" for request schema or "output" for responses.
|
||||
"""
|
||||
return getattr(service, method_name)
|
||||
|
||||
def has_validator_handler(self, service, method_name, direction):
|
||||
"""Return if the service has a validator handler for a method
|
||||
|
||||
By default, it returns True if the the method exists on the service. It
|
||||
can be customized to delegate the validators to another component.
|
||||
|
||||
The returned method will be called without arguments, and is expected
|
||||
to return the schema.
|
||||
|
||||
direction is either "input" for request schema or "output" for responses.
|
||||
"""
|
||||
return hasattr(service, method_name)
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
# Copyright 2018 ACSONE SA/NV
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
from werkzeug import Response
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
|
||||
from ..apispec.base_rest_service_apispec import BaseRestServiceAPISpec
|
||||
from ..tools import ROUTING_DECORATOR_ATTR
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def to_int(val):
|
||||
# The javascript VM ducktape only use float and so pass float
|
||||
# to the api, the werkzeug request interpret params as unicode
|
||||
# so we have to convert params from string to float to int
|
||||
if isinstance(val, int):
|
||||
return val
|
||||
if val:
|
||||
return int(float(val))
|
||||
return None
|
||||
|
||||
|
||||
def to_bool(val):
|
||||
return val in ("true", "True", "1", True)
|
||||
|
||||
|
||||
def skip_secure_params(func):
|
||||
"""
|
||||
Used to decorate methods
|
||||
:param func:
|
||||
:return:
|
||||
"""
|
||||
func.skip_secure_params = True
|
||||
return func
|
||||
|
||||
|
||||
def skip_secure_response(func):
|
||||
"""
|
||||
Used to decorate methods
|
||||
:param func:
|
||||
:return:
|
||||
"""
|
||||
func.skip_secure_response = True
|
||||
return func
|
||||
|
||||
|
||||
class BaseRestService(AbstractComponent):
|
||||
_name = "base.rest.service"
|
||||
|
||||
_description = None # description included into the openapi doc
|
||||
_is_rest_service_component = True # marker to retrieve REST components
|
||||
|
||||
def _prepare_extra_log(self, func, params, secure_params, res):
|
||||
httprequest = request.httprequest
|
||||
headers = dict(httprequest.headers)
|
||||
return {
|
||||
"application": "Rest Service",
|
||||
"request_url": httprequest.url,
|
||||
"request_method": httprequest.method,
|
||||
"params": params,
|
||||
"headers": headers,
|
||||
"secure_params": secure_params,
|
||||
"res": res,
|
||||
"status": 200,
|
||||
}
|
||||
|
||||
def _log_call(self, func, params, secure_params, res):
|
||||
"""If you want to enjoy the advanced log install the module
|
||||
logging_json"""
|
||||
if request:
|
||||
httprequest = request.httprequest
|
||||
extra = self._prepare_extra_log(func, params, secure_params, res)
|
||||
args = [httprequest.url, httprequest.method]
|
||||
message = "REST call url %s method %s"
|
||||
_logger.debug(message, *args, extra=extra)
|
||||
|
||||
def _prepare_input_params(self, method, params):
|
||||
"""
|
||||
Internal method used to process the input_param parameter. The
|
||||
result will be used to call the final method. The processing is
|
||||
delegated to the `resapi.RestMethodParam` instance specified by the
|
||||
restapi.method` decorator on the method.
|
||||
:param method:
|
||||
:param params:
|
||||
:return:
|
||||
"""
|
||||
method_name = method.__name__
|
||||
if hasattr(method, "skip_secure_params"):
|
||||
return params
|
||||
routing = getattr(method, ROUTING_DECORATOR_ATTR, None)
|
||||
if not routing:
|
||||
_logger.warning(
|
||||
"Method %s is not a public method of service %s",
|
||||
method_name,
|
||||
self._name,
|
||||
)
|
||||
raise NotFound()
|
||||
input_param = routing["input_param"]
|
||||
if input_param:
|
||||
return input_param.from_params(self, params)
|
||||
return {}
|
||||
|
||||
def _prepare_response(self, method, result):
|
||||
"""
|
||||
Internal method used to process the result of the method called by the
|
||||
controller. The result of this process is returned to the controller
|
||||
|
||||
The processing is delegated to the `resapi.RestMethodParam` instance
|
||||
specified by the `restapi.method` decorator on the method.
|
||||
:param method: method
|
||||
:param response:
|
||||
:return: dict/json or `http.Response`
|
||||
"""
|
||||
method_name = method
|
||||
if callable(method):
|
||||
method_name = method.__name__
|
||||
if hasattr(method, "skip_secure_response"):
|
||||
return result
|
||||
routing = getattr(method, ROUTING_DECORATOR_ATTR, None)
|
||||
output_param = routing["output_param"]
|
||||
if not output_param:
|
||||
_logger.warning(
|
||||
"DEPRECATED: You must define an output schema for method %s "
|
||||
"in service %s",
|
||||
method_name,
|
||||
self._name,
|
||||
)
|
||||
return result
|
||||
return output_param.to_response(self, result)
|
||||
|
||||
def dispatch(self, method_name, *args, params=None):
|
||||
"""
|
||||
This method dispatch the call to the final method.
|
||||
Before the call parameters are processed by the
|
||||
`restapi.RestMethodParam` object specified as input_param object.
|
||||
The result of the method is therefore given to the
|
||||
`restapi.RestMethodParam` object specified as output_param to build
|
||||
the final response returned by the service
|
||||
:param method_name:
|
||||
:param *args: query path paramters args
|
||||
:param params: A dictionary with the parameters of the method. Once
|
||||
secured and sanitized, these parameters will be passed
|
||||
to the method as keyword args.
|
||||
:return:
|
||||
"""
|
||||
method = getattr(self, method_name, object())
|
||||
params = params or {}
|
||||
secure_params = self._prepare_input_params(method, params)
|
||||
if isinstance(secure_params, dict):
|
||||
# for backward compatibility methods expecting json params
|
||||
# are declared as m(self, p1=None, p2=None) or m(self, **params)
|
||||
res = method(*args, **secure_params)
|
||||
else:
|
||||
res = method(*args, secure_params)
|
||||
self._log_call(method, params, secure_params, res)
|
||||
if isinstance(res, Response):
|
||||
return res
|
||||
return self._prepare_response(method, res)
|
||||
|
||||
def _validator_delete(self):
|
||||
"""
|
||||
Default validator for delete method.
|
||||
By default delete should never be called with parameters.
|
||||
"""
|
||||
return {}
|
||||
|
||||
def _validator_get(self):
|
||||
"""
|
||||
Default validator for get method.
|
||||
By default get should not be called with parameters.
|
||||
"""
|
||||
return {}
|
||||
|
||||
def _get_api_spec(self, **params):
|
||||
return BaseRestServiceAPISpec(self, **params)
|
||||
|
||||
def to_openapi(self, **params):
|
||||
"""
|
||||
Return the description of this REST service as an OpenAPI json document
|
||||
:return: json document
|
||||
"""
|
||||
api_spec = self._get_api_spec(**params)
|
||||
api_spec.generate_paths()
|
||||
return api_spec.to_dict()
|
||||
|
||||
def _get_openapi_default_parameters(self):
|
||||
return []
|
||||
|
||||
def _get_openapi_default_responses(self):
|
||||
return {
|
||||
"400": {"description": "One of the given parameter is not valid"},
|
||||
"401": {
|
||||
"description": "The user is not authorized. Authentication "
|
||||
"is required"
|
||||
},
|
||||
"404": {"description": "Requested resource not found"},
|
||||
"403": {
|
||||
"description": "You don't have the permission to access the "
|
||||
"requested resource."
|
||||
},
|
||||
}
|
||||
|
||||
@property
|
||||
def request(self):
|
||||
return self.work.request
|
||||
|
||||
@property
|
||||
def controller(self):
|
||||
return self.work.controller
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright 2021 ACSONE SA/NV
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
|
||||
from odoo.addons.component.core import Component
|
||||
|
||||
|
||||
class BaseRestServiceContextProvider(Component):
|
||||
_name = "base.rest.service.context.provider"
|
||||
_usage = "component_context_provider"
|
||||
|
||||
def __init__(self, work_context):
|
||||
super().__init__(work_context)
|
||||
self.request = work_context.request
|
||||
# pylint: disable=assignment-from-none
|
||||
self.authenticated_partner_id = self._get_authenticated_partner_id()
|
||||
|
||||
def _get_authenticated_partner_id(self):
|
||||
return None
|
||||
|
||||
def _get_component_context(self):
|
||||
return {
|
||||
"request": self.request,
|
||||
"authenticated_partner_id": self.authenticated_partner_id,
|
||||
"collection": self.collection,
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2021 ACSONE SA/NV
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
|
||||
|
||||
class AbstractUserAuthenticatedPartnerProvider(AbstractComponent):
|
||||
_name = "abstract.user.authenticated.partner.provider"
|
||||
|
||||
def _get_authenticated_partner_id(self):
|
||||
return self.env.user.partner_id.id
|
||||
Loading…
Add table
Add a link
Reference in a new issue