Browse Source

Include datetime object in return field

* Fix no fields returned by passing ID if no field is specified
pull/345/head
drpsyko101 9 months ago
parent
commit
d9611724c2
  1. 356
      rest_api_odoo/controllers/main.py

356
rest_api_odoo/controllers/main.py

@ -22,6 +22,8 @@
import json import json
import logging import logging
from datetime import datetime
from odoo import http from odoo import http
from odoo.http import request, Response from odoo.http import request, Response
from ast import literal_eval from ast import literal_eval
@ -37,195 +39,259 @@ class RestApi(http.Controller):
"""This function is used to authenticate the api-key when sending a """This function is used to authenticate the api-key when sending a
request""" request"""
user_id = request.env['res.users'].search([('api_key', '=', api_key)]) user_id = request.env["res.users"].search([("api_key", "=", api_key)])
if api_key is not None and user_id: if api_key is not None and user_id:
return True return Response(json.dumps({"message": "Authorized"}), status=200)
elif not user_id: elif not user_id:
return Response(json.dumps({'message': 'Invalid API Key'}), status=401) return Response(json.dumps({"message": "Invalid API Key"}), status=401)
return Response(json.dumps({'message': 'No API Key Provided'}), status=400) return Response(json.dumps({"message": "No API Key Provided"}), status=400)
def simplest_type(self, input): def simplest_type(self, input):
"""Try cast input into native Python class, otherwise return as string""" """Try cast input into native Python class, otherwise return as string"""
try: try:
return literal_eval(input) return literal_eval(input)
except: except Exception:
if input == 'true': # Handle lowercase booleans
if input == "true":
return True return True
if input == 'false': if input == "false":
return False return False
return input return input
def sanitize_records(self, records):
"""Sanitize records for response"""
for record in records:
for key, value in record.items():
# Manually convert datetime fields to string format
if isinstance(value, datetime):
record[key] = value.isoformat()
return records
def generate_response(self, method, **query): def generate_response(self, method, **query):
"""This function is used to generate the response based on the type """This function is used to generate the response based on the type
of request and the parameters given""" of request and the parameters given"""
model = query.pop('model') model = query.pop("model")
option = request.env['connection.api'].search( option = request.env["connection.api"].search(
[('model_id', '=', model)], limit=1) [("model_id", "=", model)], limit=1
)
model_name = option.model_id.model model_name = option.model_id.model
model_display_name = option.model_id.name model_display_name = option.model_id.name
data = {}
try: try:
data = json.loads(request.httprequest.data) data = json.loads(request.httprequest.data)
except: except Exception:
pass data = {}
fields = [] fields = []
if data: if data:
for field in data['fields']: for field in data["fields"]:
fields.append(field) fields.append(field)
if '*' in fields:
# Return records' ID by default if not specified
if not fields:
fields.append("id")
# Get all model's fields if wildcard is used
if "*" in fields:
fields = [] fields = []
record_fields = request.env[ record_fields = request.env[str(model_name)].fields_get(
str(model_name)].fields_get([], attributes=['type']) [], attributes=["type"]
)
for field, value in record_fields.items(): for field, value in record_fields.items():
value_type = value.get('type') value_type = value.get("type")
if not (value_type == 'binary' or value_type == 'datetime'): if not (value_type == "binary"):
fields.append(field) fields.append(field)
if not option: if not option:
return Response(json.dumps({'message': f'No Record Created for the model. Please contact your admininstrator to enable {method} method for {model_display_name} record.'}), status=403) return Response(
try: json.dumps(
if method == 'GET': {
if not fields: "message": f"No Record Created for the model. Please contact your admininstrator to enable {method} method for {model_display_name} record."
fields.append('id') }
if not option.is_get: ),
return Response( status=403,
json.dumps({'message': f'Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record.'}), )
status=405) if method == "GET":
else: if not option.is_get:
domains = [] return Response(
for key, value in query.items(): json.dumps(
domains.append((key, '=', self.simplest_type(value))) {
partner_records = request.env[ "message": f"Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record."
str(model_name)].search_read( }
domain=domains, ),
fields=fields status=405,
) )
return Response(
json.dumps({ domains = []
'records': partner_records for key, value in query.items():
}) domains.append((key, "=", self.simplest_type(value)))
) partner_records = request.env[str(model_name)].search_read(
if method == 'POST': domain=domains, fields=fields
if not option.is_post: )
return Response(
json.dumps({'message': f'Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record.'}), return Response(
status=405) json.dumps({"records": self.sanitize_records(partner_records)})
if not data or 'values' not in data: )
return Response(json.dumps({'message': 'No Data Provided'}), status=403) if method == "POST":
if not option.is_post:
try: return Response(
data = json.loads(request.httprequest.data) json.dumps(
new_resource = request.env[str(model_name)].create( {
data['values']) "message": f"Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record."
partner_records = request.env[ }
str(model_name)].search_read( ),
domain=[('id', '=', new_resource.id)], status=405,
fields=fields )
) if not data or "values" not in data:
return Response(json.dumps({'new_record': partner_records}), status=201) return Response(json.dumps({"message": "No Data Provided"}), status=403)
except:
return Response(json.dumps({'message': 'Invalid JSON Data'}), status=403) try:
if method == 'PUT': data = json.loads(request.httprequest.data)
if not option.is_put: new_resource = request.env[str(model_name)].create(data["values"])
return Response( partner_records = request.env[str(model_name)].search_read(
json.dumps({'message': f'Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record.'}), domain=[("id", "=", new_resource.id)], fields=fields
status=405) )
return Response(
if not 'id' in query: json.dumps({"new_record": self.sanitize_records(partner_records)}),
return Response(json.dumps({'message': 'No ID Provided'}), status=403) status=201,
if not data or 'values' not in data: )
return Response(json.dumps({'message': 'No Data Provided'}), status=403) except Exception:
return Response(
resource = request.env[str(model_name)].browse( json.dumps({"message": "Invalid JSON Data"}), status=403
int(query.get('id'))) )
if not resource.exists(): if method == "PUT":
return Response(json.dumps({'message': 'Resource not found'}), status=404) if not option.is_put:
return Response(
try: json.dumps(
data = json.loads(request.httprequest.data) {
resource.write(data['values']) "message": f"Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record."
partner_records = request.env[ }
str(model_name)].search_read( ),
domain=[('id', '=', resource.id)], status=405,
fields=fields )
)
return Response(json.dumps({'updated_record': partner_records})) if "id" not in query:
return Response(json.dumps({"message": "No ID Provided"}), status=403)
except: if not data or "values" not in data:
return Response(json.dumps({'message': 'Invalid JSON value(s) passed'}), status=403) return Response(json.dumps({"message": "No Data Provided"}), status=403)
if method == 'DELETE':
if not option.is_delete: resource_id = str(query.get("id"))
return Response( resource = request.env[str(model_name)].browse(int(resource_id))
json.dumps({'message': f'Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record.'}), if not resource.exists():
status=405) return Response(
json.dumps({"message": "Resource not found"}), status=404
if not 'id' in query: )
return Response(json.dumps({'message': 'No ID Provided'}), status=403)
try:
resource = request.env[str(model_name)].browse( data = json.loads(request.httprequest.data)
int(query.get('id'))) resource.write(data["values"])
if not resource.exists(): partner_records = request.env[str(model_name)].search_read(
return Response(json.dumps({'message': 'Resource not found'}), status=404) domain=[("id", "=", resource.id)], fields=fields
else: )
return Response(
records = request.env[ json.dumps(
str(model_name)].search_read( {"updated_record": self.sanitize_records(partner_records)}
domain=[('id', '=', resource.id)],
fields=fields
) )
resource.unlink() )
return Response(json.dumps({'message': 'Resource deleted', 'data': records}), status=202)
except: except Exception:
return Response(json.dumps({'message': 'Internal Server Error'}), status=500) return Response(
json.dumps({"message": "Invalid JSON value(s) passed"}),
@http.route(['/send_request'], type='http', status=403,
auth='none', )
methods=['GET', 'POST', 'PUT', 'DELETE'], csrf=False) if method == "DELETE":
if not option.is_delete:
return Response(
json.dumps(
{
"message": f"Method not allowed. Please contact your admininstrator to enable {method} method for {model_display_name} record."
}
),
status=405,
)
if "id" not in query:
return Response(json.dumps({"message": "No ID Provided"}), status=403)
resource_id = str(query.get("id"))
resource = request.env[str(model_name)].browse(int(resource_id))
if not resource.exists():
return Response(
json.dumps({"message": "Resource not found"}), status=404
)
partner_records = request.env[str(model_name)].search_read(
domain=[("id", "=", resource.id)], fields=fields
)
resource.unlink()
return Response(
json.dumps(
{
"message": "Resource deleted",
"data": self.sanitize_records(partner_records),
}
),
status=202,
)
# If not using any method above, simply return an error
return Response(json.dumps({"message": "Method not allowed"}), status=405)
@http.route(
["/send_request"],
type="http",
auth="none",
methods=["GET", "POST", "PUT", "DELETE"],
csrf=False,
)
def fetch_data(self, **kw): def fetch_data(self, **kw):
"""This controller will be called when sending a request to the """This controller will be called when sending a request to the
specified url, and it will authenticate the api-key and then will specified url, and it will authenticate the api-key and then will
generate the result""" generate the result"""
http_method = request.httprequest.method http_method = request.httprequest.method
api_key = request.httprequest.headers.get('api-key') api_key = request.httprequest.headers.get("api-key")
auth_api = self.auth_api_key(api_key) auth_api = self.auth_api_key(api_key)
model = kw.pop('model') model = kw.pop("model")
username = request.httprequest.headers.get('login') username = request.httprequest.headers.get("login")
password = request.httprequest.headers.get('password') password = request.httprequest.headers.get("password")
request.session.authenticate(request.session.db, username, request.session.authenticate(request.session.db, username, password)
password) model_id = request.env["ir.model"].search([("model", "=", model)])
model_id = request.env['ir.model'].search(
[('model', '=', model)])
if not model_id: if not model_id:
return Response(json.dumps( return Response(
{'message': 'Invalid model, check spelling or maybe the related module is not installed'}), json.dumps(
status=403) {
"message": "Invalid model, check spelling or maybe the related module is not installed"
}
),
status=403,
)
if auth_api == True: if auth_api.status_code == 200:
result = self.generate_response(http_method, model=model_id.id, **kw) result = self.generate_response(http_method, model=model_id.id, **kw)
return result return result
else: else:
return auth_api return auth_api
@http.route(['/odoo_connect'], type="http", auth="none", csrf=False, @http.route(
methods=['GET']) ["/odoo_connect"], type="http", auth="none", csrf=False, methods=["GET"]
)
def odoo_connect(self, **kw): def odoo_connect(self, **kw):
"""This is the controller which initializes the api transaction by """This is the controller which initializes the api transaction by
generating the api-key for specific user and database""" generating the api-key for specific user and database"""
username = request.httprequest.headers.get('login') username = request.httprequest.headers.get("login")
password = request.httprequest.headers.get('password') password = request.httprequest.headers.get("password")
db = request.httprequest.headers.get('db') db = request.httprequest.headers.get("db")
try: try:
request.session.update(http.get_default_session(), db=db) request.session.update(http.get_default_session(), db=db)
auth = request.session.authenticate(request.session.db, username, auth = request.session.authenticate(request.session.db, username, password)
password) user = request.env["res.users"].browse(auth)
user = request.env['res.users'].browse(auth)
api_key = request.env.user.generate_api(username) api_key = request.env.user.generate_api(username)
datas = json.dumps({"Status": "auth successful", datas = json.dumps(
"User": user.name, {"Status": "auth successful", "User": user.name, "api-key": api_key}
"api-key": api_key}) )
return request.make_response(data=datas) return Response(datas, status=200)
except: except Exception:
return Response(json.dumps({'message': 'wrong login credentials'}), status=401) return Response(
json.dumps({"message": "wrong login credentials"}), status=401
)

Loading…
Cancel
Save