protected virtual bool ValidateProperties(ModelStateDictionary modelState, FluidityEntityPostModel postModel, FluidityEditorFieldConfig[] configProps) { foreach (var p in postModel.Properties) { if (configProps.Any(property => property.Property.Name == p.Alias) == false) { throw new InvalidOperationException($"property with alias: {p.Alias} was not found"); } } return(true); }
protected virtual bool ValidatePropertyData(ModelStateDictionary modelState, FluidityEntityPostModel postModel, FluidityEditorFieldConfig[] configProps) { foreach (var p in configProps) { var dataTypeInfo = _dataTypeHelper.ResolveDataType(p); var postedValue = postModel.Properties.Single(x => x.Alias == p.Property.Name).Value; // Validate against the prop editor validators foreach (var result in dataTypeInfo.PropertyEditor.ValueEditor.Validators .SelectMany(v => v.Validate(postedValue, dataTypeInfo.PreValues, dataTypeInfo.PropertyEditor))) { modelState.AddPropertyError(result, p.Property.Name); } // Now we need to validate the property based on the PropertyType validation (i.e. regex and required) // NOTE: These will become legacy once we have pre-value overrides. if (p.IsRequired) { foreach (var result in dataTypeInfo.PropertyEditor.ValueEditor.RequiredValidator .Validate(postedValue, "", dataTypeInfo.PreValues, dataTypeInfo.PropertyEditor)) { modelState.AddPropertyError(result, p.Property.Name); } } if (!p.ValidationRegex.IsNullOrWhiteSpace()) { // We only want to execute the regex statement if: // * the value is null or empty AND it is required OR // * the value is not null or empty // See: http://issues.umbraco.org/issue/U4-4669 var asString = postedValue as string; if ( //Value is not null or empty (postedValue != null && asString.IsNullOrWhiteSpace() == false) //It's required || p.IsRequired) { foreach (var result in dataTypeInfo.PropertyEditor.ValueEditor.RegexValidator .Validate(postedValue, p.ValidationRegex, dataTypeInfo.PreValues, dataTypeInfo.PropertyEditor)) { modelState.AddPropertyError(result, p.Property.Name); } } } } return(modelState.IsValid); }
public object SaveEntity([ModelBinder(typeof(FluidityEntityBinder))] FluidityEntityPostModel postModel) { FluidityEntityEditModel display; var sectionConfig = Context.Config.Sections[postModel.Section]; var collectionConfig = sectionConfig.Tree.FlattenedTreeItems[postModel.Collection] as FluidityCollectionConfig; // Convert ID type for type checking var idProp = collectionConfig.IdProperty; var defaultId = idProp.Type.GetDefaultValue(); if (postModel.Id != null && postModel.Id.GetType() != idProp.Type) { var convert = postModel.Id.TryConvertTo(idProp.Type); if (convert.Success) { postModel.Id = convert.Result; } } // Get or create entity var entity = postModel.Id != null && !postModel.Id.Equals(defaultId) ? Context.Services.EntityService.GetEntity(collectionConfig, postModel.Id) : Context.Services.EntityService.NewEntity(collectionConfig); // Map property values var mapper = new FluidityEntityMapper(); entity = mapper.FromPostModel(sectionConfig, collectionConfig, postModel, entity); // Validate the property values (review ContentItemValidationHelper) var validator = new FluidityEntityPostValidator(); validator.Validate(ModelState, postModel, entity, collectionConfig); // Check to see if model is valid if (!ModelState.IsValid) { display = Context.Services.EntityService.GetEntityEditModel(sectionConfig, collectionConfig, entity); display.Errors = ModelState.ToErrorDictionary(); throw new HttpResponseException(Request.CreateValidationErrorResponse(display)); } // Do the save entity = Context.Services.EntityService.SaveEntity(collectionConfig, entity); display = Context.Services.EntityService.GetEntityEditModel(sectionConfig, collectionConfig, entity); // Return the updated model return(display); }
public void Validate(ModelStateDictionary modelState, FluidityEntityPostModel postModel, object entity, FluidityCollectionConfig config) { var configProps = config.Editor?.Tabs.SelectMany(x => x.Fields).ToArray() ?? new FluidityEditorFieldConfig[0]; if (ValidateProperties(modelState, postModel, configProps) == false) { return; } if (ValidatePropertyData(modelState, postModel, configProps) == false) { return; } if (ValidateDataAnnotations(modelState, entity) == false) { return; } }
public object FromPostModel(FluiditySectionConfig section, FluidityCollectionConfig collection, FluidityEntityPostModel postModel, object entity) { var editorProps = collection.Editor.Tabs.SelectMany(x => x.Fields).ToArray(); // Update the name property if (collection.NameProperty != null) { entity.SetPropertyValue(collection.NameProperty, postModel.Name); } // Update the individual properties foreach (var prop in postModel.Properties) { // Get the prop config var propConfig = editorProps.First(x => x.Property.Name == prop.Alias); if (!propConfig.IsReadOnly) { // Create additional data for file handling var additionalData = new Dictionary <string, object>(); // Grab any uploaded files and add them to the additional data var files = postModel.UploadedFiles.Where(x => x.PropertyAlias == prop.Alias).ToArray(); if (files.Length > 0) { additionalData.Add("files", files); } // Ensure safe filenames foreach (var file in files) { file.FileName = file.FileName.ToSafeFileName(); } // Add extra things needed to figure out where to put the files // Looking into the core code, these are not actually used for any lookups, // rather they are used to generate a unique path, so we just use the nearest // equivilaants from the fluidity api. var cuid = $"{section.Alias}_{collection.Alias}_{entity.GetPropertyValue(collection.IdProperty)}"; var puid = $"{section.Alias}_{collection.Alias}_{propConfig.Property.Name}"; additionalData.Add("cuid", ObjectExtensions.EncodeAsGuid(cuid)); additionalData.Add("puid", ObjectExtensions.EncodeAsGuid(puid)); var dataTypeInfo = _dataTypeHelper.ResolveDataType(propConfig, collection.IsReadOnly); var data = new ContentPropertyData(prop.Value, dataTypeInfo.PreValues, additionalData); if (!dataTypeInfo.PropertyEditor.ValueEditor.IsReadOnly) { var currentValue = entity.GetPropertyValue(propConfig.Property); var encryptedProp = collection.EncryptedProperties?.FirstOrDefault(x => x.Name == propConfig.Property.Name); if (encryptedProp != null) { currentValue = SecurityHelper.Decrypt(currentValue.ToString()); } if (propConfig.ValueMapper != null) { currentValue = propConfig.ValueMapper.ModelToEditor(currentValue); } var propVal = dataTypeInfo.PropertyEditor.ValueEditor.ConvertEditorToDb(data, currentValue); var supportTagsAttribute = TagExtractor.GetAttribute(dataTypeInfo.PropertyEditor); if (supportTagsAttribute != null) { var dummyProp = new Property(new PropertyType(dataTypeInfo.DataTypeDefinition), propVal); TagExtractor.SetPropertyTags(dummyProp, data, propVal, supportTagsAttribute); propVal = dummyProp.Value; } if (propConfig.ValueMapper != null) { propVal = propConfig.ValueMapper.EditorToModel(propVal); } if (encryptedProp != null) { propVal = SecurityHelper.Encrypt(propVal.ToString()); } if (propVal != null && propVal.GetType() != propConfig.Property.Type) { var convert = propVal.TryConvertTo(propConfig.Property.Type); if (convert.Success) { propVal = convert.Result; } } entity.SetPropertyValue(propConfig.Property, propVal); } } } return(entity); }