diff --git a/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.json b/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.json deleted file mode 100644 index f474d5311..000000000 --- a/rest_api_odoo/Postman Collections/Odoo REST Api.postman_collection.json +++ /dev/null @@ -1,257 +0,0 @@ -{ - "info": { - "_postman_id": "83d9071d-626d-41ed-9800-78570ed11a7c", - "name": "Odoo REST Api", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "28148668" - }, - "item": [ - { - "name": "Authentication", - "request": { - "method": "GET", - "header": [ - { - "key": "db", - "value": "sep_db", - "type": "text" - }, - { - "key": "login", - "value": "123", - "type": "text" - }, - { - "key": "password", - "value": "123", - "type": "text" - }, - { - "key": "", - "value": "", - "type": "text", - "disabled": true - } - ], - "url": { - "raw": "http://cybrosys:8016/odoo_connect", - "protocol": "http", - "host": [ - "cybrosys" - ], - "port": "8016", - "path": [ - "odoo_connect" - ] - } - }, - "response": [] - }, - { - "name": "GET records", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "login", - "value": "123", - "type": "text" - }, - { - "key": "password", - "value": "123", - "type": "text" - }, - { - "key": "api-key", - "value": "4314c30b-994e-435d-a493-50cb0d33e99d", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fields\": [\"name\",\"product_id\"]\n \n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://cybrosys:8016/send_request?model=mrp.production&Id=10", - "protocol": "http", - "host": [ - "cybrosys" - ], - "port": "8016", - "path": [ - "send_request" - ], - "query": [ - { - "key": "model", - "value": "mrp.production" - }, - { - "key": "Id", - "value": "10" - } - ] - } - }, - "response": [] - }, - { - "name": "Create Records", - "request": { - "method": "POST", - "header": [ - { - "key": "login", - "value": "123", - "type": "text" - }, - { - "key": "password", - "value": "123", - "type": "text" - }, - { - "key": "api_key", - "value": "4314c30b-994e-435d-a493-50cb0d33e99d", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fields\" :[\"name\",\"phone\"] ,\n \"values\": {\"name\": \"abc\",\n \"phone\":\"55962441552\"\n }\n\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://cybrosys:8016/send_request?model=res.partner", - "protocol": "http", - "host": [ - "cybrosys" - ], - "port": "8016", - "path": [ - "send_request" - ], - "query": [ - { - "key": "model", - "value": "res.partner" - } - ] - } - }, - "response": [] - }, - { - "name": "Update Records", - "request": { - "method": "PUT", - "header": [ - { - "key": "login", - "value": "123", - "type": "text" - }, - { - "key": "password", - "value": "123", - "type": "text" - }, - { - "key": "api-key", - "value": "d52cd3de-ad4c-49ab-a5cb-727940b8117a", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fields\" :[\"name\",\"phone\"] ,\n \"values\": {\"name\": \"abc\",\n \"phone\":\"55962441552\"\n }\n\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://cybrosys:8016/send_request?model=res.partner&Id=48", - "protocol": "http", - "host": [ - "cybrosys" - ], - "port": "8016", - "path": [ - "send_request" - ], - "query": [ - { - "key": "model", - "value": "res.partner" - }, - { - "key": "Id", - "value": "48" - } - ] - } - }, - "response": [] - }, - { - "name": "Delete Records", - "request": { - "method": "DELETE", - "header": [ - { - "key": "login", - "value": "123", - "type": "text" - }, - { - "key": "password", - "value": "123", - "type": "text" - }, - { - "key": "api-key", - "value": "d52cd3de-ad4c-49ab-a5cb-727940b8117a", - "type": "text" - } - ], - "url": { - "raw": "http://cybrosys:8016/send_request?model=res.partner&Id=48", - "protocol": "http", - "host": [ - "cybrosys" - ], - "port": "8016", - "path": [ - "send_request" - ], - "query": [ - { - "key": "model", - "value": "res.partner" - }, - { - "key": "Id", - "value": "48" - } - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file 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 af3c23388..e8c576f8e 100644 --- a/rest_api_odoo/__manifest__.py +++ b/rest_api_odoo/__manifest__.py @@ -34,7 +34,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.jpg'], diff --git a/rest_api_odoo/controllers/rest_api_odoo.py b/rest_api_odoo/controllers/rest_api_odoo.py index 23339e1a6..60ca8dfbf 100644 --- a/rest_api_odoo/controllers/rest_api_odoo.py +++ b/rest_api_odoo/controllers/rest_api_odoo.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) \ No newline at end of file diff --git a/rest_api_odoo/models/__init__.py b/rest_api_odoo/models/__init__.py index 63f0adaa4..e1750d6e9 100644 --- a/rest_api_odoo/models/__init__.py +++ b/rest_api_odoo/models/__init__.py @@ -20,4 +20,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 acfcf0ebc..000000000 --- a/rest_api_odoo/models/res_users.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding:utf-8 -*- -############################################################################# -# -# Cybrosys Technologies Pvt. Ltd. -# -# Copyright (C) 2024-TODAY Cybrosys Technologies() -# Author: Sruthi Pavithran (odoo@cybrosys.com) -# -# 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 ResUsers(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/rest_api_2.png b/rest_api_odoo/static/description/assets/screenshots/rest_api_2.png index 45063358e..94edbd0e0 100644 Binary files a/rest_api_odoo/static/description/assets/screenshots/rest_api_2.png and b/rest_api_odoo/static/description/assets/screenshots/rest_api_2.png differ diff --git a/rest_api_odoo/static/description/index.html b/rest_api_odoo/static/description/index.html index 2bdcc0ac9..5c5faeb6b 100644 --- a/rest_api_odoo/static/description/index.html +++ b/rest_api_odoo/static/description/index.html @@ -44,7 +44,7 @@ style="margin: 80px 0px !important;">

- Odoo rest API

+ Odoo Rest API

The odoo Rest API module allow us to connect to database @@ -64,27 +64,6 @@

-
-
-
- -
-
-

- Api Key Generation

-

This module - Api key generation using database - authentication. -

-
-
-
- -
-
- -
-

-
    -
  • First of all, we have to add a new - parameter in odoo conf. - file. -
  • -
  • server_wide_modules = web, base, - rest_api_odoo
    - - This will allow us to send request - to - server without - selecting database first.
    - - Incase - if you have to - 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 - field in users. -
  • - - 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. -
  • -
+ Installation

+
+
    +
  • First of all, we have to add a new + parameter in the odoo.conf + file. +
  • +
  • server_wide_modules = web, base, + rest_api_odoo
    +
      +
    • + This will allow us to send request to + server without + selecting database first. +
    • +
    • + Incase if you have to + 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 + field in users. +
      +
    • + Next we have to generate the API key + for the current user. +
    • +
    +
  • +
+
+

+ Generate API Key +

-

-
    -
  • 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://localhost:8017/odoo_connect - Replace 'localhost: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.
  • +
@@ -313,6 +250,10 @@
+

+ Create API Records +

@@ -328,13 +269,11 @@ height="auto">
-

    -
  • After rest api authentication, we +
  • After Rest API authentication, we can create records in the - rest api app. + Rest API app.
  • Here we can choose the model, and also @@ -346,7 +285,6 @@ records.
-

@@ -358,51 +296,29 @@

Get Records

- - - -
-
-
    -
  • You can send GET request to retrieve - data from the +
  • 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 the id - 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. +
  • +
  • We can specify the fields inside the JSON data, and it will + be like this - {"fields": ["name", "email"]}. + If no fields are passed , it will returns just the record's ID. + To get all of the fields, set the fields to wildcard - {"fields": ["*"]}. + Pagination can also be used by adding {"limit": 10, "offset": 0} + to the query parameter above.
  • -
  • The format for GET method will be like - this - http://localhost: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"]}.
  • -
  • This is the format of api response - {"records": - [{"id": - 10, "email": - "deco.addict82@example.com", - "name": "Deco - Addict"}]}. +
  • This is the format of API response - {"records": [{"id": + 10, "email": "deco.addict82@example.com", "name": "Deco + Addict"}]}.
@@ -416,27 +332,16 @@

- Create Records

-
-
-
-
-
-
-

+ Create Record +

    -
  • Using POST method , you can create - new records - in the +
  • 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 + in Rest API app , otherwise you will get 'method not allowed' message. @@ -453,41 +358,29 @@
  • The format for sending POST request will be like - this - http://localhost:8016/send_request?model=res.partner. + this - http://localhost:8016/send_request?model=res.partner.
  • This is the format for JSON data - - { + { "fields" :["name", "phone"] , "values": {"name": "abc", "phone":"55962441552" - } }. + } }.
  • Make sure the data entered in correct format otherwise you - will get 'Invalid JSON data' - message. + will get Invalid JSON data' + message.
  • Response will be in this format - - {"New + {"New resource": [{"id": 51, "name": "abc", "phone": - "55962441552"}]}. + "55962441552"}]}.
- -
-
-
-
-
-
-

- Update Records

@@ -498,10 +391,12 @@

+ Update Record +

  • Updation of records in the database can be done - with PUT + with PUT method.
  • You have to provide the model and @@ -521,7 +416,7 @@
  • The format for sending PUT request will be like - this - http://localhost:8016/send_request?model=res.partner&Id=46. + this - http://localhost:8016/send_request?model=res.partner&id=46.
  • Here too you have to provide the JSON data @@ -529,23 +424,11 @@ updates will be done.
  • The response format will be like - this - {"Updated + this - {"Updated resource": [{"id": 46, "email": "abc@example.com", "name": - "Toni"}]}.
  • + "Toni"}]}.
- -
-
- -
-
-
-

- Delete Records

@@ -556,10 +439,12 @@

+ Delete Record +

  • Database records can be deleted by sending - DELETE method + DELETE method request.
  • For the deletion we have to provide @@ -570,22 +455,21 @@
  • Make sure you have permission to delete files for the - selected model in the rest api + selected model in the Rest API record.
  • The delete request format will be like this - - http://localhost:8016/send_request?model=res.partner&Id=46. + http://localhost:8016/send_request?model=res.partner&Id=46.
  • The response after successful deletion will be - - + - {"Resource deleted": [{"id": 46, "email": "abc@example.com", - "name": "Toni"}]}.
  • + "name": "Toni"}]}.
-
@@ -599,7 +483,7 @@ src="assets/misc/star (1) 2.svg" alt="" width="16px">We can create - records in the rest api app. + records in the Rest API app.
  • diff --git a/rest_api_odoo/views/res_users_views.xml b/rest_api_odoo/views/res_users_views.xml deleted file mode 100644 index c6a59b1ef..000000000 --- a/rest_api_odoo/views/res_users_views.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - view.users.form.inherit.rest.api.odoo - - res.users - - - - - - - - - - -