# HG changeset patch # User Sylvain Thénault # Date 1507295658 -7200 # Node ID 1d7e4f98f9023c3bc74572b41672ed2e88d739b8 # Parent f2e6fb5ddf6885f89eb3b63ce1d4d4a7e1017f12 [uicfg] Fix autoform_section rtags wrt derivation cw 3.25 introduced the 'derived rtags' feature, but missed that `autoform_section` implementation was overriding several methods where this was implemented in the base class. The following problems are tested and fixed: * during init, we should not attempt to call `_initfunc_step2` if there is some parent, * but we should handle expansion of wildcard ('*' used as subject or object of a tag) since this is handled during init step for this class, unlike others which handle this in `get` method (i.e. at lookup time), * fix overrided `get` method to consider parent rtag if any. Closes #17107020 diff -r f2e6fb5ddf68 -r 1d7e4f98f902 cubicweb/web/test/unittest_uicfg.py --- a/cubicweb/web/test/unittest_uicfg.py Fri Oct 06 10:00:36 2017 +0200 +++ b/cubicweb/web/test/unittest_uicfg.py Fri Oct 06 15:14:18 2017 +0200 @@ -19,7 +19,10 @@ import copy import warnings -from cubicweb.devtools.testlib import CubicWebTC +from yams.buildobjs import RelationDefinition, EntityType + +from cubicweb.devtools.testlib import CubicWebTC, BaseTestCase +from cubicweb.schema import build_schema_from_namespace from cubicweb.web import uihelper, formwidgets as fwdgs from cubicweb.web.views import uicfg @@ -144,6 +147,55 @@ self.assertTrue(obj is custom_afs) +def _schema(): + + class Personne(EntityType): + pass + + class Societe(EntityType): + pass + + class Tag(EntityType): + pass + + class travaille(RelationDefinition): + subject = 'Personne' + object = 'Societe' + + class tags(RelationDefinition): + subject = 'Tag' + object = ('Personne', 'Societe', 'Tag') + + return build_schema_from_namespace(locals().items()) + + +class AutoformSectionTC(BaseTestCase): + + def test_derivation(self): + schema = _schema() + afs = uicfg.AutoformSectionRelationTags() + afs.tag_subject_of(('Personne', 'travaille', '*'), 'main', 'relations') + afs.tag_object_of(('*', 'travaille', 'Societe'), 'main', 'relations') + afs.tag_subject_of(('Tag', 'tags', '*'), 'main', 'relations') + + afs2 = afs.derive(__name__, afs.__select__) + afs2.tag_subject_of(('Personne', 'travaille', '*'), 'main', 'attributes') + afs2.tag_object_of(('*', 'travaille', 'Societe'), 'main', 'attributes') + afs2.tag_subject_of(('Tag', 'tags', 'Societe'), 'main', 'attributes') + + afs.init(schema) + afs2.init(schema) + + self.assertEqual(afs2.etype_get('Tag', 'tags', 'subject', 'Personne'), + set(('main_relations', 'muledit_hidden', 'inlined_relations'))) + self.assertEqual(afs2.etype_get('Tag', 'tags', 'subject', 'Societe'), + set(('main_attributes', 'muledit_hidden', 'inlined_attributes'))) + self.assertEqual(afs2.etype_get('Personne', 'travaille', 'subject', 'Societe'), + set(('main_attributes', 'muledit_hidden', 'inlined_attributes'))) + self.assertEqual(afs2.etype_get('Societe', 'travaille', 'object', 'Personne'), + set(('main_attributes', 'muledit_hidden', 'inlined_attributes'))) + + if __name__ == '__main__': import unittest unittest.main() diff -r f2e6fb5ddf68 -r 1d7e4f98f902 cubicweb/web/views/uicfg.py --- a/cubicweb/web/views/uicfg.py Fri Oct 06 10:00:36 2017 +0200 +++ b/cubicweb/web/views/uicfg.py Fri Oct 06 15:14:18 2017 +0200 @@ -54,12 +54,14 @@ uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True) """ +from itertools import repeat + from six import string_types from cubicweb import neg_role from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet, RelationTagsDict, NoTargetRelationTagsDict, - _ensure_str_key) + rtags_chain, _ensure_str_key) from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES @@ -203,7 +205,16 @@ class AutoformSectionRelationTags(RelationTagsSet): - """autoform relations'section""" + """autoform relations'section + + Notice that unlike other rtags where wildcard handling is done when + retrieving some value, all values are expanded here during initialization + step. + + For derived rtags, values specified for the 'main' form type are propagated + to the 'inlined' form type if unspecified. Others are fetched back from the + parent. + """ __regid__ = 'autoform_section' _allowed_form_types = ('main', 'inlined', 'muledit') @@ -215,7 +226,34 @@ def init(self, schema, check=True): super(AutoformSectionRelationTags, self).init(schema, check) - self.apply(schema, self._initfunc_step2) + if self._parent is None: + self.apply(schema, self._initfunc_step2) + else: + # we still need to expand wildcard in defined keys + for key in list(self._tagdefs): + stype, rtype, otype, role = key + rschema = schema.rschema(rtype) + if stype == '*' and stype == '*': + concrete_rdefs = rschema.rdefs.keys() + elif stype == '*': + concrete_rdefs = zip(rschema.subjects(otype), repeat(otype)) + elif otype == '*': + concrete_rdefs = zip(repeat(stype), rschema.objects(stype)) + else: + concrete_rdefs = [(stype, otype)] + for sschema, oschema in concrete_rdefs: + self._init(sschema, rschema, oschema, role) + # also, we have to copy values from 'main' to 'inlined' and + # for other undefined sections from the parent's rtag + formsections = self.get(sschema, rschema, oschema, role) + sectdict = _formsections_as_dict(formsections) + parent_formsections = self._parent.get(sschema, rschema, oschema, role) + parent_sectdict = _formsections_as_dict(parent_formsections) + for formtype, section in parent_sectdict.items(): + if formtype not in sectdict: + if formtype == 'inlined': + section = sectdict.get('main', section) + formsections.add('%s_%s' % (formtype, section)) def _init(self, sschema, rschema, oschema, role): formsections = self.init_get(sschema, rschema, oschema, role) @@ -300,7 +338,12 @@ def get(self, *key): # overriden to avoid recomputing done in parent classes - return self._tagdefs.get(key, ()) + for rtag in rtags_chain(self): + try: + return rtag._tagdefs[key] + except KeyError: + continue + return () def relations_by_section(self, entity, formtype, section, permission, strict=False):