Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
 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
Esempio n. 4
0
 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
Esempio n. 5
0
    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 []
Esempio n. 6
0
    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 []