def _create_or_combine_sharing_rule(self, cr, current_user, wizard_data, group_id, model_id, domain, restrict=False, rule_name=None, context=None): """Add a new ir.rule entry for model_id and domain on the target group_id. If ``restrict`` is True, instead of adding a rule, the domain is combined with AND operator with all existing rules in the group, to implement an additional restriction (as of 6.1, multiple rules in the same group are OR'ed by default, so a restriction must alter all existing rules) This is necessary because the personal rules of the user that is sharing are first copied to the new share group. Afterwards the filters used for sharing are applied as an additional layer of rules, which are likely to apply to the same model. The default rule algorithm would OR them (as of 6.1), which would result in a combined set of permission that could be larger than those of the user that is sharing! Hence we must forcefully AND the rules at this stage. One possibly undesirable effect can appear when sharing with a pre-existing group, in which case altering pre-existing rules would not be desired. This is addressed in the portal module. """ if rule_name is None: rule_name = _('Sharing filter created by user %s (%s) for group %s') % \ (current_user.name, current_user.login, group_id) rule_obj = self.pool.get('ir.rule') rule_ids = rule_obj.search(cr, UID_ROOT, [('groups', 'in', group_id), ('model_id', '=', model_id)]) if rule_ids: for rule in rule_obj.browse(cr, UID_ROOT, rule_ids, context=context): if rule.domain_force == domain: # don't create it twice! if restrict: continue else: self._logger.debug("Ignoring sharing rule on model %s with domain: %s the same rule exists already", model_id, domain) return if restrict: # restricting existing rules is done by adding the clause # with an AND, but we can't alter the rule if it belongs to # other groups, so we duplicate if needed rule = self._check_personal_rule_or_duplicate(cr, group_id, rule, context=context) eval_ctx = rule_obj._eval_context_for_combinations() org_domain = expression.normalize(eval(rule.domain_force, eval_ctx)) new_clause = expression.normalize(eval(domain, eval_ctx)) combined_domain = expression.AND([new_clause, org_domain]) rule.write({'domain_force': combined_domain, 'name': rule.name + _('(Modified)')}) self._logger.debug("Combining sharing rule %s on model %s with domain: %s", rule.id, model_id, domain) if not restrict: # Adding the new rule in the group is ok for normal cases, because rules # in the same group and for the same model will be combined with OR # (as of v6.1), so the desired effect is achieved. rule_obj.create(cr, UID_ROOT, { 'name': rule_name, 'model_id': model_id, 'domain_force': domain, 'groups': [(4,group_id)] }) self._logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain)
def _create_or_combine_sharing_rule(self, cr, current_user, wizard_data, group_id, model_id, domain, restrict=False, rule_name=None, context=None): """Add a new ir.rule entry for model_id and domain on the target group_id. If ``restrict`` is True, instead of adding a rule, the domain is combined with AND operator with all existing rules in the group, to implement an additional restriction (as of 6.1, multiple rules in the same group are OR'ed by default, so a restriction must alter all existing rules) This is necessary because the personal rules of the user that is sharing are first copied to the new share group. Afterwards the filters used for sharing are applied as an additional layer of rules, which are likely to apply to the same model. The default rule algorithm would OR them (as of 6.1), which would result in a combined set of permission that could be larger than those of the user that is sharing! Hence we must forcefully AND the rules at this stage. One possibly undesirable effect can appear when sharing with a pre-existing group, in which case altering pre-existing rules would not be desired. This is addressed in the portal module. """ if rule_name is None: rule_name = _('Sharing filter created by user %s (%s) for group %s') % \ (current_user.name, current_user.login, group_id) rule_obj = self.pool.get('ir.rule') rule_ids = rule_obj.search(cr, UID_ROOT, [('groups', 'in', group_id), ('model_id', '=', model_id)]) if rule_ids: for rule in rule_obj.browse(cr, UID_ROOT, rule_ids, context=context): if rule.domain_force == domain: # don't create it twice! if restrict: continue else: self._logger.debug("Ignoring sharing rule on model %s with domain: %s the same rule exists already", model_id, domain) return if restrict: # restricting existing rules is done by adding the clause # with an AND, but we can't alter the rule if it belongs to # other groups, so we duplicate if needed rule = self._check_personal_rule_or_duplicate(cr, group_id, rule, context=context) eval_ctx = rule_obj._eval_context_for_combinations() org_domain = expression.normalize(eval(rule.domain_force, eval_ctx)) new_clause = expression.normalize(eval(domain, eval_ctx)) combined_domain = expression.AND([new_clause, org_domain]) rule.write({'domain_force': combined_domain, 'name': rule.name + _('(Modified)')}) self._logger.debug("Combining sharing rule %s on model %s with domain: %s", rule.id, model_id, domain) if not rule_ids or not restrict: # Adding the new rule in the group is ok for normal cases, because rules # in the same group and for the same model will be combined with OR # (as of v6.1), so the desired effect is achieved. rule_obj.create(cr, UID_ROOT, { 'name': rule_name, 'model_id': model_id, 'domain_force': domain, 'groups': [(4,group_id)] }) self._logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain)
def _domain_force_get(self, cr, uid, ids, field_name, arg, context=None): res = {} eval_context = self._eval_context(cr, uid) for rule in self.browse(cr, uid, ids, context): if rule.domain_force: res[rule.id] = expression.normalize(eval(rule.domain_force, eval_context)) else: res[rule.id] = [] return res
def _domain_force_get(self, cr, uid, ids, field_name, arg, context=None): res = {} eval_context = self._eval_context(cr, uid) for rule in self.browse(cr, uid, ids, context): if rule.domain_force: res[rule.id] = expression.normalize( eval(rule.domain_force, eval_context)) else: res[rule.id] = [] return res
def _compute_domain(self, cr, uid, model_name, mode="read"): if mode not in self._MODES: raise ValueError("Invalid mode: %r" % (mode,)) if uid == SUPERUSER_UID: return None cr.execute( """SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id = m.id) WHERE m.model = %s AND r.perm_""" + mode + """ AND (r.id IN (SELECT rule_group_id FROM rule_group_rel g_rel JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) WHERE u_rel.uid = %s) OR r.global)""", (model_name, uid), ) rule_ids = [x[0] for x in cr.fetchall()] if rule_ids: # browse user as super-admin root to avoid access errors! user = self.pool.get("res.users").browse(cr, SUPERUSER_UID, uid) global_domains = [] # list of domains group_domains = {} # map: group -> list of domains for rule in self.browse(cr, SUPERUSER_UID, rule_ids): # read 'domain' as UID to have the correct eval context for the rule. rule_domain = self.read(cr, uid, rule.id, ["domain"])["domain"] dom = expression.normalize(rule_domain) for group in rule.groups: if group in user.groups_id: group_domains.setdefault(group, []).append(dom) if not rule.groups: global_domains.append(dom) # combine global domains and group domains if group_domains: group_domain = expression.OR(map(expression.OR, group_domains.values())) else: group_domain = [] domain = expression.AND(global_domains + [group_domain]) return domain return []
def _compute_domain(self, cr, uid, model_name, mode="read"): if mode not in self._MODES: raise ValueError('Invalid mode: %r' % (mode, )) if uid == SUPERUSER_ID: return None cr.execute( """SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id = m.id) WHERE m.model = %s AND r.perm_""" + mode + """ AND (r.id IN (SELECT rule_group_id FROM rule_group_rel g_rel JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) WHERE u_rel.uid = %s) OR r.global)""", (model_name, uid)) rule_ids = [x[0] for x in cr.fetchall()] if rule_ids: # browse user as super-admin root to avoid access errors! user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid) global_domains = [] # list of domains group_domains = {} # map: group -> list of domains for rule in self.browse(cr, SUPERUSER_ID, rule_ids): # read 'domain' as UID to have the correct eval context for the rule. rule_domain = self.read(cr, uid, rule.id, ['domain'])['domain'] dom = expression.normalize(rule_domain) for group in rule.groups: if group in user.groups_id: group_domains.setdefault(group, []).append(dom) if not rule.groups: global_domains.append(dom) # combine global domains and group domains if group_domains: group_domain = expression.OR( map(expression.OR, group_domains.values())) else: group_domain = [] domain = expression.AND(global_domains + [group_domain]) return domain return []