def test_ir_action_window(self): 'Test action windows are correctly defined' pool = Pool() ModelData = pool.get('ir.model.data') ActionWindow = pool.get('ir.action.act_window') for model_data in ModelData.search([ ('module', '=', self.module), ('model', '=', 'ir.action.act_window'), ]): action_window = ActionWindow(model_data.db_id) if not action_window.res_model: continue Model = pool.get(action_window.res_model) decoder = PYSONDecoder({ 'active_id': None, 'active_ids': [], 'active_model': action_window.res_model, }) domain = decoder.decode(action_window.pyson_domain) order = decoder.decode(action_window.pyson_order) context = decoder.decode(action_window.pyson_context) with Transaction().set_context(context): Model.search(domain, order=order, limit=action_window.limit) for action_domain in action_window.act_window_domains: if not action_domain.domain: continue Model.search(decoder.decode(action_domain.domain))
def check_fields_pyson(self): encoder = PYSONDecoder(noeval=True) for field in [ 'recipients_pyson', 'recipients_secondary_pyson', 'recipients_hidden_pyson', ]: value = getattr(self, field) if not value: continue try: pyson = encoder.decode(value) except Exception as exception: raise EmailTemplateError( gettext('ir.msg_email_template_invalid_field_pyson', template=self.rec_name, field=self.__names__(field)['field'], exception=exception)) from exception if not isinstance(pyson, list) and pyson.types() != {list}: raise EmailTemplateError( gettext( 'ir.msg_email_template_invalid_field_pyson_type', template=self.rec_name, field=self.__names__(field)['field'], ))
def check_fields_pyson(cls, templates, field_names=None): pyson_fields = { 'recipients_pyson', 'recipients_secondary_pyson', 'recipients_hidden_pyson', } if field_names: pyson_fields &= field_names if not pyson_fields: return encoder = PYSONDecoder(noeval=True) for template in templates: for field in pyson_fields: value = getattr(template, field) if not value: continue try: pyson = encoder.decode(value) except Exception as exception: raise EmailTemplateError( gettext('ir.msg_email_template_invalid_field_pyson', template=template.rec_name, field=cls.__names__(field)['field'], exception=exception)) from exception if not isinstance(pyson, list) and pyson.types() != {list}: raise EmailTemplateError( gettext( 'ir.msg_email_template_invalid_field_pyson_type', template=template.rec_name, field=cls.__names__(field)['field'], ))
def check_domain(cls, searches, field_names): decoder = PYSONDecoder() if field_names and 'domain' not in field_names: return for search in searches: try: value = decoder.decode(search.domain) except Exception as exception: raise DomainError( gettext('ir.msg_view_search_invalid_domain', domain=search.domain, search=search.rec_name)) from exception if isinstance(value, PYSON): if not value.types() == set([list]): raise DomainError( gettext('ir.msg_view_search_invalid_domain', domain=search.domain, search=search.rec_name)) elif not isinstance(value, list): raise DomainError( gettext('ir.msg_view_search_invalid_domain', domain=search.domain, search=search.rec_name)) else: try: fields.domain_validate(value) except Exception as exception: raise DomainError( gettext('ir.msg_view_search_invalid_domain', domain=search.domain, search=search.rec_name)) from exception
def get_search(cls, user_id=None): if user_id is None: user_id = Transaction().user decoder = PYSONDecoder() searches = cls.search([("user", "=", user_id)], order=[("model", "ASC"), ("name", "ASC")]) result = {} for search in searches: result.setdefault(search.model, []).append((search.id, search.name, decoder.decode(search.domain))) return result
def get_search(cls, user_id=None): if user_id is None: user_id = Transaction().user decoder = PYSONDecoder() searches = cls.search([ ('user', '=', user_id), ], order=[('model', 'ASC'), ('name', 'ASC')]) result = {} for search in searches: result.setdefault(search.model, []).append( (search.id, search.name, decoder.decode(search.domain))) return result
def test_button_change(self): "Test button change" pool = Pool() Model = pool.get('test.modelview.button_change') decoder = PYSONDecoder() view = Model.fields_view_get() tree = etree.fromstring(view['arch']) button = tree.xpath('//button[@name="test"]')[0] self.assertEqual(set(decoder.decode(button.attrib['change'])), {'name', 'extra'})
def get_search(cls): decoder = PYSONDecoder() searches = cls.search_read( [], order=[('model', 'ASC'), ('name', 'ASC')], fields_names=['id', 'name', 'model', 'domain', '_delete']) result = {} for search in searches: result.setdefault(search['model'], []).append( (search['id'], search['name'], decoder.decode(search['domain']), search['_delete'])) return result
def test_action_window(action_window): if not action_window.res_model: return Model = pool.get(action_window.res_model) for active_id, active_ids in [ (None, []), (1, [1]), (1, [1, 2]), ]: decoder = PYSONDecoder({ 'active_id': active_id, 'active_ids': active_ids, 'active_model': action_window.res_model, }) domain = decoder.decode(action_window.pyson_domain) order = decoder.decode(action_window.pyson_order) context = decoder.decode(action_window.pyson_context) search_value = decoder.decode(action_window.pyson_search_value) if action_window.context_domain: domain = [ 'AND', domain, decoder.decode(action_window.context_domain) ] with Transaction().set_context(context): Model.search(domain, order=order, limit=action_window.limit) if search_value: Model.search(search_value) for action_domain in action_window.act_window_domains: if not action_domain.domain: continue Model.search(decoder.decode(action_domain.domain)) if action_window.context_model: pool.get(action_window.context_model)
def view_get(self, model=None): key = (self.id, model) result = self._view_get_cache.get(key) if result: return result if self.inherit: if self.model == model: return self.inherit.view_get(model=model) else: arch = self.inherit.arch view_id = self.inherit.id else: arch = self.arch view_id = self.id views = self.__class__.search([ 'OR', [ ('inherit', '=', view_id), ('model', '=', model), ], [ ('id', '=', view_id), ('inherit', '!=', None), ], ]) views.sort(key=lambda v: self._module_index.get(v.module, -1), reverse=True) parser = etree.XMLParser(remove_comments=True, resolve_entities=False) tree = etree.fromstring(arch, parser=parser) decoder = PYSONDecoder({'context': Transaction().context}) for view in views: if view.domain and not decoder.decode(view.domain): continue if not view.arch or not view.arch.strip(): continue tree_inherit = etree.fromstring(view.arch, parser=parser) tree = self.inherit_apply(tree, tree_inherit) arch = etree.tostring(tree, encoding='utf-8').decode('utf-8') result = { 'type': self.rng_type, 'view_id': view_id, 'arch': arch, 'field_childs': self.field_childs, } self._view_get_cache.set(key, result) return result
def fields_get(cls, fields_names=None): """ Return the definition of each field on the model. """ definition = {} pool = Pool() Translation = pool.get('ir.translation') FieldAccess = pool.get('ir.model.field.access') ModelAccess = pool.get('ir.model.access') # Add translation to cache language = Transaction().language trans_args = [] for fname, field in cls._fields.items(): if fields_names and fname not in fields_names: continue trans_args.extend(field.definition_translations(cls, language)) Translation.get_sources(trans_args) encoder = PYSONEncoder() decoder = PYSONDecoder(noeval=True) accesses = FieldAccess.get_access([cls.__name__])[cls.__name__] for fname, field in cls._fields.items(): if fields_names and fname not in fields_names: continue definition[fname] = field.definition(cls, language) if not accesses.get(fname, {}).get('write', True): definition[fname]['readonly'] = True states = decoder.decode(definition[fname]['states']) states.pop('readonly', None) definition[fname]['states'] = encoder.encode(states) for right in ['create', 'delete']: definition[fname][right] = accesses.get(fname, {}).get(right, True) for fname in list(definition.keys()): # filter out fields which aren't in the fields_names list if fields_names: if fname not in fields_names: del definition[fname] elif not ModelAccess.check_relation( cls.__name__, fname, mode='read'): del definition[fname] return definition
def test_ir_action_window(self): 'Test action windows are correctly defined' pool = Pool() ModelData = pool.get('ir.model.data') ActionWindow = pool.get('ir.action.act_window') for model_data in ModelData.search([ ('module', '=', self.module), ('model', '=', 'ir.action.act_window'), ]): action_window = ActionWindow(model_data.db_id) if not action_window.res_model: continue Model = pool.get(action_window.res_model) for active_id, active_ids in [ (None, []), (1, [1]), (1, [1, 2]), ]: decoder = PYSONDecoder({ 'active_id': active_id, 'active_ids': active_ids, 'active_model': action_window.res_model, }) domain = decoder.decode(action_window.pyson_domain) order = decoder.decode(action_window.pyson_order) context = decoder.decode(action_window.pyson_context) search_value = decoder.decode(action_window.pyson_search_value) if action_window.context_domain: domain = [ 'AND', domain, decoder.decode(action_window.context_domain) ] with Transaction().set_context(context): Model.search(domain, order=order, limit=action_window.limit) if search_value: Model.search(search_value) for action_domain in action_window.act_window_domains: if not action_domain.domain: continue Model.search(decoder.decode(action_domain.domain)) if action_window.context_model: pool.get(action_window.context_model)
def fields_get(cls, fields_names=None, level=0): """ Return the definition of each field on the model. """ definition = {} pool = Pool() Translation = pool.get('ir.translation') FieldAccess = pool.get('ir.model.field.access') ModelAccess = pool.get('ir.model.access') # Add translation to cache language = Transaction().language trans_args = [] for fname, field in cls._fields.items(): if fields_names and fname not in fields_names: continue trans_args.extend(field.definition_translations(cls, language)) Translation.get_sources(trans_args) encoder = PYSONEncoder() decoder = PYSONDecoder(noeval=True) accesses = FieldAccess.get_access([cls.__name__])[cls.__name__] for fname, field in cls._fields.items(): if fields_names and fname not in fields_names: continue definition[fname] = field.definition(cls, language) if not accesses.get(fname, {}).get('write', True): definition[fname]['readonly'] = True states = decoder.decode(definition[fname]['states']) states.pop('readonly', None) definition[fname]['states'] = encoder.encode(states) for right in ['create', 'delete']: definition[fname][right] = accesses.get(fname, {}).get(right, True) if level > 0: relation = definition[fname].get('relation') if relation: Relation = pool.get(relation) relation_fields = Relation.fields_get(level=level - 1) definition[fname]['relation_fields'] = relation_fields for name, props in relation_fields.items(): # Convert selection into list if isinstance(props.get('selection'), str): change_with = props.get('selection_change_with') if change_with: selection = getattr(Relation(), props['selection'])() else: selection = getattr(Relation, props['selection'])() props['selection'] = selection schema = definition[fname].get('schema_model') if schema: Schema = pool.get(schema) definition[fname]['relation_fields'] = ( Schema.get_relation_fields()) for fname in list(definition.keys()): # filter out fields which aren't in the fields_names list if fields_names: if fname not in fields_names: del definition[fname] elif not ModelAccess.check_relation( cls.__name__, fname, mode='read'): del definition[fname] return definition
def get(cls, model_name, mode='read'): "Return dictionary of non-global and global rules" pool = Pool() RuleGroup = pool.get('ir.rule.group') Model = pool.get('ir.model') RuleGroup_Group = pool.get('ir.rule.group-res.group') User_Group = pool.get('res.user-res.group') rule_table = cls.__table__() rule_group = RuleGroup.__table__() rule_group_group = RuleGroup_Group.__table__() user_group = User_Group.user_group_all_table() model = Model.__table__() transaction = Transaction() assert mode in cls.modes model_names = [] model2field = defaultdict(list) def update_model_names(Model, path=None): if Model.__name__ in model_names: return model_names.append(Model.__name__) if path: model2field[Model.__name__].append(path) for field_name in Model.__access__: field = getattr(Model, field_name) Target = field.get_target() if path: target_path = path + '.' + field_name else: target_path = field_name update_model_names(Target, target_path) update_model_names(pool.get(model_name)) cursor = transaction.connection.cursor() user_id = transaction.user # root user above constraint if user_id == 0: return {}, {} cursor.execute(*rule_table.join(rule_group, condition=rule_group.id == rule_table.rule_group ).join(model, condition=rule_group.model == model.id ).select(rule_table.id, where=(model.model.in_(model_names)) & (getattr(rule_group, 'perm_%s' % mode) == Literal(True)) & (rule_group.id.in_( rule_group_group.join( user_group, condition=(rule_group_group.group == user_group.group) ).select(rule_group_group.rule_group, where=user_group.user == user_id) ) | (rule_group.default_p == Literal(True)) | (rule_group.global_p == Literal(True)) ))) ids = [x for x, in cursor] # Test if there is no rule_group that have no rule cursor.execute(*rule_group.join(model, condition=rule_group.model == model.id ).select(rule_group.id, where=(model.model.in_(model_names)) & ~rule_group.id.in_(rule_table.select(rule_table.rule_group)) & rule_group.id.in_(rule_group_group.join(user_group, condition=rule_group_group.group == user_group.group ).select(rule_group_group.rule_group, where=user_group.user == user_id)))) no_rules = cursor.fetchone() clause = defaultdict(lambda: ['OR']) clause_global = defaultdict(lambda: ['OR']) decoder = PYSONDecoder(cls._get_context()) # Use root user without context to prevent recursion with transaction.set_user(0), transaction.set_context(user=0): for rule in cls.browse(ids): assert rule.domain, ('Rule domain empty,' 'check if migration was done') dom = decoder.decode(rule.domain) target_model = rule.rule_group.model.model if target_model in model2field: target_dom = ['OR'] for field in model2field[target_model]: target_dom.append((field, 'where', dom)) dom = target_dom if rule.rule_group.global_p: clause_global[rule.rule_group].append(dom) else: clause[rule.rule_group].append(dom) if no_rules: group_id = no_rules[0] clause[RuleGroup(group_id)] = [] return clause, clause_global
def get(cls, model_name, mode='read'): "Return dictionary of non-global and global rules" pool = Pool() RuleGroup = pool.get('ir.rule.group') Model = pool.get('ir.model') RuleGroup_Group = pool.get('ir.rule.group-res.group') User_Group = pool.get('res.user-res.group') rule_table = cls.__table__() rule_group = RuleGroup.__table__() rule_group_group = RuleGroup_Group.__table__() user_group = User_Group.__table__() model = Model.__table__() transaction = Transaction() assert mode in cls.modes cursor = transaction.connection.cursor() user_id = transaction.user # root user above constraint if user_id == 0: user_id = transaction.context.get('user') if not user_id: return {}, {} cursor.execute(*rule_table.join( rule_group, condition=rule_group.id == rule_table.rule_group ).join(model, condition=rule_group.model == model.id).select( rule_table.id, where=(model.model == model_name) & (getattr(rule_group, 'perm_%s' % mode) == Literal(True)) & (rule_group.id.in_( rule_group_group.join( user_group, condition=(rule_group_group.group == user_group.group )).select(rule_group_group.rule_group, where=user_group.user == user_id)) | (rule_group.default_p == Literal(True)) | (rule_group.global_p == Literal(True))))) ids = [x for x, in cursor] # Test if there is no rule_group that have no rule cursor.execute(*rule_group.join( model, condition=rule_group.model == model.id).select( rule_group.id, where=(model.model == model_name) & ~rule_group.id.in_(rule_table.select(rule_table.rule_group)) & rule_group.id.in_( rule_group_group.join(user_group, condition=rule_group_group.group == user_group.group). select(rule_group_group.rule_group, where=user_group.user == user_id)))) no_rules = cursor.fetchone() clause = defaultdict(lambda: ['OR']) clause_global = defaultdict(lambda: ['OR']) decoder = PYSONDecoder(cls._get_context()) # Use root user without context to prevent recursion with transaction.set_user(0), transaction.set_context(user=0): for rule in cls.browse(ids): assert rule.domain, ('Rule domain empty,' 'check if migration was done') dom = decoder.decode(rule.domain) if rule.rule_group.global_p: clause_global[rule.rule_group].append(dom) else: clause[rule.rule_group].append(dom) if no_rules: group_id = no_rules[0] clause[RuleGroup(group_id)] = [] return clause, clause_global