Browse Source

[RFR] clean up community contribution

pull/396/head
Holger Brunn 8 years ago
parent
commit
f264bdb27a
No known key found for this signature in database GPG Key ID: 1C9760FECA3AE18
  1. 1
      base_mixin_restrict_field_access/__init__.py
  2. 2
      base_mixin_restrict_field_access/__openerp__.py
  3. 4
      base_mixin_restrict_field_access/controllers/__init__.py
  4. 21
      base_mixin_restrict_field_access/controllers/main.py
  5. 152
      base_mixin_restrict_field_access/models/restrict_field_access_mixin.py

1
base_mixin_restrict_field_access/__init__.py

@ -2,3 +2,4 @@
# © 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models
from . import controllers

2
base_mixin_restrict_field_access/__openerp__.py

@ -10,6 +10,6 @@
"summary": "Make it simple to restrict read and/or write access to "
"certain fields base on some condition",
"depends": [
'base',
'web',
],
}

4
base_mixin_restrict_field_access/controllers/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import main

21
base_mixin_restrict_field_access/controllers/main.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.http import request
from openerp.addons.web.controllers.main import Export
from ..models.restrict_field_access_mixin import RestrictFieldAccessMixin
class RestrictedExport(Export):
"""Don't (even offer to) export inaccessible fields"""
def fields_get(self, model):
fields = super(RestrictedExport, self).fields_get(model)
model = request.env[model]
if isinstance(model, RestrictFieldAccessMixin):
sanitised_fields = {
k: fields[k] for k in fields
if model._restrict_field_access_is_field_accessible(k)
}
return sanitised_fields
else:
return fields

152
base_mixin_restrict_field_access/models/restrict_field_access_mixin.py

@ -4,8 +4,6 @@
import json
from lxml import etree
from openerp import _, api, fields, models, SUPERUSER_ID
from openerp.addons.web.controllers.main import Export
from openerp.http import request
from openerp.osv import expression # pylint: disable=W0402
@ -72,84 +70,70 @@ class RestrictFieldAccessMixin(models.AbstractModel):
self._fields[field].null(self.env))
return result
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
"""
Remove inaccessible fields from 'fields', 'groupby' and 'orderby'.
If this removes all 'fields', return no records.
If this removes all 'groupby', group by first remaining field.
If this removes 'orderby', don't specify order.
"""
requested_fields = fields or self._columns.keys()
sanitised_fields = [
f for f in requested_fields if self._restrict_field_access_is_field_accessible(
cr, uid, [], f
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None,
orderby=False, lazy=True):
"""Restrict reading if we read an inaccessible field"""
has_inaccessible_field = False
has_inaccessible_field |= any(
not self._restrict_field_access_is_field_accessible(f)
for f in fields or self._fields.keys()
)
has_inaccessible_field |= any(
expression.is_leaf(term) and
not self._restrict_field_access_is_field_accessible(
term[0].split('.')[0]
)
for term in domain
)
if groupby:
if isinstance(groupby, basestring):
groupby = [groupby]
has_inaccessible_field |= any(
not self._restrict_field_access_is_field_accessible(
f.split(':')[0]
)
for f in groupby
)
]
if not sanitised_fields:
return []
sanitised_groupby = []
groupby = [groupby] if isinstance(groupby, basestring) else groupby
for groupby_part in groupby:
groupby_field = groupby_part.split(':')[0]
if self._restrict_field_access_is_field_accessible(cr, uid, [], groupby_field):
sanitised_groupby.append(groupby_part)
if not sanitised_groupby:
sanitised_groupby.append(sanitised_fields[0])
if orderby:
sanitised_orderby = []
for orderby_part in orderby.split(','):
orderby_field = orderby_part.split()[0]
if self._restrict_field_access_is_field_accessible(cr, uid, [], orderby_field):
sanitised_orderby.append(orderby_part)
sanitised_orderby = sanitised_orderby and ','.join(sanitised_orderby) or False
else:
sanitised_orderby = False
has_inaccessible_field |= any(
not self._restrict_field_access_is_field_accessible(f.split())
for f in orderby.split(',')
)
# just like with search, we restrict read_group to the accessible
# records, because we'd either leak data otherwise or have very wrong
# results
if has_inaccessible_field:
self._restrict_field_access_inject_restrict_field_access_domain(
domain
)
result = super(RestrictFieldAccessMixin, self).read_group(
cr,
uid,
domain,
sanitised_fields,
sanitised_groupby,
offset=offset,
limit=limit,
context=context,
orderby=sanitised_orderby,
lazy=lazy
return super(RestrictFieldAccessMixin, self).read_group(
domain, fields, groupby, offset=offset, limit=limit,
orderby=orderby, lazy=lazy
)
# Add inaccessible fields back in with null values
inaccessible_fields = [f for f in requested_fields if f not in sanitised_fields]
for field_name in inaccessible_fields:
field = self._columns[field_name]
if lazy:
result.append(
{
'__domain': [(True, '=', True)],
field_name: field.null(self.env),
field_name + '_count': 0L
}
)
else:
result.append(
{
'__domain': [(True, '=', True)],
field_name: field.null(self.env),
'__count': 0L
}
)
return result
@api.multi
def _BaseModel__export_rows(self, fields):
"""Don't export inaccessible fields"""
if isinstance(self, RestrictFieldAccessMixin):
sanitised_fields = [f for f in fields if f and self._restrict_field_access_is_field_accessible(f[0])]
return super(RestrictFieldAccessMixin, self)._BaseModel__export_rows(sanitised_fields)
else:
return super(RestrictFieldAccessMixin, self)._BaseModel__export_rows(fields)
"""Null inaccessible fields"""
result = []
for this in self:
rows = super(RestrictFieldAccessMixin, this)\
._BaseModel__export_rows(fields)
for row in rows:
for i, path in enumerate(fields):
# we only need to take care of our own fields, super calls
# __export_rows again for x2x exports
if not path or len(path) > 1:
continue
if not this._restrict_field_access_is_field_accessible(
path[0],
) and row[i]:
row[i] = self._fields[path[0]].convert_to_export(
self._fields[path[0]].null(self.env), self.env
)
result.extend(rows)
return result
@api.multi
def write(self, vals):
@ -198,6 +182,7 @@ class RestrictFieldAccessMixin(models.AbstractModel):
@api.cr_uid_context
def fields_view_get(self, cr, uid, view_id=None, view_type='form',
context=None, toolbar=False, submenu=False):
# pylint: disable=R8110
# This needs to be oldstyle because res.partner in base passes context
# as positional argument
result = super(RestrictFieldAccessMixin, self).fields_view_get(
@ -301,24 +286,13 @@ class RestrictFieldAccessMixin(models.AbstractModel):
def _restrict_field_access_is_field_accessible(self, field_name,
action='read'):
"""return True if the current user can perform specified action on
all records in self. Override for your own logic"""
all records in self. Override for your own logic.
This function is also called with an empty recordset to get a list
of fields which are accessible unconditionally"""
if self._restrict_field_access_get_is_suspended() or\
self.env.user.id == SUPERUSER_ID:
self.env.user.id == SUPERUSER_ID or\
not self and action == 'read':
return True
whitelist = self._restrict_field_access_get_field_whitelist(
action=action)
return field_name in whitelist
class RestrictedExport(Export):
"""Don't (even offer to) export inaccessible fields"""
def fields_get(self, model):
Model = request.session.model(model)
fields = Model.fields_get(False, request.context)
model = request.env[model]
if isinstance(model, RestrictFieldAccessMixin):
sanitised_fields = {k:fields[k] for k in fields if model._restrict_field_access_is_field_accessible(k)}
return sanitised_fields
else:
return fields
Loading…
Cancel
Save