def _process_permissions(schema, form, all_fields): # Get either read or write permissions depending on what type of # form this is permission_cache = {} # permission name -> allowed/disallowed # name => permission name read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) # name => permission name write_permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) security_manager = getSecurityManager() disallowed_fields = [] for field_name, field_instance in all_fields.items(): field_mode = field_instance.mode or form.mode permission_name = None base_name = _bn(field_instance) if field_mode == DISPLAY_MODE: permission_name = read_permissions.get(base_name, None) elif field_mode == INPUT_MODE: permission_name = write_permissions.get(base_name, None) if permission_name is None: continue if permission_name not in permission_cache: permission = queryUtility(IPermission, name=permission_name) if permission is None: permission_cache[permission_name] = True else: permission_cache[permission_name] = bool( security_manager.checkPermission(permission.title, form.context)) if not permission_cache.get(permission_name, True): disallowed_fields.append(field_name) return all_fields.omit(*disallowed_fields)
def _validate_vocabulary_name(self, schema, field, vocabulary_name): if not vocabulary_name: return True if ( vocabulary_name != getattr(field, 'vocabulary', None) and vocabulary_name != getattr(field, 'vocabularyName', None) ): # Determine the widget to check for vocabulary there widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) widget = widgets.get(field.getName()) if widget: if isinstance(widget, six.string_types): widget = resolveDottedName(widget) if widget: widget = widget(field, self._request) else: # default widget widget = queryMultiAdapter( (field, self._request), IFieldWidget ) if widget: widget.update() if getattr(widget, 'vocabulary', None) != vocabulary_name: return False return True
def validate(self, field_name, vocabulary_name=None): context = self.context checker = getSecurityManager().checkPermission schemata = self._get_schemata() for schema in schemata: if field_name not in schema: continue # If a vocabulary name was specified and it does not # match the vocabulary name for the field or widget, # fail. field = schema[field_name] if not self._validate_vocabulary_name(schema, field, vocabulary_name): return False # Create mapping of all schema permissions permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) permission_name = permissions.get(field_name, None) if permission_name is not None: # if we have explicit permissions, check them permission = queryUtility(IPermission, name=permission_name) if permission: return checker(permission.title, context) # If the field is in the schema, but no permission is # specified, fall back to the default edit permission return checker(self.DEFAULT_PERMISSION, context) else: raise AttributeError('No such field: {0}'.format(field_name))
def __call__(self): result = { '@context': 'http://www.w3.org/ns/hydra/context.jsonld', '@id': self.context.absolute_url(), '@type': self.context.portal_type, 'parent': { '@id': aq_parent(aq_inner(self.context)).absolute_url(), 'title': aq_parent(aq_inner(self.context)).title, 'description': aq_parent(aq_inner(self.context)).description }, 'created': json_compatible(self.context.created()), 'modified': json_compatible(self.context.modified()), 'UID': self.context.UID(), } for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue serializer = queryMultiAdapter( (field, self.context, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value return result
def serializeToJSON(context, request): result = {} permission_cache = {} for schema in iterFlowSchemata(context): if not schema.providedBy(context): continue read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if IRichTextLabel.providedBy(field): continue if not check_permission( read_permissions.get(name), context, permission_cache, ): continue serializer = queryMultiAdapter((field, context, request), IFieldSerializer) value = serializer() # Clean FlowSubmissionData values if value == removable: value = None elif isinstance(value, list): value = [v for v in value if v != removable] elif isinstance(value, tuple): value = tuple([v for v in value if v != removable]) elif isinstance(value, set): value = set([v for v in value if v != removable]) result[json_compatible(name)] = value return result
def __call__(self): result = { '@context': 'http://www.w3.org/ns/hydra/context.jsonld', '@id': self.context.absolute_url(), '@type': self.context.portal_type, 'parent': { '@id': aq_parent(aq_inner(self.context)).absolute_url(), 'title': aq_parent(aq_inner(self.context)).title, 'description': aq_parent(aq_inner(self.context)).description }, 'created': json_compatible(self.context.created()), 'modified': json_compatible(self.context.modified()), 'UID': self.context.UID(), } for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue serializer = queryMultiAdapter( (field, self.context, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value return result
def _include_fields(self, obj): """ """ result = {} # Compute fields if include_all or metadata_fields if self.include_all or self.metadata_fields: for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): # only keep relevant fields if (self.include_all and not self.metadata_fields ) or name in self.metadata_fields: if not self.check_permission( read_permissions.get(name), obj): continue # serialize the field serializer = queryMultiAdapter( (field, obj, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value return result
def __call__(self): parent = aq_parent(aq_inner(self.context)) parent_summary = getMultiAdapter( (parent, self.request), ISerializeToJsonSummary)() result = { # '@context': 'http://www.w3.org/ns/hydra/context.jsonld', '@id': self.context.absolute_url(), 'id': self.context.id, '@type': self.context.portal_type, 'parent': parent_summary, 'created': json_compatible(self.context.created()), 'modified': json_compatible(self.context.modified()), 'review_state': self._get_workflow_state(), 'UID': self.context.UID(), } for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue serializer = queryMultiAdapter( (field, self.context, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value return result
def test_mergedTaggedValueDict(self): class IBase1(Interface): pass class IBase2(Interface): pass class IBase3(Interface): pass class ISchema(IBase1, IBase2, IBase3): pass IBase1.setTaggedValue(u"foo", { 1: 1, 2: 1 }) # more specific than IBase2 and IBase3 IBase3.setTaggedValue(u"foo", { 3: 3, 2: 3, 4: 3 }) # least specific of the bases ISchema.setTaggedValue(u"foo", {4: 4, 5: 4}) # most specific self.assertEquals({ 1: 1, 2: 1, 3: 3, 4: 4, 5: 4 }, utils.mergedTaggedValueDict(ISchema, u"foo"))
def __call__(self, version=None, include_items=True): version = "current" if version is None else version obj = self.getVersion(version) parent = aq_parent(aq_inner(obj)) parent_summary = getMultiAdapter( (parent, self.request), ISerializeToJsonSummary )() result = { # '@context': 'http://www.w3.org/ns/hydra/context.jsonld', "@id": obj.absolute_url(), "id": obj.id, "@type": obj.portal_type, "parent": parent_summary, "created": json_compatible(obj.created()), "modified": json_compatible(obj.modified()), "review_state": self._get_workflow_state(obj), "UID": obj.UID(), "version": version, "layout": self.context.getLayout(), "is_folderish": False, } # Insert next/prev information nextprevious = NextPrevious(obj) result.update( {"previous_item": nextprevious.previous, "next_item": nextprevious.next} ) # Insert expandable elements result.update(expandable_elements(self.context, self.request)) # Insert field values for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name), obj): continue # serialize the field serializer = queryMultiAdapter( (field, obj, self.request), IFieldSerializer ) value = serializer() result[json_compatible(name)] = value target_url = getMultiAdapter( (self.context, self.request), IObjectPrimaryFieldTarget )() if target_url: result["targetUrl"] = target_url result["allow_discussion"] = getMultiAdapter( (self.context, self.request), name="conversation_view" ).enabled() return result
def isVisible(self): """Checks wheter the user has read permission of the field: if this is not the case, then the field is not displayed """ return PermissionChecker( mergedTaggedValueDict(self.schema, READ_PERMISSIONS_KEY), self.context, ).allowed(self.field)
def all_merged_tagged_values_dict(ifaces, key): """mergedTaggedValueDict of all interfaces for a given key usally interfaces is a list of schemas """ info = dict() for iface in ifaces: info.update(mergedTaggedValueDict(iface, key)) return info
def validate(self, field_name, vocabulary_name=None): context = self.context checker = getSecurityManager().checkPermission schemata = self._get_schemata() for schema in schemata: if field_name in schema: # If a vocabulary name was specified and it does not # match the vocabulary name for the field or widget, # fail. field = schema[field_name] if vocabulary_name and ( vocabulary_name != getattr(field, 'vocabulary', None) and vocabulary_name != getattr(field, 'vocabularyName', None)): # Determine the widget to check for vocabulary there widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) widget = widgets.get(field_name) if widget: widget = (isinstance(widget, basestring) and resolveDottedName(widget) or widget) widget = widget and widget(field, self._request) else: widget = queryMultiAdapter((field, self._request), IFieldWidget) if widget: widget.update() if getattr(widget, 'vocabulary', None) != vocabulary_name: return False # Create mapping of all schema permissions permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) permission_name = permissions.get(field_name, None) if permission_name is not None: permission = queryUtility(IPermission, name=permission_name) if permission: return checker(permission.title, context) # If the field is in the schema, but no permission is # specified, fall back to the default edit permission return checker(self.DEFAULT_PERMISSION, context) else: raise AttributeError('No such field: {0}'.format(field_name))
def updateWidgets(self): widgets = mergedTaggedValueDict(self.schema, WIDGETS_KEY) if self.field in widgets: factory = widgets[self.field] if self.fields[self.field].widgetFactory.get( self.mode, None) is None: if isinstance(factory, basestring): factory = resolveDottedName(factory) self.fields[self.field].widgetFactory = factory DisplayForm.updateWidgets(self)
def _process_permissions(schema, form, all_fields): # Get either read or write permissions depending on what type of # form this is permission_cache = {} # permission name -> allowed/disallowed # name => permission name read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY ) # name => permission name write_permissions = mergedTaggedValueDict( schema, WRITE_PERMISSIONS_KEY ) security_manager = getSecurityManager() disallowed_fields = [] for field_name, field_instance in all_fields.items(): field_mode = field_instance.mode or form.mode permission_name = None base_name = _bn(field_instance) if field_mode == DISPLAY_MODE: permission_name = read_permissions.get(base_name, None) elif field_mode == INPUT_MODE: permission_name = write_permissions.get(base_name, None) if permission_name is None: continue if permission_name not in permission_cache: permission = queryUtility(IPermission, name=permission_name) if permission is None: permission_cache[permission_name] = True else: permission_cache[permission_name] = bool( security_manager.checkPermission( permission.title, form.context ) ) if not permission_cache.get(permission_name, True): disallowed_fields.append(field_name) return all_fields.omit(*disallowed_fields)
def extractFieldInformation(schema, context, request, prefix): iro = [IEditForm, Interface] if prefix != '': prefix += '-' omitted = mergedTaggedValuesForIRO(schema, OMITTED_KEY, iro) modes = mergedTaggedValuesForIRO(schema, MODES_KEY, iro) widgets = mergedTaggedValueDict(schema, WIDGETS_KEY) if context is not None: read_permissionchecker = PermissionChecker( mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY), context, ) write_permissionchecker = PermissionChecker( mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY), context, ) read_only = [] for name, mode in modes.items(): if mode == HIDDEN_MODE: omitted[name] = True elif mode == DISPLAY_MODE: read_only.append(name) for name in schema.names(True): if context is not None: if not read_permissionchecker.allowed(name): omitted[name] = True if not write_permissionchecker.allowed(name): read_only.append(name) if isVisible(name, omitted): field = schema[name] if not IField.providedBy(field): continue if not IOmittedField.providedBy(field): yield { 'id': "%s.%s" % (schema.__identifier__, name), 'name': prefix + name, 'title': schema[name].title, 'widget': _getWidgetName(schema[name], widgets, request), 'readonly': name in read_only, }
def check_permission(self, field_name): """Check field permission.""" schema = self.get_field_schema(field_name) read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY) permission = read_permissions.get(field_name) if permission is None: return True user = api.user.get_current() return api.user.has_permission(permission, user=user, obj=self.real_context)
def get_tagged_values(schemas, key): params = {} for schema in schemas: if not schema: continue tagged_values = mergedTaggedValueDict(schema, key) for field_name in schema: widget = tagged_values.get(field_name) if widget and widget.params: params[field_name] = widget.params return params
def isVisible(self): """Checks wheter the user has read permission of the field: if this is not the case, then the field is not displayed """ try: schema = next(self.additionalSchemata) except StopIteration: schema = self.schema return PermissionChecker( mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY), self.context, ).allowed(self.field)
def get_tagged_values(schemas, key): params = {} for schema in schemas: if not schema: continue tagged_values = mergedTaggedValueDict(schema, key) for field_name in schema: widget = tagged_values.get(field_name) if IParameterizedWidget.providedBy(widget) and widget.params: params[field_name] = widget.params.copy() for k, v in params[field_name].items(): if callable(v): params[field_name][k] = v() return params
def get_widget_params(schemas): params = {} for schema in schemas: if not schema: continue tagged_values = mergedTaggedValueDict(schema, WIDGETS_KEY) for field_name in schema: widget = tagged_values.get(field_name) if IParameterizedWidget.providedBy(widget) and widget.params: params[field_name] = {} for k, v in widget.params.items(): if callable(v): v = v() params[field_name][k] = v return params
def canViewField(self, field): """returns True if the logged in user has permission to view this field """ info = mergedTaggedValueDict(field.interface, READ_PERMISSIONS_KEY) # If there is no specific read permission, assume it is view if field not in info: return getSecurityManager().checkPermission(AccessControl.Permissions.view, self) permission = queryUtility(IPermission, name=info[field]) if permission is not None: return getSecurityManager().checkPermission(permission.title, self) return False
def get_vocabulary(self): widget = self.context field = widget.field.bind(widget.context) # check field's write permission info = mergedTaggedValueDict(field.interface, WRITE_PERMISSIONS_KEY) permission_name = info.get(field.__name__, "cmf.ModifyPortalContent") permission = queryUtility(IPermission, name=permission_name) if permission is None: permission = getUtility(IPermission, name="cmf.ModifyPortalContent") if not getSecurityManager().checkPermission(permission.title, self.get_context()): raise VocabLookupException("Vocabulary lookup not allowed.") if ICollection.providedBy(field): return field.value_type.vocabulary else: return field.vocabulary
def __call__(self, version=None, include_items=True): version = 'current' if version is None else version obj = self.getVersion(version) parent = aq_parent(aq_inner(obj)) parent_summary = getMultiAdapter((parent, self.request), ISerializeToJsonSummary)() result = { # '@context': 'http://www.w3.org/ns/hydra/context.jsonld', '@id': obj.absolute_url(), 'id': obj.id, '@type': obj.portal_type, 'parent': parent_summary, 'created': json_compatible(obj.created()), 'modified': json_compatible(obj.modified()), 'review_state': self._get_workflow_state(obj), 'UID': obj.UID(), 'version': version, 'layout': self.context.getLayout(), 'is_folderish': False } # Insert expandable elements result.update(expandable_elements(self.context, self.request)) # Insert field values for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name), obj): continue serializer = queryMultiAdapter((field, obj, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value result['allow_discussion'] = getMultiAdapter( (self.context, self.request), name='conversation_view').enabled() return result
def test_mergedTaggedValueDict(self): class IBase1(Interface): pass class IBase2(Interface): pass class IBase3(Interface): pass class ISchema(IBase1, IBase2, IBase3): pass IBase1.setTaggedValue(u"foo", {1: 1, 2: 1}) # more specific than IBase2 and IBase3 IBase3.setTaggedValue(u"foo", {3: 3, 2: 3, 4: 3}) # least specific of the bases ISchema.setTaggedValue(u"foo", {4: 4, 5: 4}) # most specific self.assertEqual({1: 1, 2: 1, 3: 3, 4: 4, 5: 4}, utils.mergedTaggedValueDict(ISchema, u"foo"))
def get_vocabulary(self): widget = self.context field = widget.field.bind(widget.context) # check field's write permission info = mergedTaggedValueDict(field.interface, WRITE_PERMISSIONS_KEY) permission_name = info.get(field.__name__, 'cmf.ModifyPortalContent') permission = queryUtility(IPermission, name=permission_name) if permission is None: permission = getUtility(IPermission, name='cmf.ModifyPortalContent') if not getSecurityManager().checkPermission(permission.title, self.get_context()): raise VocabLookupException('Vocabulary lookup not allowed.') if ICollection.providedBy(field): return field.value_type.vocabulary return field.vocabulary
def __call__(self): primary_field_name = self.get_primary_field_name() for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name), self.context): continue if name != primary_field_name: continue target_adapter = queryMultiAdapter( (field, self.context, self.request), IPrimaryFieldTarget ) if target_adapter: target = target_adapter() if target: return target
def get_fields_in_order_with_permission(schema, context): checker = getSecurityManager().checkPermission permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY ) result = [] for field in getFieldsInOrder(schema): permission_name = permissions.get(field[0], None) if permission_name is not None: permission = queryUtility(IPermission, name=permission_name) if permission: if not checker(permission.title, context): # Ignore this field continue result.append(field) return result
def __call__(self, name, value): # Short circuit for things like views or viewlets if name == '': return 1 context = aq_parent(self) schema = self._get_schema(context) if schema is None: return 1 info = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) if name not in info: return 1 permission = queryUtility(IPermission, name=info[name]) if permission is not None: return getSecurityManager().checkPermission(permission.title, context) return 0
def validate(self, field_name, vocabulary_name=None): context = self.context checker = getSecurityManager().checkPermission schemata = self._get_schemata() for schema in schemata: if field_name not in schema: continue # If a vocabulary name was specified and it does not # match the vocabulary name for the field or widget, # fail. field = schema[field_name] if not self._validate_vocabulary_name( schema, field, vocabulary_name ): return False # Create mapping of all schema permissions permissions = mergedTaggedValueDict( schema, WRITE_PERMISSIONS_KEY ) permission_name = permissions.get(field_name, None) if permission_name is not None: # if we have explicit permissions, check them permission = queryUtility( IPermission, name=permission_name ) if permission: return checker(permission.title, context) # If the field is in the schema, but no permission is # specified, fall back to the default edit permission return checker(self.DEFAULT_PERMISSION, context) else: raise AttributeError('No such field: {0}'.format(field_name))
def __call__(self): parent = self.context.__parent__ if parent is not None: try: parent_summary = getMultiAdapter((parent, self.request), ISerializeToJsonSummary)() except ComponentLookupError: parent_summary = {} else: parent_summary = {} result = { '@id': '/'.join(get_physical_path(self.context)), 'id': self.context.id, '@type': self.context.portal_type, 'parent': parent_summary, 'created': json_compatible(self.context.creation_date), 'modified': json_compatible(self.context.modification_date), 'UID': self.context.UID(), } for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict(schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue serializer = queryMultiAdapter( (field, self.context, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value return result
def __call__(self, validate_all=False): data = json_body(self.request) modified = False schema_data = {} errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict( schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): field_data = schema_data.setdefault(schema, {}) if field.readonly: continue if name in data: dm = queryMultiAdapter((self.context, field), IDataManager) if not dm.canWrite(): continue if not self.check_permission(write_permissions.get(name)): continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) else: field_data[name] = value if value != dm.get(): dm.set(value) modified = True elif validate_all: # Never validate the changeNote of p.a.versioningbehavior # The Versionable adapter always returns an empty string # which is the wrong type. Should be unicode and should be # fixed in p.a.versioningbehavior if name == 'changeNote': continue dm = queryMultiAdapter((self.context, field), IDataManager) bound = field.bind(self.context) try: bound.validate(dm.get()) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) # Validate schemata for schema, field_data in schema_data.items(): validator = queryMultiAdapter( (self.context, self.request, None, schema, None), IManagerValidator) for error in validator.validate(field_data): errors.append({'error': error, 'message': error.message}) if errors: raise BadRequest(errors) if modified: notify(ObjectModifiedEvent(self.context)) return self.context
def __call__(self, validate_all=False, data=None): # noqa: ignore=C901 if data is None: data = json_body(self.request) modified = {} schema_data = {} errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): field_data = schema_data.setdefault(schema, {}) if field.readonly: continue if name in data: dm = queryMultiAdapter((self.context, field), IDataManager) if not dm.canWrite(): continue if not self.check_permission(write_permissions.get(name)): continue # set the field to missing_value if we receive null if data[name] is None: if not field.required: dm.set(field.missing_value) else: errors.append({ 'field': field.__name__, 'message': ('{} is a required field.'.format( field.__name__), 'Setting it to null is not allowed.') }) continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) else: field_data[name] = value if value != dm.get(): dm.set(value) # Collect the names of the modified fields # Use prefixed name because z3c.form does so prefixed_name = schema.__name__ + '.' + name modified.setdefault(schema, []).append(prefixed_name) elif validate_all: # Never validate the changeNote of p.a.versioningbehavior # The Versionable adapter always returns an empty string # which is the wrong type. Should be unicode and should be # fixed in p.a.versioningbehavior if name == 'changeNote': continue dm = queryMultiAdapter((self.context, field), IDataManager) bound = field.bind(self.context) try: bound.validate(dm.get()) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) # Validate schemata for schema, field_data in schema_data.items(): validator = queryMultiAdapter( (self.context, self.request, None, schema, None), IManagerValidator) for error in validator.validate(field_data): errors.append({'error': error, 'message': error.message}) if errors: raise BadRequest(errors) # We'll set the layout after the validation and and even if there # are no other changes. if 'layout' in data: layout = data['layout'] self.context.setLayout(layout) # OrderingMixin self.handle_ordering(data) if modified: descriptions = [] for interface, names in modified.items(): descriptions.append(Attributes(interface, *names)) notify(ObjectModifiedEvent(self.context, *descriptions)) return self.context
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 __call__(self, validate_all=False): data = json_body(self.request) modified = False schema_data = {} errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): field_data = schema_data.setdefault(schema, {}) if field.readonly: continue if name in data: dm = queryMultiAdapter((self.context, field), IDataManager) if not dm.canWrite(): continue if not self.check_permission(write_permissions.get(name)): continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) else: field_data[name] = value if value != dm.get(): dm.set(value) modified = True elif validate_all: # Never validate the changeNote of p.a.versioningbehavior # The Versionable adapter always returns an empty string # which is the wrong type. Should be unicode and should be # fixed in p.a.versioningbehavior if name == 'changeNote': continue dm = queryMultiAdapter((self.context, field), IDataManager) bound = field.bind(self.context) try: bound.validate(dm.get()) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) # Validate schemata for schema, field_data in schema_data.items(): validator = queryMultiAdapter( (self.context, self.request, None, schema, None), IManagerValidator) for error in validator.validate(field_data): errors.append({'error': error, 'message': error.message}) if errors: raise BadRequest(errors) if modified: notify(ObjectModifiedEvent(self.context)) return self.context
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 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 __call__(self, validate_all=False): # noqa: ignore=C901 data = json_body(self.request) modified = False schema_data = {} errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): field_data = schema_data.setdefault(schema, {}) if field.readonly: continue if name in data: dm = queryMultiAdapter((self.context, field), IDataManager) if not dm.canWrite(): continue if not self.check_permission(write_permissions.get(name)): continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) else: field_data[name] = value if IDatetime.providedBy(dm.field): # Do not compare both, just set the value. See # https://github.com/plone/plone.restapi/issues/253 dm.set(value) modified = True else: if value != dm.get(): dm.set(value) modified = True elif validate_all: # Never validate the changeNote of p.a.versioningbehavior # The Versionable adapter always returns an empty string # which is the wrong type. Should be unicode and should be # fixed in p.a.versioningbehavior if name == 'changeNote': continue dm = queryMultiAdapter((self.context, field), IDataManager) bound = field.bind(self.context) try: bound.validate(dm.get()) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) # Validate schemata for schema, field_data in schema_data.items(): validator = queryMultiAdapter( (self.context, self.request, None, schema, None), IManagerValidator) for error in validator.validate(field_data): errors.append({'error': error, 'message': error.message}) if errors: raise BadRequest(errors) # We'll set the layout after the validation and and even if there # are no other changes. if 'layout' in data: layout = data['layout'] self.context.setLayout(layout) # OrderingMixin self.handle_ordering(data) if modified: notify(ObjectModifiedEvent(self.context)) return self.context
def __call__(self, data, validate_all=False): modified = False errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict( schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if field.readonly: continue if name in data: if not self.check_permission(write_permissions.get(name)): continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) else: f = schema.get(name) try: f.validate(value) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) else: setattr(schema(self.context), name, value) if validate_all: validation = getValidationErrors(schema, schema(self.context)) if len(validation): for e in validation: errors.append({ 'message': e[1].doc(), 'field': e[0], 'error': e }) if errors: raise DeserializationError(errors) if modified: notify(ObjectModifiedEvent(self.context)) return self.context
def __call__(self, version=None): version = "current" if version is None else version if version != "current": return {} query = self._build_query() catalog = getToolByName(self.context, "portal_catalog") brains = catalog(query) batch = HypermediaBatch(self.request, brains) result = { # '@context': 'http://www.w3.org/ns/hydra/context.jsonld', "@id": self.context.absolute_url(), "id": self.context.id, "@type": "Plone Site", "title": self.context.Title(), "parent": {}, "is_folderish": True, "description": self.context.description, } if HAS_PLONE_6: # Insert Plone Site DX root field values for schema in iterSchemata(self.context): read_permissions = mergedTaggedValueDict( schema, READ_PERMISSIONS_KEY) for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name), self.context): continue # serialize the field serializer = queryMultiAdapter( (field, self.context, self.request), IFieldSerializer) value = serializer() result[json_compatible(name)] = value # Insert locking information result.update({"lock": lock_info(self.context)}) else: # Apply the fake blocks behavior in site root hack using site root properties result.update({ "blocks": self.serialize_blocks(), "blocks_layout": json.loads(getattr(self.context, "blocks_layout", "{}")), }) # Insert expandable elements result.update(expandable_elements(self.context, self.request)) result["items_total"] = batch.items_total if batch.links: result["batching"] = batch.links result["items"] = [ getMultiAdapter((brain, self.request), ISerializeToJsonSummary)() for brain in batch ] return result
def get_schema_data(self, data, validate_all): schema_data = {} errors = [] for schema in iterSchemata(self.context): write_permissions = mergedTaggedValueDict(schema, WRITE_PERMISSIONS_KEY) for name, field in getFields(schema).items(): field_data = schema_data.setdefault(schema, {}) if field.readonly: continue if name in data: dm = queryMultiAdapter((self.context, field), IDataManager) if not dm.canWrite(): continue if not self.check_permission(write_permissions.get(name)): continue # set the field to missing_value if we receive null if data[name] is None: if not field.required: if dm.get(): self.mark_field_as_changed(schema, name) dm.set(field.missing_value) else: errors.append({ "field": field.__name__, "message": ( "{} is a required field.".format( field.__name__), "Setting it to null is not allowed.", ), }) continue # Deserialize to field value deserializer = queryMultiAdapter( (field, self.context, self.request), IFieldDeserializer) if deserializer is None: continue try: value = deserializer(data[name]) except ValueError as e: errors.append({ "message": str(e), "field": name, "error": e }) except ValidationError as e: errors.append({ "message": e.doc(), "field": name, "error": e }) else: field_data[name] = value if value != dm.get(): dm.set(value) self.mark_field_as_changed(schema, name) elif validate_all: # Never validate the changeNote of p.a.versioningbehavior # The Versionable adapter always returns an empty string # which is the wrong type. Should be unicode and should be # fixed in p.a.versioningbehavior if name == "changeNote": continue dm = queryMultiAdapter((self.context, field), IDataManager) bound = field.bind(self.context) try: bound.validate(dm.get()) except ValidationError as e: errors.append({ "message": e.doc(), "field": name, "error": e }) return schema_data, errors
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