diff --git a/src/Umbraco.Cms.Api.Common/Attributes/MapToApiAttribute.cs b/src/Umbraco.Cms.Api.Common/Attributes/MapToApiAttribute.cs new file mode 100644 index 0000000000..da326bfd88 --- /dev/null +++ b/src/Umbraco.Cms.Api.Common/Attributes/MapToApiAttribute.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Cms.Api.Common.Attributes; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class MapToApiAttribute : Attribute +{ + public MapToApiAttribute(string apiName) => ApiName = apiName; + + public string ApiName { get; } +} diff --git a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiExplorerOptions.cs b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiExplorerOptions.cs index e6093cf29e..2b9179202b 100644 --- a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiExplorerOptions.cs +++ b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiExplorerOptions.cs @@ -20,6 +20,6 @@ public class ConfigureApiExplorerOptions : IConfigureOptions options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; options.AddApiVersionParametersWhenVersionNeutral = true; - options.AssumeDefaultVersionWhenUnspecified = true; + options.AssumeDefaultVersionWhenUnspecified = false; } } diff --git a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiVersioningOptions.cs b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiVersioningOptions.cs index 928ea3925e..028d731444 100644 --- a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiVersioningOptions.cs +++ b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureApiVersioningOptions.cs @@ -11,7 +11,8 @@ public class ConfigureApiVersioningOptions : IConfigureOptions +public class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions { - private readonly IUmbracoJsonTypeInfoResolver _umbracoJsonTypeInfoResolver; - - public ConfigureUmbracoSwaggerGenOptions(IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver) - { - _umbracoJsonTypeInfoResolver = umbracoJsonTypeInfoResolver; - } - public void Configure(SwaggerGenOptions swaggerGenOptions) { swaggerGenOptions.SwaggerDoc( - ManagementApiConfiguration.DefaultApiDocumentName, + DefaultApiConfiguration.ApiName, new OpenApiInfo { - Title = ManagementApiConfiguration.ApiTitle, - Version = ManagementApiConfiguration.DefaultApiVersion.ToString(), - Description = - "This shows all APIs available in this version of Umbraco - including all the legacy apis that are available for backward compatibility" + Title = "Default API", + Version = "Latest", + Description = "All endpoints not defined under specific APIs" }); - swaggerGenOptions.AddSecurityDefinition( - "OAuth", - new OpenApiSecurityScheme - { - In = ParameterLocation.Header, - Name = "Umbraco", - Type = SecuritySchemeType.OAuth2, - Description = "Umbraco Authentication", - Flows = new OpenApiOAuthFlows - { - AuthorizationCode = new OpenApiOAuthFlow - { - AuthorizationUrl = - new Uri(Paths.BackOfficeApiAuthorizationEndpoint, UriKind.Relative), - TokenUrl = new Uri(Paths.BackOfficeApiTokenEndpoint, UriKind.Relative) - } - } - }); - - swaggerGenOptions.AddSecurityRequirement(new OpenApiSecurityRequirement - { - // this weird looking construct works because OpenApiSecurityRequirement - // is a specialization of Dictionary<,> - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Id = "OAuth", Type = ReferenceType.SecurityScheme } - }, - new List() - } - }); - swaggerGenOptions.CustomOperationIds(CustomOperationId); - swaggerGenOptions.DocInclusionPredicate((_, api) => !string.IsNullOrWhiteSpace(api.GroupName)); + + swaggerGenOptions.DocInclusionPredicate((name, api) => + { + if (string.IsNullOrWhiteSpace(api.GroupName)) + { + return false; + } + + if (api.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) + { + return controllerActionDescriptor.MethodInfo.HasMapToApiAttribute(name); + + } + + return false; + }); swaggerGenOptions.TagActionsBy(api => new[] { api.GroupName }); swaggerGenOptions.OrderActionsBy(ActionOrderBy); swaggerGenOptions.DocumentFilter(); @@ -72,10 +48,11 @@ internal sealed class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions(); + swaggerGenOptions.UseOneOfForPolymorphism(); swaggerGenOptions.UseAllOfForInheritance(); - swaggerGenOptions.SelectSubTypesUsing(_umbracoJsonTypeInfoResolver.FindSubTypes); + + swaggerGenOptions.SelectDiscriminatorNameUsing(type => { @@ -89,7 +66,7 @@ internal sealed class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions x.Name); } - private static string CustomOperationId(ApiDescription api) + private static string CustomOperationId(ApiDescription api) { var httpMethod = api.HttpMethod?.ToLower().ToFirstUpper() ?? "Get"; @@ -127,12 +104,21 @@ internal sealed class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions m.Groups[1].Value.ToUpper()); + //Get map to version attribute + string? version = null; + + if (api.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) + { + version = controllerActionDescriptor.MethodInfo.GetMapToApiVersionAttributeValue(); + } + // Return the operation ID with the formatted http method verb in front, e.g. GetTrackedReferenceById - return $"{httpMethod}{formattedOperationId.ToFirstUpper()}"; + return $"{httpMethod}{formattedOperationId.ToFirstUpper()}{version}"; } - // see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#change-operation-sort-order-eg-for-ui-sorting - private static string ActionOrderBy(ApiDescription apiDesc) - => - $"{apiDesc.GroupName}_{apiDesc.ActionDescriptor.AttributeRouteInfo?.Template ?? apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.ActionDescriptor.RouteValues["action"]}_{apiDesc.HttpMethod}"; + // see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#change-operation-sort-order-eg-for-ui-sorting + private static string ActionOrderBy(ApiDescription apiDesc) + => + $"{apiDesc.GroupName}_{apiDesc.ActionDescriptor.AttributeRouteInfo?.Template ?? apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.ActionDescriptor.RouteValues["action"]}_{apiDesc.HttpMethod}"; + } diff --git a/src/Umbraco.Cms.Api.Common/Configuration/DefaultApiConfiguration.cs b/src/Umbraco.Cms.Api.Common/Configuration/DefaultApiConfiguration.cs new file mode 100644 index 0000000000..64b7419d21 --- /dev/null +++ b/src/Umbraco.Cms.Api.Common/Configuration/DefaultApiConfiguration.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Common.Configuration; + +internal static class DefaultApiConfiguration +{ + public const string ApiName = "default"; +} diff --git a/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderApiExtensions.cs b/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderApiExtensions.cs new file mode 100644 index 0000000000..360bcb7db3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderApiExtensions.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using Umbraco.Cms.Api.Common.Configuration; +using Umbraco.Cms.Api.Common.Serialization; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Web.Common.ApplicationBuilder; +using Umbraco.Extensions; +using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; + +namespace Umbraco.Cms.Api.Common.DependencyInjection; + +public static class UmbracoBuilderApiExtensions +{ + public static IUmbracoBuilder AddUmbracoApiOpenApiUI(this IUmbracoBuilder builder) + { + builder.Services.ConfigureOptions(); + builder.Services.AddApiVersioning(); + builder.Services.ConfigureOptions(); + builder.Services.AddVersionedApiExplorer(); + + builder.Services.AddSwaggerGen(); + builder.Services.ConfigureOptions(); + builder.Services.AddSingleton(); + + builder.Services.Configure(options => + { + options.AddFilter(new UmbracoPipelineFilter( + "UmbracoApiCommon", + applicationBuilder => + { + + }, + applicationBuilder => + { + IServiceProvider provider = applicationBuilder.ApplicationServices; + IWebHostEnvironment webHostEnvironment = provider.GetRequiredService(); + IOptions swaggerGenOptions = provider.GetRequiredService>(); + + + if (!webHostEnvironment.IsProduction()) + { + GlobalSettings? settings = provider.GetRequiredService>().Value; + IHostingEnvironment hostingEnvironment = provider.GetRequiredService(); + var umbracoPath = settings.GetBackOfficePath(hostingEnvironment); + + applicationBuilder.UseSwagger(swaggerOptions => + { + swaggerOptions.RouteTemplate = + $"{umbracoPath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json"; + }); + applicationBuilder.UseSwaggerUI( + swaggerUiOptions => + { + swaggerUiOptions.RoutePrefix = $"{umbracoPath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger"; + + foreach ((var name, OpenApiInfo? apiInfo) in swaggerGenOptions.Value.SwaggerGeneratorOptions.SwaggerDocs.OrderBy(x=>x.Value.Title)) + { + swaggerUiOptions.SwaggerEndpoint($"{name}/swagger.json", $"{apiInfo.Title}"); + } + }); + } + }, + applicationBuilder => + { + + })); + }); + + return builder; + } +} diff --git a/src/Umbraco.Cms.Api.Common/Extensions/MethodInfoApiCommonExtensions.cs b/src/Umbraco.Cms.Api.Common/Extensions/MethodInfoApiCommonExtensions.cs new file mode 100644 index 0000000000..3e72c097aa --- /dev/null +++ b/src/Umbraco.Cms.Api.Common/Extensions/MethodInfoApiCommonExtensions.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.Attributes; +using Umbraco.Cms.Api.Common.Configuration; + +namespace Umbraco.Extensions; + +public static class MethodInfoApiCommonExtensions +{ + + public static string? GetMapToApiVersionAttributeValue(this MethodInfo methodInfo) + { + MapToApiVersionAttribute[] mapToApis = methodInfo.GetCustomAttributes(typeof(MapToApiVersionAttribute), inherit: true).Cast().ToArray(); + + return string.Join("|", mapToApis.SelectMany(x=>x.Versions)); + } + + public static string? GetMapToApiAttributeValue(this MethodInfo methodInfo) + { + MapToApiAttribute[] mapToApis = (methodInfo.DeclaringType?.GetCustomAttributes(typeof(MapToApiAttribute), inherit: true) ?? Array.Empty()).Cast().ToArray(); + + return mapToApis.SingleOrDefault()?.ApiName; + } + + public static bool HasMapToApiAttribute(this MethodInfo methodInfo, string apiName) + { + var value = methodInfo.GetMapToApiAttributeValue(); + + return value == apiName + || (value is null && apiName == DefaultApiConfiguration.ApiName); + } +} diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/EnumSchemaFilter.cs b/src/Umbraco.Cms.Api.Common/OpenApi/EnumSchemaFilter.cs similarity index 93% rename from src/Umbraco.Cms.Api.Management/OpenApi/EnumSchemaFilter.cs rename to src/Umbraco.Cms.Api.Common/OpenApi/EnumSchemaFilter.cs index df78dc080d..fcd5ba8ccc 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/EnumSchemaFilter.cs +++ b/src/Umbraco.Cms.Api.Common/OpenApi/EnumSchemaFilter.cs @@ -4,7 +4,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Umbraco.Cms.Api.Management.OpenApi; +namespace Umbraco.Cms.Api.Common.OpenApi; public class EnumSchemaFilter : ISchemaFilter { diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/MimeTypeDocumentFilter.cs b/src/Umbraco.Cms.Api.Common/OpenApi/MimeTypeDocumentFilter.cs similarity index 96% rename from src/Umbraco.Cms.Api.Management/OpenApi/MimeTypeDocumentFilter.cs rename to src/Umbraco.Cms.Api.Common/OpenApi/MimeTypeDocumentFilter.cs index b9d4f2e364..c1acfdadf1 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/MimeTypeDocumentFilter.cs +++ b/src/Umbraco.Cms.Api.Common/OpenApi/MimeTypeDocumentFilter.cs @@ -2,7 +2,7 @@ using Swashbuckle.AspNetCore.SwaggerGen; using Umbraco.Extensions; -namespace Umbraco.Cms.Api.Management.OpenApi; +namespace Umbraco.Cms.Api.Common.OpenApi; /// /// This filter explicitly removes all other mime types than application/json from the produced OpenAPI document when application/json is accepted. diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/OperationIdRegexes.cs b/src/Umbraco.Cms.Api.Common/OpenApi/OperationIdRegexes.cs similarity index 94% rename from src/Umbraco.Cms.Api.Management/OpenApi/OperationIdRegexes.cs rename to src/Umbraco.Cms.Api.Common/OpenApi/OperationIdRegexes.cs index 4b764ceaa3..60a114c218 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/OperationIdRegexes.cs +++ b/src/Umbraco.Cms.Api.Common/OpenApi/OperationIdRegexes.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; -namespace Umbraco.Cms.Api.Management.OpenApi; +namespace Umbraco.Cms.Api.Common.OpenApi; /// /// This is the regexes used to generate the operation IDs, the benefit of this being partial with GeneratedRegex diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/SchemaIdGenerator.cs b/src/Umbraco.Cms.Api.Common/OpenApi/SchemaIdGenerator.cs similarity index 96% rename from src/Umbraco.Cms.Api.Management/OpenApi/SchemaIdGenerator.cs rename to src/Umbraco.Cms.Api.Common/OpenApi/SchemaIdGenerator.cs index eba4e06135..b2a76cde53 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/SchemaIdGenerator.cs +++ b/src/Umbraco.Cms.Api.Common/OpenApi/SchemaIdGenerator.cs @@ -1,7 +1,7 @@ using System.Text.RegularExpressions; using Umbraco.Extensions; -namespace Umbraco.Cms.Api.Management.OpenApi; +namespace Umbraco.Cms.Api.Common.OpenApi; internal static class SchemaIdGenerator { diff --git a/src/Umbraco.Infrastructure/Serialization/IUmbracoJsonTypeInfoResolver.cs b/src/Umbraco.Cms.Api.Common/Serialization/IUmbracoJsonTypeInfoResolver.cs similarity index 76% rename from src/Umbraco.Infrastructure/Serialization/IUmbracoJsonTypeInfoResolver.cs rename to src/Umbraco.Cms.Api.Common/Serialization/IUmbracoJsonTypeInfoResolver.cs index 1aecc6c2ec..009f05e4e4 100644 --- a/src/Umbraco.Infrastructure/Serialization/IUmbracoJsonTypeInfoResolver.cs +++ b/src/Umbraco.Cms.Api.Common/Serialization/IUmbracoJsonTypeInfoResolver.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization.Metadata; -namespace Umbraco.Cms.Infrastructure.Serialization; +namespace Umbraco.Cms.Api.Common.Serialization; public interface IUmbracoJsonTypeInfoResolver : IJsonTypeInfoResolver { diff --git a/src/Umbraco.Infrastructure/Serialization/UmbracoJsonTypeInfoResolver.cs b/src/Umbraco.Cms.Api.Common/Serialization/UmbracoJsonTypeInfoResolver.cs similarity index 98% rename from src/Umbraco.Infrastructure/Serialization/UmbracoJsonTypeInfoResolver.cs rename to src/Umbraco.Cms.Api.Common/Serialization/UmbracoJsonTypeInfoResolver.cs index 02180322ee..8ce1955a2b 100644 --- a/src/Umbraco.Infrastructure/Serialization/UmbracoJsonTypeInfoResolver.cs +++ b/src/Umbraco.Cms.Api.Common/Serialization/UmbracoJsonTypeInfoResolver.cs @@ -3,7 +3,7 @@ using System.Text.Json; using System.Text.Json.Serialization.Metadata; using Umbraco.Cms.Core.Composing; -namespace Umbraco.Cms.Infrastructure.Serialization; +namespace Umbraco.Cms.Api.Common.Serialization; public sealed class UmbracoJsonTypeInfoResolver : DefaultJsonTypeInfoResolver, IUmbracoJsonTypeInfoResolver { diff --git a/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj b/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj index f979fbd49b..08f4ec69f8 100644 --- a/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj +++ b/src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj @@ -11,8 +11,11 @@ + + + diff --git a/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoDeliveryApiSwaggerGenOptions.cs b/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoDeliveryApiSwaggerGenOptions.cs new file mode 100644 index 0000000000..c61a5aad80 --- /dev/null +++ b/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoDeliveryApiSwaggerGenOptions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Umbraco.Cms.Api.Delivery.Configuration; + +public class ConfigureUmbracoDeliveryApiSwaggerGenOptions: IConfigureOptions +{ + public void Configure(SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SwaggerDoc( + DeliveryApiConfiguration.ApiName, + new OpenApiInfo + { + Title = DeliveryApiConfiguration.ApiTitle, + Version = "Latest", + }); + } +} diff --git a/src/Umbraco.Cms.Api.Delivery/Configuration/DeliveryApiConfiguration.cs b/src/Umbraco.Cms.Api.Delivery/Configuration/DeliveryApiConfiguration.cs new file mode 100644 index 0000000000..4f0fc17fa9 --- /dev/null +++ b/src/Umbraco.Cms.Api.Delivery/Configuration/DeliveryApiConfiguration.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Delivery.Configuration; + +internal static class DeliveryApiConfiguration +{ + internal const string ApiTitle = "Umbraco Delivery API"; + + internal const string ApiName = "delivery"; +} diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/DeliveryApiControllerBase.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/DeliveryApiControllerBase.cs index 323211726b..a939c816a5 100644 --- a/src/Umbraco.Cms.Api.Delivery/Controllers/DeliveryApiControllerBase.cs +++ b/src/Umbraco.Cms.Api.Delivery/Controllers/DeliveryApiControllerBase.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.Attributes; using Umbraco.Cms.Api.Common.Filters; +using Umbraco.Cms.Api.Delivery.Configuration; using Umbraco.Cms.Api.Delivery.Filters; using Umbraco.Cms.Core; @@ -10,6 +12,7 @@ namespace Umbraco.Cms.Api.Delivery.Controllers; [DeliveryApiAccess] [JsonOptionsName(Constants.JsonOptionsNames.DeliveryApi)] [LocalizeFromAcceptLanguageHeader] +[MapToApi(DeliveryApiConfiguration.ApiName)] public abstract class DeliveryApiControllerBase : Controller { } diff --git a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs index 6f2ed5a2a3..b6e52ada7c 100644 --- a/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Api.Common.Configuration; using Umbraco.Cms.Api.Common.DependencyInjection; using Umbraco.Cms.Api.Delivery.Accessors; +using Umbraco.Cms.Api.Delivery.Configuration; using Umbraco.Cms.Api.Delivery.Json; using Umbraco.Cms.Api.Delivery.Rendering; using Umbraco.Cms.Api.Delivery.Services; @@ -28,10 +29,8 @@ public static class UmbracoBuilderExtensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.ConfigureOptions(); - builder.Services.AddApiVersioning(); - builder.Services.ConfigureOptions(); - builder.Services.AddVersionedApiExplorer(); + builder.Services.ConfigureOptions(); + builder.AddUmbracoApiOpenApiUI(); builder .Services diff --git a/src/Umbraco.Cms.Api.Management/Configuration/ConfigureUmbracoManagementApiSwaggerGenOptions.cs b/src/Umbraco.Cms.Api.Management/Configuration/ConfigureUmbracoManagementApiSwaggerGenOptions.cs new file mode 100644 index 0000000000..4279b27992 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Configuration/ConfigureUmbracoManagementApiSwaggerGenOptions.cs @@ -0,0 +1,67 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using Umbraco.Cms.Api.Common.Serialization; +using Umbraco.Cms.Api.Management.Controllers.Security; +using Umbraco.Cms.Api.Management.DependencyInjection; +using Umbraco.Cms.Api.Management.OpenApi; + +namespace Umbraco.Cms.Api.Management.Configuration; + +public class ConfigureUmbracoManagementApiSwaggerGenOptions : IConfigureOptions +{ + private IUmbracoJsonTypeInfoResolver _umbracoJsonTypeInfoResolver; + + public ConfigureUmbracoManagementApiSwaggerGenOptions(IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver) + { + _umbracoJsonTypeInfoResolver = umbracoJsonTypeInfoResolver; + } + + public void Configure(SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SwaggerDoc( + ManagementApiConfiguration.ApiName, + new OpenApiInfo + { + Title = ManagementApiConfiguration.ApiTitle, + Version = "Latest", + Description = "This shows all APIs available in this version of Umbraco - including all the legacy apis that are available for backward compatibility", + }); + + swaggerGenOptions.OperationFilter(); + swaggerGenOptions.SelectSubTypesUsing(_umbracoJsonTypeInfoResolver.FindSubTypes); + + swaggerGenOptions.AddSecurityDefinition( + "OAuth", + new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Name = "Umbraco", + Type = SecuritySchemeType.OAuth2, + Description = "Umbraco Authentication", + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = + new Uri(Paths.BackOfficeApiAuthorizationEndpoint, UriKind.Relative), + TokenUrl = new Uri(Paths.BackOfficeApiTokenEndpoint, UriKind.Relative) + } + } + }); + + swaggerGenOptions.AddSecurityRequirement(new OpenApiSecurityRequirement + { + // this weird looking construct works because OpenApiSecurityRequirement + // is a specialization of Dictionary<,> + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Id = "OAuth", Type = ReferenceType.SecurityScheme } + }, + new List() + } + }); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/ManagementApiControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/ManagementApiControllerBase.cs index 971d3faa63..ded3ffaba4 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/ManagementApiControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/ManagementApiControllerBase.cs @@ -1,11 +1,14 @@ using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.Attributes; using Umbraco.Cms.Api.Common.Filters; +using Umbraco.Cms.Api.Management.DependencyInjection; using Umbraco.Cms.Core.Security; using Umbraco.New.Cms.Core; namespace Umbraco.Cms.Api.Management.Controllers; +[MapToApi(ManagementApiConfiguration.ApiName)] [JsonOptionsName(Constants.JsonOptionsNames.BackOffice)] public class ManagementApiControllerBase : Controller { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs index 807bf6ead0..36459f1e09 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs @@ -8,7 +8,7 @@ using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.RecycleBin; -public abstract class RecycleBinControllerBase : Controller +public abstract class RecycleBinControllerBase : ManagementApiControllerBase where TItem : RecycleBinItemResponseModel, new() { private readonly IEntityService _entityService; diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApiVersioningBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApiVersioningBuilderExtensions.cs deleted file mode 100644 index fa6ca98367..0000000000 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApiVersioningBuilderExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Versioning; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Cms.Api.Management.DependencyInjection; - -internal static class ApiVersioningBuilderExtensions -{ - internal static IUmbracoBuilder AddApiVersioning(this IUmbracoBuilder builder) - { - builder.Services.AddApiVersioning(options => - { - options.DefaultApiVersion = ManagementApiConfiguration.DefaultApiVersion; - options.ReportApiVersions = true; - options.ApiVersionReader = new UrlSegmentApiVersionReader(); - options.AssumeDefaultVersionWhenUnspecified = true; - options.UseApiBehavior = false; - }); - - builder.Services.AddVersionedApiExplorer(options => - { - options.DefaultApiVersion = ManagementApiConfiguration.DefaultApiVersion; - options.GroupNameFormat = "'v'VVV"; - options.SubstituteApiVersionInUrl = true; - options.AddApiVersionParametersWhenVersionNeutral = true; - options.AssumeDefaultVersionWhenUnspecified = true; - }); - - return builder; - } -} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs index 173c8eecf6..e7ce795dd5 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs @@ -52,37 +52,6 @@ internal static class ApplicationBuilderExtensions })); }); - internal static IApplicationBuilder UseSwagger(this IApplicationBuilder applicationBuilder) - { - IServiceProvider provider = applicationBuilder.ApplicationServices; - IWebHostEnvironment webHostEnvironment = provider.GetRequiredService(); - - if (webHostEnvironment.IsProduction()) - { - return applicationBuilder; - } - - GlobalSettings settings = provider.GetRequiredService>().Value; - IHostingEnvironment hostingEnvironment = provider.GetRequiredService(); - var backOfficePath = settings.GetBackOfficePath(hostingEnvironment); - - applicationBuilder.UseSwagger(swaggerOptions => - { - swaggerOptions.RouteTemplate = $"{backOfficePath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json"; - }); - applicationBuilder.UseSwaggerUI( - swaggerUiOptions => - { - swaggerUiOptions.SwaggerEndpoint($"{backOfficePath}/swagger/v1/swagger.json", $"{ManagementApiConfiguration.ApiTitle} {ManagementApiConfiguration.DefaultApiVersion}"); - swaggerUiOptions.RoutePrefix = $"{backOfficePath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger"; - - swaggerUiOptions.OAuthClientId(New.Cms.Core.Constants.OauthClientIds.Swagger); - swaggerUiOptions.OAuthUsePkce(); - }); - - return applicationBuilder; - } - internal static IApplicationBuilder UseEndpoints(this IApplicationBuilder applicationBuilder) { IServiceProvider provider = applicationBuilder.ApplicationServices; diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiBuilderExtensions.cs deleted file mode 100644 index 36f21e98c9..0000000000 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiBuilderExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; -using Umbraco.Cms.Api.Management.Controllers.Dictionary; -using Umbraco.Cms.Api.Management.Controllers.Security; -using Umbraco.Cms.Api.Management.OpenApi; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Api.Management.DependencyInjection; - -internal static class ManagementApiBuilderExtensions -{ - internal static IUmbracoBuilder AddSwaggerGen(this IUmbracoBuilder builder) - { - builder.Services.AddSwaggerGen(); - builder.Services.ConfigureOptions(); - builder.Services.AddSingleton(); - - - return builder; - } -} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs index 2bda069414..06cf731861 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs @@ -4,9 +4,7 @@ namespace Umbraco.Cms.Api.Management.DependencyInjection; internal static class ManagementApiConfiguration { - internal const string ApiTitle = "Umbraco Backoffice API"; + internal const string ApiTitle = "Umbraco Management API"; - internal const string DefaultApiDocumentName = "v1"; - - internal static ApiVersion DefaultApiVersion => new(1, 0); + internal const string ApiName = "management"; } diff --git a/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs b/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs index d62d8028af..198e1a86e3 100644 --- a/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs +++ b/src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs @@ -4,6 +4,7 @@ using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Api.Common.Configuration; using Umbraco.Cms.Api.Common.DependencyInjection; +using Umbraco.Cms.Api.Management.Configuration; using Umbraco.Cms.Api.Management.DependencyInjection; using Umbraco.Cms.Api.Management.Serialization; using Umbraco.Cms.Web.Common.ApplicationBuilder; @@ -46,21 +47,11 @@ public class ManagementApiComposer : IComposer .AddUserGroups() .AddPackages() .AddEntitys() - .AddBackOfficeAuthentication() - .AddApiVersioning() - .AddSwaggerGen(); + .AddBackOfficeAuthentication(); services .ConfigureOptions() .ConfigureOptions() - .Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter( - "BackOfficeManagementApiFilter", - applicationBuilder => applicationBuilder.UseProblemDetailsExceptionHandling(), - applicationBuilder => applicationBuilder.UseSwagger(), - applicationBuilder => applicationBuilder.UseEndpoints())); - }) .AddControllers() .AddJsonOptions(_ => { @@ -69,6 +60,16 @@ public class ManagementApiComposer : IComposer .AddJsonOptions(New.Cms.Core.Constants.JsonOptionsNames.BackOffice, _ => { }); services.ConfigureOptions( ); + services.ConfigureOptions( ); + + services.Configure(options => + { + options.AddFilter(new UmbracoPipelineFilter( + "BackOfficeManagementApiFilter", + applicationBuilder => applicationBuilder.UseProblemDetailsExceptionHandling(), + applicationBuilder => { }, + applicationBuilder => applicationBuilder.UseEndpoints())); + }); // FIXME: when this is moved to core, make the AddUmbracoOptions extension private again and remove core InternalsVisibleTo for Umbraco.Cms.Api.Management builder.AddUmbracoOptions(); diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 758e73dcf2..af0dc40f67 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -1,9 +1,9 @@ { "openapi": "3.0.1", "info": { - "title": "Umbraco Backoffice API", + "title": "Umbraco Management API", "description": "This shows all APIs available in this version of Umbraco - including all the legacy apis that are available for backward compatibility", - "version": "1.0" + "version": "Latest" }, "paths": { "/umbraco/management/api/v1/audit-log": { @@ -11,7 +11,7 @@ "tags": [ "Audit Log" ], - "operationId": "GetAuditLog", + "operationId": "GetAuditLog1.0", "parameters": [ { "name": "orderDirection", @@ -66,7 +66,7 @@ "tags": [ "Audit Log" ], - "operationId": "GetAuditLogById", + "operationId": "GetAuditLogById1.0", "parameters": [ { "name": "id", @@ -130,7 +130,7 @@ "tags": [ "Audit Log" ], - "operationId": "GetAuditLogTypeByLogType", + "operationId": "GetAuditLogTypeByLogType1.0", "parameters": [ { "name": "logType", @@ -186,7 +186,7 @@ "tags": [ "Culture" ], - "operationId": "GetCulture", + "operationId": "GetCulture1.0", "parameters": [ { "name": "skip", @@ -226,7 +226,7 @@ "tags": [ "Data Type" ], - "operationId": "PostDataType", + "operationId": "PostDataType1.0", "requestBody": { "content": { "application/json": { @@ -275,7 +275,7 @@ "tags": [ "Data Type" ], - "operationId": "GetDataTypeById", + "operationId": "GetDataTypeById1.0", "parameters": [ { "name": "id", @@ -311,7 +311,7 @@ "tags": [ "Data Type" ], - "operationId": "DeleteDataTypeById", + "operationId": "DeleteDataTypeById1.0", "parameters": [ { "name": "id", @@ -346,7 +346,7 @@ "tags": [ "Data Type" ], - "operationId": "PutDataTypeById", + "operationId": "PutDataTypeById1.0", "parameters": [ { "name": "id", @@ -396,7 +396,7 @@ "tags": [ "Data Type" ], - "operationId": "PostDataTypeByIdCopy", + "operationId": "PostDataTypeByIdCopy1.0", "parameters": [ { "name": "id", @@ -446,7 +446,7 @@ "tags": [ "Data Type" ], - "operationId": "GetDataTypeByIdIsUsed", + "operationId": "GetDataTypeByIdIsUsed1.0", "parameters": [ { "name": "id", @@ -480,7 +480,7 @@ "tags": [ "Data Type" ], - "operationId": "PostDataTypeByIdMove", + "operationId": "PostDataTypeByIdMove1.0", "parameters": [ { "name": "id", @@ -520,7 +520,7 @@ "tags": [ "Data Type" ], - "operationId": "GetDataTypeByIdReferences", + "operationId": "GetDataTypeByIdReferences1.0", "parameters": [ { "name": "id", @@ -561,7 +561,7 @@ "tags": [ "Data Type" ], - "operationId": "PostDataTypeFolder", + "operationId": "PostDataTypeFolder1.0", "requestBody": { "content": { "application/json": { @@ -597,7 +597,7 @@ "tags": [ "Data Type" ], - "operationId": "GetDataTypeFolderById", + "operationId": "GetDataTypeFolderById1.0", "parameters": [ { "name": "id", @@ -633,7 +633,7 @@ "tags": [ "Data Type" ], - "operationId": "DeleteDataTypeFolderById", + "operationId": "DeleteDataTypeFolderById1.0", "parameters": [ { "name": "id", @@ -658,7 +658,7 @@ "tags": [ "Data Type" ], - "operationId": "PutDataTypeFolderById", + "operationId": "PutDataTypeFolderById1.0", "parameters": [ { "name": "id", @@ -698,7 +698,7 @@ "tags": [ "Data Type" ], - "operationId": "GetDataTypeItem", + "operationId": "GetDataTypeItem1.0", "parameters": [ { "name": "id", @@ -739,7 +739,7 @@ "tags": [ "Data Type" ], - "operationId": "GetTreeDataTypeChildren", + "operationId": "GetTreeDataTypeChildren1.0", "parameters": [ { "name": "parentId", @@ -795,7 +795,7 @@ "tags": [ "Data Type" ], - "operationId": "GetTreeDataTypeRoot", + "operationId": "GetTreeDataTypeRoot1.0", "parameters": [ { "name": "skip", @@ -843,7 +843,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetDictionary", + "operationId": "GetDictionary1.0", "parameters": [ { "name": "skip", @@ -881,7 +881,7 @@ "tags": [ "Dictionary" ], - "operationId": "PostDictionary", + "operationId": "PostDictionary1.0", "requestBody": { "content": { "application/json": { @@ -940,7 +940,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetDictionaryById", + "operationId": "GetDictionaryById1.0", "parameters": [ { "name": "id", @@ -976,7 +976,7 @@ "tags": [ "Dictionary" ], - "operationId": "DeleteDictionaryById", + "operationId": "DeleteDictionaryById1.0", "parameters": [ { "name": "id", @@ -1011,7 +1011,7 @@ "tags": [ "Dictionary" ], - "operationId": "PutDictionaryById", + "operationId": "PutDictionaryById1.0", "parameters": [ { "name": "id", @@ -1061,7 +1061,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetDictionaryByIdExport", + "operationId": "GetDictionaryByIdExport1.0", "parameters": [ { "name": "id", @@ -1104,7 +1104,7 @@ "tags": [ "Dictionary" ], - "operationId": "PostDictionaryByIdMove", + "operationId": "PostDictionaryByIdMove1.0", "parameters": [ { "name": "id", @@ -1154,7 +1154,7 @@ "tags": [ "Dictionary" ], - "operationId": "PostDictionaryImport", + "operationId": "PostDictionaryImport1.0", "requestBody": { "content": { "application/json": { @@ -1203,7 +1203,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetDictionaryItem", + "operationId": "GetDictionaryItem1.0", "parameters": [ { "name": "id", @@ -1244,7 +1244,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetTreeDictionaryChildren", + "operationId": "GetTreeDictionaryChildren1.0", "parameters": [ { "name": "parentId", @@ -1292,7 +1292,7 @@ "tags": [ "Dictionary" ], - "operationId": "GetTreeDictionaryRoot", + "operationId": "GetTreeDictionaryRoot1.0", "parameters": [ { "name": "skip", @@ -1332,7 +1332,7 @@ "tags": [ "Document Blueprint" ], - "operationId": "GetDocumentBlueprintItem", + "operationId": "GetDocumentBlueprintItem1.0", "parameters": [ { "name": "id", @@ -1373,7 +1373,7 @@ "tags": [ "Document Blueprint" ], - "operationId": "GetTreeDocumentBlueprintRoot", + "operationId": "GetTreeDocumentBlueprintRoot1.0", "parameters": [ { "name": "skip", @@ -1413,7 +1413,7 @@ "tags": [ "Document Type" ], - "operationId": "GetDocumentTypeById", + "operationId": "GetDocumentTypeById1.0", "parameters": [ { "name": "id", @@ -1451,7 +1451,7 @@ "tags": [ "Document Type" ], - "operationId": "GetDocumentTypeItem", + "operationId": "GetDocumentTypeItem1.0", "parameters": [ { "name": "id", @@ -1492,7 +1492,7 @@ "tags": [ "Document Type" ], - "operationId": "GetTreeDocumentTypeChildren", + "operationId": "GetTreeDocumentTypeChildren1.0", "parameters": [ { "name": "parentId", @@ -1548,7 +1548,7 @@ "tags": [ "Document Type" ], - "operationId": "GetTreeDocumentTypeRoot", + "operationId": "GetTreeDocumentTypeRoot1.0", "parameters": [ { "name": "skip", @@ -1596,7 +1596,7 @@ "tags": [ "Document" ], - "operationId": "PostDocument", + "operationId": "PostDocument1.0", "requestBody": { "content": { "application/json": { @@ -1638,7 +1638,7 @@ "tags": [ "Document" ], - "operationId": "GetDocumentById", + "operationId": "GetDocumentById1.0", "parameters": [ { "name": "id", @@ -1674,7 +1674,7 @@ "tags": [ "Document" ], - "operationId": "DeleteDocumentById", + "operationId": "DeleteDocumentById1.0", "parameters": [ { "name": "id", @@ -1702,7 +1702,7 @@ "tags": [ "Document" ], - "operationId": "PutDocumentById", + "operationId": "PutDocumentById1.0", "parameters": [ { "name": "id", @@ -1745,7 +1745,7 @@ "tags": [ "Document" ], - "operationId": "PostDocumentByIdCopy", + "operationId": "PostDocumentByIdCopy1.0", "parameters": [ { "name": "id", @@ -1857,7 +1857,7 @@ "tags": [ "Document" ], - "operationId": "PutDocumentByIdMove", + "operationId": "PutDocumentByIdMove1.0", "parameters": [ { "name": "id", @@ -1979,7 +1979,7 @@ "tags": [ "Document" ], - "operationId": "GetDocumentItem", + "operationId": "GetDocumentItem1.0", "parameters": [ { "name": "id", @@ -2035,7 +2035,7 @@ "tags": [ "Document" ], - "operationId": "GetRecycleBinDocumentChildren", + "operationId": "GetRecycleBinDocumentChildren1.0", "parameters": [ { "name": "parentId", @@ -2086,7 +2086,7 @@ "tags": [ "Document" ], - "operationId": "GetRecycleBinDocumentRoot", + "operationId": "GetRecycleBinDocumentRoot1.0", "parameters": [ { "name": "skip", @@ -2129,7 +2129,7 @@ "tags": [ "Document" ], - "operationId": "GetTreeDocumentChildren", + "operationId": "GetTreeDocumentChildren1.0", "parameters": [ { "name": "parentId", @@ -2192,7 +2192,7 @@ "tags": [ "Document" ], - "operationId": "GetTreeDocumentRoot", + "operationId": "GetTreeDocumentRoot1.0", "parameters": [ { "name": "skip", @@ -2247,7 +2247,7 @@ "tags": [ "Health Check" ], - "operationId": "GetHealthCheckGroup", + "operationId": "GetHealthCheckGroup1.0", "parameters": [ { "name": "skip", @@ -2287,7 +2287,7 @@ "tags": [ "Health Check" ], - "operationId": "GetHealthCheckGroupByName", + "operationId": "GetHealthCheckGroupByName1.0", "parameters": [ { "name": "name", @@ -2324,7 +2324,7 @@ "tags": [ "Health Check" ], - "operationId": "PostHealthCheckGroupByNameCheck", + "operationId": "PostHealthCheckGroupByNameCheck1.0", "parameters": [ { "name": "name", @@ -2361,7 +2361,7 @@ "tags": [ "Health Check" ], - "operationId": "PostHealthCheckExecuteAction", + "operationId": "PostHealthCheckExecuteAction1.0", "requestBody": { "content": { "application/json": { @@ -2408,7 +2408,7 @@ "tags": [ "Help" ], - "operationId": "GetHelp", + "operationId": "GetHelp1.0", "parameters": [ { "name": "section", @@ -2478,7 +2478,7 @@ "tags": [ "Indexer" ], - "operationId": "GetIndexer", + "operationId": "GetIndexer1.0", "parameters": [ { "name": "skip", @@ -2516,7 +2516,7 @@ "tags": [ "Indexer" ], - "operationId": "GetIndexerByIndexName", + "operationId": "GetIndexerByIndexName1.0", "parameters": [ { "name": "indexName", @@ -2560,7 +2560,7 @@ "tags": [ "Indexer" ], - "operationId": "PostIndexerByIndexNameRebuild", + "operationId": "PostIndexerByIndexNameRebuild1.0", "parameters": [ { "name": "indexName", @@ -2600,7 +2600,7 @@ "tags": [ "Install" ], - "operationId": "GetInstallSettings", + "operationId": "GetInstallSettings1.0", "responses": { "400": { "description": "Bad Request", @@ -2644,7 +2644,7 @@ "tags": [ "Install" ], - "operationId": "PostInstallSetup", + "operationId": "PostInstallSetup1.0", "requestBody": { "content": { "application/json": { @@ -2690,7 +2690,7 @@ "tags": [ "Install" ], - "operationId": "PostInstallValidateDatabase", + "operationId": "PostInstallValidateDatabase1.0", "requestBody": { "content": { "application/json": { @@ -2726,7 +2726,7 @@ "tags": [ "Language" ], - "operationId": "GetLanguage", + "operationId": "GetLanguage1.0", "parameters": [ { "name": "skip", @@ -2764,7 +2764,7 @@ "tags": [ "Language" ], - "operationId": "PostLanguage", + "operationId": "PostLanguage1.0", "requestBody": { "content": { "application/json": { @@ -2813,7 +2813,7 @@ "tags": [ "Language" ], - "operationId": "GetLanguageByIsoCode", + "operationId": "GetLanguageByIsoCode1.0", "parameters": [ { "name": "isoCode", @@ -2848,7 +2848,7 @@ "tags": [ "Language" ], - "operationId": "DeleteLanguageByIsoCode", + "operationId": "DeleteLanguageByIsoCode1.0", "parameters": [ { "name": "isoCode", @@ -2889,7 +2889,7 @@ "tags": [ "Language" ], - "operationId": "PutLanguageByIsoCode", + "operationId": "PutLanguageByIsoCode1.0", "parameters": [ { "name": "isoCode", @@ -2938,7 +2938,7 @@ "tags": [ "Language" ], - "operationId": "GetLanguageItem", + "operationId": "GetLanguageItem1.0", "parameters": [ { "name": "isoCode", @@ -2978,7 +2978,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerLevel", + "operationId": "GetLogViewerLevel1.0", "parameters": [ { "name": "skip", @@ -3018,7 +3018,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerLevelCount", + "operationId": "GetLogViewerLevelCount1.0", "parameters": [ { "name": "startDate", @@ -3070,7 +3070,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerLog", + "operationId": "GetLogViewerLog1.0", "parameters": [ { "name": "skip", @@ -3150,7 +3150,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerMessageTemplate", + "operationId": "GetLogViewerMessageTemplate1.0", "parameters": [ { "name": "skip", @@ -3216,7 +3216,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerSavedSearch", + "operationId": "GetLogViewerSavedSearch1.0", "parameters": [ { "name": "skip", @@ -3254,7 +3254,7 @@ "tags": [ "Log Viewer" ], - "operationId": "PostLogViewerSavedSearch", + "operationId": "PostLogViewerSavedSearch1.0", "requestBody": { "content": { "application/json": { @@ -3300,7 +3300,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerSavedSearchByName", + "operationId": "GetLogViewerSavedSearchByName1.0", "parameters": [ { "name": "name", @@ -3335,7 +3335,7 @@ "tags": [ "Log Viewer" ], - "operationId": "DeleteLogViewerSavedSearchByName", + "operationId": "DeleteLogViewerSavedSearchByName1.0", "parameters": [ { "name": "name", @@ -3361,7 +3361,7 @@ "tags": [ "Log Viewer" ], - "operationId": "GetLogViewerValidateLogsSize", + "operationId": "GetLogViewerValidateLogsSize1.0", "parameters": [ { "name": "startDate", @@ -3402,7 +3402,7 @@ "tags": [ "Media Type" ], - "operationId": "GetMediaTypeById", + "operationId": "GetMediaTypeById1.0", "parameters": [ { "name": "id", @@ -3440,7 +3440,7 @@ "tags": [ "Media Type" ], - "operationId": "GetMediaTypeItem", + "operationId": "GetMediaTypeItem1.0", "parameters": [ { "name": "id", @@ -3481,7 +3481,7 @@ "tags": [ "Media Type" ], - "operationId": "GetTreeMediaTypeChildren", + "operationId": "GetTreeMediaTypeChildren1.0", "parameters": [ { "name": "parentId", @@ -3537,7 +3537,7 @@ "tags": [ "Media Type" ], - "operationId": "GetTreeMediaTypeRoot", + "operationId": "GetTreeMediaTypeRoot1.0", "parameters": [ { "name": "skip", @@ -3585,7 +3585,7 @@ "tags": [ "Media" ], - "operationId": "PostMedia", + "operationId": "PostMedia1.0", "requestBody": { "content": { "application/json": { @@ -3627,7 +3627,7 @@ "tags": [ "Media" ], - "operationId": "GetMediaById", + "operationId": "GetMediaById1.0", "parameters": [ { "name": "id", @@ -3663,7 +3663,7 @@ "tags": [ "Media" ], - "operationId": "DeleteMediaById", + "operationId": "DeleteMediaById1.0", "parameters": [ { "name": "id", @@ -3691,7 +3691,7 @@ "tags": [ "Media" ], - "operationId": "PutMediaById", + "operationId": "PutMediaById1.0", "parameters": [ { "name": "id", @@ -3734,7 +3734,7 @@ "tags": [ "Media" ], - "operationId": "PutMediaByIdMove", + "operationId": "PutMediaByIdMove1.0", "parameters": [ { "name": "id", @@ -3777,7 +3777,7 @@ "tags": [ "Media" ], - "operationId": "GetMediaItem", + "operationId": "GetMediaItem1.0", "parameters": [ { "name": "id", @@ -3826,7 +3826,7 @@ "tags": [ "Media" ], - "operationId": "GetRecycleBinMediaChildren", + "operationId": "GetRecycleBinMediaChildren1.0", "parameters": [ { "name": "parentId", @@ -3877,7 +3877,7 @@ "tags": [ "Media" ], - "operationId": "GetRecycleBinMediaRoot", + "operationId": "GetRecycleBinMediaRoot1.0", "parameters": [ { "name": "skip", @@ -3920,7 +3920,7 @@ "tags": [ "Media" ], - "operationId": "GetTreeMediaChildren", + "operationId": "GetTreeMediaChildren1.0", "parameters": [ { "name": "parentId", @@ -3976,7 +3976,7 @@ "tags": [ "Media" ], - "operationId": "GetTreeMediaItem", + "operationId": "GetTreeMediaItem1.0", "parameters": [ { "name": "id", @@ -4027,7 +4027,7 @@ "tags": [ "Media" ], - "operationId": "GetTreeMediaRoot", + "operationId": "GetTreeMediaRoot1.0", "parameters": [ { "name": "skip", @@ -4075,7 +4075,7 @@ "tags": [ "Member Group" ], - "operationId": "GetMemberGroupItem", + "operationId": "GetMemberGroupItem1.0", "parameters": [ { "name": "id", @@ -4116,7 +4116,7 @@ "tags": [ "Member Group" ], - "operationId": "GetTreeMemberGroupRoot", + "operationId": "GetTreeMemberGroupRoot1.0", "parameters": [ { "name": "skip", @@ -4156,7 +4156,7 @@ "tags": [ "Member Type" ], - "operationId": "GetMemberTypeItem", + "operationId": "GetMemberTypeItem1.0", "parameters": [ { "name": "id", @@ -4197,7 +4197,7 @@ "tags": [ "Member Type" ], - "operationId": "GetTreeMemberTypeRoot", + "operationId": "GetTreeMemberTypeRoot1.0", "parameters": [ { "name": "skip", @@ -4237,7 +4237,7 @@ "tags": [ "Member" ], - "operationId": "GetMemberItem", + "operationId": "GetMemberItem1.0", "parameters": [ { "name": "id", @@ -4278,7 +4278,7 @@ "tags": [ "Models Builder" ], - "operationId": "PostModelsBuilderBuild", + "operationId": "PostModelsBuilderBuild1.0", "responses": { "200": { "description": "Success" @@ -4301,7 +4301,7 @@ "tags": [ "Models Builder" ], - "operationId": "GetModelsBuilderDashboard", + "operationId": "GetModelsBuilderDashboard1.0", "responses": { "200": { "description": "Success", @@ -4325,7 +4325,7 @@ "tags": [ "Models Builder" ], - "operationId": "GetModelsBuilderStatus", + "operationId": "GetModelsBuilderStatus1.0", "responses": { "200": { "description": "Success", @@ -4349,7 +4349,7 @@ "tags": [ "Object Types" ], - "operationId": "GetObjectTypes", + "operationId": "GetObjectTypes1.0", "parameters": [ { "name": "skip", @@ -4389,7 +4389,7 @@ "tags": [ "Package" ], - "operationId": "PostPackageByNameRunMigration", + "operationId": "PostPackageByNameRunMigration1.0", "parameters": [ { "name": "name", @@ -4425,7 +4425,7 @@ "tags": [ "Package" ], - "operationId": "GetPackageCreated", + "operationId": "GetPackageCreated1.0", "parameters": [ { "name": "skip", @@ -4463,7 +4463,7 @@ "tags": [ "Package" ], - "operationId": "PostPackageCreated", + "operationId": "PostPackageCreated1.0", "requestBody": { "content": { "application/json": { @@ -4512,7 +4512,7 @@ "tags": [ "Package" ], - "operationId": "GetPackageCreatedById", + "operationId": "GetPackageCreatedById1.0", "parameters": [ { "name": "id", @@ -4548,7 +4548,7 @@ "tags": [ "Package" ], - "operationId": "DeletePackageCreatedById", + "operationId": "DeletePackageCreatedById1.0", "parameters": [ { "name": "id", @@ -4573,7 +4573,7 @@ "tags": [ "Package" ], - "operationId": "PutPackageCreatedById", + "operationId": "PutPackageCreatedById1.0", "parameters": [ { "name": "id", @@ -4613,7 +4613,7 @@ "tags": [ "Package" ], - "operationId": "GetPackageCreatedByIdDownload", + "operationId": "GetPackageCreatedByIdDownload1.0", "parameters": [ { "name": "id", @@ -4648,7 +4648,7 @@ "tags": [ "Package" ], - "operationId": "GetPackageManifest", + "operationId": "GetPackageManifest1.0", "responses": { "200": { "description": "Success", @@ -4675,7 +4675,7 @@ "tags": [ "Package" ], - "operationId": "GetPackageMigrationStatus", + "operationId": "GetPackageMigrationStatus1.0", "parameters": [ { "name": "skip", @@ -4715,7 +4715,7 @@ "tags": [ "Partial View" ], - "operationId": "GetPartialViewItem", + "operationId": "GetPartialViewItem1.0", "parameters": [ { "name": "id", @@ -4755,7 +4755,7 @@ "tags": [ "Partial View" ], - "operationId": "GetTreePartialViewChildren", + "operationId": "GetTreePartialViewChildren1.0", "parameters": [ { "name": "path", @@ -4802,7 +4802,7 @@ "tags": [ "Partial View" ], - "operationId": "GetTreePartialViewRoot", + "operationId": "GetTreePartialViewRoot1.0", "parameters": [ { "name": "skip", @@ -4842,7 +4842,7 @@ "tags": [ "Profiling" ], - "operationId": "GetProfilingStatus", + "operationId": "GetProfilingStatus1.0", "responses": { "200": { "description": "Success", @@ -4864,7 +4864,7 @@ "tags": [ "Profiling" ], - "operationId": "PutProfilingStatus", + "operationId": "PutProfilingStatus1.0", "requestBody": { "content": { "application/json": { @@ -4890,7 +4890,7 @@ "tags": [ "Property Type" ], - "operationId": "GetPropertyTypeIsUsed", + "operationId": "GetPropertyTypeIsUsed1.0", "parameters": [ { "name": "contentTypeId", @@ -4937,7 +4937,7 @@ "tags": [ "Published Cache" ], - "operationId": "PostPublishedCacheCollect", + "operationId": "PostPublishedCacheCollect1.0", "responses": { "200": { "description": "Success" @@ -4950,7 +4950,7 @@ "tags": [ "Published Cache" ], - "operationId": "PostPublishedCacheRebuild", + "operationId": "PostPublishedCacheRebuild1.0", "responses": { "200": { "description": "Success" @@ -4963,7 +4963,7 @@ "tags": [ "Published Cache" ], - "operationId": "PostPublishedCacheReload", + "operationId": "PostPublishedCacheReload1.0", "responses": { "200": { "description": "Success" @@ -4976,7 +4976,7 @@ "tags": [ "Published Cache" ], - "operationId": "GetPublishedCacheStatus", + "operationId": "GetPublishedCacheStatus1.0", "responses": { "200": { "description": "Success", @@ -5164,7 +5164,7 @@ "tags": [ "Relation Type" ], - "operationId": "PostRelationType", + "operationId": "PostRelationType1.0", "requestBody": { "content": { "application/json": { @@ -5210,7 +5210,7 @@ "tags": [ "Relation Type" ], - "operationId": "GetRelationTypeById", + "operationId": "GetRelationTypeById1.0", "parameters": [ { "name": "id", @@ -5246,7 +5246,7 @@ "tags": [ "Relation Type" ], - "operationId": "DeleteRelationTypeById", + "operationId": "DeleteRelationTypeById1.0", "parameters": [ { "name": "id", @@ -5278,7 +5278,7 @@ "tags": [ "Relation Type" ], - "operationId": "PutRelationTypeById", + "operationId": "PutRelationTypeById1.0", "parameters": [ { "name": "id", @@ -5346,7 +5346,7 @@ "tags": [ "Relation Type" ], - "operationId": "GetRelationTypeItem", + "operationId": "GetRelationTypeItem1.0", "parameters": [ { "name": "id", @@ -5387,7 +5387,7 @@ "tags": [ "Relation Type" ], - "operationId": "GetTreeRelationTypeRoot", + "operationId": "GetTreeRelationTypeRoot1.0", "parameters": [ { "name": "skip", @@ -5427,7 +5427,7 @@ "tags": [ "Relation" ], - "operationId": "GetRelationById", + "operationId": "GetRelationById1.0", "parameters": [ { "name": "id", @@ -5465,7 +5465,7 @@ "tags": [ "Relation" ], - "operationId": "GetRelationChildRelationByChildId", + "operationId": "GetRelationChildRelationByChildId1.0", "parameters": [ { "name": "childId", @@ -5520,7 +5520,7 @@ "tags": [ "Relation" ], - "operationId": "GetRelationTypeById", + "operationId": "GetRelationTypeById1.0", "parameters": [ { "name": "id", @@ -5569,7 +5569,7 @@ "tags": [ "Script" ], - "operationId": "GetScriptItem", + "operationId": "GetScriptItem1.0", "parameters": [ { "name": "path", @@ -5609,7 +5609,7 @@ "tags": [ "Script" ], - "operationId": "GetTreeScriptChildren", + "operationId": "GetTreeScriptChildren1.0", "parameters": [ { "name": "path", @@ -5656,7 +5656,7 @@ "tags": [ "Script" ], - "operationId": "GetTreeScriptRoot", + "operationId": "GetTreeScriptRoot1.0", "parameters": [ { "name": "skip", @@ -5696,7 +5696,7 @@ "tags": [ "Searcher" ], - "operationId": "GetSearcher", + "operationId": "GetSearcher1.0", "parameters": [ { "name": "skip", @@ -5734,7 +5734,7 @@ "tags": [ "Searcher" ], - "operationId": "GetSearcherBySearcherNameQuery", + "operationId": "GetSearcherBySearcherNameQuery1.0", "parameters": [ { "name": "searcherName", @@ -5797,7 +5797,7 @@ "tags": [ "Security" ], - "operationId": "GetSecurityBackOfficeAuthorize", + "operationId": "GetSecurityBackOfficeAuthorize1.0", "responses": { "200": { "description": "Success" @@ -5810,7 +5810,7 @@ "tags": [ "Security" ], - "operationId": "PostSecurityBackOfficeLogin", + "operationId": "PostSecurityBackOfficeLogin1.0", "requestBody": { "content": { "application/json": { @@ -5836,7 +5836,7 @@ "tags": [ "Server" ], - "operationId": "GetServerStatus", + "operationId": "GetServerStatus1.0", "responses": { "400": { "description": "Bad Request", @@ -5870,7 +5870,7 @@ "tags": [ "Server" ], - "operationId": "GetServerVersion", + "operationId": "GetServerVersion1.0", "responses": { "400": { "description": "Bad Request", @@ -5904,7 +5904,7 @@ "tags": [ "Static File" ], - "operationId": "GetStaticFileItem", + "operationId": "GetStaticFileItem1.0", "parameters": [ { "name": "path", @@ -5944,7 +5944,7 @@ "tags": [ "Static File" ], - "operationId": "GetTreeStaticFileChildren", + "operationId": "GetTreeStaticFileChildren1.0", "parameters": [ { "name": "path", @@ -5991,7 +5991,7 @@ "tags": [ "Static File" ], - "operationId": "GetTreeStaticFileRoot", + "operationId": "GetTreeStaticFileRoot1.0", "parameters": [ { "name": "skip", @@ -6031,7 +6031,7 @@ "tags": [ "Stylesheet" ], - "operationId": "GetStylesheetItem", + "operationId": "GetStylesheetItem1.0", "parameters": [ { "name": "path", @@ -6071,7 +6071,7 @@ "tags": [ "Stylesheet" ], - "operationId": "GetTreeStylesheetChildren", + "operationId": "GetTreeStylesheetChildren1.0", "parameters": [ { "name": "path", @@ -6118,7 +6118,7 @@ "tags": [ "Stylesheet" ], - "operationId": "GetTreeStylesheetRoot", + "operationId": "GetTreeStylesheetRoot1.0", "parameters": [ { "name": "skip", @@ -6158,7 +6158,7 @@ "tags": [ "Tag" ], - "operationId": "GetTag", + "operationId": "GetTag1.0", "parameters": [ { "name": "query", @@ -6219,7 +6219,7 @@ "tags": [ "Telemetry" ], - "operationId": "GetTelemetry", + "operationId": "GetTelemetry1.0", "parameters": [ { "name": "skip", @@ -6257,7 +6257,7 @@ "tags": [ "Telemetry" ], - "operationId": "GetTelemetryLevel", + "operationId": "GetTelemetryLevel1.0", "responses": { "200": { "description": "Success", @@ -6279,7 +6279,7 @@ "tags": [ "Telemetry" ], - "operationId": "PostTelemetryLevel", + "operationId": "PostTelemetryLevel1.0", "requestBody": { "content": { "application/json": { @@ -6315,7 +6315,7 @@ "tags": [ "Template" ], - "operationId": "PostTemplate", + "operationId": "PostTemplate1.0", "requestBody": { "content": { "application/json": { @@ -6364,7 +6364,7 @@ "tags": [ "Template" ], - "operationId": "GetTemplateById", + "operationId": "GetTemplateById1.0", "parameters": [ { "name": "id", @@ -6400,7 +6400,7 @@ "tags": [ "Template" ], - "operationId": "DeleteTemplateById", + "operationId": "DeleteTemplateById1.0", "parameters": [ { "name": "id", @@ -6435,7 +6435,7 @@ "tags": [ "Template" ], - "operationId": "PutTemplateById", + "operationId": "PutTemplateById1.0", "parameters": [ { "name": "id", @@ -6485,7 +6485,7 @@ "tags": [ "Template" ], - "operationId": "GetTemplateItem", + "operationId": "GetTemplateItem1.0", "parameters": [ { "name": "id", @@ -6526,7 +6526,7 @@ "tags": [ "Template" ], - "operationId": "PostTemplateQueryExecute", + "operationId": "PostTemplateQueryExecute1.0", "requestBody": { "content": { "application/json": { @@ -6563,7 +6563,7 @@ "tags": [ "Template" ], - "operationId": "GetTemplateQuerySettings", + "operationId": "GetTemplateQuerySettings1.0", "responses": { "200": { "description": "Success", @@ -6587,7 +6587,7 @@ "tags": [ "Template" ], - "operationId": "GetTemplateScaffold", + "operationId": "GetTemplateScaffold1.0", "responses": { "200": { "description": "Success", @@ -6614,7 +6614,7 @@ "tags": [ "Template" ], - "operationId": "GetTreeTemplateChildren", + "operationId": "GetTreeTemplateChildren1.0", "parameters": [ { "name": "parentId", @@ -6662,7 +6662,7 @@ "tags": [ "Template" ], - "operationId": "GetTreeTemplateRoot", + "operationId": "GetTreeTemplateRoot1.0", "parameters": [ { "name": "skip", @@ -6702,7 +6702,7 @@ "tags": [ "Temporary File" ], - "operationId": "PostTemporaryfile", + "operationId": "PostTemporaryfile1.0", "requestBody": { "content": { "multipart/form-data": { @@ -6762,7 +6762,7 @@ "tags": [ "Temporary File" ], - "operationId": "GetTemporaryfileById", + "operationId": "GetTemporaryfileById1.0", "parameters": [ { "name": "id", @@ -6815,7 +6815,7 @@ "tags": [ "Temporary File" ], - "operationId": "DeleteTemporaryfileById", + "operationId": "DeleteTemporaryfileById1.0", "parameters": [ { "name": "id", @@ -6859,7 +6859,7 @@ "tags": [ "Tracked Reference" ], - "operationId": "GetTrackedReferenceById", + "operationId": "GetTrackedReferenceById1.0", "parameters": [ { "name": "id", @@ -6916,7 +6916,7 @@ "tags": [ "Tracked Reference" ], - "operationId": "GetTrackedReferenceDescendantsByParentId", + "operationId": "GetTrackedReferenceDescendantsByParentId1.0", "parameters": [ { "name": "parentId", @@ -6971,7 +6971,7 @@ "tags": [ "Tracked Reference" ], - "operationId": "GetTrackedReferenceItem", + "operationId": "GetTrackedReferenceItem1.0", "parameters": [ { "name": "id", @@ -7031,7 +7031,7 @@ "tags": [ "Upgrade" ], - "operationId": "PostUpgradeAuthorize", + "operationId": "PostUpgradeAuthorize1.0", "responses": { "200": { "description": "Success" @@ -7064,7 +7064,7 @@ "tags": [ "Upgrade" ], - "operationId": "GetUpgradeSettings", + "operationId": "GetUpgradeSettings1.0", "responses": { "200": { "description": "Success", @@ -7098,7 +7098,7 @@ "tags": [ "User Group" ], - "operationId": "PostUserGroup", + "operationId": "PostUserGroup1.0", "requestBody": { "content": { "application/json": { @@ -7142,7 +7142,7 @@ "tags": [ "User Group" ], - "operationId": "GetUserGroup", + "operationId": "GetUserGroup1.0", "parameters": [ { "name": "skip", @@ -7182,7 +7182,7 @@ "tags": [ "User Group" ], - "operationId": "GetUserGroupById", + "operationId": "GetUserGroupById1.0", "parameters": [ { "name": "id", @@ -7218,7 +7218,7 @@ "tags": [ "User Group" ], - "operationId": "DeleteUserGroupById", + "operationId": "DeleteUserGroupById1.0", "parameters": [ { "name": "id", @@ -7243,7 +7243,7 @@ "tags": [ "User Group" ], - "operationId": "PutUserGroupById", + "operationId": "PutUserGroupById1.0", "parameters": [ { "name": "id", @@ -7283,7 +7283,7 @@ "tags": [ "User Groups" ], - "operationId": "GetUserGroupsItem", + "operationId": "GetUserGroupsItem1.0", "parameters": [ { "name": "id", @@ -7324,7 +7324,7 @@ "tags": [ "User" ], - "operationId": "PostUser", + "operationId": "PostUser1.0", "requestBody": { "content": { "application/json": { @@ -7372,7 +7372,7 @@ "tags": [ "User" ], - "operationId": "GetUser", + "operationId": "GetUser1.0", "parameters": [ { "name": "skip", @@ -7412,7 +7412,7 @@ "tags": [ "User" ], - "operationId": "GetUserById", + "operationId": "GetUserById1.0", "parameters": [ { "name": "id", @@ -7470,7 +7470,7 @@ "tags": [ "User" ], - "operationId": "PutUserById", + "operationId": "PutUserById1.0", "parameters": [ { "name": "id", @@ -7576,7 +7576,7 @@ "tags": [ "User" ], - "operationId": "PostUserChangePasswordById", + "operationId": "PostUserChangePasswordById1.0", "parameters": [ { "name": "id", @@ -7613,7 +7613,7 @@ "tags": [ "User" ], - "operationId": "PostUserDisable", + "operationId": "PostUserDisable1.0", "requestBody": { "content": { "application/json": { @@ -7649,7 +7649,7 @@ "tags": [ "User" ], - "operationId": "PostUserEnable", + "operationId": "PostUserEnable1.0", "requestBody": { "content": { "application/json": { @@ -7685,7 +7685,7 @@ "tags": [ "User" ], - "operationId": "GetUserFilter", + "operationId": "GetUserFilter1.0", "parameters": [ { "name": "skip", @@ -7763,7 +7763,7 @@ "tags": [ "User" ], - "operationId": "PostUserInvite", + "operationId": "PostUserInvite1.0", "requestBody": { "content": { "application/json": { @@ -7789,7 +7789,7 @@ "tags": [ "User" ], - "operationId": "PostUserSetUserGroups", + "operationId": "PostUserSetUserGroups1.0", "requestBody": { "content": { "application/json": { @@ -7815,7 +7815,7 @@ "tags": [ "User" ], - "operationId": "PostUserUnlock", + "operationId": "PostUserUnlock1.0", "requestBody": { "content": { "application/json": { @@ -7851,7 +7851,7 @@ "tags": [ "Users" ], - "operationId": "GetUsersItem", + "operationId": "GetUsersItem1.0", "parameters": [ { "name": "id", diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs b/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs index daddedafac..2346800b74 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs +++ b/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs @@ -1,13 +1,20 @@ using Microsoft.AspNetCore.Http; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; +using Umbraco.Cms.Api.Management.DependencyInjection; +using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.OpenApi; -internal class ReponseHeaderOperationFilter : IOperationFilter +internal class ResponseHeaderOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { + if (context.MethodInfo.HasMapToApiAttribute(ManagementApiConfiguration.ApiName) == false) + { + return; + } + foreach ((var key, OpenApiResponse? value) in operation.Responses) { switch (int.Parse(key)) diff --git a/src/Umbraco.Cms.Api.Management/Serialization/ConfigureUmbracoBackofficeJsonOptions.cs b/src/Umbraco.Cms.Api.Management/Serialization/ConfigureUmbracoBackofficeJsonOptions.cs index 7e30203d86..a511a8d4c2 100644 --- a/src/Umbraco.Cms.Api.Management/Serialization/ConfigureUmbracoBackofficeJsonOptions.cs +++ b/src/Umbraco.Cms.Api.Management/Serialization/ConfigureUmbracoBackofficeJsonOptions.cs @@ -2,6 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; +using Umbraco.Cms.Api.Common.Serialization; using Umbraco.Cms.Infrastructure.Serialization; namespace Umbraco.Cms.Api.Management.Serialization; diff --git a/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs b/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs index ecb3112d7c..aee1f6fa7c 100644 --- a/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs +++ b/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs @@ -35,7 +35,7 @@ internal sealed class OpenAPIContractTest : UmbracoTestServerTestBase var officePath = GlobalSettings.GetBackOfficePath(HostingEnvironment); var urlToContract = $"{officePath}/management/api/openapi.json"; - var swaggerPath = $"{officePath}/swagger/v1/swagger.json"; + var swaggerPath = $"{officePath}/swagger/management/swagger.json"; var apiContract = JObject.Parse(await Client.GetStringAsync(urlToContract)); var generatedJsonString = await Client.GetStringAsync(swaggerPath); diff --git a/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index abc642e645..975031cf25 100644 --- a/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -80,7 +80,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest builder.ConfigureTestServices(services => { services.AddSingleton(); - + // Add a test auth scheme with a test auth handler to authn and assign the user services.AddAuthentication(TestAuthHandler.TestAuthenticationScheme) .AddScheme( @@ -245,6 +245,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest .AddWebsite() .AddUmbracoSqlServerSupport() .AddUmbracoSqliteSupport() + .AddDeliveryApi() .AddTestServices(TestHelper); // This is the important one! CustomTestSetup(builder); @@ -256,7 +257,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest /// protected virtual void ConfigureTestServices(IServiceCollection services) { - + } protected void Configure(IApplicationBuilder app)