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, |
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, ()) |
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 |
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) |