Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to connect to Odoo database from an android application

I am developping an Android application, and I'd like to retrieve data from an Odoo server.

For that I developped a custom module in Odoo, in which I created a controller.

My controller :

import json
import xmlrpc.client as xmlrpclib
from odoo import http
from openerp.http import Response

class resUserController(http.Controller):
    url = '<my url>'
    db = '<name of my database>'

    @http.route('/user/login', type='json', method='GET', auth='public')
    def get_login(self, **kwargs):
        username = kwargs.get('email')
        password = kwargs.get('password')
        common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(self.url), allow_none=True)

        uid = common.authenticate(self.db, username, password, {})
        if uid:
            Response.status = '200 Succesful operation'
            json_result = {'token': uid}
            return json.dumps(json_result)
        Response.status = '400 Invalid credentials'
        return

When I call it from a python script to try it, it works fine and I get a <Response [200]> and a json {u'jsonrpc': u'2.0', u'result': u'{"token": 8}', u'id': None} with the id of the account I connect to.

But then I have an other function I call with an other route in the same controller, but with auth='user' this time, because I want the user to be able to see only informations he has rights on.

@http.route('/user/getInfo', type='json', method='GET', auth='user')
def get_info(self, **kwargs):
    uid = 1
    password = '<my admin password>'
    models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(self.url), allow_none=True)
    info = models.execute_kw(self.db, uid, password, 'res.users',
                             'search_read', [[['id', '=', kwargs.get('token')]]],
                             {'fields': ['info']})[0]['invite_code']
    if info:
        Response.status = '200 Succesful operation'
        json_result = {'info': info}
        return json.dumps(json_result)
    Response.status = '404 User not found'
    return

This function works fine when I use auth='public', but when I go for auth='user', I get the following json response :

Response [200]

{  
    u'jsonrpc': u'2.0',   
    u'id': None,   
    u'error': {  
        u'message': u'Odoo Session Expired',   
        u'code': 100,  
        u'data': {  
            u'debug': u'Traceback (most recent call last):  
                      File "/usr/lib/python3/dist-packages/odoo/http.py", line 650, in _handle_exception  
                      return super(JsonRequest, self)._handle_exception(exception)  
                      File "/usr/lib/python3/dist-packages/odoo/http.py", line 310, in _handle_exception  
                      raise pycompat.reraise(type(exception), exception, sys.exc_info()[2])  
                      File "/usr/lib/python3/dist-packages/odoo/tools/pycompat.py", line 87, in reraise  
                      raise value  
                      File "/usr/lib/python3/dist-packages/odoo/addons/http_routing/models/ir_http.py", line 342, in _dispatch  
                      cls._authenticate(func.routing[\'auth\'])  
                      File "/usr/lib/python3/dist-packages/odoo/addons/base/ir/ir_http.py", line 117, in _authenticate  
                      getattr(cls, "_auth_method_%s" % auth_method)()  
                      File "/usr/lib/python3/dist-packages/odoo/addons/base/ir/ir_http.py", line 90, in _auth_method_user  
                      raise http.SessionExpiredException("Session expired")  
                      odoo.http.SessionExpiredException: Session expired',   
            u'exception_type': u'internal_error',   
            u'message': u'Session expired',   
            u'name': u'odoo.http.SessionExpiredException',  
            u'arguments': [u'Session expired'] 
        }  
    }  
}

I based my work on This documentation, which is an official Odoo doc, but here are the problems :

1 It ask me to write my admin password in each function, which seems dangerous.

2 After authentication, I get the id of my user, but no session token. Then how can I inform my function with auth='user' that I'm connected and to which user?

Here is my script to test my calls :

import requests
import json

url_connect = "<my url>/user/login"
url = "<my url>/user/getInfo"
headers = {'Content-Type': 'application/json'}
data_connect = {
                "params": {
                           "email": "<my test account email>",
                           "password": "<my test account password>",
                }
    }
data = {
        "params": {
                   "token": <my test account id>,
            }
       }
data_json = json.dumps(data)
r = requests.get(url=url_connect, data=json.dumps(data_connect), headers=headers)
print(r)
print(r.json())
r = requests.get(url=url, data=data_json, headers=headers)
print(r)
print(r.json())
like image 213
T.Nel Avatar asked Oct 18 '18 14:10

T.Nel


People also ask

Does Odoo have a mobile app?

You can easily convert your Odoo store into a beautiful mobile application with the help of the Odoo Mobile App for Android & iOS. Customers may quickly download the app onto their mobile devices, which provides a better user experience. As a result, they can conveniently shop for products while on the go.

How do I log into Odoo app?

Odoo Web Login Screen v9 Then go to you odoo webinterface to the module section and start "Update module list". Then look for the "Odoo Web Login Screen" in Apps (module list) and install. I hope you enjoy checking out what all you can do with this application.

Which server is used for Odoo?

ngnix, apache as web servers to deploy Odoo.

What is Odoo app store?

Odoo is a suite of open source business apps that covers all your company needs: CRM, eCommerce, Accounting, Inventory, Point of Sale, Project Management, and more. The mobile app offers a smooth and friendly user experience that has been carefully built to ensure quick and seamless user adoption.


2 Answers

Things to note:

  • Never send credentials in a GET request
  • All Odoo RPC requests are POST requests
  • You don't need a custom login route if you use /web/session/authenticate
  • The External API is intended to be used outside of odoo framework. When developing a module use self.env['< model >'] if inside a model or http.request.env['< model >'] if in a controller
  • The call to /web/session/authenticate returns a json containing the session_id, which you have to pass it in the cookies to subsequent requests until you call /web/session/destroy to logout.

Here is an example using /web/session/autenticate:

import requests
import json

url_connect = "http://localhost:8069/web/session/authenticate"
url = "http://localhost:8069/web/session/get_session_info"

headers = {'Content-Type': 'application/json'}

data_connect = {
    "params": {
        "db": "demo1",
        "login": "admin",
        "password": "admin",
    }
}

data = {}

session = requests.Session()

r = session.post(url=url_connect, data=json.dumps(data_connect), headers=headers)

if r.ok:
    result = r.json()['result']

    if result.get('session_id'):
        session.cookies['session_id'] = result.get('session_id')

r = session.post(url=url, data=json.dumps(data), headers=headers)
print(r)
print(r.json())

To get the info from your controller you could use request.env.user which holds the logged user at the moment and since you specify auth='user' it is required to be a valid. The sample code might look like:

from odoo.http import request

class UserController(http.Controller):
  @http.route('/user/getInfo', type='json', method='POST', auth='user')
  def get_info(self, **kwargs):
    current_user = request.env.user

    Response.status = '200 Succesful operation'
    json_result = {'info': current_user.info}
    return json.dumps(json_result)
like image 63
Yusnel Rojas García Avatar answered Oct 17 '22 05:10

Yusnel Rojas García


Very well write question, you have done the homework. This works for me to be able to authenticate the mobile users sessions using an api style requests.

@http.route([
    '/m/login/email',
], type='http', auth="public", website=True, methods=["POST"], csrf=False)
def users_login_email(self, **kwargs):
    if kwargs:
        data = json.loads(kwargs.keys()[0])
    else:
        data = json.loads(request.httprequest.data)

    email = data.get('email')
    password = data.get('password')

    if not request.session.db:
        setup_db()
    uid = request.session.authenticate(request.session.db, email, password)
    if uid:
        return self._user_details(uid)
    body = json.dumps({"body": ["Credenciales Incorrectas"]})
    return werkzeug.wrappers.Response(body, status=403, headers=[
        ('Content-Type', 'application/json'), ('Content-Length', len(body))
    ])

Also I didn't use auth='user' to don't let Odoo to mess with redirects and web stuffs checks. I use this annotation wrapper in my controllers routes that require an authenticated user to return the proper HTTP error status code

def check_user(f):
    @functools.wraps(f)
    def wrap(*args, **kwargs):
        if not request.session.db:
            setup_db()

        request.uid = request.session.uid

        if not request.uid:
            body = json.dumps({"body": ["Session Expired"]})
            return werkzeug.wrappers.Response(body, status=403, headers=[
                ('Content-Type', 'application/json'), ('Content-Length', len(body))
            ])

        return f(*args, **kwargs)

    return wrap

You could use it like this:

@check_user
@http.route([
    '/m/<int:shop_id>/cart/info',
], type='http', auth="public", website=True)
def cart_info(self, shop_id, **kwargs):
like image 25
Axel Mendoza Avatar answered Oct 17 '22 05:10

Axel Mendoza