Skip to content

Commit 083c174

Browse files
committed
Merge PR #78 into 18.0
Signed-off-by simahawk
2 parents 023c8c0 + 5d55d62 commit 083c174

27 files changed

+2399
-0
lines changed

endpoint/README.rst

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
========
2+
Endpoint
3+
========
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:5b9d2b71d09ff066cd8d17ae88885c36a1eca061387e2a18d62d526b4844edfc
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
18+
:alt: License: LGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb--api-lightgray.png?logo=github
20+
:target: https://github.com/OCA/web-api/tree/18.0/endpoint
21+
:alt: OCA/web-api
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/web-api-18-0/web-api-18-0-endpoint
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/web-api&target_branch=18.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
Provide an endpoint framework allowing users to define their own custom
32+
endpoint.
33+
34+
Thanks to endpoint mixin the endpoint records are automatically
35+
registered as real Odoo routes.
36+
37+
You can easily code what you want in the code snippet.
38+
39+
NOTE: for security reasons any kind of RPC call is blocked on endpoint
40+
records.
41+
42+
**Table of contents**
43+
44+
.. contents::
45+
:local:
46+
47+
Configuration
48+
=============
49+
50+
Go to "Technical -> Endpoints" and create a new endpoint.
51+
52+
Known issues / Roadmap
53+
======================
54+
55+
- add validation of request data
56+
- add api docs generation
57+
- handle multiple routes per endpoint
58+
59+
Bug Tracker
60+
===========
61+
62+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web-api/issues>`_.
63+
In case of trouble, please check there if your issue has already been reported.
64+
If you spotted it first, help us to smash it by providing a detailed and welcomed
65+
`feedback <https://github.com/OCA/web-api/issues/new?body=module:%20endpoint%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
66+
67+
Do not contact contributors directly about support or help with technical issues.
68+
69+
Credits
70+
=======
71+
72+
Authors
73+
-------
74+
75+
* Camptocamp
76+
77+
Contributors
78+
------------
79+
80+
- Simone Orsi <simone.orsi@camptocamp.com>
81+
82+
Maintainers
83+
-----------
84+
85+
This module is maintained by the OCA.
86+
87+
.. image:: https://odoo-community.org/logo.png
88+
:alt: Odoo Community Association
89+
:target: https://odoo-community.org
90+
91+
OCA, or the Odoo Community Association, is a nonprofit organization whose
92+
mission is to support the collaborative development of Odoo features and
93+
promote its widespread use.
94+
95+
.. |maintainer-simahawk| image:: https://github.com/simahawk.png?size=40px
96+
:target: https://github.com/simahawk
97+
:alt: simahawk
98+
99+
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
100+
101+
|maintainer-simahawk|
102+
103+
This module is part of the `OCA/web-api <https://github.com/OCA/web-api/tree/18.0/endpoint>`_ project on GitHub.
104+
105+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

endpoint/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import controllers
2+
from . import models

endpoint/__manifest__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2021 Camptocamp SA
2+
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
3+
4+
{
5+
"name": "Endpoint",
6+
"summary": """Provide custom endpoint machinery.""",
7+
"version": "18.0.1.0.0",
8+
"license": "LGPL-3",
9+
"development_status": "Beta",
10+
"author": "Camptocamp,Odoo Community Association (OCA)",
11+
"maintainers": ["simahawk"],
12+
"website": "https://github.com/OCA/web-api",
13+
"depends": ["endpoint_route_handler", "rpc_helper"],
14+
"data": [
15+
"data/server_action.xml",
16+
"security/ir.model.access.csv",
17+
"security/ir_rule.xml",
18+
"views/endpoint_view.xml",
19+
],
20+
"demo": [
21+
"demo/endpoint_demo.xml",
22+
],
23+
}

endpoint/controllers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import main

endpoint/controllers/main.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright 2021 Camptocamp SA
2+
# @author: Simone Orsi <simone.orsi@camptocamp.com>
3+
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
4+
5+
6+
import json
7+
8+
from werkzeug.exceptions import NotFound
9+
10+
from odoo import http
11+
from odoo.http import Response, request
12+
13+
14+
class EndpointControllerMixin:
15+
def _handle_endpoint(self, env, model, endpoint_route, **params):
16+
endpoint = self._find_endpoint(env, model, endpoint_route)
17+
if not endpoint:
18+
raise NotFound()
19+
endpoint._validate_request(request)
20+
result = endpoint._handle_request(request)
21+
return self._handle_result(result)
22+
23+
def _handle_result(self, result):
24+
response = result.get("response")
25+
if isinstance(response, Response):
26+
# Full response already provided
27+
return response
28+
payload = result.get("payload", "")
29+
status = result.get("status_code", 200)
30+
headers = result.get("headers", {})
31+
return self._make_json_response(payload, headers=headers, status=status)
32+
33+
# TODO: probably not needed anymore as controllers are automatically registered
34+
def _make_json_response(self, payload, headers=None, status=200, **kw):
35+
# TODO: guess out type?
36+
data = json.dumps(payload)
37+
if headers is None:
38+
headers = {}
39+
headers["Content-Type"] = "application/json"
40+
resp = request.make_response(data, headers=headers)
41+
resp.status = str(status)
42+
return resp
43+
44+
def _find_endpoint(self, env, model, endpoint_route):
45+
return env[model]._find_endpoint(endpoint_route)
46+
47+
def auto_endpoint(self, model, endpoint_route, **params):
48+
"""Default method to handle auto-generated endpoints"""
49+
env = request.env
50+
return self._handle_endpoint(env, model, endpoint_route, **params)
51+
52+
53+
class EndpointController(http.Controller, EndpointControllerMixin):
54+
pass

endpoint/data/server_action.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo noupdate="1">
3+
<record id="server_action_registry_sync" model="ir.actions.server">
4+
<field name="name">Sync registry</field>
5+
<field name="type">ir.actions.server</field>
6+
<field name="model_id" ref="endpoint.model_endpoint_endpoint" />
7+
<field name="binding_model_id" ref="endpoint.model_endpoint_endpoint" />
8+
<field name="binding_type">action</field>
9+
<field name="state">code</field>
10+
<field name="code">records.write({"registry_sync": True})
11+
</field>
12+
</record>
13+
</odoo>

endpoint/demo/endpoint_demo.xml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo noupdate="1">
3+
<record id="endpoint_demo_1" model="endpoint.endpoint">
4+
<field name="name">Demo Endpoint 1</field>
5+
<field name="route">/demo/one</field>
6+
<field name="request_method">GET</field>
7+
<field name="exec_mode">code</field>
8+
<field name="code_snippet">
9+
result = {"response": Response("ok")}
10+
</field>
11+
</record>
12+
13+
<record id="endpoint_demo_2" model="endpoint.endpoint">
14+
<field name="name">Demo Endpoint 2</field>
15+
<field name="route">/demo/as_demo_user</field>
16+
<field name="request_method">GET</field>
17+
<field name="auth_type">public</field>
18+
<field name="exec_as_user_id" ref="base.user_demo" />
19+
<field name="exec_mode">code</field>
20+
<field name="code_snippet">
21+
result = {"response": Response("My name is: " + user.name)}
22+
</field>
23+
</record>
24+
25+
<record id="endpoint_demo_3" model="endpoint.endpoint">
26+
<field name="name">Demo Endpoint 3</field>
27+
<field name="route">/demo/json_data</field>
28+
<field name="request_method">GET</field>
29+
<field name="auth_type">public</field>
30+
<field name="exec_as_user_id" ref="base.user_demo" />
31+
<field name="exec_mode">code</field>
32+
<field name="code_snippet">
33+
result = {"payload": {"a": 1, "b": 2}}
34+
</field>
35+
</record>
36+
37+
<record id="endpoint_demo_4" model="endpoint.endpoint">
38+
<field name="name">Demo Endpoint 4</field>
39+
<field name="route">/demo/raise_not_found</field>
40+
<field name="request_method">GET</field>
41+
<field name="auth_type">public</field>
42+
<field name="exec_as_user_id" ref="base.user_demo" />
43+
<field name="exec_mode">code</field>
44+
<field name="code_snippet">
45+
raise werkzeug.exceptions.NotFound()
46+
</field>
47+
</record>
48+
49+
<record id="endpoint_demo_5" model="endpoint.endpoint">
50+
<field name="name">Demo Endpoint 5</field>
51+
<field name="route">/demo/raise_validation_error</field>
52+
<field name="request_method">GET</field>
53+
<field name="auth_type">public</field>
54+
<field name="exec_as_user_id" ref="base.user_demo" />
55+
<field name="exec_mode">code</field>
56+
<field name="code_snippet">
57+
raise exceptions.ValidationError("Sorry, you cannot do this!")
58+
</field>
59+
</record>
60+
61+
<record id="endpoint_demo_6" model="endpoint.endpoint">
62+
<field name="name">Demo Endpoint 6</field>
63+
<field name="route">/demo/value_from_request</field>
64+
<field name="request_method">GET</field>
65+
<field name="auth_type">public</field>
66+
<field name="exec_as_user_id" ref="base.user_demo" />
67+
<field name="exec_mode">code</field>
68+
<field name="code_snippet">
69+
result = {"response": Response(request.params.get("your_name", ""))}
70+
</field>
71+
</record>
72+
73+
<record id="endpoint_demo_7" model="endpoint.endpoint">
74+
<field name="name">Demo Endpoint 7</field>
75+
<field name="route">/demo/bad_method</field>
76+
<field name="request_method">GET</field>
77+
<field name="exec_mode">code</field>
78+
<field name="auth_type">public</field>
79+
<field name="exec_as_user_id" ref="base.user_demo" />
80+
<field name="code_snippet">
81+
result = {"payload": "Method used:" + request.httprequest.method}
82+
</field>
83+
</record>
84+
</odoo>

0 commit comments

Comments
 (0)