diff --git a/CHANGELOG b/CHANGELOG
index 5b10ab3b0f..7ca0302abb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Read, write, create, delete permission on record rules
* Add reset_default method to ir.default
* Doesn't append '%' to "like", "ilike" clauses
* Handle database dump and restore with password
diff --git a/trytond/ir/rule.py b/trytond/ir/rule.py
index 3fb72b3e47..4d43850df9 100644
--- a/trytond/ir/rule.py
+++ b/trytond/ir/rule.py
@@ -23,6 +23,10 @@ class RuleGroup(ModelSQL, ModelView):
'rule_group_id', 'group_id', 'Groups')
users = fields.Many2Many('ir.rule.group-res.user',
'rule_group_id', 'user_id', 'Users')
+ perm_read = fields.Boolean('Read Access')
+ perm_write = fields.Boolean('Write Access')
+ perm_create = fields.Boolean('Create Access')
+ perm_delete = fields.Boolean('Delete Access')
def __init__(self):
super(RuleGroup, self).__init__()
@@ -40,6 +44,18 @@ class RuleGroup(ModelSQL, ModelView):
def default_default_p(self, cursor, user, context=None):
return False
+ def default_perm_read(self, cursor, user, context=None):
+ return True
+
+ def default_perm_write(self, cursor, user, context=None):
+ return True
+
+ def default_perm_create(self, cursor, user, context=None):
+ return True
+
+ def default_perm_delete(self, cursor, user, context=None):
+ return True
+
def delete(self, cursor, user, ids, context=None):
res = super(RuleGroup, self).delete(cursor, user, ids,
context=context)
@@ -123,9 +139,11 @@ class Rule(ModelSQL, ModelView):
res.append((i, i))
return res
- def domain_get(self, cursor, user, model_name, context=None):
+ def domain_get(self, cursor, user, model_name, mode='read', context=None):
if context is None:
context = {}
+ assert mode in ['read', 'write', 'create', 'delete'], \
+ 'Invalid domain mode for security'
# root user above constraint
if user == 0:
@@ -147,6 +165,7 @@ class Rule(ModelSQL, ModelView):
'JOIN "' + model_obj._table + '" m ON (g.model = m.id)) ' \
"ON (g.id = r.rule_group) " \
"WHERE m.model = %s "
+ "AND g.perm_" + mode + " "
"AND (g.id IN (" \
'SELECT rule_group_id ' \
'FROM "' + rule_group_user_obj._table + '" ' \
diff --git a/trytond/ir/rule.xml b/trytond/ir/rule.xml
index 4149eecf28..97e9a911b5 100644
--- a/trytond/ir/rule.xml
+++ b/trytond/ir/rule.xml
@@ -15,6 +15,16 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+
+
+
+
+
+
+
@@ -32,6 +42,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+
diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py
index af517c36a8..66cc1a31b9 100644
--- a/trytond/model/modelsql.py
+++ b/trytond/model/modelsql.py
@@ -362,6 +362,16 @@ class ModelSQL(ModelStorage):
cursor2.close()
raise
+ domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor, user,
+ self._name, mode='create', context=context)
+ if domain1:
+ cursor.execute('SELECT id FROM "' + self._table + '" ' \
+ 'WHERE id = %s AND (' + domain1 + ')',
+ [id_new] + domain2)
+ if not cursor.rowcount:
+ self.raise_user_error(cursor, 'access_error',
+ self._description, context=context)
+
upd_todo.sort(lambda x, y: self._columns[x].priority - \
self._columns[y].priority)
for field in upd_todo:
@@ -413,7 +423,7 @@ class ModelSQL(ModelStorage):
# construct a clause for the rules :
domain1, domain2 = rule_obj.domain_get(cursor, user, self._name,
- context=context)
+ mode='read', context=context)
fields_related = {}
datetime_fields = []
@@ -773,7 +783,7 @@ class ModelSQL(ModelStorage):
upd1.append(user)
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor,
- user, self._name, context=context)
+ user, self._name, mode='write', context=context)
if domain1:
domain1 = ' AND (' + domain1 + ') '
for i in range(0, len(ids), cursor.IN_MAX):
@@ -994,7 +1004,7 @@ class ModelSQL(ModelStorage):
delete_ctx['_delete'][self._name].update(ids)
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor, user,
- self._name, context=context)
+ self._name, mode='delete', context=context)
if domain1:
domain1 = ' AND (' + domain1 + ') '
@@ -1121,7 +1131,7 @@ class ModelSQL(ModelStorage):
# construct a clause for the rules :
domain1, domain2 = rule_obj.domain_get(cursor, user, self._name,
- context=context)
+ mode='read', context=context)
if domain1:
if qu1:
qu1 += ' AND ' + domain1