Browse Source

Continued with refactorings.

pull/336/head
Sebastian Stehle 7 years ago
parent
commit
5f98cf838d
  1. 1
      src/Squidex/Areas/Api/Config/Swagger/ODataQueryParamsProcessor.cs
  2. 62
      src/Squidex/Areas/Api/Config/Swagger/SecurityProcessor.cs
  3. 2
      src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs
  4. 59
      src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs
  5. 10
      src/Squidex/Areas/Api/Config/Swagger/ThemeProcessor.cs
  6. 6
      src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs
  7. 26
      src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasSwaggerGenerator.cs
  8. 49
      src/Squidex/Pipeline/Swagger/SwaggerHelper.cs

1
src/Squidex/Areas/Api/Config/Swagger/ODataQueryParamsProcessor.cs

@ -23,6 +23,7 @@ namespace Squidex.Areas.Api.Config.Swagger
public ODataQueryParamsProcessor(string supportedPath, string entity, bool supportSearch)
{
this.entity = entity;
this.supportSearch = supportSearch;
this.supportedPath = supportedPath;
}

62
src/Squidex/Areas/Api/Config/Swagger/SecurityProcessor.cs

@ -0,0 +1,62 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.Extensions.Options;
using NSwag;
using NSwag.SwaggerGeneration.Processors.Security;
using Squidex.Config;
namespace Squidex.Areas.Api.Config.Swagger
{
public class SecurityProcessor : SecurityDefinitionAppender
{
public SecurityProcessor(IOptions<MyUrlsOptions> urlOptions)
: base(Constants.SecurityDefinition, CreateOAuthSchema(urlOptions.Value))
{
}
private static SwaggerSecurityScheme CreateOAuthSchema(MyUrlsOptions urlOptions)
{
var securityScheme = new SwaggerSecurityScheme();
var tokenUrl = urlOptions.BuildUrl($"{Constants.IdentityServerPrefix}/connect/token", false);
securityScheme.TokenUrl = tokenUrl;
var securityDocs = LoadDocs("security");
var securityText = securityDocs.Replace("<TOKEN_URL>", tokenUrl);
securityScheme.Description = securityText;
securityScheme.Type = SwaggerSecuritySchemeType.OAuth2;
securityScheme.Flow = SwaggerOAuth2Flow.Application;
securityScheme.Scopes = new Dictionary<string, string>
{
{ Constants.ApiScope, "Read and write access to the API" }
};
return securityScheme;
}
private static string LoadDocs(string name)
{
var assembly = typeof(SecurityProcessor).GetTypeInfo().Assembly;
using (var resourceStream = assembly.GetManifestResourceStream($"Squidex.Docs.{name}.md"))
{
using (var streamReader = new StreamReader(resourceStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}

2
src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs

@ -16,7 +16,7 @@ namespace Squidex.Areas.Api.Config.Swagger
{
app.UseSwagger(settings =>
{
settings.Path = $"{Constants.ApiPrefix}/swagger/v1/swagger.json";
settings.Path = $"{Constants.ApiPrefix}/swagger/{{documentName}}/swagger.json";
});
}
}

59
src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs

@ -7,19 +7,15 @@
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NJsonSchema;
using NJsonSchema.Generation.TypeMappers;
using NodaTime;
using NSwag.AspNetCore;
using NSwag.SwaggerGeneration;
using NSwag.SwaggerGeneration.Processors;
using NSwag.SwaggerGeneration.Processors.Security;
using Squidex.Areas.Api.Controllers.Contents.Generator;
using Squidex.Areas.Api.Controllers.Rules.Models;
using Squidex.Config;
using Squidex.Infrastructure;
using Squidex.Pipeline.Swagger;
namespace Squidex.Areas.Api.Config.Swagger
{
@ -30,63 +26,37 @@ namespace Squidex.Areas.Api.Config.Swagger
services.AddSingletonAs<RuleActionProcessor>()
.As<IDocumentProcessor>();
services.AddSingletonAs<ThemeProcessor>()
.As<IDocumentProcessor>();
services.AddSingletonAs<XmlTagProcessor>()
.As<IDocumentProcessor>();
services.AddSingletonAs<ScopesProcessor>()
.As<IOperationProcessor>();
services.AddSingletonAs<TagByGroupNameProcessor>()
.As<IOperationProcessor>();
services.AddSingletonAs<XmlResponseTypesProcessor>()
.As<IOperationProcessor>();
services.AddSingleton(c =>
{
var settings = new SwaggerDocumentSettings { SchemaType = SchemaType.OpenApi3 };
return new SwaggerDocumentRegistration(settings.DocumentName, generator);
}))
settings.DocumentProcessors.Add(new RuleActionProcessor());
settings.DocumentProcessors.Add(new XmlTagProcessor());
settings.OperationProcessors.Add(new TagByGroupNameProcessor());
settings.OperationProcessors.Add(new XmlResponseTypesProcessor());
services.AddOpenApiDocument(configure =>
services.AddOpenApiDocument(settings =>
{
var urlOptions = configure.GetService<IOptions<MyUrlsOptions>>().Value;
settings.ConfigureName();
settings.ConfigureSchemaSettings();
configure.AddAssetODataParams();
configure.ConfigureNames();
configure.ConfigurePaths(urlOptions);
configure.ConfigureSchemaSettings();
configure.ConfigureIdentity(urlOptions);
settings.OperationProcessors.Add(new ODataQueryParamsProcessor("/apps/{app}/assets", "assets", false));
});
services.AddTransient<SchemasSwaggerGenerator>();
}
public static void AddAssetODataParams<T>(this T settings) where T : SwaggerGeneratorSettings
{
settings.OperationProcessors.Add(new ODataQueryParamsProcessor("/apps/{app}/assets", "assets", false));
}
public static void ConfigureNames<T>(this T settings) where T : SwaggerGeneratorSettings
public static void ConfigureName<T>(this T settings) where T : SwaggerGeneratorSettings
{
settings.Title = "Squidex API";
}
public static void ConfigureIdentity<T>(this T settings, MyUrlsOptions urlOptions) where T : SwaggerGeneratorSettings
{
settings.DocumentProcessors.Add(
new SecurityDefinitionAppender(
Constants.SecurityDefinition, SwaggerHelper.CreateOAuthSchema(urlOptions)));
settings.OperationProcessors.Add(new ScopesProcessor());
}
public static void ConfigureSchemaSettings<T>(this T settings) where T : SwaggerGeneratorSettings
{
settings.DefaultEnumHandling = EnumHandling.String;
@ -99,15 +69,10 @@ namespace Squidex.Areas.Api.Config.Swagger
schema.Type = JsonObjectType.String;
schema.Format = JsonFormatStrings.DateTime;
}),
new PrimitiveTypeMapper(typeof(Language), s => s.Type = JsonObjectType.String),
new PrimitiveTypeMapper(typeof(RefToken), s => s.Type = JsonObjectType.String)
};
settings.DocumentProcessors.Add(new RuleActionProcessor());
settings.DocumentProcessors.Add(new XmlTagProcessor());
settings.OperationProcessors.Add(new TagByGroupNameProcessor());
settings.OperationProcessors.Add(new XmlResponseTypesProcessor());
}
}
}

10
src/Squidex/Areas/Api/Config/Swagger/LogoProcessor.cs → src/Squidex/Areas/Api/Config/Swagger/ThemeProcessor.cs

@ -15,15 +15,15 @@ using Squidex.Infrastructure.Tasks;
namespace Squidex.Areas.Api.Config.Swagger
{
public class LogoProcessor : IDocumentProcessor
public sealed class ThemeProcessor : IDocumentProcessor
{
private const string Background = "#3f83df";
private readonly string logo;
private readonly string url;
public LogoProcessor(IOptions<MyUrlsOptions> urlOptions)
public ThemeProcessor(IOptions<MyUrlsOptions> urlOptions)
{
logo = urlOptions.Value.BuildUrl("images/logo-white.png", false);
url = urlOptions.Value.BuildUrl("images/logo-white.png", false);
}
public Task ProcessAsync(DocumentProcessorContext context)
@ -32,7 +32,7 @@ namespace Squidex.Areas.Api.Config.Swagger
context.Document.Info.ExtensionData = new Dictionary<string, object>
{
["x-logo"] = new { url = logo, backgroundColor = Background }
["x-logo"] = new { url, backgroundColor = Background }
};
return TaskHelper.Done;

6
src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs

@ -60,12 +60,10 @@ namespace Squidex.Areas.Api.Config.Swagger
private static async Task AddInternalErrorResponseAsync(OperationProcessorContext context, SwaggerOperation operation)
{
if (operation.Responses.ContainsKey("500"))
if (!operation.Responses.ContainsKey("500"))
{
return;
operation.AddResponse("500", "Operation failed", await context.SchemaGenerator.GetErrorDtoSchemaAsync(context.SchemaResolver));
}
operation.AddResponse("500", "Operation failed", await context.SchemaGenerator.GetErrorDtoSchemaAsync(context.SchemaResolver));
}
private static void RemoveOkResponse(SwaggerOperation operation)

26
src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemasSwaggerGenerator.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -14,6 +15,8 @@ using NJsonSchema;
using NSwag;
using NSwag.AspNetCore;
using NSwag.SwaggerGeneration;
using NSwag.SwaggerGeneration.Processors;
using NSwag.SwaggerGeneration.Processors.Contexts;
using Squidex.Areas.Api.Config.Swagger;
using Squidex.Config;
using Squidex.Domain.Apps.Entities.Apps;
@ -31,12 +34,16 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator
private SwaggerDocument document;
private JsonSchemaResolver schemaResolver;
public SchemasSwaggerGenerator(IOptions<MyUrlsOptions> urlOptions)
public SchemasSwaggerGenerator(IOptions<MyUrlsOptions> urlOptions, IEnumerable<IDocumentProcessor> documentProcessors)
{
this.urlOptions = urlOptions.Value;
settings.ConfigureNames();
settings.Conf
settings.ConfigureSchemaSettings();
foreach (var processor in documentProcessors)
{
settings.DocumentProcessors.Add(processor);
}
}
public async Task<SwaggerDocument> Generate(HttpContext httpContext, IAppEntity app, IEnumerable<ISchemaEntity> schemas)
@ -50,6 +57,19 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator
await GenerateDefaultErrorsAsync();
var context =
new DocumentProcessorContext(document,
Enumerable.Empty<Type>(),
Enumerable.Empty<Type>(),
schemaResolver,
schemaGenerator,
settings);
foreach (var processor in settings.DocumentProcessors)
{
await processor.ProcessAsync(context);
}
return document;
}

49
src/Squidex/Pipeline/Swagger/SwaggerHelper.cs

@ -7,9 +7,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using NJsonSchema;
@ -21,19 +19,6 @@ namespace Squidex.Pipeline.Swagger
{
public static class SwaggerHelper
{
public static string LoadDocs(string name)
{
var assembly = typeof(SwaggerHelper).GetTypeInfo().Assembly;
using (var resourceStream = assembly.GetManifestResourceStream($"Squidex.Docs.{name}.md"))
{
using (var streamReader = new StreamReader(resourceStream))
{
return streamReader.ReadToEnd();
}
}
}
public static SwaggerDocument CreateApiDocument(HttpContext context, MyUrlsOptions urlOptions, string appName)
{
var scheme =
@ -43,7 +28,6 @@ namespace Squidex.Pipeline.Swagger
var document = new SwaggerDocument
{
Tags = new List<SwaggerTag>(),
Schemes = new List<SwaggerSchema>
{
scheme
@ -58,13 +42,9 @@ namespace Squidex.Pipeline.Swagger
},
Info = new SwaggerInfo
{
ExtensionData = new Dictionary<string, object>
{
["x-logo"] = new { url = urlOptions.BuildUrl("images/logo-white.png", false), backgroundColor = "#3f83df" }
},
Title = $"Squidex API for {appName} App", Version = "1.0"
Title = $"Squidex API for {appName} App"
},
BasePath = "/api"
BasePath = Constants.ApiPrefix
};
if (!string.IsNullOrWhiteSpace(context.Request.Host.Value))
@ -72,34 +52,9 @@ namespace Squidex.Pipeline.Swagger
document.Host = context.Request.Host.Value;
}
document.SecurityDefinitions.Add(Constants.SecurityDefinition, CreateOAuthSchema(urlOptions));
return document;
}
public static SwaggerSecurityScheme CreateOAuthSchema(MyUrlsOptions urlOptions)
{
var tokenUrl = urlOptions.BuildUrl($"{Constants.IdentityServerPrefix}/connect/token", false);
var securityDocs = LoadDocs("security");
var securityText = securityDocs.Replace("<TOKEN_URL>", tokenUrl);
var result =
new SwaggerSecurityScheme
{
TokenUrl = tokenUrl,
Type = SwaggerSecuritySchemeType.OAuth2,
Flow = SwaggerOAuth2Flow.Application,
Scopes = new Dictionary<string, string>
{
{ Constants.ApiScope, "Read and write access to the API" }
},
Description = securityText
};
return result;
}
public static async Task<JsonSchema4> GetErrorDtoSchemaAsync(this JsonSchemaGenerator schemaGenerator, JsonSchemaResolver resolver)
{
var errorType = typeof(ErrorDto);

Loading…
Cancel
Save