| |
| import json |
| import math |
| import logging |
| import requests |
|
|
| from odoo import http, _, exceptions |
| from odoo.http import request |
|
|
| from .serializers import Serializer |
| from .exceptions import QueryFormatError |
|
|
|
|
| _logger = logging.getLogger(__name__) |
|
|
|
|
| def error_response(error, msg): |
| return { |
| "jsonrpc": "2.0", |
| "id": None, |
| "error": { |
| "code": 200, |
| "message": msg, |
| "data": { |
| "name": str(error), |
| "debug": "", |
| "message": msg, |
| "arguments": list(error.args), |
| "exception_type": type(error).__name__ |
| } |
| } |
| } |
|
|
|
|
| class OdooAPI(http.Controller): |
| @http.route( |
| '/auth/', |
| type='json', auth='none', methods=["POST"], csrf=False) |
| def authenticate(self, *args, **post): |
| try: |
| login = post["login"] |
| except KeyError: |
| raise exceptions.AccessDenied(message='`login` is required.') |
|
|
| try: |
| password = post["password"] |
| except KeyError: |
| raise exceptions.AccessDenied(message='`password` is required.') |
|
|
| try: |
| db = post["db"] |
| except KeyError: |
| raise exceptions.AccessDenied(message='`db` is required.') |
|
|
| http.request.session.authenticate(db, login, password) |
| res = request.env['ir.http'].session_info() |
| return res |
|
|
| @http.route( |
| '/object/<string:model>/<string:function>', |
| type='json', auth='user', methods=["POST"], csrf=False) |
| def call_model_function(self, model, function, **post): |
| args = [] |
| kwargs = {} |
| if "args" in post: |
| args = post["args"] |
| if "kwargs" in post: |
| kwargs = post["kwargs"] |
| model = request.env[model] |
| result = getattr(model, function)(*args, **kwargs) |
| return result |
|
|
| @http.route( |
| '/object/<string:model>/<int:rec_id>/<string:function>', |
| type='json', auth='user', methods=["POST"], csrf=False) |
| def call_obj_function(self, model, rec_id, function, **post): |
| args = [] |
| kwargs = {} |
| if "args" in post: |
| args = post["args"] |
| if "kwargs" in post: |
| kwargs = post["kwargs"] |
| obj = request.env[model].browse(rec_id).ensure_one() |
| result = getattr(obj, function)(*args, **kwargs) |
| return result |
|
|
| @http.route( |
| '/api/<string:model>', |
| type='http', auth='user', methods=['GET'], csrf=False) |
| def get_model_data(self, model, **params): |
| try: |
| records = request.env[model].search([]) |
| except KeyError as e: |
| msg = "The model `%s` does not exist." % model |
| res = error_response(e, msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| if "query" in params: |
| query = params["query"] |
| else: |
| query = "{*}" |
|
|
| if "order" in params: |
| orders = json.loads(params["order"]) |
| else: |
| orders = "" |
|
|
| if "filter" in params: |
| filters = json.loads(params["filter"]) |
| records = request.env[model].search(filters, order=orders) |
|
|
| prev_page = None |
| next_page = None |
| total_page_number = 1 |
| current_page = 1 |
|
|
| if "page_size" in params: |
| page_size = int(params["page_size"]) |
| count = len(records) |
| total_page_number = math.ceil(count/page_size) |
|
|
| if "page" in params: |
| current_page = int(params["page"]) |
| else: |
| current_page = 1 |
| start = page_size*(current_page-1) |
| stop = current_page*page_size |
| records = records[start:stop] |
| next_page = current_page+1 \ |
| if 0 < current_page + 1 <= total_page_number \ |
| else None |
| prev_page = current_page-1 \ |
| if 0 < current_page - 1 <= total_page_number \ |
| else None |
|
|
| if "limit" in params: |
| limit = int(params["limit"]) |
| records = records[0:limit] |
|
|
| try: |
| serializer = Serializer(records, query, many=True) |
| data = serializer.data |
| except (SyntaxError, QueryFormatError) as e: |
| res = error_response(e, e.msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| res = { |
| "count": len(records), |
| "prev": prev_page, |
| "current": current_page, |
| "next": next_page, |
| "total_pages": total_page_number, |
| "result": data |
| } |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| @http.route( |
| '/api/<string:model>/<int:rec_id>', |
| type='http', auth='user', methods=['GET'], csrf=False) |
| def get_model_rec(self, model, rec_id, **params): |
| try: |
| records = request.env[model].search([]) |
| except KeyError as e: |
| msg = "The model `%s` does not exist." % model |
| res = error_response(e, msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| if "query" in params: |
| query = params["query"] |
| else: |
| query = "{*}" |
|
|
| |
| record = records.browse(rec_id).ensure_one() |
|
|
| try: |
| serializer = Serializer(record, query) |
| data = serializer.data |
| except (SyntaxError, QueryFormatError) as e: |
| res = error_response(e, e.msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| return http.Response( |
| json.dumps(data), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| @http.route( |
| '/api/<string:model>/', |
| type='json', auth="user", methods=['POST'], csrf=False) |
| def post_model_data(self, model, **post): |
| try: |
| data = post['data'] |
| except KeyError: |
| msg = "`data` parameter is not found on POST request body" |
| raise exceptions.ValidationError(msg) |
|
|
| try: |
| model_to_post = request.env[model] |
| except KeyError: |
| msg = "The model `%s` does not exist." % model |
| raise exceptions.ValidationError(msg) |
|
|
| |
|
|
| if "context" in post: |
| context = post["context"] |
| record = model_to_post.with_context(**context).create(data) |
| else: |
| record = model_to_post.create(data) |
| return record.id |
|
|
| |
| @http.route( |
| '/api/<string:model>/<int:rec_id>/', |
| type='json', auth="user", methods=['PUT'], csrf=False) |
| def put_model_record(self, model, rec_id, **post): |
| try: |
| data = post['data'] |
| except KeyError: |
| msg = "`data` parameter is not found on PUT request body" |
| raise exceptions.ValidationError(msg) |
|
|
| try: |
| model_to_put = request.env[model] |
| except KeyError: |
| msg = "The model `%s` does not exist." % model |
| raise exceptions.ValidationError(msg) |
|
|
| if "context" in post: |
| |
| rec = model_to_put.with_context(**post["context"])\ |
| .browse(rec_id).ensure_one() |
| else: |
| rec = model_to_put.browse(rec_id).ensure_one() |
|
|
| |
| for field in data: |
| if isinstance(data[field], dict): |
| operations = [] |
| for operation in data[field]: |
| if operation == "push": |
| operations.extend( |
| (4, rec_id, _) |
| for rec_id |
| in data[field].get("push") |
| ) |
| elif operation == "pop": |
| operations.extend( |
| (3, rec_id, _) |
| for rec_id |
| in data[field].get("pop") |
| ) |
| elif operation == "delete": |
| operations.extend( |
| (2, rec_id, _) |
| for rec_id |
| in data[field].get("delete") |
| ) |
| else: |
| data[field].pop(operation) |
|
|
| data[field] = operations |
| elif isinstance(data[field], list): |
| data[field] = [(6, _, data[field])] |
| else: |
| pass |
|
|
| try: |
| return rec.write(data) |
| except Exception as e: |
| |
| return False |
|
|
| |
| @http.route( |
| '/api/<string:model>/', |
| type='json', auth="user", methods=['PUT'], csrf=False) |
| def put_model_records(self, model, **post): |
| try: |
| data = post['data'] |
| except KeyError: |
| msg = "`data` parameter is not found on PUT request body" |
| raise exceptions.ValidationError(msg) |
|
|
| try: |
| model_to_put = request.env[model] |
| except KeyError: |
| msg = "The model `%s` does not exist." % model |
| raise exceptions.ValidationError(msg) |
|
|
| |
| filters = post["filter"] |
|
|
| if "context" in post: |
| recs = model_to_put.with_context(**post["context"])\ |
| .search(filters) |
| else: |
| recs = model_to_put.search(filters) |
|
|
| |
| for field in data: |
| if isinstance(data[field], dict): |
| operations = [] |
| for operation in data[field]: |
| if operation == "push": |
| operations.extend( |
| (4, rec_id, _) |
| for rec_id |
| in data[field].get("push") |
| ) |
| elif operation == "pop": |
| operations.extend( |
| (3, rec_id, _) |
| for rec_id |
| in data[field].get("pop") |
| ) |
| elif operation == "delete": |
| operations.extend( |
| (2, rec_id, _) |
| for rec_id in |
| data[field].get("delete") |
| ) |
| else: |
| pass |
|
|
| data[field] = operations |
| elif isinstance(data[field], list): |
| data[field] = [(6, _, data[field])] |
| else: |
| pass |
|
|
| if recs.exists(): |
| try: |
| return recs.write(data) |
| except Exception as e: |
| |
| return False |
| else: |
| |
| return True |
|
|
| |
| @http.route( |
| '/api/<string:model>/<int:rec_id>/', |
| type='http', auth="user", methods=['DELETE'], csrf=False) |
| def delete_model_record(self, model, rec_id, **post): |
| try: |
| model_to_del_rec = request.env[model] |
| except KeyError as e: |
| msg = "The model `%s` does not exist." % model |
| res = error_response(e, msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| |
| rec = model_to_del_rec.browse(rec_id).ensure_one() |
|
|
| try: |
| is_deleted = rec.unlink() |
| res = { |
| "result": is_deleted |
| } |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
| except Exception as e: |
| res = error_response(e, str(e)) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| |
| @http.route( |
| '/api/<string:model>/', |
| type='http', auth="user", methods=['DELETE'], csrf=False) |
| def delete_model_records(self, model, **post): |
| filters = json.loads(post["filter"]) |
|
|
| try: |
| model_to_del_rec = request.env[model] |
| except KeyError as e: |
| msg = "The model `%s` does not exist." % model |
| res = error_response(e, msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| |
| recs = model_to_del_rec.search(filters) |
|
|
| try: |
| is_deleted = recs.unlink() |
| res = { |
| "result": is_deleted |
| } |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
| except Exception as e: |
| res = error_response(e, str(e)) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| @http.route( |
| '/api/<string:model>/<int:rec_id>/<string:field>', |
| type='http', auth="user", methods=['GET'], csrf=False) |
| def get_binary_record(self, model, rec_id, field, **post): |
| try: |
| request.env[model] |
| except KeyError as e: |
| msg = "The model `%s` does not exist." % model |
| res = error_response(e, msg) |
| return http.Response( |
| json.dumps(res), |
| status=200, |
| mimetype='application/json' |
| ) |
|
|
| rec = request.env[model].browse(rec_id).ensure_one() |
| if rec.exists(): |
| src = getattr(rec, field).decode("utf-8") |
| else: |
| src = False |
| return http.Response( |
| src |
| ) |
|
|