You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.9 KiB
104 lines
3.9 KiB
# -*- coding: utf-8 -*-
|
|
|
|
import json
|
|
import logging
|
|
from functools import wraps
|
|
|
|
from odoo import http
|
|
import werkzeug
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class ApiException(Exception):
|
|
INVALID_REQUEST = 'invalid_request'
|
|
|
|
def __init__(self, message, code=None):
|
|
super(Exception, self).__init__(message)
|
|
self.code = code if code else self.INVALID_REQUEST
|
|
|
|
def to_json(self):
|
|
return {
|
|
'error': self.code,
|
|
'error_message': self.message
|
|
}
|
|
|
|
def resource(path, method, auth='user', clients=None):
|
|
assert auth in ['user', 'client']
|
|
|
|
def endpoint_decorator(func):
|
|
@http.route(path, auth='public', type='http', methods=[method, 'OPTIONS'], csrf=False)
|
|
@wraps(func)
|
|
def func_wrapper(self, req, **query):
|
|
cors_headers = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-Debug-Mode, Authorization',
|
|
'Access-Control-Max-Age': 60 * 60 * 24,
|
|
}
|
|
if req.httprequest.method == 'OPTIONS':
|
|
return http.Response(
|
|
status=200,
|
|
headers=cors_headers
|
|
)
|
|
|
|
try:
|
|
access_token = None
|
|
if 'Authorization' in req.httprequest.headers:
|
|
authorization_header = req.httprequest.headers['Authorization']
|
|
if authorization_header[:7] == 'Bearer ':
|
|
access_token = authorization_header.split(' ', 1)[1]
|
|
if access_token is None:
|
|
access_token = query.get('access_token')
|
|
if not access_token:
|
|
raise ApiException(
|
|
'access_token param is missing',
|
|
'invalid_request',
|
|
)
|
|
if auth == 'user':
|
|
token = req.env['galicea_openid_connect.access_token'].sudo().search(
|
|
[('token', '=', access_token)]
|
|
)
|
|
if not token:
|
|
raise ApiException(
|
|
'access_token is invalid',
|
|
'invalid_request',
|
|
)
|
|
req.uid = token.user_id.id
|
|
elif auth == 'client':
|
|
token = req.env['galicea_openid_connect.client_access_token'].sudo().search(
|
|
[('token', '=', access_token)]
|
|
)
|
|
if not token:
|
|
raise ApiException(
|
|
'access_token is invalid',
|
|
'invalid_request',
|
|
)
|
|
req.uid = token.client_id.system_user_id.id
|
|
|
|
if clients:
|
|
if token.client_id.id not in map(lambda c: req.env.ref(c).id, clients):
|
|
raise ApiException('Access denied', 'restricted_app')
|
|
|
|
ctx = req.context.copy()
|
|
ctx.update({'client_id': token.client_id.id})
|
|
req.context = ctx
|
|
|
|
response = func(self, req, **query)
|
|
return werkzeug.Response(
|
|
response=json.dumps(response),
|
|
headers=cors_headers,
|
|
status=200
|
|
)
|
|
except Exception as e:
|
|
status = 400
|
|
if not isinstance(e, ApiException):
|
|
_logger.exception('Unexpected exception while processing API request')
|
|
e = ApiException('Unexpected server error', 'server_error')
|
|
status = 500
|
|
return werkzeug.Response(
|
|
response=json.dumps(e.to_json()),
|
|
status=status,
|
|
headers=cors_headers
|
|
)
|
|
|
|
return func_wrapper
|
|
return endpoint_decorator
|