diff --git a/API/Program.cs b/API/Program.cs index 02bb18b9..d35c5802 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -15,7 +15,6 @@ using OpenShock.Common.Services.LCGNodeProvisioner; using OpenShock.Common.Services.Ota; using OpenShock.Common.Services.Turnstile; -using OpenShock.Common.Swagger; using Serilog; var builder = OpenShockApplication.CreateDefaultBuilder(args); @@ -47,8 +46,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddSwaggerExt(); - builder.Services.AddSingleton(); builder.AddCloudflareTurnstileService(); diff --git a/Common/Common.csproj b/Common/Common.csproj index 49b9b52d..ee7eb1dc 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -12,6 +12,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -31,7 +32,6 @@ - diff --git a/Common/DataAnnotations/EmailAddressAttribute.cs b/Common/DataAnnotations/EmailAddressAttribute.cs index cf7a3ec0..269d08aa 100644 --- a/Common/DataAnnotations/EmailAddressAttribute.cs +++ b/Common/DataAnnotations/EmailAddressAttribute.cs @@ -1,9 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Net.Mail; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; using OpenShock.Common.Constants; -using OpenShock.Common.DataAnnotations.Interfaces; namespace OpenShock.Common.DataAnnotations; @@ -14,7 +11,7 @@ namespace OpenShock.Common.DataAnnotations; /// Inherits from . /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] -public sealed class EmailAddressAttribute : ValidationAttribute, IParameterAttribute +public sealed class EmailAddressAttribute : ValidationAttribute { /// /// Example value used to generate OpenApi documentation. @@ -55,15 +52,4 @@ public sealed class EmailAddressAttribute : ValidationAttribute, IParameterAttri return ValidationResult.Success; } - - /// - public void Apply(OpenApiSchema schema) - { - //if (ShouldValidate) schema.Pattern = ???; - - schema.Example = new OpenApiString(ExampleValue); - } - - /// - public void Apply(OpenApiParameter parameter) => Apply(parameter.Schema); } \ No newline at end of file diff --git a/Common/DataAnnotations/Interfaces/IOperationAttribute.cs b/Common/DataAnnotations/Interfaces/IOperationAttribute.cs deleted file mode 100644 index d47bd156..00000000 --- a/Common/DataAnnotations/Interfaces/IOperationAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.OpenApi.Models; - -namespace OpenShock.Common.DataAnnotations.Interfaces; - -/// -/// Represents an interface for operation attributes that can be applied to an OpenApiOperation instance. -/// -public interface IOperationAttribute -{ - /// - /// Applies the operation attribute to the given OpenApiOperation instance. - /// - /// The OpenApiOperation instance to apply the attribute to. - void Apply(OpenApiOperation operation); -} \ No newline at end of file diff --git a/Common/DataAnnotations/Interfaces/IParameterAttribute.cs b/Common/DataAnnotations/Interfaces/IParameterAttribute.cs deleted file mode 100644 index 295f4d5e..00000000 --- a/Common/DataAnnotations/Interfaces/IParameterAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.OpenApi.Models; - -namespace OpenShock.Common.DataAnnotations.Interfaces; - -/// -/// Represents an interface for parameter attributes that can be applied to an OpenApiSchema or OpenApiParameter instance. -/// -public interface IParameterAttribute -{ - /// - /// Applies the parameter attribute to the given OpenApiSchema instance. - /// - /// The OpenApiSchema instance to apply the attribute to. - void Apply(OpenApiSchema schema); - - /// - /// Applies the parameter attribute to the given OpenApiParameter instance. - /// - /// The OpenApiParameter instance to apply the attribute to. - void Apply(OpenApiParameter parameter); -} \ No newline at end of file diff --git a/Common/DataAnnotations/OpenApiSchemas.cs b/Common/DataAnnotations/OpenApiSchemas.cs deleted file mode 100644 index fe003b4e..00000000 --- a/Common/DataAnnotations/OpenApiSchemas.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using OpenShock.Common.Models; - -namespace OpenShock.Common.DataAnnotations; - -public static class OpenApiSchemas -{ - public static OpenApiSchema SemVerSchema => new OpenApiSchema { - Title = "SemVer", - Type = "string", - Pattern = /* lang=regex */ "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", - Example = new OpenApiString("1.0.0-dev+a16f2") - }; - - public static OpenApiSchema PauseReasonEnumSchema => new OpenApiSchema { - Title = nameof(PauseReason), - Type = "integer", - Description = """ - An integer representing the reason(s) for the shocker being paused, expressed as a bitfield where reasons are OR'd together. - - Each bit corresponds to: - - 1: Shocker - - 2: Share - - 4: ShareLink - - For example, a value of 6 (2 | 4) indicates both 'Share' and 'ShareLink' reasons. - """, - Example = new OpenApiInteger(6) - }; -} diff --git a/Common/DataAnnotations/PasswordAttribute.cs b/Common/DataAnnotations/PasswordAttribute.cs index 2aa2a8f1..f0fa11b7 100644 --- a/Common/DataAnnotations/PasswordAttribute.cs +++ b/Common/DataAnnotations/PasswordAttribute.cs @@ -1,9 +1,5 @@ using System.ComponentModel.DataAnnotations; -using System.Net.Mail; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; using OpenShock.Common.Constants; -using OpenShock.Common.DataAnnotations.Interfaces; namespace OpenShock.Common.DataAnnotations; @@ -14,7 +10,7 @@ namespace OpenShock.Common.DataAnnotations; /// Inherits from . /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] -public sealed class PasswordAttribute : ValidationAttribute, IParameterAttribute +public sealed class PasswordAttribute : ValidationAttribute { /// /// Example value used to generate OpenApi documentation. @@ -55,15 +51,4 @@ public sealed class PasswordAttribute : ValidationAttribute, IParameterAttribute return ValidationResult.Success; } - - /// - public void Apply(OpenApiSchema schema) - { - //if (ShouldValidate) schema.Pattern = ???; - - schema.Example = new OpenApiString(ExampleValue); - } - - /// - public void Apply(OpenApiParameter parameter) => Apply(parameter.Schema); } \ No newline at end of file diff --git a/Common/DataAnnotations/UsernameAttribute.cs b/Common/DataAnnotations/UsernameAttribute.cs index c0b366d7..2b4692d0 100644 --- a/Common/DataAnnotations/UsernameAttribute.cs +++ b/Common/DataAnnotations/UsernameAttribute.cs @@ -1,7 +1,4 @@ using System.ComponentModel.DataAnnotations; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using OpenShock.Common.DataAnnotations.Interfaces; using OpenShock.Common.Validation; namespace OpenShock.Common.DataAnnotations; @@ -13,7 +10,7 @@ namespace OpenShock.Common.DataAnnotations; /// Inherits from . /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] -public sealed class UsernameAttribute : ValidationAttribute, IParameterAttribute +public sealed class UsernameAttribute : ValidationAttribute { /// /// Example value used to generate OpenApi documentation. @@ -50,15 +47,4 @@ public sealed class UsernameAttribute : ValidationAttribute, IParameterAttribute error => new ValidationResult($"{error.Type} - {error.Message}") ); } - - /// - public void Apply(OpenApiSchema schema) - { - //if (ShouldValidate) schema.Pattern = ???; - - schema.Example = new OpenApiString(ExampleValue); - } - - /// - public void Apply(OpenApiParameter parameter) => Apply(parameter.Schema); } \ No newline at end of file diff --git a/Common/Models/LegacyDataResponse.cs b/Common/Models/LegacyDataResponse.cs index 6ca85caf..d4206bff 100644 --- a/Common/Models/LegacyDataResponse.cs +++ b/Common/Models/LegacyDataResponse.cs @@ -13,4 +13,4 @@ public LegacyDataResponse(T data, string message = "") public required string Message { get; set; } public required T Data { get; set; } -} \ No newline at end of file +} diff --git a/Common/Models/LegacyEmptyResponse.cs b/Common/Models/LegacyEmptyResponse.cs index cef9787c..77572581 100644 --- a/Common/Models/LegacyEmptyResponse.cs +++ b/Common/Models/LegacyEmptyResponse.cs @@ -13,4 +13,4 @@ public LegacyEmptyResponse(string message, object? data = null) public required string Message { get; set; } public object? Data { get; set; } -} \ No newline at end of file +} diff --git a/Common/OpenApi/OpenApiDocumentTransformer.cs b/Common/OpenApi/OpenApiDocumentTransformer.cs new file mode 100644 index 00000000..3e85d35a --- /dev/null +++ b/Common/OpenApi/OpenApiDocumentTransformer.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.OpenApi; +using Microsoft.OpenApi.Models; +using OpenShock.Common.Authentication; +using OpenShock.Common.Constants; + +namespace OpenShock.Common.OpenApi; + +public sealed class OpenApiDocumentTransformer : IOpenApiDocumentTransformer +{ + public Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken) + { + document.Info = new OpenApiInfo + { + Title = "OpenShock API", + Description = "Test description of API", + Version = "v" + context.DocumentName, + TermsOfService = new Uri("https://github.com/OpenShock/"), + Contact = new OpenApiContact + { + Name = "Support", + Url = new Uri("mailto:support@openshock.app"), + Email = "support@openshock.app" + }, + License = new OpenApiLicense + { + Name = "GNU affero General Public License v3.0", + Url = new Uri("https://github.com/OpenShock/API/blob/develop/LICENSE") + } + }; + document.Servers = [ +#if DEBUG + new OpenApiServer { Url = "https://localhost" }, +#endif + new OpenApiServer { Url = "https://api.openshock.app" }, + new OpenApiServer { Url = "https://api.openshock.dev" } + ]; + + return Task.CompletedTask; + } +} diff --git a/Common/OpenApi/OpenApiOperationTransformer.cs b/Common/OpenApi/OpenApiOperationTransformer.cs new file mode 100644 index 00000000..05c30bcd --- /dev/null +++ b/Common/OpenApi/OpenApiOperationTransformer.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.OpenApi; +using Microsoft.OpenApi.Models; + +namespace OpenShock.Common.OpenApi; + +public sealed class OpenApiOperationTransformer : IOpenApiOperationTransformer +{ + public Task TransformAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + if (context.Description.ActionDescriptor is not ControllerActionDescriptor actionDescriptor) + { + throw new NotImplementedException(); + } + + operation.OperationId = actionDescriptor.ControllerName + actionDescriptor.ActionName; + + return Task.CompletedTask; + } +} diff --git a/Common/OpenApi/OpenApiSchemaUtils.cs b/Common/OpenApi/OpenApiSchemaUtils.cs new file mode 100644 index 00000000..ab9bb351 --- /dev/null +++ b/Common/OpenApi/OpenApiSchemaUtils.cs @@ -0,0 +1,89 @@ +using Microsoft.AspNetCore.OpenApi; +using OpenShock.Common.Models; +using System.Text.Json.Serialization.Metadata; + +namespace OpenShock.Common.OpenApi; + +public static class OpenApiSchemaUtils +{ + private static readonly HashSet CollectionTypes = + [ + typeof(List<>), + typeof(IList<>), + typeof(IReadOnlyList<>), + typeof(IEnumerable<>), + typeof(IAsyncEnumerable<>), + typeof(IReadOnlyCollection<>) + ]; + + private static bool IsCollection(Type genericDef) => CollectionTypes.Contains(genericDef); + + private static bool IsSystemType(Type type) + { + if (Type.GetTypeCode(type) is not (TypeCode.Empty or TypeCode.Object or TypeCode.DBNull)) + return true; + + return type == typeof(Guid) || type == typeof(DateTimeOffset) || type == typeof(TimeSpan) || type == typeof(Uri); + } + + private static string? GetFriendlyGenericTypeName(Type type) + { + string suffix = ""; + + while (type.IsGenericType || type.IsArray) + { + if (type.IsArray) + { + suffix = "Array" + suffix; + type = type.GetElementType()!; + continue; + } + + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (genericTypeDefinition == typeof(LegacyDataResponse<>) || genericTypeDefinition == typeof(Nullable<>)) + { + type = type.GetGenericArguments()[0]; + if (IsSystemType(type)) return null; + continue; + } + + if (IsCollection(genericTypeDefinition)) + { + suffix = "Array" + suffix; + type = type.GetGenericArguments()[0]; + continue; + } + + if (genericTypeDefinition == typeof(Paginated<>)) + { + suffix = "Page" + suffix; + type = type.GetGenericArguments()[0]; + continue; + } + + throw new NotImplementedException(); + } + + return type.Name + suffix; + } + + private static string? GetFriendlyName(Type type) + { + if (IsSystemType(type)) return null; + + + if (type.IsGenericType || type.IsArray) return GetFriendlyGenericTypeName(type); + + return type.Name; + } + + + public static void ConfigureOptions(OpenApiOptions options) + { + options.CreateSchemaReferenceId = (jsonTypeInfo) => GetFriendlyName(jsonTypeInfo.Type); + + options.AddDocumentTransformer(); + options.AddOperationTransformer(); + } +} diff --git a/Common/OpenShockMiddlewareHelper.cs b/Common/OpenShockMiddlewareHelper.cs index 902634d9..24ff71c7 100644 --- a/Common/OpenShockMiddlewareHelper.cs +++ b/Common/OpenShockMiddlewareHelper.cs @@ -72,15 +72,15 @@ public static async Task UseCommonOpenShockMiddleware(this return remoteIp != null && metricsAllowedIpNetworks.Any(x => x.Contains(remoteIp)); }); - app.UseSwagger(); + app.MapOpenApi() + .CacheOutput(); - Action scalarOptions = options => + app.MapScalarApiReference("/openapi/scalar", options => options - .WithOpenApiRoutePattern("/swagger/{documentName}/swagger.json") + .WithOpenApiRoutePattern("/openapi/{documentName}.json") .AddDocument("1", "Version 1") - .AddDocument("2", "Version 2"); - - app.MapScalarApiReference("/scalar/viewer", scalarOptions); + .AddDocument("2", "Version 2") + ); app.MapControllers(); diff --git a/Common/OpenShockServiceHelper.cs b/Common/OpenShockServiceHelper.cs index c325590a..0caf8a66 100644 --- a/Common/OpenShockServiceHelper.cs +++ b/Common/OpenShockServiceHelper.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.OpenApi; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection.Extensions; using OpenShock.Common.Authentication; @@ -9,6 +10,7 @@ using OpenShock.Common.Authentication.Services; using OpenShock.Common.ExceptionHandle; using OpenShock.Common.JsonSerialization; +using OpenShock.Common.OpenApi; using OpenShock.Common.OpenShockDb; using OpenShock.Common.Options; using OpenShock.Common.Problems; @@ -116,7 +118,10 @@ public static IServiceCollection AddOpenShockServices(this IServiceCollection se x.JsonSerializerOptions.Converters.Add(new PermissionTypeConverter()); x.JsonSerializerOptions.Converters.Add(new CustomJsonStringEnumConverter()); }); - + + services.AddOpenApi("1", OpenApiSchemaUtils.ConfigureOptions); + services.AddOpenApi("2", OpenApiSchemaUtils.ConfigureOptions); + var apiVersioningBuilder = services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); diff --git a/Common/Swagger/AttributeFilter.cs b/Common/Swagger/AttributeFilter.cs deleted file mode 100644 index a186a942..00000000 --- a/Common/Swagger/AttributeFilter.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.OpenApi.Models; -using OpenShock.Common.Authentication; -using OpenShock.Common.DataAnnotations.Interfaces; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace OpenShock.Common.Swagger; - -public sealed class AttributeFilter : ISchemaFilter, IParameterFilter, IOperationFilter -{ - public void Apply(OpenApiParameter parameter, ParameterFilterContext context) - { - // Apply OpenShock Parameter Attributes - foreach (var attribute in context.ParameterInfo?.GetCustomAttributes(true).OfType() ?? []) - { - attribute.Apply(parameter); - } - - // Apply OpenShock Parameter Attributes - foreach (var attribute in context.PropertyInfo?.GetCustomAttributes(true).OfType() ?? []) - { - attribute.Apply(parameter); - } - } - - public void Apply(OpenApiSchema schema, SchemaFilterContext context) - { - // Apply OpenShock Parameter Attributes - foreach (var attribute in context.MemberInfo?.GetCustomAttributes(true).OfType() ?? []) - { - attribute.Apply(schema); - } - } - - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - // Apply OpenShock Parameter Attributes - foreach (var attribute in context.MethodInfo?.GetCustomAttributes(true).OfType() ?? []) - { - attribute.Apply(operation); - } - - // Get Authorize attribute - var attributes = context.MethodInfo?.DeclaringType?.GetCustomAttributes(true) - .Union(context.MethodInfo.GetCustomAttributes(true)) - .OfType() - .ToArray() ?? []; - - if (attributes.Length != 0) - { - if (attributes.Count(attr => !string.IsNullOrEmpty(attr.AuthenticationSchemes)) > 1) throw new Exception("Dunno what to apply to this method (multiple authentication attributes with schemes set)"); - - var scheme = attributes.Select(attr => attr.AuthenticationSchemes).SingleOrDefault(scheme => !string.IsNullOrEmpty(scheme)); - var roles = attributes.Select(attr => attr.Roles).Where(roles => !string.IsNullOrEmpty(roles)).SelectMany(roles => roles!.Split(',')).Select(role => role.Trim()).ToArray(); - var policies = attributes.Select(attr => attr.Policy).Where(policies => !string.IsNullOrEmpty(policies)).SelectMany(policies => policies!.Split(',')).Select(policy => policy.Trim()).ToArray(); - - // Add what should be show inside the security section - List securityInfos = []; - if (!string.IsNullOrEmpty(scheme)) securityInfos.Add($"{nameof(AuthorizeAttribute.AuthenticationSchemes)}:{scheme}"); - if (roles.Length > 0) securityInfos.Add($"{nameof(AuthorizeAttribute.Roles)}:{string.Join(',', roles)}"); - if (policies.Length > 0) securityInfos.Add($"{nameof(AuthorizeAttribute.Policy)}:{string.Join(',', policies)}"); - - List securityRequirements = []; - foreach (var authenticationScheme in scheme?.Split(',').Select(s => s.Trim()) ?? []) - { - securityRequirements.AddRange(authenticationScheme switch - { - OpenShockAuthSchemas.UserSessionCookie => [ - new OpenApiSecurityRequirement {{ - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.UserSessionCookie, - Type = ReferenceType.SecurityScheme, - } - }, - securityInfos - }} - ], - OpenShockAuthSchemas.ApiToken => [ - new OpenApiSecurityRequirement {{ - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.ApiToken, - Type = ReferenceType.SecurityScheme, - } - }, - securityInfos - }} - ], - OpenShockAuthSchemas.HubToken => [ - new OpenApiSecurityRequirement {{ - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.HubToken, - Type = ReferenceType.SecurityScheme - } - }, - securityInfos - }} - ], - _ => [], - }); - } - - operation.Security = securityRequirements; - } - else - { - operation.Security.Clear(); - } - } -} diff --git a/Common/Swagger/SwaggerGenExtensions.cs b/Common/Swagger/SwaggerGenExtensions.cs deleted file mode 100644 index c0b130ee..00000000 --- a/Common/Swagger/SwaggerGenExtensions.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Microsoft.OpenApi.Models; -using OpenShock.Common.Constants; -using OpenShock.Common.DataAnnotations; -using OpenShock.Common.Models; -using Semver; -using OpenShock.Common.Utils; -using Asp.Versioning; -using OpenShock.Common.Extensions; -using OpenShock.Common.Authentication; - -namespace OpenShock.Common.Swagger; - -public static class SwaggerGenExtensions -{ - public static IServiceCollection AddSwaggerExt(this IServiceCollection services) where TProgram : class - { - var assembly = typeof(TProgram).Assembly; - - string assemblyName = assembly - .GetName() - .Name ?? throw new NullReferenceException("Assembly name"); - - var versions = assembly.GetAllControllerEndpointAttributes() - .SelectMany(type => type.Versions) - .Select(v => v.ToString()) - .ToHashSet() - .OrderBy(v => v) - .ToArray(); - - if (versions.Any(v => !int.TryParse(v, out _))) - { - throw new InvalidDataException($"Found invalid API versions: [{string.Join(", ", versions.Where(v => !int.TryParse(v, out _)))}]"); - } - - return services - .AddSwaggerGen(options => - { - options.CustomOperationIds(e => - $"{e.ActionDescriptor.RouteValues["controller"]}_{e.ActionDescriptor.AttributeRouteInfo?.Name ?? e.ActionDescriptor.RouteValues["action"]}"); - options.SchemaFilter(); - options.ParameterFilter(); - options.OperationFilter(); - options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, assemblyName + ".xml"), true); - options.AddSecurityDefinition(OpenShockAuthSchemas.UserSessionCookie, new OpenApiSecurityScheme - { - Name = AuthConstants.UserSessionCookieName, - Description = "Enter user session cookie", - In = ParameterLocation.Cookie, - Type = SecuritySchemeType.ApiKey, - Scheme = OpenShockAuthSchemas.UserSessionCookie, - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.UserSessionCookie, - Type = ReferenceType.SecurityScheme, - } - }); - options.AddSecurityDefinition(OpenShockAuthSchemas.ApiToken, new OpenApiSecurityScheme - { - Name = AuthConstants.ApiTokenHeaderName, - Description = "Enter API Token", - In = ParameterLocation.Header, - Type = SecuritySchemeType.ApiKey, - Scheme = OpenShockAuthSchemas.ApiToken, - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.ApiToken, - Type = ReferenceType.SecurityScheme, - } - }); - options.AddSecurityDefinition(OpenShockAuthSchemas.HubToken, new OpenApiSecurityScheme - { - Name = AuthConstants.HubTokenHeaderName, - Description = "Enter hub token", - In = ParameterLocation.Header, - Type = SecuritySchemeType.ApiKey, - Scheme = OpenShockAuthSchemas.HubToken, - Reference = new OpenApiReference - { - Id = OpenShockAuthSchemas.HubToken, - Type = ReferenceType.SecurityScheme, - } - }); - options.AddServer(new OpenApiServer { Url = "https://api.openshock.app" }); - options.AddServer(new OpenApiServer { Url = "https://api.openshock.dev" }); -#if DEBUG - options.AddServer(new OpenApiServer { Url = "https://localhost" }); -#endif - foreach (var version in versions) - { - options.SwaggerDoc("v" + version, new OpenApiInfo { Title = "OpenShock", Version = version }); - } - options.MapType(() => OpenApiSchemas.SemVerSchema); - options.MapType(() => OpenApiSchemas.PauseReasonEnumSchema); - - // Avoid nullable strings everywhere - options.SupportNonNullableReferenceTypes(); - }) - .ConfigureOptions(); - } -} diff --git a/Common/Utils/ConfigureSwaggerOptions.cs b/Common/Utils/ConfigureSwaggerOptions.cs deleted file mode 100644 index 2dbc2694..00000000 --- a/Common/Utils/ConfigureSwaggerOptions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Asp.Versioning.ApiExplorer; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace OpenShock.Common.Utils; - -public sealed class ConfigureSwaggerOptions : IConfigureNamedOptions -{ - private readonly IApiVersionDescriptionProvider _provider; - - public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) - { - _provider = provider; - } - - public void Configure(SwaggerGenOptions options) - { - // add swagger document for every API version discovered - foreach (var description in _provider.ApiVersionDescriptions) - options.SwaggerDoc( - description.GroupName, - CreateVersionInfo(description)); - } - - public void Configure(string? name, SwaggerGenOptions options) => Configure(options); - - private static OpenApiInfo CreateVersionInfo( - ApiVersionDescription description) - { - var info = new OpenApiInfo - { - Title = "OpenShock.API", - Version = description.ApiVersion.ToString() - }; - if (description.IsDeprecated) info.Description += " This API version has been deprecated."; - return info; - } -} \ No newline at end of file diff --git a/LiveControlGateway/Program.cs b/LiveControlGateway/Program.cs index 37c2ef8e..a40e09dc 100644 --- a/LiveControlGateway/Program.cs +++ b/LiveControlGateway/Program.cs @@ -4,7 +4,6 @@ using OpenShock.Common.JsonSerialization; using OpenShock.Common.Services.Device; using OpenShock.Common.Services.Ota; -using OpenShock.Common.Swagger; using OpenShock.LiveControlGateway; using OpenShock.LiveControlGateway.LifetimeManager; using OpenShock.LiveControlGateway.Options; @@ -33,8 +32,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddSwaggerExt(); - //services.AddHealthChecks().AddCheck("database"); builder.Services.AddHostedService();