[FIX] base: keep evaluation context unchanged
Before this commit, the evaluation context was forced with sudo(False) as the call to _render_qweb_html was made with sudo(True). The sudo was removed to prevent rendering a report on any object. This was problematic for reports such as sale.order portal page where the public user does not have access to the record but uses a custom verification mechanism using an access_token field and then calling _render with sudo. This commit moves the sudo call to keep the _get_evaluation_context with the same environment and allow to call _render with sudo Add tests with sale portal building the report as low-priviledge user closes odoo/odoo#56890 X-original-commit: 57665a02f7b4cd113f8f40ec47c58a518fe8669c Related: odoo/enterprise#12845 Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo.addons.sale.tests.common import TestSaleCommon
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
@@ -122,3 +122,59 @@ class TestAccessRights(TestSaleCommon):
|
||||
# Employee can't delete the SO
|
||||
with self.assertRaises(AccessError):
|
||||
self.order.with_user(self.company_data['default_user_employee']).unlink()
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestAccessRightsControllers(HttpCase):
|
||||
|
||||
def test_access_controller(self):
|
||||
|
||||
portal_so = self.env.ref("sale.portal_sale_order_2").sudo()
|
||||
portal_so._portal_ensure_token()
|
||||
token = portal_so.access_token
|
||||
|
||||
private_so = self.env.ref("sale.sale_order_1")
|
||||
|
||||
self.authenticate(None, None)
|
||||
|
||||
# Test public user can't print an order without a token
|
||||
req = self.url_open(
|
||||
url='/my/orders/%s?report_type=pdf' % portal_so.id,
|
||||
allow_redirects=False,
|
||||
)
|
||||
self.assertEqual(req.status_code, 302)
|
||||
|
||||
# or with a random token
|
||||
req = self.url_open(
|
||||
url='/my/orders/%s?access_token=%s&report_type=pdf' % (
|
||||
portal_so.id,
|
||||
"foo",
|
||||
),
|
||||
allow_redirects=False,
|
||||
)
|
||||
self.assertEqual(req.status_code, 302)
|
||||
|
||||
# but works fine with the right token
|
||||
req = self.url_open(
|
||||
url='/my/orders/%s?access_token=%s&report_type=pdf' % (
|
||||
portal_so.id,
|
||||
token,
|
||||
),
|
||||
allow_redirects=False,
|
||||
)
|
||||
self.assertEqual(req.status_code, 200)
|
||||
|
||||
self.authenticate("portal", "portal")
|
||||
|
||||
# do not need the token when logged in
|
||||
req = self.url_open(
|
||||
url='/my/orders/%s?report_type=pdf' % portal_so.id,
|
||||
allow_redirects=False,
|
||||
)
|
||||
self.assertEqual(req.status_code, 200)
|
||||
|
||||
# but still can't access another order
|
||||
req = self.url_open(
|
||||
url='/my/orders/%s?report_type=pdf' % private_so.id,
|
||||
allow_redirects=False,
|
||||
)
|
||||
self.assertEqual(req.status_code, 302)
|
||||
|
||||
@@ -694,13 +694,13 @@ class IrActionsReport(models.Model):
|
||||
data = {}
|
||||
data.setdefault('report_type', 'pdf')
|
||||
|
||||
# access the report details with sudo() but evaluation context as sudo(False)
|
||||
# access the report details with sudo() but evaluation context as current user
|
||||
self_sudo = self.sudo()
|
||||
|
||||
# In case of test environment without enough workers to perform calls to wkhtmltopdf,
|
||||
# fallback to render_html.
|
||||
if (tools.config['test_enable'] or tools.config['test_file']) and not self.env.context.get('force_report_rendering'):
|
||||
return self_sudo._render_qweb_html(res_ids, data=data)
|
||||
return self._render_qweb_html(res_ids, data=data)
|
||||
|
||||
# As the assets are generated during the same transaction as the rendering of the
|
||||
# templates calling them, there is a scenario where the assets are unreachable: when
|
||||
@@ -791,7 +791,7 @@ class IrActionsReport(models.Model):
|
||||
data = {}
|
||||
data.setdefault('report_type', 'text')
|
||||
data = self._get_rendering_context(docids, data)
|
||||
return self._render_template(self.report_name, data), 'text'
|
||||
return self._render_template(self.sudo().report_name, data), 'text'
|
||||
|
||||
@api.model
|
||||
def _render_qweb_html(self, docids, data=None):
|
||||
@@ -801,7 +801,7 @@ class IrActionsReport(models.Model):
|
||||
data = {}
|
||||
data.setdefault('report_type', 'html')
|
||||
data = self._get_rendering_context(docids, data)
|
||||
return self._render_template(self.report_name, data), 'html'
|
||||
return self._render_template(self.sudo().report_name, data), 'html'
|
||||
|
||||
@api.model
|
||||
def _get_rendering_context_model(self):
|
||||
@@ -810,23 +810,23 @@ class IrActionsReport(models.Model):
|
||||
|
||||
@api.model
|
||||
def _get_rendering_context(self, docids, data):
|
||||
# access the report details with sudo() but evaluation context as current user
|
||||
self_sudo = self.sudo()
|
||||
|
||||
# If the report is using a custom model to render its html, we must use it.
|
||||
# Otherwise, fallback on the generic html rendering.
|
||||
report_model = self._get_rendering_context_model()
|
||||
report_model = self_sudo._get_rendering_context_model()
|
||||
|
||||
data = data and dict(data) or {}
|
||||
|
||||
|
||||
if report_model is not None:
|
||||
# _render_ may be executed in sudo but evaluation context as real user
|
||||
report_model = report_model.sudo(False)
|
||||
data.update(report_model._get_report_values(docids, data=data))
|
||||
else:
|
||||
# _render_ may be executed in sudo but evaluation context as real user
|
||||
docs = self.env[self.model].sudo(False).browse(docids)
|
||||
docs = self.env[self_sudo.model].browse(docids)
|
||||
data.update({
|
||||
'doc_ids': docids,
|
||||
'doc_model': self.model,
|
||||
'doc_model': self_sudo.model,
|
||||
'docs': docs,
|
||||
})
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user