Filter search result of model with resource
The user needs to have read access to the resource target. Closes #12588
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from sql.conditionals import Coalesce
|
||||
|
||||
from trytond.i18n import lazy_gettext
|
||||
from trytond.model import Index, ModelSQL, ModelStorage, ModelView, fields
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Eval
|
||||
from trytond.tools import grouped_slice
|
||||
from trytond.transaction import Transaction, without_check_access
|
||||
|
||||
__all__ = ['ResourceAccessMixin', 'ResourceMixin', 'resource_copy']
|
||||
@@ -61,6 +65,41 @@ class ResourceAccessMixin(ModelStorage):
|
||||
return [
|
||||
(model, {'create': 'write', 'delete': 'write'}.get(mode, mode))]
|
||||
|
||||
@classmethod
|
||||
def search(
|
||||
cls, domain, offset=0, limit=None, order=None, count=False,
|
||||
query=False):
|
||||
transaction = Transaction()
|
||||
result = super().search(
|
||||
domain, offset=offset, limit=limit, order=order,
|
||||
count=False if not query else count, query=query)
|
||||
if not query and transaction.user and transaction.check_access:
|
||||
records = result
|
||||
resources = defaultdict(set)
|
||||
allowed = set()
|
||||
with without_check_access():
|
||||
records = cls.browse(records)
|
||||
for record in records:
|
||||
if record.resource:
|
||||
resources[record.resource.__class__].add(
|
||||
record.resource.id)
|
||||
|
||||
for Model, ids in resources.items():
|
||||
for sub_ids in grouped_slice(ids):
|
||||
allowed.update(Model.search([
|
||||
('id', 'in', list(sub_ids)),
|
||||
]))
|
||||
|
||||
records = [
|
||||
r for r in records
|
||||
if not r.resource or r.resource in allowed]
|
||||
if count:
|
||||
result = len(records)
|
||||
else:
|
||||
# re-browse to have same context
|
||||
result = cls.browse(records)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def read(cls, ids, fields_names):
|
||||
cls.check_access(ids, mode='read')
|
||||
|
||||
@@ -78,3 +78,28 @@ class ResourceTestCase(unittest.TestCase):
|
||||
|
||||
note = Note(note.id)
|
||||
self.assertEqual(user_note.write_date, write_date)
|
||||
|
||||
@with_transaction()
|
||||
def test_resources_rule(self):
|
||||
"Test resources rules are applied on search"
|
||||
pool = Pool()
|
||||
Note = pool.get('ir.note')
|
||||
Warning = pool.get('res.user.warning')
|
||||
|
||||
warning1 = Warning(user=0, name="root")
|
||||
warning1.save()
|
||||
note1 = Note(resource=warning1)
|
||||
note1.save()
|
||||
warning2 = Warning(user=1, name="admin")
|
||||
warning2.save()
|
||||
note2 = Note(resource=warning2)
|
||||
note2.save()
|
||||
|
||||
with Transaction().set_context(_check_access=True):
|
||||
notes = Note.search([])
|
||||
count = Note.search([], count=True)
|
||||
query = Note.search([], query=True)
|
||||
|
||||
self.assertEqual(notes, [note2])
|
||||
self.assertEqual(count, 1)
|
||||
self.assertTrue(query)
|
||||
|
||||
Reference in New Issue
Block a user