def test_inherited_schema_still_has_tagged_value(self): """An inherited schema should still have the tagged value information inherited from its superclass. """ class IFoo(form.Schema): """Class with a searchable field """ searchable('baz') baz = schema.TextLine(title=u'baz') class IBar(IFoo): """Schema class which inherits a field from IFoo. """ self.assertEquals([], mergedTaggedValueList(IFoo, SEARCHABLE_KEY)) self.assertEquals([], mergedTaggedValueList(IBar, SEARCHABLE_KEY)) grok_component('IFoo', IFoo) grok_component('IBar', IBar) self.assertEquals([(Interface, 'baz', 'true')], mergedTaggedValueList(IFoo, SEARCHABLE_KEY)) self.assertEquals([(Interface, 'baz', 'true')], mergedTaggedValueList(IBar, SEARCHABLE_KEY))
def __call__(self, context, query=None): results = [] field_ids = [] exclude = ['im_handle', 'use_parent_address'] exclude_behaviors = ['plone.app.content.interfaces.INameFromTitle'] behaviors = set() portal_types = api.portal.get_tool('portal_types') contact_portal_types = ['person', 'organization', 'position', 'held_position'] # noqa for contact_portal_type in contact_portal_types: schema = getUtility( IDexterityFTI, name=contact_portal_type).lookupSchema() fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) for name, field in getFieldsInOrder(schema): if name not in exclude and name not in field_ids: visible_name = u'{0}: {1}'.format( contact_portal_type, field.title) field_ids.append(name) results.append((name, visible_name)) portal_type = getattr(portal_types, contact_portal_type) behaviors.update(set(portal_type.behaviors)) try: # remove duplicates photo results.remove(('photo', u'held_position: Photo')) except ValueError: pass for behavior in behaviors: if behavior not in exclude_behaviors: try: # not able to get fields from IDirectoryContactDetails # with nameToInterface(context, behavior) if behavior == 'cpskin.core.behaviors.directorycontact.IDirectoryContactDetails': # noqa from cpskin.core.behaviors.directorycontact import ( IDirectoryContactDetails) interface = IDirectoryContactDetails else: interface = nameToInterface(context, behavior) fieldsets = mergedTaggedValueList(interface, FIELDSETS_KEY) for name, field in getFieldsInOrder(interface): if name not in exclude and name not in field_ids: if not fieldsets: visible_name = field.title else: fieldset = [ fieldset for fieldset in fieldsets if name in fieldset.fields # noqa ][0] field_ids.append(name) visible_name = u'{0}: {1}'.format( fieldset.label, field.title) results.append((name, visible_name)) except: pass items = [ SimpleTerm(i, i, j) for i, j in results if j ] return SimpleVocabulary(items)
def __call__(self, context, query=None): results = [] field_ids = [] exclude = ['im_handle', 'use_parent_address'] exclude_behaviors = ['plone.app.content.interfaces.INameFromTitle'] behaviors = set() portal_types = api.portal.get_tool('portal_types') contact_portal_types = [ 'person', 'organization', 'position', 'held_position' ] # noqa for contact_portal_type in contact_portal_types: schema = getUtility(IDexterityFTI, name=contact_portal_type).lookupSchema() fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) for name, field in getFieldsInOrder(schema): if name not in exclude and name not in field_ids: visible_name = u'{0}: {1}'.format(contact_portal_type, field.title) field_ids.append(name) results.append((name, visible_name)) portal_type = getattr(portal_types, contact_portal_type) behaviors.update(set(portal_type.behaviors)) try: # remove duplicates photo results.remove(('photo', u'held_position: Photo')) except ValueError: pass for behavior in behaviors: if behavior not in exclude_behaviors: try: # not able to get fields from IDirectoryContactDetails # with nameToInterface(context, behavior) if behavior == 'cpskin.core.behaviors.directorycontact.IDirectoryContactDetails': # noqa from cpskin.core.behaviors.directorycontact import ( IDirectoryContactDetails) interface = IDirectoryContactDetails else: interface = nameToInterface(context, behavior) fieldsets = mergedTaggedValueList(interface, FIELDSETS_KEY) for name, field in getFieldsInOrder(interface): if name not in exclude and name not in field_ids: if not fieldsets: visible_name = field.title else: fieldset = [ fieldset for fieldset in fieldsets if name in fieldset.fields # noqa ][0] field_ids.append(name) visible_name = u'{0}: {1}'.format( fieldset.label, field.title) results.append((name, visible_name)) except: pass items = [SimpleTerm(i, i, j) for i, j in results if j] return SimpleVocabulary(items)
def update(self): schemas = [self.form.schema] if IDexterityContent.providedBy(self.context): fti = getUtility(IDexterityFTI, name=self.context.portal_type) for name in fti.behaviors: behavior = queryUtility(IBehavior, name=name) if behavior and behavior.interface.extends(model.Schema): schemas.append(behavior.interface) directives = [] for schema in schemas: directives += mergedTaggedValueList(schema, DEPENDENCY_KEY) dependencies = {} for directive in directives: dependencies.setdefault(directive.name, []).append(directive) todo = collections.deque([self.form]) while todo: group = todo.pop() if hasattr(group, "groups"): todo.extendleft(group.groups) for (name, field) in group.fields.items(): depends = dependencies.get(name, None) if depends is None: continue field.field._dependencies = depends
def test_schema_directives_store_tagged_values(self): """Test, if the schema directive values are stored as tagged values. """ class IDummy(form.Schema): """Dummy schema class. """ searchable('foo') foo = schema.TextLine(title=u'Foo') self.assertEquals([], mergedTaggedValueList(IDummy, SEARCHABLE_KEY)) grok_component('IDummy', IDummy) self.assertEquals([(Interface, 'foo', 'true')], mergedTaggedValueList(IDummy, SEARCHABLE_KEY))
def processFieldMoves(form, schema, prefix=''): """Process all field moves stored under ORDER_KEY in the schema tagged value. This should be run after all schemata have been processed with processFields(). """ # (name, 'before'/'after', other name) order = mergedTaggedValueList(schema, ORDER_KEY) for field_name, direction, relative_to in order: # Handle shortcut: leading . means 'in this schema'. May be useful # if you want to move a field relative to one in the current # schema or (more likely) a base schema of the current schema, without # having to repeat the full prefix of this schema. if relative_to.startswith('.'): relative_to = relative_to[1:] if prefix: relative_to = expandPrefix(prefix) + relative_to try: if direction == 'before': move(form, field_name, before=relative_to, prefix=prefix) elif direction == 'after': move(form, field_name, after=relative_to, prefix=prefix) except KeyError: # The relative_to field doesn't exist pass
def update(self): schemas = [self.form.schema] if IDexterityContent.providedBy(self.context): fti = component.getUtility( IDexterityFTI, name=self.context.portal_type) for name in fti.behaviors: behavior = component.queryUtility(IBehavior, name=name) if behavior and behavior.interface.extends(Schema): schemas.append(behavior.interface) directives = [] for schema in schemas: directives += mergedTaggedValueList(schema, DEPENDENCY_KEY) dependencies = {} for directive in directives: dependencies.setdefault(directive.name, []).append(directive) todo=collections.deque([self.form]) while todo: group=todo.pop() if hasattr(group, "groups"): todo.extendleft(group.groups) for (name, field) in group.fields.items(): depends=dependencies.get(name, None) if depends is None: continue field.field._dependencies=depends
def test_inherited_schema_still_has_tagged_value(self): """An inherited schema should still have the tagged value information inherited from its superclass. """ class IFoo(model.Schema): """Class with a searchable field """ searchable('baz') baz = schema.TextLine(title=u'baz') class IBar(IFoo): """Schema class which inherits a field from IFoo. """ self.assertEqual([(Interface, 'baz', 'true')], mergedTaggedValueList(IFoo, SEARCHABLE_KEY)) self.assertEqual([(Interface, 'baz', 'true')], mergedTaggedValueList(IBar, SEARCHABLE_KEY))
def get_soundfile_field(context): assignable = IBehaviorAssignable(context, None) if assignable is None: return for behavior_registration in assignable.enumerateBehaviors(): schema = behavior_registration.interface for tgv in mergedTaggedValueList(schema, SOUNDFILE_KEY): if tgv.soundfile: return tgv.soundfile
def get_searchable_fields(iface): fieldnames = [] for flag_iface, fieldname, value in mergedTaggedValueList( iface, SEARCHABLE_KEY): if flag_iface == iface and value: fieldnames.append(fieldname) return fieldnames
def get_soundcloud_accessors(context): accessors = [] assignable = IBehaviorAssignable(context, None) if assignable is None: return accessors for behavior_registration in assignable.enumerateBehaviors(): schema = behavior_registration.interface for tgv in mergedTaggedValueList(schema, SOUNDCLOUD_KEY): for accessor in tgv.accessors: accessors.append((schema, accessor,)) return accessors
def get_multilingual_directives(schemas): params = {} for schema in schemas: if not schema: continue tagged_values = mergedTaggedValueList(schema, MULTILINGUAL_KEY) result = {field_name: value for _, field_name, value in tagged_values} for field_name, value in result.items(): params[field_name] = {} params[field_name]["language_independent"] = value return params
def test_inherited_schema_still_has_tagged_value(self): """An inherited schema should still have the tagged value information inherited from its superclass. """ class IFoo(model.Schema): """Class with a searchable field """ languageindependent('baz') baz = schema.TextLine(title=u'baz') class IBar(IFoo): """Schema class which inherits a field from IFoo. """ self.assertEqual([(Interface, 'baz', 'true')], mergedTaggedValueList(IFoo, languageindependent.key)) self.assertTrue(ILanguageIndependentField.providedBy(IFoo['baz'])) self.assertEqual([(Interface, 'baz', 'true')], mergedTaggedValueList(IBar, languageindependent.key)) self.assertTrue(ILanguageIndependentField.providedBy(IBar['baz']))
def test_schema_directives_store_tagged_values(self): """Test, if the schema directive values are stored as tagged values. """ class IDummy(model.Schema): """Dummy schema class. """ languageindependent('foo') foo = schema.TextLine(title=u'Foo') self.assertEqual([(Interface, 'foo', 'true')], mergedTaggedValueList(IDummy, languageindependent.key)) self.assertTrue(ILanguageIndependentField.providedBy(IDummy['foo']))
def getLanguageIndependent(context): portal_type = context.portal_type fti = getUtility(IDexterityFTI, name=portal_type) schemata = getAdditionalSchemata(context=context, portal_type=portal_type) schemas = tuple(schemata) + (fti.lookupSchema(), ) fields = set() for schema in schemas: entries = mergedTaggedValueList(schema, LANGUAGE_INDEPENDENT_KEY) for interface, name, value in entries: field = schema[name] fields.add(field) return fields
def update(self): fieldsets=mergedTaggedValueList(self.form.schema, FIELDSETS_KEY) if not isinstance(self.form.groups, list): self.form.groups=list(self.form.groups) groups=dict([(group.__name__, (index, group)) for (index,group) in enumerate(self.form.groups)]) for fieldset in fieldsets: layout=getattr(fieldset, "layout", None) if layout is None: continue if fieldset.__name__ not in groups: continue (index, group)=groups[fieldset.__name__] if not IGroup.providedBy(group): group=self.form.groups[index]=group(self.context, self.request, self.form) group.layout=layout
def mergedTaggedValuesForIRO(schema, name, iro): # BBB: this should be in plone.autoform.utils, and # mergedTaggedValuesForForm should use this # filter out settings irrelevant to this form threeples = [t for t in mergedTaggedValueList(schema, name) if t[0] in iro] def by_iro(threeple): interface = threeple[0] return iro.index(interface) threeples.sort(key=by_iro) d = {} # Now iterate through in the reverse order -- the values assigned last win. for _, fieldName, value in reversed(threeples): d[fieldName] = value return d
def get_searchable_contexts_and_fields(obj): """Returns a generator of tuples, which contains a storage object for each schema (adapted `obj`) and a list of fields on this schema which are searchable. """ for schemata in iterSchemata(obj): fields = [] tagged_values = mergedTaggedValueList(schemata, SEARCHABLE_KEY) if not tagged_values: continue for i, name, v in tagged_values: fields.append(schema.getFields(schemata).get(name)) if fields: storage = schemata(obj) yield storage, fields
def update(self): fieldsets = mergedTaggedValueList(self.form.schema, FIELDSETS_KEY) if not isinstance(self.form.groups, list): self.form.groups = list(self.form.groups) groups = dict([(group.__name__, (index, group)) for (index, group) in enumerate(self.form.groups)]) for fieldset in fieldsets: layout = getattr(fieldset, "layout", None) if layout is None: continue if fieldset.__name__ not in groups: continue (index, group) = groups[fieldset.__name__] if not IGroup.providedBy(group): group = self.form.groups[index] = group( self.context, self.request, self.form) group.layout = layout
def test_mergedTaggedValueList(self): class IBase1(Interface): pass class IBase2(Interface): pass class IBase3(Interface): pass class ISchema(IBase1, IBase2, IBase3): pass IBase1.setTaggedValue(u"foo", [1, 2]) # more specific than IBase2 and IBase3 IBase3.setTaggedValue(u"foo", [3, 4]) # least specific of the bases ISchema.setTaggedValue(u"foo", [4, 5]) # most specific self.assertEqual([3, 4, 1, 2, 4, 5], utils.mergedTaggedValueList(ISchema, u"foo"))
def test_mergedTaggedValueList(self): class IBase1(Interface): pass class IBase2(Interface): pass class IBase3(Interface): pass class ISchema(IBase1, IBase2, IBase3): pass IBase1.setTaggedValue(u"foo", [1, 2]) # more specific than IBase2 and IBase3 IBase3.setTaggedValue(u"foo", [3, 4]) # least specific of the bases ISchema.setTaggedValue(u"foo", [4, 5]) # most specific self.assertEquals([3, 4, 1, 2, 4, 5], utils.mergedTaggedValueList(ISchema, u"foo"))
def mergedTaggedValuesForIRO(schema, name, iro): """Finds a list of (interface, fieldName, value) 3-ples from the tagged value named 'name', on 'schema' and all of its bases. Returns a dict of fieldName => value, where the value is from the tuple for that fieldName whose interface is highest in the interface resolution order, among the interfaces actually provided by 'form'. """ # filter out settings irrelevant to this form threeples = [t for t in mergedTaggedValueList(schema, name) if t[0] in iro] # Sort by interface resolution order of the form interface, # then by IRO of the interface the value came from # (that is the input order, so we can rely on Python's stable sort) def by_iro(threeple): interface = threeple[0] return iro.index(interface) threeples.sort(key=by_iro) d = {} # Now iterate through in the reverse order -- the values assigned last win. for _, fieldName, value in reversed(threeples): d[fieldName] = value return d
def get_searchable_contexts_and_fields(obj): """Returns a generator of tuples, which contains a storage object for each schema (adapted `obj`) and a list of fields on this schema which are searchable. """ for schemata in iterSchemata(obj): fields = [] tagged_values = mergedTaggedValueList(schemata, SEARCHABLE_KEY) if not tagged_values: continue for _i, name, _v in tagged_values: field = schema.getFields(schemata).get(name) if not field: dottedname = '.'.join((schemata.__module__, schemata.__name__)) logging.error('%s has no field "%s"', dottedname, name) else: fields.append(field) if fields: storage = schemata(obj) yield storage, fields
def test_marking_field_as_searchable(self): self.assertEquals([], mergedTaggedValueList(IExample, SEARCHABLE_KEY)) searchable(IExample, u'foo') self.assertEquals([(IExample, 'foo', 'true')], mergedTaggedValueList(IExample, SEARCHABLE_KEY))
def processFields(form, schema, prefix='', defaultGroup=None, permissionChecks=True): """Add the fields from the schema to the form, taking into account the hints in the various tagged values as well as fieldsets. If prefix is given, the fields will be prefixed with this prefix. If defaultGroup is given (as a Fieldset instance), any field not explicitly placed into a particular fieldset, will be added to the given group, which must exist already. If permissionChecks is false, permission checks are ignored. """ # Get data from tagged values, flattening data from super-interfaces # Note: The names always refer to a field in the schema, and never # contain a prefix. # { name => True } omitted = mergedTaggedValuesForForm(schema, OMITTED_KEY, form) # { name => e.g. 'hidden' } modes = mergedTaggedValuesForForm(schema, MODES_KEY, form) # { name => widget/dotted name } widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) # list of IFieldset instances fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) # Get either read or write permissions depending on what type of # form this is readPermissions = {} # field name -> permission name writePermissions = {} # field name -> permission name permissionCache = {} # permission name -> allowed/disallowed if permissionChecks: # name => permission name readPermissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY ) # name => permission name writePermissions = mergedTaggedValueDict( schema, WRITE_PERMISSIONS_KEY ) securityManager = getSecurityManager() # Find the fields we should not worry about groups = {} doNotProcess = list(form.fields.keys()) for fieldName, status in omitted.items(): if status and status != 'false': doNotProcess.append(_fn(prefix, fieldName)) for group in form.groups: doNotProcess.extend(list(group.fields.keys())) groupName = getattr(group, '__name__', group.label) groups[groupName] = group # Find all allowed fields so that we have something to select from omitReadOnly = form.mode != DISPLAY_MODE allFields = field.Fields( schema, prefix=prefix, omitReadOnly=omitReadOnly ).omit(*doNotProcess) # Check permissions if permissionChecks: disallowedFields = [] for fieldName, fieldInstance in allFields.items(): fieldName = fieldInstance.__name__ fieldMode = fieldInstance.mode or form.mode permissionName = None if fieldMode == DISPLAY_MODE: permissionName = readPermissions.get(_bn(fieldInstance), None) elif fieldMode == INPUT_MODE: permissionName = writePermissions.get(_bn(fieldInstance), None) if permissionName is not None: if permissionName not in permissionCache: permission = queryUtility(IPermission, name=permissionName) if permission is None: permissionCache[permissionName] = True else: permissionCache[permissionName] = bool( securityManager.checkPermission( permission.title, form.context ) ) if not permissionCache.get(permissionName, True): disallowedFields.append(fieldName) allFields = allFields.omit(*disallowedFields) # Keep track of which fields are in a fieldset, and, by elimination, # which ones are not fieldsetFields = [] for fieldset in fieldsets: for fieldName in fieldset.fields: fieldsetFields.append(_fn(prefix, fieldName)) # Set up the default fields, widget factories and widget modes newFields = allFields.omit(*fieldsetFields) _processWidgets(form, widgets, modes, newFields) if not defaultGroup: form.fields += newFields else: groups[defaultGroup].fields += newFields # Set up fields for fieldsets for fieldset in fieldsets: newFields = allFields.select(*[_fn(prefix, fieldName) for fieldName in fieldset.fields if _fn(prefix, fieldName) in allFields]) if getattr(form, 'showEmptyGroups', False) or (len(newFields) > 0): _processWidgets(form, widgets, modes, newFields) if fieldset.__name__ not in groups: group = GroupFactory(fieldset.__name__, label=fieldset.label, description=fieldset.description, fields=newFields) form.groups.append(group) groups[group.__name__] = group else: groups[fieldset.__name__].fields += newFields
def updateFieldsFromSchemata(self): # If the form is called from the ++widget++ traversal namespace, # we won't have a user yet. In this case, we can't perform permission # checks. have_user = bool(self.request.get('AUTHENTICATED_USER', False)) # Turn fields into an instance variable, since we will be modifying it self.fields = field.Fields(self.fields) # Copy groups to an instance variable and ensure that we have # the more mutable factories, rather than 'Group' subclasses groups = [] for group in self.groups: group_name = getattr(group, '__name__', group.label) fieldset_group = GroupFactory( group_name, field.Fields(group.fields), group.label, getattr(group, 'description', None) ) groups.append(fieldset_group) # Copy to instance variable only after we have potentially read from # the class self.groups = groups prefixes = {} if self.schema is not None: processFields(self, self.schema, permissionChecks=have_user) # Set up all widgets, modes, omitted fields and fieldsets for schema in self.additionalSchemata: # Find the prefix to use for this form and cache for next round prefix = self.getPrefix(schema) if prefix and prefix in prefixes: prefix = schema.__identifier__ prefixes[schema] = prefix # By default, there's no default group, i.e. fields go # straight into the default fieldset defaultGroup = None # Create groups from schemata if requested and set default # group if self.autoGroups: # use interface name, or prefix for anonymous schema group_name = schema.__name__ or prefix or None # Look for group - note that previous processFields # may have changed the groups list, so we can't easily # store this in a dict. found = False for g in self.groups: if group_name == getattr(g, '__name__', g.label): found = True break if not found: fieldset_group = GroupFactory( group_name, field.Fields(), label=group_name, description=schema.__doc__, order=DEFAULT_ORDER, ) self.groups.append(fieldset_group) defaultGroup = group_name processFields( self, schema, prefix=prefix, defaultGroup=defaultGroup, permissionChecks=have_user ) # Then process relative field movements. The base schema is processed # last to allow it to override any movements made in additional # schemata. rules = None for schema in self.additionalSchemata: order = mergedTaggedValueList(schema, ORDER_KEY) rules = self._calculate_field_moves( order, prefix=prefixes[schema], rules=rules, ) if self.schema is not None: order = mergedTaggedValueList(self.schema, ORDER_KEY) rules = self._calculate_field_moves(order, rules=rules) self._cleanup_rules(rules) self._process_field_moves(rules) self._process_group_order()
def _process_fieldsets(form, schema, groups, all_fields, prefix, default_group): """ Keep track of which fields are in a fieldset, and, by elimination, which ones are not """ # { name => e.g. 'hidden' } modes = mergedTaggedValuesForForm(schema, MODES_KEY, form) # { name => widget/dotted name } widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) # list of IFieldset instances fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) # process primary schema fieldsets fieldset_fields = [] for fieldset in fieldsets: for field_name in fieldset.fields: fieldset_fields.append(_process_prefixed_name(prefix, field_name)) # Set up the default fields, widget factories and widget modes new_fields = all_fields.omit(*fieldset_fields) _process_widgets(form, widgets, modes, new_fields) if not default_group: form.fields += new_fields else: groups[default_group].fields += new_fields # Set up fields for fieldsets for fieldset in fieldsets: new_fields = all_fields.select(*[ _process_prefixed_name(prefix, name) for name in fieldset.fields if _process_prefixed_name(prefix, name) in all_fields ]) if fieldset.__name__ in groups: # Process also, if no fields are defined to allow fieldset-only # configurations via plone.supermodel fieldset directive. group = groups[fieldset.__name__] group.fields += new_fields if (fieldset.label and group.label != fieldset.label and group.__name__ != fieldset.label # defaults to name! ): group.label = fieldset.label if (fieldset.description and group.description != fieldset.description): group.description = fieldset.description if (fieldset.order and fieldset.order != DEFAULT_ORDER and fieldset.order != group.order): group.order = fieldset.order if len(new_fields) > 0 or getattr(form, 'showEmptyGroups', False): _process_widgets(form, widgets, modes, new_fields) if fieldset.__name__ not in groups: group = GroupFactory(fieldset.__name__, label=fieldset.label, description=fieldset.description, order=fieldset.order, fields=new_fields) form.groups.append(group) groups[group.__name__] = group
def processFields(form, schema, prefix='', defaultGroup=None, permissionChecks=True): """Add the fields from the schema to the form, taking into account the hints in the various tagged values as well as fieldsets. If prefix is given, the fields will be prefixed with this prefix. If defaultGroup is given (as a Fieldset instance), any field not explicitly placed into a particular fieldset, will be added to the given group, which must exist already. If permissionChecks is false, permission checks are ignored. """ # Get data from tagged values, flattening data from super-interfaces # Note: The names always refer to a field in the schema, and never contain a prefix. omitted = mergedTaggedValuesForForm(schema, OMITTED_KEY, form) # { name => True } modes = mergedTaggedValuesForForm(schema, MODES_KEY, form) # { name => e.g. 'hidden' } widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) # { name => widget/dotted name } fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) # list of IFieldset instances # Get either read or write permissions depending on what type of form this is readPermissions = {} # field name -> permission name writePermissions = {} # field name -> permission name permissionCache = {} # permission name -> allowed/disallowed if permissionChecks: readPermissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) # name => permission name writePermissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) # name => permission name securityManager = getSecurityManager() # Find the fields we should not worry about groups = {} doNotProcess = list(form.fields.keys()) for fieldName, status in omitted.items(): if status and status != 'false': doNotProcess.append(_fn(prefix, fieldName)) for group in form.groups: doNotProcess.extend(list(group.fields.keys())) groupName = getattr(group, '__name__', group.label) groups[groupName] = group # Find all allowed fields so that we have something to select from omitReadOnly = form.mode != DISPLAY_MODE allFields = field.Fields(schema, prefix=prefix, omitReadOnly=omitReadOnly).omit(*doNotProcess) # Check permissions if permissionChecks: disallowedFields = [] for fieldName, fieldInstance in allFields.items(): fieldName = fieldInstance.__name__ fieldMode = fieldInstance.mode or form.mode permissionName = None if fieldMode == DISPLAY_MODE: permissionName = readPermissions.get(_bn(fieldInstance), None) elif fieldMode == INPUT_MODE: permissionName = writePermissions.get(_bn(fieldInstance), None) if permissionName is not None: if permissionName not in permissionCache: permission = queryUtility(IPermission, name=permissionName) if permission is None: permissionCache[permissionName] = True else: permissionCache[permissionName] = bool(securityManager.checkPermission(permission.title, form.context)) if not permissionCache.get(permissionName, True): disallowedFields.append(fieldName) allFields = allFields.omit(*disallowedFields) # Keep track of which fields are in a fieldset, and, by elimination, # which ones are not fieldsetFields = [] for fieldset in fieldsets: for fieldName in fieldset.fields: fieldsetFields.append(_fn(prefix, fieldName)) # Set up the default fields, widget factories and widget modes newFields = allFields.omit(*fieldsetFields) _processWidgets(form, widgets, modes, newFields) if not defaultGroup: form.fields += newFields else: groups[defaultGroup].fields += newFields # Set up fields for fieldsets for fieldset in fieldsets: newFields = allFields.select(*[_fn(prefix, fieldName) for fieldName in fieldset.fields if _fn(prefix, fieldName) in allFields]) if len(newFields) > 0: _processWidgets(form, widgets, modes, newFields) if fieldset.__name__ not in groups: form.groups.append(GroupFactory(fieldset.__name__, label=fieldset.label, description=fieldset.description, fields=newFields)) else: groups[fieldset.__name__].fields += newFields
def _process_fieldsets( form, schema, groups, all_fields, prefix, default_group ): """ Keep track of which fields are in a fieldset, and, by elimination, which ones are not """ # { name => e.g. 'hidden' } modes = mergedTaggedValuesForForm(schema, MODES_KEY, form) # { name => widget/dotted name } widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) # list of IFieldset instances fieldsets = mergedTaggedValueList(schema, FIELDSETS_KEY) # process primary schema fieldsets fieldset_fields = [] for fieldset in fieldsets: for field_name in fieldset.fields: fieldset_fields.append(_process_prefixed_name(prefix, field_name)) # Set up the default fields, widget factories and widget modes new_fields = all_fields.omit(*fieldset_fields) _process_widgets(form, widgets, modes, new_fields) if not default_group: form.fields += new_fields else: groups[default_group].fields += new_fields # Set up fields for fieldsets for fieldset in fieldsets: new_fields = all_fields.select( *[_process_prefixed_name(prefix, name) for name in fieldset.fields if _process_prefixed_name(prefix, name) in all_fields] ) if fieldset.__name__ in groups: # Process also, if no fields are defined to allow fieldset-only # configurations via plone.supermodel fieldset directive. group = groups[fieldset.__name__] group.fields += new_fields if ( fieldset.label and group.label != fieldset.label and group.__name__ != fieldset.label # defaults to name! ): group.label = fieldset.label if ( fieldset.description and group.description != fieldset.description ): group.description = fieldset.description if ( fieldset.order and fieldset.order != DEFAULT_ORDER and fieldset.order != group.order ): group.order = fieldset.order if len(new_fields) > 0 or getattr(form, 'showEmptyGroups', False): _process_widgets(form, widgets, modes, new_fields) if fieldset.__name__ not in groups: group = GroupFactory(fieldset.__name__, label=fieldset.label, description=fieldset.description, order=fieldset.order, fields=new_fields) form.groups.append(group) groups[group.__name__] = group
def updateFieldsFromSchemata(self): # If the form is called from the ++widget++ traversal namespace, # we won't have a user yet. In this case, we can't perform permission # checks. have_user = bool(self.request.get('AUTHENTICATED_USER', False)) # Turn fields into an instance variable, since we will be modifying it self.fields = field.Fields(self.fields) # Copy groups to an instance variable and ensure that we have # the more mutable factories, rather than 'Group' subclasses groups = [] for group in self.groups: group_name = getattr(group, '__name__', group.label) fieldset_group = GroupFactory(group_name, field.Fields(group.fields), group.label, getattr(group, 'description', None)) groups.append(fieldset_group) # Copy to instance variable only after we have potentially read from # the class self.groups = groups prefixes = {} if self.schema is not None: processFields(self, self.schema, permissionChecks=have_user) # Set up all widgets, modes, omitted fields and fieldsets for schema in self.additionalSchemata: # Find the prefix to use for this form and cache for next round prefix = self.getPrefix(schema) if prefix and prefix in prefixes: prefix = schema.__identifier__ prefixes[schema] = prefix # By default, there's no default group, i.e. fields go # straight into the default fieldset defaultGroup = None # Create groups from schemata if requested and set default # group if self.autoGroups: # use interface name, or prefix for anonymous schema group_name = schema.__name__ or prefix or None # Look for group - note that previous processFields # may have changed the groups list, so we can't easily # store this in a dict. found = False for g in self.groups: if group_name == getattr(g, '__name__', g.label): found = True break if not found: fieldset_group = GroupFactory( group_name, field.Fields(), label=group_name, description=schema.__doc__, order=DEFAULT_ORDER, ) self.groups.append(fieldset_group) defaultGroup = group_name processFields(self, schema, prefix=prefix, defaultGroup=defaultGroup, permissionChecks=have_user) # Then process relative field movements. The base schema is processed # last to allow it to override any movements made in additional # schemata. rules = {'__all__': {}} for schema in self.additionalSchemata: order = mergedTaggedValueList(schema, ORDER_KEY) rules = self._calculate_field_moves( order, prefix=prefixes[schema], rules=rules, ) if self.schema is not None: order = mergedTaggedValueList(self.schema, ORDER_KEY) rules = self._calculate_field_moves(order, rules=rules) self._cleanup_rules(rules) self._process_field_moves(rules) self._process_group_order()