diff --git a/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.zip b/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.zip deleted file mode 100644 index d2a8392f5..000000000 Binary files a/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.zip and /dev/null differ diff --git a/rest_api_odoo/__manifest__.py b/rest_api_odoo/__manifest__.py index 76914b0e7..694df2e04 100644 --- a/rest_api_odoo/__manifest__.py +++ b/rest_api_odoo/__manifest__.py @@ -33,7 +33,7 @@ "depends": ['base', 'web'], "data": [ 'security/ir.model.access.csv', - 'views/res_users_views.xml', + 'security/res_api_odoo_security.xml', 'views/connection_api_views.xml' ], 'images': ['static/description/banner.png'], diff --git a/rest_api_odoo/controllers/main.py b/rest_api_odoo/controllers/main.py index 0f02df40b..f5892d604 100644 --- a/rest_api_odoo/controllers/main.py +++ b/rest_api_odoo/controllers/main.py @@ -24,27 +24,43 @@ import json import logging from datetime import datetime -from odoo import http +from odoo import http, models from odoo.http import request, Response from ast import literal_eval _logger = logging.getLogger(__name__) -class RestApi(http.Controller): - """This is a controller which is used to generate responses based on the - api requests""" +class IrHttp(models.AbstractModel): + """This model is used to authenticate the api-key when sending a request""" + _inherit = "ir.http" - def auth_api_key(self, api_key): + @classmethod + def _auth_method_rest_api(cls): """This function is used to authenticate the api-key when sending a request""" - user_id = request.env["res.users"].search([("api_key", "=", api_key)]) - if api_key is not None and user_id: - return Response(json.dumps({"message": "Authorized"}), status=200) - elif not user_id: - return Response(json.dumps({"message": "Invalid API Key"}), status=401) - return Response(json.dumps({"message": "No API Key Provided"}), status=400) + try: + api_key = request.httprequest.headers.get("Authorization").lstrip("Bearer ") + if not api_key: + raise PermissionError("Invalid API key provided.") + + user_id = request.env["res.users.apikeys"]._check_credentials( + scope="rpc", key=api_key + ) + request.update_env(user_id) + except Exception as e: + _logger.error(e) + return Response( + json.dumps({"message": e.args[0]}), + status=401, + content_type="application/json", + ) + + +class RestApi(http.Controller): + """This is a controller which is used to generate responses based on the + api requests""" def simplest_type(self, input): """Try cast input into native Python class, otherwise return as string""" @@ -123,7 +139,8 @@ class RestApi(http.Controller): ) return Response( - json.dumps({"records": self.sanitize_records(partner_records)}) + json.dumps({"records": self.sanitize_records(partner_records)}), + content_type="application/json", ) if method == "POST": if not option.is_post: @@ -139,6 +156,7 @@ class RestApi(http.Controller): return Response( json.dumps({"new_record": self.sanitize_records(partner_records)}), status=201, + content_type="application/json", ) if method == "PUT": if not option.is_put: @@ -162,7 +180,8 @@ class RestApi(http.Controller): return Response( json.dumps( {"updated_record": self.sanitize_records(partner_records)} - ) + ), + content_type="application/json", ) if method == "DELETE": if not option.is_delete: @@ -188,12 +207,17 @@ class RestApi(http.Controller): } ), status=202, + content_type="application/json", ) # If not using any method above, simply return an error raise NotImplementedError() except ValueError as e: - return Response(json.dumps({"message": e.args[0]}), status=403) + return Response( + json.dumps({"message": e.args[0]}), + status=403, + content_type="application/json", + ) except NotImplementedError as e: return Response( json.dumps( @@ -202,16 +226,20 @@ class RestApi(http.Controller): } ), status=405, + content_type="application/json", ) - except Exception: + except Exception as e: + _logger.error(e) return Response( - json.dumps({"message": "Internal server error"}), status=500 + json.dumps({"message": f"Internal server error. {e.args[0]}"}), + status=500, + content_type="application/json", ) @http.route( ["/send_request"], type="http", - auth="none", + auth="rest_api", methods=["GET", "POST", "PUT", "DELETE"], csrf=False, ) @@ -221,12 +249,7 @@ class RestApi(http.Controller): generate the result""" http_method = request.httprequest.method - api_key = request.httprequest.headers.get("api-key") - auth_api = self.auth_api_key(api_key) model = kw.pop("model") - username = request.httprequest.headers.get("login") - password = request.httprequest.headers.get("password") - request.session.authenticate(request.session.db, username, password) model_id = request.env["ir.model"].search([("model", "=", model)]) if not model_id: return Response( @@ -236,34 +259,7 @@ class RestApi(http.Controller): } ), status=403, + content_type="application/json", ) - if auth_api.status_code == 200: - result = self.generate_response(http_method, model=model_id.id, **kw) - return result - else: - return auth_api - - @http.route( - ["/odoo_connect"], type="http", auth="none", csrf=False, methods=["GET"] - ) - def odoo_connect(self, **kw): - """This is the controller which initializes the api transaction by - generating the api-key for specific user and database""" - - username = request.httprequest.headers.get("login") - password = request.httprequest.headers.get("password") - db = request.httprequest.headers.get("db") - try: - request.session.update(http.get_default_session(), db=db) - auth = request.session.authenticate(request.session.db, username, password) - user = request.env["res.users"].browse(auth) - api_key = request.env.user.generate_api(username) - datas = json.dumps( - {"Status": "auth successful", "User": user.name, "api-key": api_key} - ) - return Response(datas) - except Exception: - return Response( - json.dumps({"message": "wrong login credentials"}), status=401 - ) + return self.generate_response(http_method, model=model_id.id, **kw) diff --git a/rest_api_odoo/models/__init__.py b/rest_api_odoo/models/__init__.py index e9bf22051..27f8df7c3 100644 --- a/rest_api_odoo/models/__init__.py +++ b/rest_api_odoo/models/__init__.py @@ -21,4 +21,3 @@ ############################################################################# from . import connection_api -from . import res_users diff --git a/rest_api_odoo/models/res_users.py b/rest_api_odoo/models/res_users.py deleted file mode 100644 index a2d861f36..000000000 --- a/rest_api_odoo/models/res_users.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding:utf-8 -*- -############################################################################# -# -# Cybrosys Technologies Pvt. Ltd. -# -# Copyright (C) 2023-TODAY Cybrosys Technologies() -# Author: Cybrosys Techno Solutions() -# -# You can modify it under the terms of the GNU LESSER -# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. -# -# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE -# (LGPL v3) along with this program. -# If not, see . -# -############################################################################# - -import uuid -from odoo import fields, models - - -class UserLogin(models.Model): - """This class is used to inherit users and add api key generation""" - _inherit = 'res.users' - - api_key = fields.Char(string="API Key", readonly=True, - help="Api key for connecting with the " - "Database.The key will be " - "generated when authenticating " - "rest api.") - - def generate_api(self, username): - """This function is used to generate api-key for each user""" - users = self.env['res.users'].sudo().search([('login', '=', username)]) - if not users.api_key: - users.api_key = str(uuid.uuid4()) - key = users.api_key - else: - key = users.api_key - return key diff --git a/rest_api_odoo/security/res_api_odoo_security.xml b/rest_api_odoo/security/res_api_odoo_security.xml new file mode 100644 index 000000000..545fd5132 --- /dev/null +++ b/rest_api_odoo/security/res_api_odoo_security.xml @@ -0,0 +1,32 @@ + + + + + + REST API + Helps you manage your REST API records. + 17 + + + + Manager + + + + + + + + + + All REST APIs + + [(1,'=',1)] + + + + + \ No newline at end of file diff --git a/rest_api_odoo/static/description/assets/screenshots/screenshot_2.png b/rest_api_odoo/static/description/assets/screenshots/screenshot_2.png index c892dd068..94edbd0e0 100644 Binary files a/rest_api_odoo/static/description/assets/screenshots/screenshot_2.png and b/rest_api_odoo/static/description/assets/screenshots/screenshot_2.png differ diff --git a/rest_api_odoo/static/description/index.html b/rest_api_odoo/static/description/index.html index 59b955d1e..fff5c7eb1 100644 --- a/rest_api_odoo/static/description/index.html +++ b/rest_api_odoo/static/description/index.html @@ -23,7 +23,7 @@

- Odoo rest API

+ Odoo Rest API @@ -138,7 +138,7 @@
- Authentication using the generated api key. + Authentication using the generated API key.
@@ -223,23 +223,15 @@ uninstall the module , you have to remove this parameter.
- Next we can install the module. -
  • After installing the Rest api app we can see a new api key +
  • After installing the Rest API app we can see a new API key field in users.
  • - - Next we have to generate the api-key for the current + - Next we have to generate the API-key for the current user.
    -
  • You can import the postman collections provided in the app - folder for authentication and interacting with database in - various methods. -
  • -
    -
    -
    @@ -248,27 +240,8 @@

      -
    • Next you have to select the database and login.
    • -
    • We have attached Postman collections through which - you can - authenticate REST api. -
    • -
    • First, extract the zip file. Then, you will obtain the JSON-format file, which you can directly import into POSTMAN.
    • -
    • The url format will be like this - http://cybrosys:8016/odoo_connect - Replace 'cybrosys:8016' with your localhost port number. -
    • -
    • You have to provide database name, username and password - through the headers while sending request. -
    • -
    • If the authentication is successful , an api key will be - generated for the current user. -
    • -
    • This key will be used when sending api requests to - database. -
    • -
    • The response will be like this - {"Status": "auth - successful", "User": "Mitchell Admin", "api-key": - "66c2ebab-d4dc-42f0-87d0-d1646e887569"}.
    • +
    • Next you have to generate the API key under My Profile > Account Security.
    • +
    • Set the name of the API key according to your needs.

    - Create records in Rest api app + Create records in Rest API app

      -
    • After rest api authentication, we can create records in the - rest api app. +
    • After creating the API key, we can create records in the + Rest API app.
    • Here we can choose the model, and also we can choose the http methods.
    • -
    • The api response will be based on these records.
    • +
    • The API response will be based on these records.

    You can send GET request to retrieve data from the database. -
  • The postman collection has been provided with app files for - sending request from postman. -
  • -
  • You have to provide username, password and api key through - the header. +
  • You have to provide the API key in the header: Authorization: Bearer {API_KEY} + where {API_KEY} should be replaced with the actual API key.
  • -
  • Model can be passed as argument as the technical name , and - also if you want - specific record you can provide any related fields to the module as well. +
  • Model can be passed as argument as the technical name, and + also if you want to get a specific record you can provide any + of the related fields to the module as well.
  • -
  • The format for GET method will be like this - http://cybrosys:8016/send_request?model=res.partner&Id=10. +
  • The format for GET method will be like this - http://cybrosys:8016/send_request?model=res.partner&id=10.
  • We can specify the fields inside the JSON data, and it will be like this - {"fields": ["name", "email"]}. @@ -329,7 +299,7 @@ Pagination can also be used by adding {"limit": 10, "offset": 0} to the query parameter above.
  • -
  • This is the format of api response - {"records": [{"id": +
  • This is the format of API response - {"records": [{"id": 10, "email": "deco.addict82@example.com", "name": "Deco Addict"}]}.
  • @@ -346,16 +316,13 @@
  • Using POST method , you can create new records in the database.
  • -
  • Just make sure you enabled POST method for the model record - in rest api app , otherwise you will get 'method not +
  • Just make sure you enabled POST method for the model record + in Rest API app , otherwise you will get 'method not allowed' message.
  • For creating record you have to provide the JSON data along with the model.
  • -
  • You can make use of the postman collection that we have - added with app files. -
  • The format for sending POST request will be like this - http://cybrosys:8016/send_request?model=res.partner.
  • This is the format for JSON data - { @@ -384,11 +351,7 @@
  • You have to provide the model and also the id or the record that you want to update.
  • -
  • You can use the Postman collection that we have provided and , you - will be always have to send request with your login - credentials. Otherwise, it will be showing access denied. -
  • -
  • The format for sending PUT request will be like this - http://cybrosys:8016/send_request?model=res.partner&Id=46. +
  • The format for sending PUT request will be like this - http://cybrosys:8016/send_request?model=res.partner&Id=46.
  • Here too you have to provide the JSON data through which the updates will be done. @@ -413,7 +376,7 @@ id that we want to delete.
  • Make sure you have permission to delete files for the - selected model in the rest api record. + selected model in the Rest API record.
  • The delete request format will be like this - http://cybrosys:8016/send_request?model=res.partner&Id=46.
  • @@ -848,7 +811,7 @@