[FIX] openerp, web: make execute and call_kw invoke methods in the new API
Also refactor the test to prevent private methods to be remotely called.
This commit is contained in:
@@ -27,7 +27,7 @@ from cStringIO import StringIO
|
||||
|
||||
import odoo
|
||||
import odoo.modules.registry
|
||||
from odoo.api import Environment
|
||||
from odoo.api import call_kw, Environment
|
||||
from odoo.modules import get_resource_path
|
||||
from odoo.tools import topological_sort
|
||||
from odoo.tools.translate import _
|
||||
@@ -35,6 +35,7 @@ from odoo.tools.misc import str2bool, xlwt
|
||||
from odoo import http
|
||||
from odoo.http import request, serialize_exception as _serialize_exception, content_disposition
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.models import check_method_name
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -840,10 +841,8 @@ class DataSet(http.Controller):
|
||||
return self._call_kw(model, method, args, {})
|
||||
|
||||
def _call_kw(self, model, method, args, kwargs):
|
||||
if method.startswith('_'):
|
||||
raise AccessError(_("Underscore prefixed methods cannot be remotely called"))
|
||||
|
||||
return getattr(request.registry.get(model), method)(request.cr, request.uid, *args, **kwargs)
|
||||
check_method_name(method)
|
||||
return call_kw(request.env[model], method, args, kwargs)
|
||||
|
||||
@http.route('/web/dataset/call', type='json', auth="user")
|
||||
def call(self, model, method, args, domain_id=None, context_id=None):
|
||||
|
||||
@@ -67,9 +67,9 @@ return AbstractWebClient.extend({
|
||||
logo_edit: function(ev) {
|
||||
var self = this;
|
||||
ev.preventDefault();
|
||||
self.alive(new Model("res.users").get_func("read")(session.uid, ["company_id"])).then(function(res) {
|
||||
self.alive(new Model("res.users").call("read", [[session.uid], ["company_id"]])).then(function(data) {
|
||||
self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
|
||||
result.res_id = res.company_id[0];
|
||||
result.res_id = data[0].company_id[0];
|
||||
result.target = "new";
|
||||
result.views = [[false, 'form']];
|
||||
result.flags = {
|
||||
@@ -94,7 +94,8 @@ return AbstractWebClient.extend({
|
||||
var state = $.bbq.getState(true);
|
||||
if (_.isEmpty(state) || state.action === "login") {
|
||||
self.menu.is_bound.done(function() {
|
||||
new Model("res.users").call("read", [session.uid, ["action_id"]]).done(function(data) {
|
||||
new Model("res.users").call("read", [[session.uid], ["action_id"]]).done(function(result) {
|
||||
var data = result[0];
|
||||
if(data.action_id) {
|
||||
self.action_manager.do_action(data.action_id[0]);
|
||||
self.menu.open_action(data.action_id[0]);
|
||||
|
||||
@@ -42,6 +42,7 @@ __all__ = [
|
||||
'cr_uid_ids', 'cr_uid_ids_context',
|
||||
'cr_uid_records', 'cr_uid_records_context',
|
||||
'constrains', 'depends', 'onchange', 'returns',
|
||||
'call_kw',
|
||||
]
|
||||
|
||||
import logging
|
||||
@@ -76,6 +77,19 @@ WRAPPED_ATTRS = ('__module__', '__name__', '__doc__', '_constrains',
|
||||
INHERITED_ATTRS = ('_returns',)
|
||||
|
||||
|
||||
class Params(object):
|
||||
def __init__(self, args, kwargs):
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
def __str__(self):
|
||||
params = []
|
||||
for arg in self.args:
|
||||
params.append(repr(arg))
|
||||
for item in sorted(self.kwargs.iteritems()):
|
||||
params.append("%s=%r" % item)
|
||||
return ', '.join(params)
|
||||
|
||||
|
||||
class Meta(type):
|
||||
""" Metaclass that automatically decorates traditional-style methods by
|
||||
guessing their API. It also implements the inheritance of the
|
||||
@@ -643,6 +657,30 @@ def expected(decorator, func):
|
||||
|
||||
|
||||
|
||||
def call_kw_model(method, self, args, kwargs):
|
||||
context, args, kwargs = split_context(method, args, kwargs)
|
||||
recs = self.with_context(context or {})
|
||||
_logger.debug("call %s.%s(%s)", recs, method.__name__, Params(args, kwargs))
|
||||
result = method(recs, *args, **kwargs)
|
||||
return downgrade(method, result, recs, args, kwargs)
|
||||
|
||||
def call_kw_multi(method, self, args, kwargs):
|
||||
ids, args = args[0], args[1:]
|
||||
context, args, kwargs = split_context(method, args, kwargs)
|
||||
recs = self.with_context(context or {}).browse(ids)
|
||||
_logger.debug("call %s.%s(%s)", recs, method.__name__, Params(args, kwargs))
|
||||
result = method(recs, *args, **kwargs)
|
||||
return downgrade(method, result, recs, args, kwargs)
|
||||
|
||||
def call_kw(model, name, args, kwargs):
|
||||
""" Invoke the given method ``name`` on the recordset ``model``. """
|
||||
method = getattr(type(model), name)
|
||||
if getattr(method, '_api', None) == 'model':
|
||||
return call_kw_model(method, model, args, kwargs)
|
||||
else:
|
||||
return call_kw_multi(method, model, args, kwargs)
|
||||
|
||||
|
||||
class Environment(Mapping):
|
||||
""" An environment wraps data for ORM records:
|
||||
|
||||
|
||||
@@ -113,6 +113,14 @@ def check_pg_name(name):
|
||||
if len(name) > 63:
|
||||
raise ValidationError("Table name %r is too long" % name)
|
||||
|
||||
# match private methods, to prevent their remote invocation
|
||||
regex_private = re.compile(r'^(_.*|init)$')
|
||||
|
||||
def check_method_name(name):
|
||||
""" Raise an ``AccessError`` if ``name`` is a private method name. """
|
||||
if regex_private.match(name):
|
||||
raise AccessError(_('Private methods (such as %s) cannot be called remotely.') % (name,))
|
||||
|
||||
POSTGRES_CONFDELTYPES = {
|
||||
'RESTRICT': 'r',
|
||||
'NO ACTION': 'a',
|
||||
|
||||
@@ -9,6 +9,7 @@ import time
|
||||
|
||||
import openerp
|
||||
from openerp.exceptions import UserError, ValidationError, QWebException
|
||||
from openerp.models import check_method_name
|
||||
from openerp.tools.translate import translate
|
||||
from openerp.tools.translate import _
|
||||
|
||||
@@ -164,10 +165,11 @@ def check(f):
|
||||
return wrapper
|
||||
|
||||
def execute_cr(cr, uid, obj, method, *args, **kw):
|
||||
object = openerp.registry(cr.dbname).get(obj)
|
||||
if object is None:
|
||||
recs = openerp.api.Environment(cr, uid, {}).get(obj)
|
||||
if recs is None:
|
||||
raise UserError(_("Object %s doesn't exist") % obj)
|
||||
return getattr(object, method)(cr, uid, *args, **kw)
|
||||
return openerp.api.call_kw(recs, method, args, kw)
|
||||
|
||||
|
||||
def execute_kw(db, uid, obj, method, args, kw=None):
|
||||
return execute(db, uid, obj, method, *args, **kw or {})
|
||||
@@ -176,8 +178,7 @@ def execute_kw(db, uid, obj, method, args, kw=None):
|
||||
def execute(db, uid, obj, method, *args, **kw):
|
||||
threading.currentThread().dbname = db
|
||||
with openerp.registry(db).cursor() as cr:
|
||||
if method.startswith('_'):
|
||||
raise UserError(_('Private methods (such as %s) cannot be called remotely.') % (method,))
|
||||
check_method_name(method)
|
||||
res = execute_cr(cr, uid, obj, method, *args, **kw)
|
||||
if res is None:
|
||||
_logger.info('The method %s of the object %s can not return `None` !', method, obj)
|
||||
|
||||
Reference in New Issue
Block a user