Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [16.0] base_rest #312

Closed
wants to merge 2 commits into from
Closed
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
6 changes: 0 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
exclude: |
(?x)
# NOT INSTALLABLE ADDONS
^base_rest/|
^base_rest_auth_api_key/|
^base_rest_auth_jwt/|
^base_rest_auth_user_service/|
^base_rest_datamodel/|
^base_rest_demo/|
^base_rest_pydantic/|
^datamodel/|
^extendable/|
^graphql_base/|
^graphql_demo/|
^model_serializer/|
Expand Down
8 changes: 4 additions & 4 deletions base_rest/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"summary": """
Develop your own high level REST APIs for Odoo thanks to this addon.
""",
"version": "15.0.1.2.0",
"version": "16.0.1.0.0",
"development_status": "Beta",
"license": "LGPL-3",
"author": "ACSONE SA/NV, " "Odoo Community Association (OCA)",
Expand All @@ -18,12 +18,12 @@
"views/base_rest_view.xml",
],
"assets": {
"web.assets_common": [
"web.assets_frontend": [
"base_rest/static/src/scss/base_rest.scss",
"base_rest/static/src/js/swagger_ui.js",
"base_rest/static/src/js/swagger.js",
],
},
"demo": [],
"external_dependencies": {
"python": [
"cerberus",
Expand All @@ -32,5 +32,5 @@
"apispec>=4.0.0",
]
},
"installable": False,
"installable": True,
}
4 changes: 1 addition & 3 deletions base_rest/controllers/api_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ def api(self, collection, service_name):
service,
controller_class,
):
openapi_doc = service.to_openapi(
default_auth=controller_class._default_auth
)
openapi_doc = service.to_openapi(default_auth=controller_class)
return self.make_json_response(openapi_doc)

def _get_api_urls(self):
Expand Down
115 changes: 76 additions & 39 deletions base_rest/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
from werkzeug.exceptions import BadRequest

from odoo import models
from odoo.http import Controller, ControllerType, Response, request
from odoo.http import Controller, Response, request

from odoo.addons.component.core import WorkContext, _get_addon_name
from odoo.addons.component.core import WorkContext

from ..core import _rest_controllers_per_module

# from odoo.http import Controller, ControllerType, Response, request


_logger = logging.getLogger(__name__)


Expand All @@ -25,43 +28,44 @@ def __init__(self, name, env):
self.id = None


class RestControllerType(ControllerType):

# pylint: disable=E0213
def __init__(cls, name, bases, attrs): # noqa: B902
if (
"RestController" in globals()
and RestController in bases
and Controller not in bases
):
# to be registered as a controller into the ControllerType,
# our RestConrtroller must be a direct child of Controller
bases += (Controller,)
super(RestControllerType, cls).__init__(name, bases, attrs)
if "RestController" not in globals() or not any(
issubclass(b, RestController) for b in bases
):
return
# register the rest controller into the rest controllers registry
root_path = getattr(cls, "_root_path", None)
collection_name = getattr(cls, "_collection_name", None)
if root_path and collection_name:
cls._module = _get_addon_name(cls.__module__)
_rest_controllers_per_module[cls._module].append(
{
"root_path": root_path,
"collection_name": collection_name,
"controller_class": cls,
}
)
_logger.debug(
"Added rest controller %s for module %s",
_rest_controllers_per_module[cls._module][-1],
cls._module,
)


class RestController(Controller, metaclass=RestControllerType):
# class RestControllerType(ControllerType):
#
# # pylint: disable=E0213
# def __init__(cls, name, bases, attrs): # noqa: B902
# if (
# "RestController" in globals()
# and RestController in bases
# and Controller not in bases
# ):
# # to be registered as a controller into the ControllerType,
# # our RestConrtroller must be a direct child of Controller
# bases += (Controller,)
# super(RestControllerType, cls).__init__(name, bases, attrs)
# if "RestController" not in globals() or not any(
# issubclass(b, RestController) for b in bases
# ):
# return
# # register the rest controller into the rest controllers registry
# root_path = getattr(cls, "_root_path", None)
# collection_name = getattr(cls, "_collection_name", None)
# if root_path and collection_name:
# cls._module = _get_addon_name(cls.__module__)
# _rest_controllers_per_module[cls._module].append(
# {
# "root_path": root_path,
# "collection_name": collection_name,
# "controller_class": cls,
# }
# )
# _logger.debug(
# "Added rest controller %s for module %s",
# _rest_controllers_per_module[cls._module][-1],
# cls._module,
# )


# class RestController(Controller, metaclass=RestControllerType):
class RestController(Controller):
"""Generic REST Controller

This controller is the base controller used by as base controller for all the REST
Expand Down Expand Up @@ -130,6 +134,39 @@ class ControllerB(ControllerB):

_component_context_provider = "component_context_provider"

@classmethod
def __init_subclass__(cls):
if (
"RestController" in globals()
and RestController in cls.__bases__
and Controller not in cls.__bases__
):
cls.__bases__ += (Controller,)
super().__init_subclass__()
if "RestController" not in globals() or not any(
issubclass(b, RestController) for b in cls.__bases__
):
return
# register the rest controller into the rest controllers registry
root_path = getattr(cls, "_root_path", None)
collection_name = getattr(cls, "_collection_name", None)
if root_path and collection_name:
path = cls.__module__.split(".")
module = path[2] if path[:2] == ["odoo", "addons"] else ""
cls._module = module # _get_addon_name(cls.__module__, cls._module)
_rest_controllers_per_module[cls].append(
{
"root_path": root_path,
"collection_name": collection_name,
"controller_class": cls,
}
)
_logger.debug(
"Added rest controller %s for module %s",
_rest_controllers_per_module[cls][-1],
cls._module,
)

def _get_component_context(self, collection=None):
"""
This method can be inherited to add parameter into the component
Expand Down
49 changes: 26 additions & 23 deletions base_rest/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,22 @@
)
from werkzeug.utils import escape

import odoo
from odoo.exceptions import (
AccessDenied,
AccessError,
MissingError,
UserError,
ValidationError,
)
from odoo.http import HttpRequest, Root, SessionExpiredException, request

# from odoo.http import HttpRequest, Root, SessionExpiredException, request
from odoo.http import Request, SessionExpiredException, request
from odoo.tools import ustr
from odoo.tools.config import config

from .core import _rest_services_routes
# import odoo
# from .core import _rest_services_routes


_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -116,7 +119,7 @@ def get_headers(environ=None):
return exception


class HttpRestRequest(HttpRequest):
class HttpRestRequest(Request):
"""Http request that always return json, usefull for rest api"""

def __init__(self, httprequest):
Expand Down Expand Up @@ -216,22 +219,22 @@ def make_json_response(self, data, headers=None, cookies=None):
return self.make_response(data, headers=headers, cookies=cookies)


ori_get_request = Root.get_request


def get_request(self, httprequest):
db = httprequest.session.db
if db and odoo.service.db.exp_db_exist(db):
# on the very first request processed by a worker,
# registry is not loaded yet
# so we enforce its loading here to make sure that
# _rest_services_databases is not empty
odoo.registry(db)
rest_routes = _rest_services_routes.get(db, [])
for root_path in rest_routes:
if httprequest.path.startswith(root_path):
return HttpRestRequest(httprequest)
return ori_get_request(self, httprequest)


Root.get_request = get_request
# ori_get_request = Application.get_request
#
#
# def get_request(self, httprequest):
# db = httprequest.session.db
# if db and odoo.service.db.exp_db_exist(db):
# # on the very first request processed by a worker,
# # registry is not loaded yet
# # so we enforce its loading here to make sure that
# # _rest_services_databases is not empty
# odoo.registry(db)
# rest_routes = _rest_services_routes.get(db, [])
# for root_path in rest_routes:
# if httprequest.path.startswith(root_path):
# return HttpRestRequest(httprequest)
# return ori_get_request(self, httprequest)
#
#
# Application.get_request = get_request
12 changes: 8 additions & 4 deletions base_rest/models/rest_service_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ def _register_hook(self):
self.build_registry(services_registry)
# we also have to remove the RestController from the
# controller_per_module registry since it's an abstract controller
controllers = http.controllers_per_module["base_rest"]
controllers = http.Controller.children_classes["base_rest"]
# controllers = [
# (name, cls) for name, cls in controllers if "RestController" not in name
# ]
controllers = [
(name, cls) for name, cls in controllers if "RestController" not in name
(name) for name in controllers if "RestController" not in name.__name__
]
http.controllers_per_module["base_rest"] = controllers
http.Controller.children_classes["base_rest"] = controllers
# create the final controller providing the http routes for
# the services available into the current database
self._build_controllers_routes(services_registry)
Expand Down Expand Up @@ -104,7 +107,8 @@ def _build_controller(self, service, controller_def):

# register our conroller into the list of available controllers
name_class = ("{}.{}".format(ctrl_cls.__module__, ctrl_cls.__name__), ctrl_cls)
http.controllers_per_module[addon_name].append(name_class)
http.Controller.children_classes[addon_name] = name_class
# http.controllers_per_module[addon_name].append(name_class)
self._apply_defaults_to_controller_routes(controller_class=ctrl_cls)

def _apply_defaults_to_controller_routes(self, controller_class):
Expand Down
16 changes: 16 additions & 0 deletions base_rest/static/src/js/swagger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
odoo.define("base_rest.swagger", function (require) {
"use strict";

var publicWidget = require("web.public.widget");
var SwaggerUi = require("base_rest.swagger_ui");

publicWidget.registry.Swagger = publicWidget.Widget.extend({
selector: "#swagger-ui",
start: function () {
var def = this._super.apply(this, arguments);
var swagger_ui = new SwaggerUi("#swagger-ui");
swagger_ui.start();
return def;
},
});
});
2 changes: 1 addition & 1 deletion base_rest/static/src/js/swagger_ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ odoo.define("base_rest.swagger_ui", function (require) {
onComplete: function () {
if (this.web_btn === undefined) {
this.web_btn = $(
"<a class='fa fa-th swg-odoo-web-btn' href='/web' accesskey='h'></a>"
"<a class='fa fa-th-large swg-odoo-web-btn' href='/web' accesskey='h'></a>"
);
$(".topbar").prepend(this.web_btn);
}
Expand Down
13 changes: 1 addition & 12 deletions base_rest/views/openapi_template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,14 @@
/>

<t t-call-assets="web.assets_common" t-css="false" />
<t t-call-assets="web.assets_frontend" t-css="false" />
<t t-call-assets="web.assets_frontend" t-css="true" />
<t t-call-assets="base_rest.assets_swagger" t-css="false" />
</t>
<t t-set="head" t-value="head" />
</t>

<body>
<div id="swagger-ui" t-att-data-settings='json.dumps(swagger_settings)' />

<script>
odoo.define('base_rest.swagger', function (require) {
var SwaggerUi = require('base_rest.swagger_ui');
var swagger_ui = new SwaggerUi('#swagger-ui');
$(function() {
swagger_ui.start();
});
return swagger_ui;
});
</script>
</body>
</template>
</odoo>
6 changes: 2 additions & 4 deletions base_rest_datamodel/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
"name": "Base Rest Datamodel",
"summary": """
Datamodel binding for base_rest""",
"version": "15.0.1.1.0",
"version": "16.0.1.0.0",
"license": "LGPL-3",
"author": "ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/rest-framework",
"depends": ["base_rest", "datamodel"],
"data": [],
"demo": [],
"external_dependencies": {"python": ["apispec>=4.0.0", "marshmallow"]},
"installable": False,
"installable": True,
}
6 changes: 2 additions & 4 deletions base_rest_demo/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "Base Rest Demo",
"summary": """
Demo addon for Base REST""",
"version": "15.0.1.0.1",
"version": "16.0.1.0.0",
"development_status": "Beta",
"license": "LGPL-3",
"author": "ACSONE SA/NV, " "Odoo Community Association (OCA)",
Expand All @@ -18,10 +18,8 @@
"component",
"extendable",
],
"data": [],
"demo": [],
"external_dependencies": {
"python": ["jsondiff", "extendable-pydantic", "pydantic"]
},
"installable": False,
"installable": True,
}
Loading