Как подключиться к базе данных Odoo из приложения для Android

Я разрабатываю приложение для Android и хочу получать данные с сервера Odoo.

Для этого я разработал специальный модуль в Odoo, в котором создал контроллер.

Мой контроллер:

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

Когда я вызываю его из сценария python, чтобы попробовать, он работает нормально, и я получаю <Response [200]> и json {u'jsonrpc': u'2.0', u'result': u'{"token": 8}', u'id': None} с идентификатором учетной записи, к которой я подключаюсь.

Но затем у меня есть другая функция, которую я вызываю с другим маршрутом в том же контроллере, но на этот раз с auth='user', потому что я хочу, чтобы пользователь мог видеть только ту информацию, на которую у него есть права.

@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

Эта функция отлично работает, когда я использую auth='public', но когда я использую auth='user', я получаю следующий ответ json:

Ответ [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'] 
        }  
    }  
}

Я основывал свою работу на этой документации, которая является официальным документом Odoo. , но вот проблемы:

1 Он просит меня написать пароль администратора для каждой функции, что кажется опасным.

2 После аутентификации я получаю идентификатор своего пользователя, но не токен сеанса. Тогда как я могу сообщить своей функции с auth='user', что я подключен и к какому пользователю?

Вот мой сценарий для проверки моих звонков:

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())

person T.Nel    schedule 18.10.2018    source источник
comment
Я также пытался подключиться, используя ‹мой URL› / web / session / Authenticate, который является встроенным контроллером odoo. Он работает нормально и возвращает мне идентификатор сеанса. Но как тогда использовать этот sessionID? Я бы попытался передать его в свои параметры, но не работает лучше, у меня все еще есть тот же ответ об истечении срока действия сеанса Odoo   -  person T.Nel    schedule 18.10.2018
comment
stackoverflow.com/ questions / 59191576 /   -  person nightmare    schedule 05.12.2019


Ответы (2)


На заметку:

  • Никогда не отправлять учетные данные в запросе GET
  • Все запросы Odoo RPC являются запросами POST.
  • Вам не нужен пользовательский маршрут входа, если вы используете / web / session / authentication
  • Внешний API предназначен для использования вне рамок odoo. При разработке модуля используйте self.env ['‹model>'], если внутри модели, или http.request.env ['‹ model>'], если в контроллере.
  • Вызов / web / session / authenticate возвращает json, содержащий session_id, который вы должны передавать в файлах cookie для последующих запросов, пока вы не вызовете / web / session / destroy для выхода.

Вот пример использования / 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())

Чтобы получить информацию от вашего контроллера, вы можете использовать request.env.user, который содержит зарегистрированного пользователя в данный момент, и, поскольку вы указываете auth = 'user', он должен быть действительным. Пример кода может выглядеть так:

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)
person Yusnel Rojas García    schedule 19.10.2018

Очень хорошо напишите вопрос, вы сделали домашнее задание. Это работает для меня, чтобы иметь возможность аутентифицировать сеансы мобильных пользователей с помощью запросов в стиле api.

@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))
    ])

Также я не использовал auth='user', чтобы Odoo не связывался с перенаправлениями и проверками веб-материалов. Я использую эту оболочку аннотаций в маршрутах моих контроллеров, которые требуют, чтобы аутентифицированный пользователь возвращал правильный код состояния ошибки HTTP.

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

Вы можете использовать это так:

@check_user
@http.route([
    '/m/<int:shop_id>/cart/info',
], type='http', auth="public", website=True)
def cart_info(self, shop_id, **kwargs):
person Axel Mendoza    schedule 25.10.2018
comment
Спасибо за решение без базовых HTTP-перенаправлений Odoo. Это может стать проблемой, и если да, я попробую ваше решение. - person T.Nel; 26.10.2018