cubicweb/web/views/uicfg.py
changeset 11854 056de1196ef8
parent 11853 c71339453c1e
child 11932 7b2247098f58
equal deleted inserted replaced
11853:c71339453c1e 11854:056de1196ef8
    52    # Adds all subjects of the entry_of relation in the add menu of the ``Blog``
    52    # Adds all subjects of the entry_of relation in the add menu of the ``Blog``
    53    # primary view
    53    # primary view
    54    uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
    54    uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
    55 """
    55 """
    56 
    56 
    57 
       
    58 from warnings import warn
       
    59 
       
    60 from six import string_types
    57 from six import string_types
    61 
    58 
    62 from cubicweb import neg_role
    59 from cubicweb import neg_role
    63 from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
    60 from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
    64                             RelationTagsDict, NoTargetRelationTagsDict,
    61                             RelationTagsDict, NoTargetRelationTagsDict,
    91                     section = 'relations'
    88                     section = 'relations'
    92                 else:
    89                 else:
    93                     section = 'sideboxes'
    90                     section = 'sideboxes'
    94             self.tag_relation((sschema, rschema, oschema, role), section)
    91             self.tag_relation((sschema, rschema, oschema, role), section)
    95 
    92 
       
    93 
    96 primaryview_section = PrimaryViewSectionRelationTags()
    94 primaryview_section = PrimaryViewSectionRelationTags()
    97 
    95 
    98 
    96 
    99 class DisplayCtrlRelationTags(NoTargetRelationTagsDict):
    97 class DisplayCtrlRelationTags(NoTargetRelationTagsDict):
   100     """primary view display controller configuration"""
    98     """primary view display controller configuration"""
   153 # * 'system'
   151 # * 'system'
   154 # * 'schema'
   152 # * 'schema'
   155 # * 'hidden'
   153 # * 'hidden'
   156 # * 'subobject' (not displayed by default)
   154 # * 'subobject' (not displayed by default)
   157 
   155 
   158 class InitializableDict(dict): # XXX not a rtag. Turn into an appobject?
   156 class InitializableDict(dict):  # XXX not a rtag. Turn into an appobject?
   159     def __init__(self, *args, **kwargs):
   157     def __init__(self, *args, **kwargs):
   160         super(InitializableDict, self).__init__(*args, **kwargs)
   158         super(InitializableDict, self).__init__(*args, **kwargs)
   161         self.__defaults = dict(self)
   159         self.__defaults = dict(self)
   162 
   160 
   163     def init(self, schema, check=True):
   161     def init(self, schema, check=True):
   172             elif eschema.is_subobject(strict=True):
   170             elif eschema.is_subobject(strict=True):
   173                 self.setdefault(eschema, 'subobject')
   171                 self.setdefault(eschema, 'subobject')
   174             else:
   172             else:
   175                 self.setdefault(eschema, 'application')
   173                 self.setdefault(eschema, 'application')
   176 
   174 
       
   175 
   177 indexview_etype_section = InitializableDict(
   176 indexview_etype_section = InitializableDict(
   178     EmailAddress='subobject',
   177     EmailAddress='subobject',
   179     Bookmark='system',
   178     Bookmark='system',
   180     # entity types in the 'system' table by default (managers only)
   179     # entity types in the 'system' table by default (managers only)
   181     CWUser='system', CWGroup='system',
   180     CWUser='system', CWGroup='system',
   182     )
   181 )
   183 
   182 
   184 
   183 
   185 # autoform.AutomaticEntityForm configuration ##################################
   184 # autoform.AutomaticEntityForm configuration ##################################
   186 
   185 
   187 def _formsections_as_dict(formsections):
   186 def _formsections_as_dict(formsections):
   188     result = {}
   187     result = {}
   189     for formsection in formsections:
   188     for formsection in formsections:
   190         formtype, section = formsection.split('_', 1)
   189         formtype, section = formsection.split('_', 1)
   191         result[formtype] = section
   190         result[formtype] = section
   192     return result
   191     return result
       
   192 
   193 
   193 
   194 def _card_and_comp(sschema, rschema, oschema, role):
   194 def _card_and_comp(sschema, rschema, oschema, role):
   195     rdef = rschema.rdef(sschema, oschema)
   195     rdef = rschema.rdef(sschema, oschema)
   196     if role == 'subject':
   196     if role == 'subject':
   197         card = rdef.cardinality[0]
   197         card = rdef.cardinality[0]
   198         composed = not rschema.final and rdef.composite == 'object'
   198         composed = not rschema.final and rdef.composite == 'object'
   199     else:
   199     else:
   200         card = rdef.cardinality[1]
   200         card = rdef.cardinality[1]
   201         composed = not rschema.final and rdef.composite == 'subject'
   201         composed = not rschema.final and rdef.composite == 'subject'
   202     return card, composed
   202     return card, composed
       
   203 
   203 
   204 
   204 class AutoformSectionRelationTags(RelationTagsSet):
   205 class AutoformSectionRelationTags(RelationTagsSet):
   205     """autoform relations'section"""
   206     """autoform relations'section"""
   206     __regid__ = 'autoform_section'
   207     __regid__ = 'autoform_section'
   207 
   208 
   235             # (eg RichTextField, FileField...)
   236             # (eg RichTextField, FileField...)
   236             sectdict.setdefault('main', 'hidden')
   237             sectdict.setdefault('main', 'hidden')
   237             sectdict.setdefault('muledit', 'hidden')
   238             sectdict.setdefault('muledit', 'hidden')
   238             sectdict.setdefault('inlined', 'hidden')
   239             sectdict.setdefault('inlined', 'hidden')
   239         # ensure we have a tag for each form type
   240         # ensure we have a tag for each form type
   240         if not 'main' in sectdict:
   241         if 'main' not in sectdict:
   241             if sschema.is_metadata(rschema):
   242             if sschema.is_metadata(rschema):
   242                 sectdict['main'] = 'metadata'
   243                 sectdict['main'] = 'metadata'
   243             else:
   244             else:
   244                 card, composed = _card_and_comp(sschema, rschema, oschema, role)
   245                 card, composed = _card_and_comp(sschema, rschema, oschema, role)
   245                 if card in '1+':
   246                 if card in '1+':
   246                     sectdict['main'] = 'attributes'
   247                     sectdict['main'] = 'attributes'
   247                     if not 'muledit' in sectdict:
   248                     if 'muledit' not in sectdict:
   248                         sectdict['muledit'] = 'attributes'
   249                         sectdict['muledit'] = 'attributes'
   249                 elif rschema.final:
   250                 elif rschema.final:
   250                     sectdict['main'] = 'attributes'
   251                     sectdict['main'] = 'attributes'
   251                 else:
   252                 else:
   252                     sectdict['main'] = 'relations'
   253                     sectdict['main'] = 'relations'
   253         if not 'muledit' in sectdict:
   254         if 'muledit' not in sectdict:
   254             sectdict['muledit'] = 'hidden'
   255             sectdict['muledit'] = 'hidden'
   255             if sectdict['main'] == 'attributes':
   256             if sectdict['main'] == 'attributes':
   256                 card, composed = _card_and_comp(sschema, rschema, oschema, role)
   257                 card, composed = _card_and_comp(sschema, rschema, oschema, role)
   257                 if card in '1+' and not composed:
   258                 if card in '1+' and not composed:
   258                     sectdict['muledit'] = 'attributes'
   259                     sectdict['muledit'] = 'attributes'
   259         if not 'inlined' in sectdict:
   260         if 'inlined' not in sectdict:
   260             sectdict['inlined'] = sectdict['main']
   261             sectdict['inlined'] = sectdict['main']
   261         # recompute formsections and set it to avoid recomputing
   262         # recompute formsections and set it to avoid recomputing
   262         for formtype, section in sectdict.items():
   263         for formtype, section in sectdict.items():
   263             formsections.add('%s_%s' % (formtype, section))
   264             formsections.add('%s_%s' % (formtype, section))
   264 
   265 
   266         if isinstance(formtype, tuple):
   267         if isinstance(formtype, tuple):
   267             for ftype in formtype:
   268             for ftype in formtype:
   268                 self.tag_relation(key, ftype, section)
   269                 self.tag_relation(key, ftype, section)
   269             return
   270             return
   270         assert formtype in self._allowed_form_types, \
   271         assert formtype in self._allowed_form_types, \
   271                'formtype should be in (%s), not %s' % (
   272             'formtype should be in (%s), not %s' % (
   272             ','.join(self._allowed_form_types), formtype)
   273                 ','.join(self._allowed_form_types), formtype)
   273         assert section in self._allowed_values[formtype], \
   274         assert section in self._allowed_values[formtype], \
   274                'section for %s should be in (%s), not %s' % (
   275             'section for %s should be in (%s), not %s' % (
   275             formtype, ','.join(self._allowed_values[formtype]), section)
   276                 formtype, ','.join(self._allowed_values[formtype]), section)
   276         rtags = self._tagdefs.setdefault(_ensure_str_key(key),
   277         rtags = self._tagdefs.setdefault(_ensure_str_key(key),
   277                                          self.tag_container_cls())
   278                                          self.tag_container_cls())
   278         # remove previous section for this form type if any
   279         # remove previous section for this form type if any
   279         if rtags:
   280         if rtags:
   280             for tag in rtags.copy():
   281             for tag in rtags.copy():
   291             for tag in tags:
   292             for tag in tags:
   292                 assert '_' in tag, (tag, tags)
   293                 assert '_' in tag, (tag, tags)
   293                 section, value = tag.split('_', 1)
   294                 section, value = tag.split('_', 1)
   294                 rtags[section] = value
   295                 rtags[section] = value
   295         cls = self.tag_container_cls
   296         cls = self.tag_container_cls
   296         rtags = cls('_'.join([section,value])
   297         rtags = cls('_'.join([section, value])
   297                     for section,value in rtags.items())
   298                     for section, value in rtags.items())
   298         return rtags
   299         return rtags
   299 
   300 
   300     def get(self, *key):
   301     def get(self, *key):
   301         # overriden to avoid recomputing done in parent classes
   302         # overriden to avoid recomputing done in parent classes
   302         return self._tagdefs.get(key, ())
   303         return self._tagdefs.get(key, ())
   308 
   309 
   309         `strict`:
   310         `strict`:
   310           bool telling if having local role is enough (strict = False) or not
   311           bool telling if having local role is enough (strict = False) or not
   311         """
   312         """
   312         tag = '%s_%s' % (formtype, section)
   313         tag = '%s_%s' % (formtype, section)
   313         eschema  = entity.e_schema
   314         eschema = entity.e_schema
   314         cw = entity._cw
   315         cw = entity._cw
   315         permsoverrides = cw.vreg['uicfg'].select('autoform_permissions_overrides', cw, entity=entity)
   316         permsoverrides = cw.vreg['uicfg'].select('autoform_permissions_overrides', cw,
       
   317                                                  entity=entity)
   316         if entity.has_eid():
   318         if entity.has_eid():
   317             eid = entity.eid
   319             eid = entity.eid
   318         else:
   320         else:
   319             eid = None
   321             eid = None
   320             strict = False
   322             strict = False
   327         for rschema, targetschemas, role in eschema.relation_definitions(True):
   329         for rschema, targetschemas, role in eschema.relation_definitions(True):
   328             _targetschemas = []
   330             _targetschemas = []
   329             for tschema in targetschemas:
   331             for tschema in targetschemas:
   330                 # check section's tag first, potentially lower cost than
   332                 # check section's tag first, potentially lower cost than
   331                 # checking permission which may imply rql queries
   333                 # checking permission which may imply rql queries
   332                 if not tag in self.etype_get(eschema, rschema, role, tschema):
   334                 if tag not in self.etype_get(eschema, rschema, role, tschema):
   333                     continue
   335                     continue
   334                 rdef = rschema.role_rdef(eschema, tschema, role)
   336                 rdef = rschema.role_rdef(eschema, tschema, role)
   335                 if rschema.final:
   337                 if rschema.final:
   336                     if not rdef.has_perm(cw, permission, eid=eid,
   338                     if not rdef.has_perm(cw, permission, eid=eid,
   337                                          creating=eid is None):
   339                                          creating=eid is None):
   349             targetschemas = _targetschemas
   351             targetschemas = _targetschemas
   350             rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
   352             rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
   351             # XXX tag allowing to hijack the permission machinery when
   353             # XXX tag allowing to hijack the permission machinery when
   352             # permission is not verifiable until the entity is actually
   354             # permission is not verifiable until the entity is actually
   353             # created...
   355             # created...
   354             if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
   356             if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(
       
   357                     eschema, rschema, role):
   355                 yield (rschema, targetschemas, role)
   358                 yield (rschema, targetschemas, role)
   356                 continue
   359                 continue
   357             if not rschema.final and role == 'subject':
   360             if not rschema.final and role == 'subject':
   358                 # on relation with cardinality 1 or ?, we need delete perm as well
   361                 # on relation with cardinality 1 or ?, we need delete perm as well
   359                 # if the relation is already set
   362                 # if the relation is already set
   479           afs.set_muledit_editable('CWUser', ('firstname', 'surname', 'in_group'))
   482           afs.set_muledit_editable('CWUser', ('firstname', 'surname', 'in_group'))
   480         """
   483         """
   481         for attr in attrs:
   484         for attr in attrs:
   482             self.edit_as_attr(self, etype, attr, formtype='muledit')
   485             self.edit_as_attr(self, etype, attr, formtype='muledit')
   483 
   486 
       
   487 
   484 autoform_section = AutoformSectionRelationTags()
   488 autoform_section = AutoformSectionRelationTags()
   485 
   489 
   486 
   490 
   487 # relations'field class
   491 # relations'field class
   488 
   492 
   497 
   501 
   498         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   502         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   499 
   503 
   500         """
   504         """
   501         self._tag_etype_attr(etype, attr, '*', field)
   505         self._tag_etype_attr(etype, attr, '*', field)
       
   506 
   502 
   507 
   503 autoform_field = AutoformFieldTags()
   508 autoform_field = AutoformFieldTags()
   504 
   509 
   505 
   510 
   506 # relations'field explicit kwargs (given to field's __init__)
   511 # relations'field explicit kwargs (given to field's __init__)
   558 # set of tags of the form <action>_on_new on relations. <action> is a
   563 # set of tags of the form <action>_on_new on relations. <action> is a
   559 # schema action (add/update/delete/read), and when such a tag is found
   564 # schema action (add/update/delete/read), and when such a tag is found
   560 # permissions checking is by-passed and supposed to be ok
   565 # permissions checking is by-passed and supposed to be ok
   561 class AutoFormPermissionsOverrides(RelationTagsSet):
   566 class AutoFormPermissionsOverrides(RelationTagsSet):
   562     __regid__ = 'autoform_permissions_overrides'
   567     __regid__ = 'autoform_permissions_overrides'
       
   568 
   563 
   569 
   564 autoform_permissions_overrides = AutoFormPermissionsOverrides()
   570 autoform_permissions_overrides = AutoFormPermissionsOverrides()
   565 
   571 
   566 
   572 
   567 class ReleditTags(NoTargetRelationTagsDict):
   573 class ReleditTags(NoTargetRelationTagsDict):
   614                 edittarget = None
   620                 edittarget = None
   615             if not edittarget:
   621             if not edittarget:
   616                 edittarget = 'related' if composite else 'rtype'
   622                 edittarget = 'related' if composite else 'rtype'
   617                 self.tag_relation((sschema, rschema, oschema, role),
   623                 self.tag_relation((sschema, rschema, oschema, role),
   618                                   {'edit_target': edittarget})
   624                                   {'edit_target': edittarget})
   619         if not 'novalue_include_rtype' in values:
   625         if 'novalue_include_rtype' not in values:
   620             showlabel = primaryview_display_ctrl.get(
   626             showlabel = primaryview_display_ctrl.get(
   621                 sschema, rschema, oschema, role).get('showlabel', True)
   627                 sschema, rschema, oschema, role).get('showlabel', True)
   622             self.tag_relation((sschema, rschema, oschema, role),
   628             self.tag_relation((sschema, rschema, oschema, role),
   623                               {'novalue_include_rtype': not showlabel})
   629                               {'novalue_include_rtype': not showlabel})
       
   630 
   624 
   631 
   625 reledit_ctrl = ReleditTags()
   632 reledit_ctrl = ReleditTags()
   626 
   633 
   627 
   634 
   628 # boxes.EditBox configuration #################################################
   635 # boxes.EditBox configuration #################################################
   654     def append_to_addmenu(self, etype, attr, createdtype='*'):
   661     def append_to_addmenu(self, etype, attr, createdtype='*'):
   655         """adds `attr` in the actions box *addrelated* submenu of `etype`.
   662         """adds `attr` in the actions box *addrelated* submenu of `etype`.
   656 
   663 
   657         :param etype: the entity type as a string
   664         :param etype: the entity type as a string
   658         :param attr: the name of the attribute or relation to hide
   665         :param attr: the name of the attribute or relation to hide
   659         :param createdtype: the target type of the relation (optional, defaults to '*' (all possible types))
   666         :param createdtype: the target type of the relation
       
   667                             (optional, defaults to '*' (all possible types))
   660 
   668 
   661         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   669         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   662 
   670 
   663         """
   671         """
   664         self._tag_etype_attr(etype, attr, createdtype, True)
   672         self._tag_etype_attr(etype, attr, createdtype, True)
   666     def remove_from_addmenu(self, etype, attr, createdtype='*'):
   674     def remove_from_addmenu(self, etype, attr, createdtype='*'):
   667         """removes `attr` from the actions box *addrelated* submenu of `etype`.
   675         """removes `attr` from the actions box *addrelated* submenu of `etype`.
   668 
   676 
   669         :param etype: the entity type as a string
   677         :param etype: the entity type as a string
   670         :param attr: the name of the attribute or relation to hide
   678         :param attr: the name of the attribute or relation to hide
   671         :param createdtype: the target type of the relation (optional, defaults to '*' (all possible types))
   679         :param createdtype: the target type of the relation
       
   680                             (optional, defaults to '*' (all possible types))
   672 
   681 
   673         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   682         `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation)
   674         """
   683         """
   675         self._tag_etype_attr(etype, attr, createdtype, False)
   684         self._tag_etype_attr(etype, attr, createdtype, False)
   676 
   685 
       
   686 
   677 actionbox_appearsin_addmenu = ActionBoxUicfg()
   687 actionbox_appearsin_addmenu = ActionBoxUicfg()
   678 
       
   679 
   688 
   680 
   689 
   681 def registration_callback(vreg):
   690 def registration_callback(vreg):
   682     vreg.register_all(globals().values(), __name__)
   691     vreg.register_all(globals().values(), __name__)
   683     indexview_etype_section.init(vreg.schema)
   692     indexview_etype_section.init(vreg.schema)