public IEnumerable <Permission> GetPermissions() { var permissions = new List <Permission>(); permissions.Add(ManageAllHashedStringFields); permissions.Add(ManageOwnHashedStringFields); IEnumerable <ContentPartDefinition> partDefinitions = _contentDefinitionManager.ListPartDefinitions(); // LINQ. var tmp = partDefinitions .Where(cpd => cpd.Fields.Any(cpfd => cpfd.FieldDefinition.Name.Equals("HashedStringField"))) .SelectMany(cpd => cpd.Fields .Where(cpfd => cpfd.FieldDefinition.Name.Equals("HashedStringField")) .Select(cpfd => new[] { _secureFieldService.GetAllHashedPermission(cpd.Name, cpfd.Name), _secureFieldService.GetOwnHashedPermission(cpd.Name, cpfd.Name) })); permissions.AddRange(tmp.SelectMany(p => p)); return(permissions); }
public void Describe(DescribeFilterContext describe) { foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { // This query returns all EncryptedStringFieldDefinitions in the parts where there's at least one EncryptedStringField. var encryptedStringFieldDefinitions = part.Fields.Where(fd => fd.FieldDefinition.Name.Equals("EncryptedStringField")); var localPart = part; foreach (var field in encryptedStringFieldDefinitions) { var localField = field; // The following code generates the list of filters you can apply on EncryptedStringFields. // Fields are grouped by part. describe .For( part.Name + "ContentFields", T("{0} Content Fields", part.Name.CamelFriendly()), T("Content Fields for {0}", part.Name.CamelFriendly())) .Element( localPart.Name + "." + localField.Name, T(localField.DisplayName), T("Value for {0}", localField.DisplayName), context => ApplyFilter(context, part, field), DisplayFilter, SecureStringFieldForm.FormName); } } }
public async Task Setup(IDictionary <string, object> properties, Action <string, string> reportError) { var features = _extensionManager.GetFeatures(); var featuresToEnable = features.Where(x => x.Id == "ThisNetWorks.OrchardCore.GoogleMaps"); await _shellFeatureManager.EnableFeaturesAsync(featuresToEnable, true); var ctds = _contentDefinitionManager.ListPartDefinitions(); if (ctds.FirstOrDefault(x => x.Name == "BlogPost") != null) { _contentDefinitionManager.AlterTypeDefinition("BlogPost", builder => builder .WithPart("GoogleMapPart")); var query = _session.Query <ContentItem>() .With <ContentItemIndex>(x => x.ContentType == "BlogPost" && x.Published); var blogPosts = await query.ListAsync(); foreach (var blogPost in blogPosts) { blogPost.Alter <GoogleMapPart>(part => { part.Marker = new LatLng { Lat = GoogleMapsSettings.DefaultLatitude, Lng = GoogleMapsSettings.DefaultLongitude }; }); _session.Save(blogPost); } } }
public void Describe(DescribeFilterContext describe) { foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { var booleanFields = part.Fields.Where(field => field.FieldDefinition.Name == typeof(BooleanField).Name); if (!booleanFields.Any()) { continue; } var descriptor = describe.For( part.Name + "ContentFields", T("{0} Content Fields", part.Name.CamelFriendly()), T("Content Fields for {0}", part.Name.CamelFriendly())); foreach (var field in booleanFields) { descriptor.Element( typeof(TokenizedBooleanFilter).Name, T("{0}: Tokenized Value", field.DisplayName), T("The tokenized boolean value of the field."), context => ApplyFilter(context, part, field), context => DisplayFilter(context, part, field), TokenizedBooleanFilterForm.FormName ); } } }
public void Describe(DescribeContext context) { Func <IShapeFactory, object> form = shape => { var f = Shape.Form( Id: "AnyOfContentParts", _Parts: Shape.SelectList( Id: "contentparts", Name: "ContentParts", Title: T("Content parts"), Description: T("Select some content parts."), Size: 10, Multiple: true ) ); f._Parts.Add(new SelectListItem { Value = "", Text = T("Any").Text }); foreach (var contentPart in _contentDefinitionManager.ListPartDefinitions().OrderBy(x => x.Name)) { f._Parts.Add(new SelectListItem { Value = contentPart.Name, Text = contentPart.Name }); } return(f); }; context.Form("ContentPartsFilter", form); }
public static IEnumerable <ContentTypeDefinition> ListUserDefinedTypeDefinitions(this IContentDefinitionManager contentDefinitionManager) { var contentTypes = contentDefinitionManager.ListTypeDefinitions(); var parts = contentDefinitionManager.ListPartDefinitions(); return(contentTypes.Where(t => parts.Any(p => p.Name == t.Name))); }
public ActionResult Index() { var model = new MetadataIndexViewModel { TypeDefinitions = _contentDefinitionManager.ListTypeDefinitions(), PartDefinitions = _contentDefinitionManager.ListPartDefinitions() }; var types = new XElement("Types"); foreach (var type in model.TypeDefinitions) { types.Add(_contentDefinitionWriter.Export(type)); } var parts = new XElement("Parts"); foreach (var part in model.PartDefinitions) { parts.Add(_contentDefinitionWriter.Export(part)); } var stringWriter = new StringWriter(); using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = " " })) { if (xmlWriter != null) { new XElement("Orchard", types, parts).WriteTo(xmlWriter); } } model.ExportText = stringWriter.ToString(); return(View(model)); }
public IEnumerable <EditPartViewModel> GetParts(bool metadataPartsOnly) { var typeNames = new HashSet <string>(GetTypes().Select(ctd => ctd.Name)); // user-defined parts // except for those parts with the same name as a type (implicit type's part or a mistake) var userContentParts = _contentDefinitionManager.ListPartDefinitions() .Where(cpd => !typeNames.Contains(cpd.Name)) .Select(cpd => new EditPartViewModel(cpd)) .ToDictionary( k => k.Name, v => v); // code-defined parts var codeDefinedParts = metadataPartsOnly ? Enumerable.Empty <EditPartViewModel>() : _contentPartDrivers .Select(d => d.GetPartInfo()) .Where(cpd => !userContentParts.ContainsKey(cpd.PartName)) .Select(cpi => new EditPartViewModel { Name = cpi.PartName, DisplayName = cpi.PartName }) .ToList(); // Order by display name return(codeDefinedParts .Union(userContentParts.Values) .OrderBy(m => m.DisplayName)); }
public IEnumerable <dynamic> BuildLayoutEditors() { var contentParts = _contentDefinitionManager .ListPartDefinitions() .OrderBy(p => p.Name); var contentFields = _contentDefinitionManager .ListPartDefinitions() .SelectMany(p => p.Fields) .OrderBy(f => f.DisplayName); return(new[] { Shape.LayoutElements_Part_LayoutEditor( Order: "10", ContentParts: contentParts ), Shape.LayoutElements_Field_LayoutEditor( Order: "11", ContentFields: contentFields ) }); }
public TaxonomyPartHandler( IRepository <TaxonomyPartRecord> repository, ITaxonomyService taxonomyService, IContentDefinitionManager contentDefinitionManager) { string previousName = null; Filters.Add(StorageFilter.For(repository)); OnPublished <TaxonomyPart>((context, part) => { var previousTermTypeName = part.TermTypeName; if (previousName == null || part.Name == previousName) { // is it a new taxonomy ? taxonomyService.CreateTermContentType(part); } else { // keep the previous term type name as it would otherwise force us // to update all terms to use another type part.TermTypeName = previousTermTypeName; // update existing fields foreach (var partDefinition in contentDefinitionManager.ListPartDefinitions()) { foreach (var field in partDefinition.Fields) { if (field.FieldDefinition.Name == typeof(TaxonomyField).Name) { if (field.Settings.GetModel <TaxonomyFieldSettings>().Taxonomy == previousName) { contentDefinitionManager.AlterPartDefinition(partDefinition.Name, cfg => cfg.WithField(field.Name, builder => builder.WithSetting("TaxonomyFieldSettings.Taxonomy", part.Name))); } } } } } }); OnLoading <TaxonomyPart>((context, part) => part.TermsField.Loader(x => taxonomyService.GetTerms(part.Id))); OnUpdating <TitlePart>((context, part) => { // if altering the title of a taxonomy, save the name if (part.As <TaxonomyPart>() != null) { previousName = part.Title; } }); }
public OptionSetPartHandler( IRepository <OptionSetPartRecord> repository, IOptionSetService optionSetService, IContentDefinitionManager contentDefinitionManager) { int?previousId = null; Filters.Add(StorageFilter.For(repository)); OnPublished <OptionSetPart>((context, part) => { var previousTermTypeName = part.TermTypeName; if (previousId != null && part.Id != previousId) { // remove previous term type contentDefinitionManager.DeleteTypeDefinition(previousTermTypeName); // update existing fields foreach (var partDefinition in contentDefinitionManager.ListPartDefinitions()) { foreach (var field in partDefinition.Fields) { if (field.FieldDefinition.Name == typeof(OptionSetField).Name) { if (field.Settings.GetModel <OptionSetFieldSettings>().OptionSetId == previousId) { contentDefinitionManager.AlterPartDefinition(partDefinition.Name, cfg => cfg.WithField(field.Name, builder => builder.WithSetting("TaxonomyFieldSettings.TaxonomyId", part.Id.ToString()))); } } } } } }); OnLoading <OptionSetPart>((context, part) => part.OptionItemsField.Loader(x => optionSetService.GetOptionItems(part.Id))); OnUpdating <TitlePart>((context, part) => { // if altering the title of a taxonomy, save the name if (part.As <OptionSetPart>() != null) { previousId = part.Id; } }); }
public void Describe(DescribeFilterContext describe) { foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { if (!part.Fields.Any()) { continue; } var descriptor = describe.For(part.Name + "ContentFields", T("{0} Content Fields", part.Name.CamelFriendly()), T("Content Fields for {0}", part.Name.CamelFriendly())); foreach (var field in part.Fields) { var localField = field; var localPart = part; var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == localField.FieldDefinition.Name)).ToList(); var membersContext = new DescribeMembersContext( (storageName, storageType, displayName, description) => { // look for a compatible field type editor IConcreteFieldTypeEditor concreteFieldTypeEditor = _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(localField.FieldDefinition.Name, storageType)) ?? _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(storageType)); IFieldTypeEditor fieldTypeEditor = concreteFieldTypeEditor; if (fieldTypeEditor == null) { return; } descriptor.Element( type: localPart.Name + "." + localField.Name + "." + storageName, name: new LocalizedString(localField.DisplayName + (displayName != null ? ":" + displayName.Text : "")), description: description ?? T("{0} property for {1}", storageName, localField.DisplayName), filter: context => concreteFieldTypeEditor.ApplyFilter(context, storageName, storageType, localPart, localField), display: context => fieldTypeEditor.DisplayFilter(localPart.Name.CamelFriendly() + "." + localField.DisplayName, storageName, context.State), form: fieldTypeEditor.FormName); }); foreach (var driver in drivers) { driver.Describe(membersContext); } } } }
public TaxonomyPartHandler( IRepository<TaxonomyPartRecord> repository, ITaxonomyService taxonomyService, IContentDefinitionManager contentDefinitionManager) { string previousName = null; Filters.Add(StorageFilter.For(repository)); OnPublished<TaxonomyPart>((context, part) => { var previousTermTypeName = part.TermTypeName; if (previousName == null || part.Name == previousName) { // is it a new taxonomy ? taxonomyService.CreateTermContentType(part); } else { // keep the previous term type name as it would otherwise force us // to update all terms to use another type part.TermTypeName = previousTermTypeName; // update existing fields foreach (var partDefinition in contentDefinitionManager.ListPartDefinitions()) { foreach (var field in partDefinition.Fields) { if (field.FieldDefinition.Name == typeof (TaxonomyField).Name) { if (field.Settings.GetModel<TaxonomyFieldSettings>().Taxonomy == previousName) { contentDefinitionManager.AlterPartDefinition(partDefinition.Name, cfg => cfg.WithField(field.Name, builder => builder.WithSetting("TaxonomyFieldSettings.Taxonomy", part.Name))); } } } } } }); OnLoading<TaxonomyPart>( (context, part) => part.TermsField.Loader(x => taxonomyService.GetTerms(part.Id))); OnUpdating<TitlePart>((context, part) => { // if altering the title of a taxonomy, save the name if (part.As<TaxonomyPart>() != null) { previousName = part.Title; } }); }
public void Describe(DescribeFilterContext describe) { foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { if (!part.Fields.Any()) { continue; } var descriptor = describe.For(part.Name + "ContentFieldsNullSafe", T("{0} Content Fields (null-safe)", part.Name.CamelFriendly()), T("Content Fields for {0} (null-safe).", part.Name.CamelFriendly())); foreach (var field in part.Fields) { var localField = field; var localPart = part; var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == localField.FieldDefinition.Name)).ToList(); var membersContext = new DescribeMembersContext((storageName, storageType, displayName, description) => { // Look for a compatible field type editor. IFieldTypeEditor fieldTypeEditor = _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(storageType)); if (fieldTypeEditor == null) { return; } descriptor.Element( type: localPart.Name + "." + localField.Name + "." + storageName, name: new LocalizedString(localField.DisplayName + (displayName != null ? ":" + displayName.Text : "") + " (null-safe)"), description: new LocalizedString(description != null ? description + " (null-safe)" : "No filter will be applied if the filter value is empty, so items indexed as null in the database won't be excluded from the result."), filter: context => ApplyFilter(context, fieldTypeEditor, storageName, storageType, localPart, localField), display: context => fieldTypeEditor.DisplayFilter(localPart.Name + "." + localField.DisplayName, storageName, context.State), form: fieldTypeEditor.FormName); }); foreach (var driver in drivers) { driver.Describe(membersContext); } } } }
public OptionSetPartHandler( IRepository<OptionSetPartRecord> repository, IOptionSetService optionSetService, IContentDefinitionManager contentDefinitionManager) { int? previousId = null; Filters.Add(StorageFilter.For(repository)); OnPublished<OptionSetPart>((context, part) => { var previousTermTypeName = part.TermTypeName; if (previousId != null && part.Id != previousId) { // remove previous term type contentDefinitionManager.DeleteTypeDefinition(previousTermTypeName); // update existing fields foreach (var partDefinition in contentDefinitionManager.ListPartDefinitions()) { foreach (var field in partDefinition.Fields) { if (field.FieldDefinition.Name == typeof (OptionSetField).Name) { if (field.Settings.GetModel<OptionSetFieldSettings>().OptionSetId == previousId) { contentDefinitionManager.AlterPartDefinition(partDefinition.Name, cfg => cfg.WithField(field.Name, builder => builder.WithSetting("TaxonomyFieldSettings.TaxonomyId", part.Id.ToString()))); } } } } } }); OnLoading<OptionSetPart>((context, part) => part.OptionItemsField.Loader(x => optionSetService.GetOptionItems(part.Id))); OnUpdating<TitlePart>((context, part) => { // if altering the title of a taxonomy, save the name if (part.As<OptionSetPart>() != null) { previousId = part.Id; } }); }
// Migration content part definitions. // This code can be removed in a later version. public int UpdateFrom4() { var partDefinitions = _contentDefinitionManager.ListPartDefinitions(); foreach (var partDefinition in partDefinitions) { var existingPartSettings = partDefinition.Settings.ToObject <ContentPartSettings>(); // Do this before creating builder, so settings are removed from the builder settings object. // Remove existing properties from JObject var contentTypeSettingsProperties = existingPartSettings.GetType().GetProperties(); foreach (var property in contentTypeSettingsProperties) { partDefinition.Settings.Remove(property.Name); } _contentDefinitionManager.AlterPartDefinition(partDefinition.Name, partBuilder => { partBuilder.WithSettings(existingPartSettings); foreach (var fieldDefinition in partDefinition.Fields) { var existingFieldSettings = fieldDefinition.Settings.ToObject <ContentPartFieldSettings>(); // Do this before creating builder, so settings are removed from the builder settings object. // Remove existing properties from JObject var fieldSettingsProperties = existingFieldSettings.GetType().GetProperties(); foreach (var property in fieldSettingsProperties) { fieldDefinition.Settings.Remove(property.Name); } partBuilder.WithField(fieldDefinition.Name, fieldBuilder => { fieldBuilder.WithSettings(existingFieldSettings); }); } }); } return(5); }
/// <summary> /// Migrate existing ContentField settings to WithSettings<typeparamref name="TSettings"/> /// This method will be removed in a future release. /// </summary> /// <typeparam name="TField"></typeparam> /// <typeparam name="TSettings"></typeparam> /// <param name="manager"></param> public static void MigrateFieldSettings <TField, TSettings>(this IContentDefinitionManager manager) where TField : ContentField where TSettings : class { var partDefinitions = manager.ListPartDefinitions(); foreach (var partDefinition in partDefinitions) { manager.AlterPartDefinition(partDefinition.Name, partBuilder => { foreach (var fieldDefinition in partDefinition.Fields.Where(x => x.FieldDefinition.Name == typeof(TField).Name)) { var existingFieldSettings = fieldDefinition.Settings.ToObject <TSettings>(); // Do this before creating builder, so settings are removed from the builder settings object. // Remove existing properties from JObject var fieldSettingsProperties = existingFieldSettings.GetType().GetProperties(); var hasSetting = false; foreach (var property in fieldSettingsProperties) { if (fieldDefinition.Settings.ContainsKey(property.Name)) { hasSetting = true; fieldDefinition.Settings.Remove(property.Name); } } // Only include settings if the definition already has at least one of these settings. if (hasSetting) { partBuilder.WithField(fieldDefinition.Name, fieldBuilder => { fieldBuilder.WithSettings(existingFieldSettings); }); } } }); } }
public TaxonomyPartHandler( IRepository <TaxonomyPartRecord> repository, ITaxonomyService taxonomyService, IContentDefinitionManager contentDefinitionManager, ILocalizationService localizationService = null) //Localization feature may not be active { string previousName = null; Filters.Add(StorageFilter.For(repository)); OnPublished <TaxonomyPart>((context, part) => { if (string.IsNullOrWhiteSpace(part.TermTypeName)) { // is it a new taxonomy ? taxonomyService.CreateTermContentType(part); } else { // update existing fields foreach (var partDefinition in contentDefinitionManager.ListPartDefinitions()) { foreach (var field in partDefinition.Fields) { if (field.FieldDefinition.Name == typeof(TaxonomyField).Name) { if (field.Settings.GetModel <TaxonomyFieldSettings>().Taxonomy == previousName) { //could either be a name change, or we could be publishing a translation if (localizationService != null) //Localization feature may not be active { var locPart = part.ContentItem.As <LocalizationPart>(); if (locPart != null) { var localizedTaxonomies = localizationService .GetLocalizations(part.ContentItem) //versions in all cultures .Where(pa => pa.ContentItem.Id != part.ContentItem.Id) //but not the one we are publishing .Select(pa => { var tax = pa.ContentItem.As <TaxonomyPart>(); //the TaxonomyPart return(tax == null ? string.Empty : tax.Name); //get its name (with sanity check) }); if (localizedTaxonomies.Contains(previousName)) { continue; //this is a new localization, so move along } } } contentDefinitionManager.AlterPartDefinition(partDefinition.Name, cfg => cfg.WithField(field.Name, builder => builder.WithSetting("TaxonomyFieldSettings.Taxonomy", part.Name))); } } } } } }); OnLoading <TaxonomyPart>((context, part) => part.TermsField.Loader(() => taxonomyService.GetTerms(part.Id))); OnUpdating <TitlePart>((context, part) => { // if altering the title of a taxonomy, save the name if (part.As <TaxonomyPart>() != null) { previousName = part.Title; } }); }
public void Describe(DescribeGroupByContext describe) { foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { if (!part.Fields.Any()) { continue; } var descriptor = describe.For(part.Name + "ContentFields", T("{0} Content Fields", part.Name.CamelFriendly()), T("Content Fields for {0}", part.Name.CamelFriendly())); foreach (var field in part.Fields) { var localField = field; var localPart = part; var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == localField.FieldDefinition.Name)).ToList(); var membersContext = new DescribeMembersContext( (storageName, storageType, displayName, description) => { // look for a compatible field type editor IFieldTypeEditor fieldTypeEditor = _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(storageType)); if (fieldTypeEditor == null) { return; } if (localField.FieldDefinition.Name == "NumericField") { this.DescribeNumericFieldMemberContext( localField: localField, description: description, storageName: storageName, descriptor: descriptor, displayName: displayName, fieldTypeEditor: fieldTypeEditor, localPart: localPart); } else if (localField.FieldDefinition.Name == "EnumerationField") { //field.FieldDefinition.Name List <AggregateMethods> methods = new List <AggregateMethods>(); methods.Add(AggregateMethods.Count); descriptor.Element( type: localPart.Name + "." + localField.Name + "." + storageName, name: T(localField.DisplayName), description: T("group the result by {0} values", localField.DisplayName), run: (query, method) => this.fieldAggregateQueryService.RunEnumerationAggregation(query, method, localField.Name, localPart.Name), aggregateMethods: methods, display: context => fieldTypeEditor.DisplayFilter(localPart.Name.CamelFriendly() + "." + localField.DisplayName, storageName, context.State)); } }); foreach (var driver in drivers) { driver.Describe(membersContext); } } } }
public void Process(DocumentProcessorContext context) { if (!_openApiOptions.ContentTypes.ProcessContentTypes) { return; } _contentDefinitionManager ??= _httpContextAccessor.HttpContext.RequestServices.GetRequiredService <IContentDefinitionManager>(); var contentElementDtoSchema = context.SchemaGenerator.Generate(typeof(ContentElementDto), context.SchemaResolver); // Due to issue with NJsonSchema we force set additional properties here to false // because it is defined on the base class. // cf. https://github.com/RicoSuter/NSwag/issues/2818 contentElementDtoSchema.AllowAdditionalProperties = false; var fieldDtoSchema = context.SchemaGenerator.Generate(typeof(ContentFieldDto), context.SchemaResolver); fieldDtoSchema.AllowAdditionalProperties = false; var ctds = _contentDefinitionManager.ListTypeDefinitions(); var allFieldDefinitions = ctds .SelectMany(x => x.Parts.SelectMany(p => p.PartDefinition.Fields)) .Select(x => x.FieldDefinition).ToLookup(x => x.Name, StringComparer.OrdinalIgnoreCase); // Process fields foreach (var contentFieldOption in _contentOptions.ContentFieldOptions) { if (!_openApiOptions.ContentTypes.IncludeAllFields) { if (!allFieldDefinitions.Contains(contentFieldOption.Type.Name)) { continue; } } if (_openApiOptions.ContentTypes.ExcludedFields.Any(x => string.Equals(x, contentFieldOption.Type.Name, StringComparison.OrdinalIgnoreCase))) { continue; } var fieldSchema = context.SchemaGenerator.Generate(contentFieldOption.Type, context.SchemaResolver); fieldSchema.AllOf.ElementAt(1).AllowAdditionalProperties = false; // remove first AllOf and reinsert the fieldDtoSchema as the ref. InsertDtoReferenceSchema(fieldSchema, fieldDtoSchema); // Change schema regisitration name to 'TextFieldDto' AlterSchemaDefinition(context, contentFieldOption.Type.Name, _openApiOptions.ContentTypes.SchemaNameExtension); } // Process Parts // Note we have to use the content definition manager here // because parts may be created dynamically. // We also include definitions for code only parts, like ContainedPart var contentItemSchema = context.SchemaResolver.GetSchema(typeof(ContentItem), false); // This should end up being ignored, because we remove it from the nswag.config var contentItemDtoSchema = context.SchemaGenerator.Generate(typeof(ContentItemDto), context.SchemaResolver); contentItemDtoSchema.AllowAdditionalProperties = false; //var contentItemDtoSchema = context.Document.Definitions["ContentItemDto"]; var partDtoSchema = context.SchemaGenerator.Generate(typeof(ContentPartDto), context.SchemaResolver); partDtoSchema.AllowAdditionalProperties = false; var allPartDefinitions = _contentDefinitionManager.ListPartDefinitions(); // Register code only parts first. foreach (var registeredPartOption in _contentOptions.ContentPartOptions) { // Is also registered in the part definitions. if (allPartDefinitions.Any(x => x.Name == registeredPartOption.Type.Name)) { continue; } // Has no fields as it is code only var partSchema = context.SchemaGenerator.Generate(registeredPartOption.Type, context.SchemaResolver); partSchema.AllOf.ElementAt(1).AllowAdditionalProperties = false; // remove first AllOf and reinsert the partDtoSchema as the ref. InsertDtoReferenceSchema(partSchema, partDtoSchema); // Use ActualProperties here, not Properties AlterArrayPropertiesToContentItemDtoSchema(partSchema.ActualProperties, contentItemSchema, contentItemDtoSchema); // Change schema regisitration name to 'ContainedPartDto' AlterSchemaDefinition(context, registeredPartOption.Type.Name, _openApiOptions.ContentTypes.SchemaNameExtension); } // Then register parts defined in the part definitions. foreach (var partDefinition in allPartDefinitions) { // check to see if it is a hard typed part. if (_contentOptions.ContentPartOptionsLookup.TryGetValue(partDefinition.Name, out var contentPartOption)) { var partSchema = context.SchemaGenerator.Generate(contentPartOption.Type, context.SchemaResolver); partSchema.AllOf.ElementAt(1).AllowAdditionalProperties = false; // remove first AllOf and reinsert the partDtoSchema as the ref. InsertDtoReferenceSchema(partSchema, partDtoSchema); //TODO test this, it's being added as a direct property // but the other properties are added as part of all of // so we might need to find all of index 1 and insert it there foreach (var field in partDefinition.Fields) { // Lookup field definition. if (context.Document.Definitions.TryGetValue(field.FieldDefinition.Name + _openApiOptions.ContentTypes.SchemaNameExtension, out var fieldSchema)) { // Add field as property. var propertySchema = new JsonSchemaProperty { Type = JsonObjectType.Object, IsNullableRaw = true }; propertySchema.OneOf.Add(new JsonSchema { Type = JsonObjectType.Object, Reference = fieldSchema.ActualSchema }); partSchema.Properties[field.Name] = propertySchema; } } foreach (var allOfSchema in partSchema.AllOf) { AlterArrayPropertiesToContentItemDtoSchema(allOfSchema.ActualProperties, contentItemSchema, contentItemDtoSchema); } // Change schema regisitration name to 'HtmlPartDto' AlterSchemaDefinition(context, contentPartOption.Type.Name, _openApiOptions.ContentTypes.SchemaNameExtension); } else // This builds dynamic parts. { // We need to skip registrations for type definition parts. if (ctds.Any(x => x.Name == partDefinition.Name)) { continue; } var partReferenceSchema = new JsonSchema { Type = JsonObjectType.Object, Reference = partDtoSchema.ActualSchema, AllowAdditionalProperties = false }; var partSchema = new JsonSchema { Type = JsonObjectType.Object, AllowAdditionalProperties = false }; partSchema.AllOf.Add(partReferenceSchema); foreach (var field in partDefinition.Fields) { // Lookup field definition. if (context.Document.Definitions.TryGetValue(field.FieldDefinition.Name + _openApiOptions.ContentTypes.SchemaNameExtension, out var fieldSchema)) { // Add field as property. var propertySchema = new JsonSchemaProperty { Type = JsonObjectType.Object, IsNullableRaw = true }; propertySchema.OneOf.Add(new JsonSchema { Type = JsonObjectType.Object, Reference = fieldSchema.ActualSchema }); partSchema.Properties[field.Name] = propertySchema; } } context.Document.Definitions[partDefinition.Name + _openApiOptions.ContentTypes.SchemaNameExtension] = partSchema; } } // Content Types var typeDtoSchema = context.SchemaGenerator.Generate(typeof(ContentItemDto), context.SchemaResolver); typeDtoSchema.AllowAdditionalProperties = false; typeDtoSchema.ActualTypeSchema.DiscriminatorObject = new OpenApiDiscriminator { //PropertyName = "discriminator", PropertyName = "ContentType", // TODO a custom one of these might help create types automatically. // Particularly useful for Flow.ContentItems etc. JsonInheritanceConverter = new JsonInheritanceConverter("ContentType") }; foreach (var ctd in ctds) { if (_openApiOptions.ContentTypes.ExcludedTypes.Any(x => string.Equals(x, ctd.Name))) { continue; } var typeReferenceSchema = new JsonSchema { Type = JsonObjectType.Object, Reference = typeDtoSchema.ActualSchema, AllowAdditionalProperties = false }; var typeSchema = new JsonSchema { Type = JsonObjectType.Object, AllowAdditionalProperties = false }; typeSchema.AllOf.Add(typeReferenceSchema); var typeFieldPartDefinition = ctd.Parts.FirstOrDefault(x => x.PartDefinition.Name == ctd.Name); // Not all content types will have a 'FieldDefinitionPart' until fields are added. if (typeFieldPartDefinition != null) { // Add Field Part container var partSchema = new JsonSchema { Type = JsonObjectType.Object, AllowAdditionalProperties = false }; var partReferenceSchema = new JsonSchema { Type = JsonObjectType.Object, AllowAdditionalProperties = false, Reference = partDtoSchema.ActualSchema }; partSchema.AllOf.Add(partReferenceSchema); // TODO move to method foreach (var field in typeFieldPartDefinition.PartDefinition.Fields) { // Lookup field definition. if (context.Document.Definitions.TryGetValue(field.FieldDefinition.Name + _openApiOptions.ContentTypes.SchemaNameExtension, out var fieldSchema)) { // Add field as property. var propertySchema = new JsonSchemaProperty { Type = JsonObjectType.Object, IsNullableRaw = true }; propertySchema.OneOf.Add(new JsonSchema { Type = JsonObjectType.Object, Reference = fieldSchema.ActualSchema }); partSchema.Properties[field.Name] = propertySchema; } } // Don't add "Part" here because users often create their own TypePart. context.Document.Definitions[ctd.Name + _openApiOptions.ContentTypes.SchemaNameExtension] = partSchema; // Add fieldpart as property. var typePropertySchema = new JsonSchemaProperty { Type = JsonObjectType.Object, IsNullableRaw = true }; typePropertySchema.OneOf.Add(new JsonSchema { Type = JsonObjectType.Object, Reference = partSchema.ActualSchema }); typeSchema.Properties[typeFieldPartDefinition.Name] = typePropertySchema; } // Add all other parts var parts = ctd.Parts.Where(x => x.PartDefinition.Name != ctd.Name); foreach (var partDefinition in parts) { // Lookup part definition. if (context.Document.Definitions.TryGetValue(partDefinition.PartDefinition.Name + _openApiOptions.ContentTypes.SchemaNameExtension, out var typePartSchema)) { // Add part as property. var propertySchema = new JsonSchemaProperty { Type = JsonObjectType.Object, IsNullableRaw = true }; propertySchema.OneOf.Add(new JsonSchema { Type = JsonObjectType.Object, Reference = typePartSchema.ActualSchema }); typeSchema.Properties[partDefinition.Name] = propertySchema; } } // Add final definition. context.Document.Definitions[ctd.Name + _openApiOptions.ContentTypes.SchemaTypeNameExtension + _openApiOptions.ContentTypes.SchemaNameExtension] = typeSchema; // Add discriminator mappings to actual type schema typeDtoSchema.ActualTypeSchema.DiscriminatorObject.Mapping.Add( ctd.Name + _openApiOptions.ContentTypes.SchemaTypeNameExtension + _openApiOptions.ContentTypes.SchemaNameExtension, new JsonSchema { Reference = typeSchema } ); } }