tmijail / Odoo-Power-BI-Connector

Query Odoo from Power BI.
Mozilla Public License 2.0
76 stars 52 forks source link

Error when using search_read for people without Administrator permissions #6

Open ghost opened 2 years ago

ghost commented 2 years ago

I've found that if you run the search_read method, unless your user account has Administrator Settings permission an error occurs as below.

Odoo Server Error: You are not allowed to access 'Model Access' (ir.model.access) records.

This operation is allowed for the following groups:

Contact your administrator to request access if necessary. Details: Traceback (most recent call last): File "/data/build/odoo/odoo/http.py", line 1452, in _dispatch_nodb result = request.dispatch() File "/data/build/odoo/odoo/http.py", line 684, in dispatch result = self._call_function(self.params) File "/data/build/odoo/odoo/http.py", line 361, in _call_function return self.endpoint(*args, *kwargs) File "/data/build/odoo/odoo/http.py", line 913, in call return self.method(args, kw) File "/data/build/odoo/odoo/http.py", line 532, in response_wrap response = f(*args, kw) File "/data/build/odoo/odoo/addons/base/controllers/rpc.py", line 96, in jsonrpc return dispatch_rpc(service, method, args) File "/data/build/odoo/odoo/http.py", line 141, in dispatch_rpc result = dispatch(method, params) File "/data/build/odoo/odoo/service/model.py", line 41, in dispatch res = fn(db, uid, params) File "/data/build/odoo/odoo/service/model.py", line 168, in execute_kw return execute(db, uid, obj, method, args, kw or {}) File "/data/build/odoo/odoo/service/model.py", line 94, in wrapper return f(dbname, *args, kwargs) File "/data/build/odoo/odoo/service/model.py", line 175, in execute res = execute_cr(cr, uid, obj, method, *args, *kw) File "/data/build/odoo/odoo/service/model.py", line 159, in execute_cr result = odoo.api.call_kw(recs, method, args, kw) File "/data/build/odoo/odoo/api.py", line 395, in call_kw result = _call_kw_model(method, model, args, kwargs) File "/data/build/odoo/odoo/api.py", line 368, in _call_kw_model result = method(recs, args, kwargs) File "/data/build/odoo/odoo/models.py", line 2254, in read_group result = self._read_group_raw(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) File "/data/build/odoo/odoo/models.py", line 2276, in _read_group_raw self.check_access_rights('read') File "/data/build/odoo/odoo/models.py", line 3332, in check_access_rights return self.env['ir.model.access'].check(self._name, operation, raise_exception) File "", line 2, in check File "/data/build/odoo/odoo/tools/cache.py", line 90, in lookup value = d[key] = self.method(*args, **kwargs) File "/data/build/odoo/odoo/addons/base/models/ir_model.py", line 1805, in check raise AccessError(msg) Exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last): File "/data/build/odoo/odoo/http.py", line 640, in _handle_exception return super(JsonRequest, self)._handle_exception(exception) File "/data/build/odoo/odoo/http.py", line 316, in _handle_exception raise exception.with_traceback(None) from new_cause odoo.exceptions.AccessError: You are not allowed to access 'Model Access' (ir.model.access) records.

This operation is allowed for the following groups:

Contact your administrator to request access if necessary.

tmijail commented 2 years ago

Thanks for pointing this out. I hadn't run into this issue.

Short answer:

If you don't have permission to read ir.model.access, you need to pass the list of fields you want to read to search_read. Instead of

= search_read("res.partner", { {"is_company", "=", true} }, [order="customer_rank"])

you should run

= search_read("res.partner", { {"is_company", "=", true} }, [order="customer_rank", fields={"name", "email", "phone"}])

Long answer:

If you have a one2many field on a model, that field isn't actually stored on that model's table, it is instead stored on the referenced model's table as many2one fields. This means that if you want to read a one2many field, you need permission to read the referenced model.

If you run

= search_read("res.partner", { }, [fields={"invoice_ids"}])

you need to have permission to read account.move as well as res.partner.

The behaviour of Odoo's search_read is such that if you don't specify fields it queries all the model's fields, but that might include one2many fields which reference models the user isn't able to read, resulting in an AccessError.

I want this connector to eventually be usable by people with limited or no knowledge of Odoo development. They'd just select the tables they want to query from the "Get data" dialog and use the PowerBI UI or PowerQuery functions to manipulate the data. The connector would determine the most efficient search_read call possible such that the server does the most amount of work and transmits the least amount of data possible (query folding).

For that to be achievable, when you call search_read without passing the fields parameter, the connector first checks ir.model.access and excludes from the query any one2many fields which reference models you can't read. Instead of returning an error, it will return all the columns you have permission to read.


I'll add something to the readme and to the search_read docstring.

Also, if anyone knows of a better way of checking if a one2many field is readable (maybe even including ir.rule checks) without requiring the installation of a custom module on the server, I'm all ears.

ghost commented 2 years ago

Thanks @tmijail for this helpful and detailed reply. Makes a lot of sense. If I have any ideas that could help, will let you know.