public void OnMetadataCreated(ModelMetadata metadata) { var extendedMetadata = metadata as ExtendedMetadata; if (extendedMetadata == null) { return; } var suffix = this.TypesFormatSuffix ?? (extendedMetadata.AdditionalValues.ContainsKey("TypesFormatSuffix") ? extendedMetadata.AdditionalValues["TypesFormatSuffix"] as string : null); var allowedTypes = this.AllowedTypes.Select(a => a.FullName.ToLowerInvariant()).ToList(); var restrictedTypes = this.RestrictedTypes.Select(r => r.FullName.ToLowerInvariant()).ToList(); var injectedAllowedTypesAttribute = InjectedAllowedTypes.GetInjectedAllowedTypesAttribute(extendedMetadata.ContainerType, extendedMetadata.PropertyName); if (injectedAllowedTypesAttribute != null) { allowedTypes = allowedTypes.Concat( injectedAllowedTypesAttribute.AllowedTypes.Select(x => x.FullName.ToLowerInvariant())) .Distinct() .ToList(); restrictedTypes = restrictedTypes.Concat( injectedAllowedTypesAttribute.RestrictedTypes.Select(x => x.FullName.ToLowerInvariant())) .Distinct() .ToList(); } if (!string.IsNullOrEmpty(suffix)) { allowedTypes = allowedTypes.ToArray().Select(a => a + "." + suffix).ToList(); restrictedTypes = restrictedTypes.ToArray().Select(a => a + "." + suffix).ToList(); } var allowedTypesArray = allowedTypes.ToArray(); var restrictedTypesArray = restrictedTypes.ToArray(); extendedMetadata.EditorConfiguration["AllowedTypes"] = allowedTypesArray; extendedMetadata.EditorConfiguration["RestrictedTypes"] = restrictedTypesArray; extendedMetadata.EditorConfiguration["AllowedDndTypes"] = allowedTypesArray; extendedMetadata.EditorConfiguration["RestrictedDndTypes"] = restrictedTypesArray; extendedMetadata.OverlayConfiguration["AllowedDndTypes"] = allowedTypesArray; extendedMetadata.OverlayConfiguration["RestrictedDndTypes"] = restrictedTypesArray; }
public void Initialize(InitializationEngine context) { InjectedAvailableModelSettings.RegisterCustomAvailableModelSettings(new Dictionary <Type, ContentTypeAvailableModelSetting> { //{ // typeof(MediaPage) , new ContentTypeAvailableModelSetting // { // Availability = Availability.Specific, // Included = new HashSet<Type> {typeof(CoolPage) } // } //} }); InjectedAllowedTypes.RegisterInjectedAllowedTypesAttributes(new Dictionary <string, InjectedAllowedTypesAttribute> { //{ // string.Format("{0}.{1}",typeof(MediaPage).Name, nameof(MediaPage.ContentArea)), new InjectedAllowedTypesAttribute // { // AllowedTypes = new [] {typeof(MusicBlock)} // } //} }); }
protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value == null) { return(null); } var validationMessage = string.Empty; var stringBuilder = new StringBuilder(); var allowedTypes = this.AllowedTypes; var restrictedTypes = this.RestrictedTypes; var contentReferences = new List <ContentReference>(); if (value is ContentArea) { var contentArea = value as ContentArea; contentReferences = contentArea.Items.Select(x => x.ContentLink).ToList(); } else if (value is IEnumerable <ContentReference> ) { var references = value as IEnumerable <ContentReference>; contentReferences = references.ToList(); } else if (value is ContentReference) { var contentReference = value as ContentReference; contentReferences.Add(contentReference); } foreach (var contentReference in contentReferences) { var content = _contentLoader.Get <IContent>(contentReference); var type = content.GetOriginalType(); var interfaces = type.GetInterfaces(); var injectedAllowedTypesAttribute = InjectedAllowedTypes.GetInjectedAllowedTypesAttribute(validationContext.ObjectInstance.GetOriginalType(), validationContext.MemberName); if (injectedAllowedTypesAttribute != null) { allowedTypes = allowedTypes.Concat(injectedAllowedTypesAttribute.AllowedTypes).Distinct().ToArray(); restrictedTypes = restrictedTypes.Concat(injectedAllowedTypesAttribute.RestrictedTypes).Distinct().ToArray(); } if (restrictedTypes.Contains(type) || restrictedTypes.Any(x => interfaces.Any(i => i == x))) { var message = string.Format( LocalizationService.Current.GetString("/injectedallowedtypes/errormessages/notallowed"), type.Name, validationContext.MemberName); validationMessage = stringBuilder.Append(message).AppendLine(".").ToString(); } if (!allowedTypes.Contains(type) && !allowedTypes.Any(x => interfaces.Any(i => i == x))) { var message = string.Format( LocalizationService.Current.GetString("/injectedallowedtypes/errormessages/notallowed"), type.Name, validationContext.MemberName); validationMessage = stringBuilder.Append(message).AppendLine(".").ToString(); } } if (string.IsNullOrEmpty(validationMessage)) { return(null); } var validationResult = new ValidationResult(validationMessage); return(validationResult); }
/// <summary> /// Almost exact implementation of the AssignValuesToPropertyDefinition in the ContentDataAttributeScanningAssigner /// the only thing that differs is the added call to CustomAllowedTypes.GetMergedAllowedTypesAttribute. /// That call allows us to add more types to the Allowed/RestricedTypes without using the AllowedTypes attribute. /// </summary> /// <param name="propertyDefinitionModel"></param> /// <param name="property"></param> /// <param name="parentModel"></param> public override void AssignValuesToPropertyDefinition(PropertyDefinitionModel propertyDefinitionModel, PropertyInfo property, ContentTypeModel parentModel) { if (property.IsAutoGenerated() && !property.IsAutoVirtualPublic()) { var exceptionMessage = string.Format(CultureInfo.InvariantCulture, "The property '{0}' on the content type '{1}' is autogenerated but not virtual declared.", property.Name, property.DeclaringType.Name); throw new InvalidOperationException(exceptionMessage); } //This is our added logic to merge a predefined AllowedTypes attribute with our own AllowedTypes specified in code. #region ModularAllowedTypes var customAttributes = Attribute.GetCustomAttributes(property, true).ToList(); var injectedAllowedTypesAttribute = InjectedAllowedTypes.GetInjectedAllowedTypesAttribute(parentModel.ModelType, property.Name); var specifiedAllowedTypesAttribute = property.GetCustomAttribute <InjectedAllowedTypesAttribute>(); //We DO NOT include an existing AllowedTypesAttribute in the merge, because if the AllowedTypesAttribute is used, EPiServer will ONLY //look at the AllowedTypesAttribute thus making the validation fail. We can't hook into that method as far as I know so you will need //to use the InjectedAllowedTypesAttribute instead of the AllowedTypesAttribute. if (customAttributes.Any(x => x is AllowedTypesAttribute)) { var existingAllowedTypesAttribute = customAttributes.FirstOrDefault(x => x is AllowedTypesAttribute) as AllowedTypesAttribute; if (injectedAllowedTypesAttribute != null) { var mergedAllowedTypesAttribute = InjectedAllowedTypes.MergeAttributes(injectedAllowedTypesAttribute, specifiedAllowedTypesAttribute); customAttributes.Remove(existingAllowedTypesAttribute); customAttributes.Add(mergedAllowedTypesAttribute); } } else { var mergedAllowedTypesAttribute = InjectedAllowedTypes.MergeAttributes(injectedAllowedTypesAttribute, specifiedAllowedTypesAttribute); if (mergedAllowedTypesAttribute != null) { customAttributes.Add(mergedAllowedTypesAttribute); } } #endregion foreach (var attribute in customAttributes) { if (attribute is BackingTypeAttribute) { var backingTypeAttribute = attribute as BackingTypeAttribute; if (backingTypeAttribute.BackingType != null) { if (!typeof(PropertyData).IsAssignableFrom(backingTypeAttribute.BackingType)) { var exceptionMessage = string.Format(CultureInfo.InvariantCulture, "The backing type '{0}' attributed to the property '{1}' on '{2}' does not inherit PropertyData.", backingTypeAttribute.BackingType.FullName, property.Name, property.DeclaringType.Name); throw new TypeMismatchException(exceptionMessage); } if (property.IsAutoVirtualPublic()) { ValidateTypeCompability(property, backingTypeAttribute.BackingType); } } propertyDefinitionModel.BackingType = backingTypeAttribute.BackingType; } else if (attribute is AllowedTypesAttribute) { var allowedTypesAttribute = attribute as AllowedTypesAttribute; VerifyAllowedTypesAttribute(allowedTypesAttribute, property); } else if (attribute is DisplayAttribute) { var displayAttribute = attribute as DisplayAttribute; propertyDefinitionModel.DisplayName = displayAttribute.GetName(); propertyDefinitionModel.Description = displayAttribute.GetDescription(); propertyDefinitionModel.Order = displayAttribute.GetOrder(); propertyDefinitionModel.TabName = displayAttribute.GetGroupName(); } else if (attribute is ScaffoldColumnAttribute) { var scaffoldColumnAttribute = attribute as ScaffoldColumnAttribute; propertyDefinitionModel.AvailableInEditMode = scaffoldColumnAttribute.Scaffold; } else if (attribute is CultureSpecificAttribute) { var specificAttribute = attribute as CultureSpecificAttribute; ThrowIfBlockProperty(specificAttribute, property); propertyDefinitionModel.CultureSpecific = specificAttribute.IsCultureSpecific; } else if (attribute is RequiredAttribute) { var requiredAttribute = attribute as RequiredAttribute; ThrowIfBlockProperty(requiredAttribute, property); propertyDefinitionModel.Required = true; } else if (attribute is SearchableAttribute) { var searchableAttribute = attribute as SearchableAttribute; ThrowIfBlockProperty(searchableAttribute, property); propertyDefinitionModel.Searchable = searchableAttribute.IsSearchable; } else if (attribute is UIHintAttribute) { var uiHintAttribute = attribute as UIHintAttribute; if (!string.IsNullOrEmpty(uiHintAttribute.UIHint)) { if (string.Equals(uiHintAttribute.PresentationLayer, "website")) { propertyDefinitionModel.TemplateHint = uiHintAttribute.UIHint; } else if (string.IsNullOrEmpty(uiHintAttribute.PresentationLayer) && string.IsNullOrEmpty(propertyDefinitionModel.TemplateHint)) { propertyDefinitionModel.TemplateHint = uiHintAttribute.UIHint; } } } propertyDefinitionModel.Attributes.AddAttribute(attribute); } }