Skip to content

Commit

Permalink
Code Review
Browse files Browse the repository at this point in the history
  • Loading branch information
majouda committed Oct 9, 2024
1 parent 6931bf3 commit b3fe41f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 146 deletions.
9 changes: 4 additions & 5 deletions private_data_group/controllers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
from odoo import _
from odoo.exceptions import AccessError, ValidationError
from odoo.http import request
from typing import Iterable, List


def _get_related_model(model: str, relation: str):
def _get_related_model(model, relation):
model_cls = request.env[model]

if relation not in model_cls._fields:
Expand All @@ -21,14 +20,14 @@ def _get_related_model(model: str, relation: str):
return comodel_name


def _raise_private_field_access_error(model: str, field: str):
def _raise_private_field_access_error(model, field):
raise AccessError(
_('You do not have access to the field {field} of model {model}')
.format(field=field, model=model)
)


def check_model_fields_access(model: str, fields: Iterable[str]):
def check_model_fields_access(model, fields):
env = request.env
if env.user.has_private_data_access():
return
Expand All @@ -48,6 +47,6 @@ def check_model_fields_access(model: str, fields: Iterable[str]):
_raise_private_field_access_error(model, field)


def extract_fields_from_domain(domain: List):
def extract_fields_from_domain(domain):
field_tuples = [e for e in domain if isinstance(e, (list, tuple))]
return [t[0] for t in field_tuples]
126 changes: 68 additions & 58 deletions private_data_group/controllers/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,102 +8,112 @@
)
from odoo import http
from odoo.http import request
from typing import Iterable
from .common import check_model_fields_access, extract_fields_from_domain


METHODS_WITH_ORDERBY = [
'search',
'search_read',
'read_group',
"search",
"search_read",
"read_group",
]


ORDERBY_ARGUMENT_NAMES = {
'search': 'order',
'search_read': 'order',
'read_group': 'orderby',
"search": "order",
"search_read": "order",
"read_group": "orderby",
}


ORDERBY_ARGUMENT_INDEXES = {
'search': 3,
'search_read': 4,
'read_group': 5,
"search": 3,
"search_read": 4,
"read_group": 5,
}


def _get_orderby_from_args_and_kwargs(method: str, args: list, kwargs: dict):
"""Get the orderby from the given args and kwargs.
class DataSetWithPrivateFields(DataSet):
"""Add access restriction to private fields."""

If neither the args or kwargs contain the orderby (which is a valid case),
an empty orderby is returned.
def _get_orderby_from_args_and_kwargs(self, method, args, kwargs):
"""Get the orderby from the given args and kwargs.
:param method: the method called.
:param args: the arguments passed through rpc.
:param kargs: the keyword arguments passed through rpc.
:return: the given orderby.
"""
argument_name = ORDERBY_ARGUMENT_NAMES[method]
argument_index = ORDERBY_ARGUMENT_INDEXES[method]
If neither the args or kwargs contain the orderby (which is a valid case),
an empty orderby is returned.
args = args or []
kwargs = kwargs or {}
:param method: the method called.
:param args: the arguments passed through rpc.
:param kargs: the keyword arguments passed through rpc.
:return: the given orderby.
"""
argument_name = ORDERBY_ARGUMENT_NAMES[method]
argument_index = ORDERBY_ARGUMENT_INDEXES[method]

if len(args) > argument_index:
return args[argument_index]
args = args or []
kwargs = kwargs or {}

return kwargs.get(argument_name) or None
if len(args) > argument_index:
return args[argument_index]

return kwargs.get(argument_name) or None

def _parse_fields_from_orderby_clause(order_clause: str):
parts = order_clause.split(',')
return [p.split(' ')[0] for p in parts]
def _parse_fields_from_orderby_clause(self, order_clause):
parts = order_clause.split(",")
return [p.split(" ")[0] for p in parts]

def _filter_unauthorized_fields(self, model, record_values):
"""Filter unauthorized fields from the given record values."""
env = request.env
if env.user.has_private_data_access():
return record_values

def _filter_unauthorized_fields(model: str, record_values: Iterable[dict]):
"""Filter unauthorized fields from the given record values."""
env = request.env
if env.user.has_private_data_access():
return record_values
private_fields = env["ir.private.field"].get_model_private_fields(model)

private_fields = env['ir.private.field'].get_model_private_fields(model)
def without_private_fields(r):
return {k: v for k, v in r.items() if k not in private_fields}

def without_private_fields(r):
return {k: v for k, v in r.items() if k not in private_fields}
return [without_private_fields(r) for r in record_values]

return [without_private_fields(r) for r in record_values]
def _extract_groupby_from_args_and_kwargs(self, args, kwargs):
groupby = args[2] if len(args) > 2 else kwargs.get("groupby", [])
groupby_fields = [groupby] if isinstance(groupby, str) else groupby
return [f.split(":")[0] for f in groupby_fields]

@http.route("/web/dataset/search_read", type="json", auth="user")
def search_read(
self, model, fields=False, offset=0, limit=False, domain=None, sort=None
):
fields_to_check = set()

def _extract_groupby_from_args_and_kwargs(args: list, kwargs: dict):
groupby = args[2] if len(args) > 2 else kwargs.get('groupby', [])
groupby_fields = [groupby] if isinstance(groupby, str) else groupby
return [f.split(':')[0] for f in groupby_fields]
if sort:
fields_to_check.update(self._parse_fields_from_orderby_clause(sort))

if domain:
fields_to_check.update(extract_fields_from_domain(domain))

class DataSetWithPrivateFields(DataSet):
"""Add access restriction to private fields."""
check_model_fields_access(model, fields_to_check)

@http.route('/web/dataset/search_read', type='json', auth="user")
def search_read(self, model, fields=False, offset=0, limit=False, domain=None,
sort=None):
return request.env[model].with_context(
active_model=model).web_search_read(
domain, fields, offset=offset, limit=limit, order=sort)
res = request.env[model].web_search_read(
domain, fields, offset=offset, limit=limit, order=sort
)
res["records"] = self._filter_unauthorized_fields(model, res["records"])
return res

def _call_kw(self, model, method, args, kwargs):
fields_to_check = set()

if method == 'web_search_read':
kwargs['context']['active_model'] = model
if method == "web_search_read":
kwargs["context"]["active_model"] = model

if method == 'read_group':
fields_to_check.update(_extract_groupby_from_args_and_kwargs(args, kwargs))
if method == "read_group":
fields_to_check.update(
self._extract_groupby_from_args_and_kwargs(args, kwargs)
)

if method in METHODS_WITH_ORDERBY:
orderby = _get_orderby_from_args_and_kwargs(method, args, kwargs)
orderby = self._get_orderby_from_args_and_kwargs(method, args, kwargs)
if orderby:
fields_to_check.update(_parse_fields_from_orderby_clause(orderby))
fields_to_check.update(self._parse_fields_from_orderby_clause(orderby))

if method in SEARCH_METHODS:
domain = get_domain_from_args_and_kwargs(method, args, kwargs)
Expand All @@ -114,7 +124,7 @@ def _call_kw(self, model, method, args, kwargs):

res = super()._call_kw(model, method, args, kwargs)

if method in ('read', 'search_read'):
res = _filter_unauthorized_fields(model, res)
if method in ("read", "search_read"):
res = self._filter_unauthorized_fields(model, res)

return res
51 changes: 30 additions & 21 deletions private_data_group/i18n/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-25 19:18+0000\n"
"PO-Revision-Date: 2022-09-25 15:22-0400\n"
"Last-Translator: <>\n"
"POT-Creation-Date: 2024-10-09 15:27+0000\n"
"PO-Revision-Date: 2024-10-09 15:27+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
"Language: fr\n"
"X-Generator: Poedit 2.0.6\n"

#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__active
Expand All @@ -27,6 +25,11 @@ msgstr "Actif"
msgid "Archived"
msgstr "Archivé"

#. module: private_data_group
#: model:ir.model,name:private_data_group.model_base
msgid "Base"
msgstr ""

#. module: private_data_group
#: model:ir.model,name:private_data_group.model_res_partner
msgid "Contact"
Expand All @@ -35,12 +38,12 @@ msgstr ""
#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__create_uid
msgid "Created by"
msgstr ""
msgstr "Créé par"

#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__create_date
msgid "Created on"
msgstr ""
msgstr "Créé le"

#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__display_name
Expand All @@ -66,17 +69,17 @@ msgstr ""
#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field____last_update
msgid "Last Modified on"
msgstr ""
msgstr "Dernière modification le"

#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__write_uid
msgid "Last Updated by"
msgstr ""
msgstr "Dernière mise à jour par"

#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__write_date
msgid "Last Updated on"
msgstr ""
msgstr "Dernière mise à jour le"

#. module: private_data_group
#: model:res.groups,name:private_data_group.group_private_data
Expand All @@ -93,7 +96,7 @@ msgstr "Modèle"
#. module: private_data_group
#: model:ir.model.fields,field_description:private_data_group.field_ir_private_field__model_select_id
msgid "Model Select"
msgstr ""
msgstr "Sélection du modèle"

#. module: private_data_group
#: model:ir.model,name:private_data_group.model_ir_private_field
Expand All @@ -111,26 +114,32 @@ msgstr "Champs privés"
#. module: private_data_group
#: model:ir.model.fields,help:private_data_group.field_ir_private_field__model_id
msgid "The model this field belongs to"
msgstr ""
msgstr "Le modèle auquel ce champ appartient"

#. module: private_data_group
#: model:ir.model,name:private_data_group.model_res_users
msgid "Users"
msgstr ""
msgid "User"
msgstr "Utilisateur"

#. module: private_data_group
#: model:ir.model,name:private_data_group.model_ir_ui_view
msgid "View"
msgstr ""
msgstr "Vue"

#. module: private_data_group
#: code:addons/private_data_group/models/res_partner.py:8
#. odoo-python
#: code:addons/private_data_group/models/res_partner.py:0
#, python-format
msgid "You are not authorized to access the partner id={} because it is a private address."
msgstr "Vous n'êtes pas autorisé à accéder au partenaire id={} car il s'agit d'une adresse privée."
msgid ""
"You are not authorized to access the partner id={} because it is a private "
"address."
msgstr ""
"Vous n'êtes pas autorisé à accéder au partenaire id={} car il s'agit d'une "
"adresse privée."

#. module: private_data_group
#: code:addons/private_data_group/controllers/common.py:27
#. odoo-python
#: code:addons/private_data_group/controllers/common.py:0
#, python-format
msgid "You do not have access to the field {field} of model {model}"
msgstr "Vous n'avez pas accès au champ {field} du modèle {model}."
1 change: 0 additions & 1 deletion private_data_group/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
ir_ui_view,
res_partner,
res_users,
base
)
Loading

0 comments on commit b3fe41f

Please sign in to comment.