Skip to content

Commit

Permalink
Improved Swagger output
Browse files Browse the repository at this point in the history
  • Loading branch information
da3dsoul committed Oct 5, 2023
1 parent 98a2bff commit 9765698
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 33 deletions.
5 changes: 3 additions & 2 deletions Shoko.Server/API/APIExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ public static IServiceCollection AddAPI(this IServiceCollection services)

options.AddPlugins();

options.MapType<SeriesType>(() => new OpenApiSchema { Type = "string" });
options.MapType<EpisodeType>(() => new OpenApiSchema { Type = "string" });
options.SchemaFilter<EnumSchemaFilter<EpisodeType>>();
options.SchemaFilter<EnumSchemaFilter<SeriesType>>();
options.SchemaFilter<EnumSchemaFilter<Filter.FilterExpressionHelp.FilterExpressionParameterType>>();

options.CustomSchemaIds(GetTypeName);
});
Expand Down
21 changes: 21 additions & 0 deletions Shoko.Server/API/Swagger/EnumSchemaFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Shoko.Server.API.Swagger;

public class EnumSchemaFilter<T> : ISchemaFilter where T : struct, Enum
{
private string[] _names;

public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (!context.Type.IsEnum) return;
if (context.Type != typeof(T)) return;

model.Enum.Clear();
_names ??= Enum.GetNames<T>();
Array.ForEach(_names, name => model.Enum.Add(new OpenApiString(name)));
}
}
24 changes: 14 additions & 10 deletions Shoko.Server/API/v3/Controllers/FilterController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,14 @@ public ActionResult<Filter> AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b

/// <summary>
/// Lists the available expressions.
/// The word "Filterable" is used a lot. It is a generic word for a series or group, depending on what the filter is set to apply to.
/// Expression: The identifier used to create the expression. eg. And, Not, HasTag.
/// Type: Parameters have a type, and this is the type that needs to match.
/// Left, Right, Parameter, and SecondParameter show what type the expression supports as parameters.
/// Left and Right are Expressions or Selectors. Parameters are constants.
/// </summary>
/// <remarks>
/// The word "Filterable" is used a lot. It is a generic word for a series or group, depending on what the filter is set to apply to.
/// Expression: The identifier used to create the expression. eg. And, Not, HasTag.
/// Type: Parameters have a type, and this is the type that needs to match.
/// Left, Right, Parameter, and SecondParameter show what type the expression supports as parameters.
/// Left and Right are Expressions or Selectors. Parameters are constants.
/// </remarks>
[HttpGet("Expressions")]
public ActionResult<Filter.FilterExpressionHelp[]> GetExpressions()
{
Expand Down Expand Up @@ -163,12 +165,14 @@ public ActionResult<Filter> AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b

/// <summary>
/// Lists the available sorting expressions. These are basically selectors that the filter system uses to sort.
/// The word "Filterable" is used a lot. It is a generic word for a series or group, depending on what the filter is set to apply to.
/// Type: The identifier used to create the expression. eg. AddedDate.
/// IsInverted: Whether the sorting should be in descending order.
/// Next: If the expression returns equal values, it defers to the next expression to sort more predictably.
/// For example, MissingEpisodeCount,Descending -> AirDate, Descending would have thing with the most missing episodes, then the last aired first.
/// </summary>
/// <remarks>
/// The word "Filterable" is used a lot. It is a generic word for a series or group, depending on what the filter is set to apply to.
/// Type: The identifier used to create the expression. eg. AddedDate.
/// IsInverted: Whether the sorting should be in descending order.
/// Next: If the expression returns equal values, it defers to the next expression to sort more predictably.
/// For example, MissingEpisodeCount,Descending -> AirDate, Descending would have thing with the most missing episodes, then the last aired first.
/// </remarks>
[HttpGet("SortingCriteria")]
public ActionResult<Filter.SortingCriteriaHelp[]> GetSortingCriteria()
{
Expand Down
40 changes: 20 additions & 20 deletions Shoko.Server/API/v3/Models/Shoko/Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,39 +69,39 @@ public class FilterIDs : IDs
public class FilterCondition
{
/// <summary>
/// Condition Type. What it does.
/// This is not the GroupFilterConditionType, but the type of the FilterExpression, with 'Expression' removed.
/// Condition Type. What it does.<br/>
/// This is not the GroupFilterConditionType, but the type of the FilterExpression, with 'Expression' removed.<br/>
/// ex. And, Or, Not, HasAudioLanguage
/// </summary>
[Required]
public string Type { get; set; }

/// <summary>
/// The first, or left, child expression.
/// This might be another logic operator like And, a selector for data like Today's Date, or an expression like HasAudioLanguage.
/// The first, or left, child expression.<br/>
/// This might be another logic operator like And, a selector for data like Today's Date, or an expression like HasAudioLanguage.<br/>
/// Whether this is included depends on the expression.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public FilterCondition? Left { get; set; }

/// <summary>
/// The second, or right, child expression.
/// This might be another logic operator like And, a selector for data like Today's Date, or an expression like HasAudioLanguage.
/// The second, or right, child expression.<br/>
/// This might be another logic operator like And, a selector for data like Today's Date, or an expression like HasAudioLanguage.<br/>
/// Whether this is included depends on the expression.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public FilterCondition? Right { get; set; }

/// <summary>
/// The actual value to compare. Dependent on the expression type.
/// The actual value to compare. Dependent on the expression type.<br/>
/// Coerced this to string to make things easier.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string? Parameter { get; set; }

/// <summary>
/// The actual value to compare. Dependent on the expression type.
/// Very few things have a second parameter. Seasons are one of them
/// The actual value to compare. Dependent on the expression type.<br/>
/// Very few things have a second parameter. Seasons are one of them<br/>
/// Coerced this to string to make things easier.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Expand All @@ -111,7 +111,7 @@ public class FilterCondition
public class FilterExpressionHelp
{
/// <summary>
/// The internal type name of the FilterExpression
/// The internal type name of the FilterExpression<br/>
/// This is what you give the API, not actually the internal type (it is the internal type without the word Expression)
/// </summary>
[Required]
Expand All @@ -138,15 +138,15 @@ public class FilterExpressionHelp
public FilterExpressionParameterType? Left { get; init; }

/// <summary>
/// The parameter types that the <see cref="FilterCondition.Right"/> property requires
/// The parameter types that the <see cref="FilterCondition.Right"/> property requires<br/>
/// If multiple are given, then at least one is required
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public FilterExpressionParameterType? Right { get; init; }

/// <summary>
/// The parameter type that the <see cref="FilterCondition.Parameter"/> property requires.
/// The parameter type that the <see cref="FilterCondition.Parameter"/> property requires.<br/>
/// This will always be a string for simplicity in type safety, but the type is what it expects
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Expand All @@ -164,7 +164,7 @@ public class FilterExpressionHelp
public string[]? PossibleSecondParameters { get; init; }

/// <summary>
/// The parameter type that the <see cref="FilterCondition.SecondParameter"/> property requires
/// The parameter type that the <see cref="FilterCondition.SecondParameter"/> property requires<br/>
/// This will always be a string for simplicity in type safety, but the type is what it expects
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Expand All @@ -188,8 +188,8 @@ public bool ShouldSerializePossibleSecondParameters()
}

/// <summary>
/// The type of the parameter. Expressions return a boolean, Selectors return the type of their name, and the rest are values from the user.
/// Dates are in yyyy-MM-dd format
/// The type of the parameter. Expressions return a boolean, Selectors return the type of their name, and the rest are values from the user.<br/>
/// Dates are in yyyy-MM-dd format<br/>
/// TimeSpans are in d:HH:mm:ss.ffff format (f is milliseconds)
/// </summary>
public enum FilterExpressionParameterType
Expand All @@ -208,7 +208,7 @@ public enum FilterExpressionParameterType
public class SortingCriteriaHelp
{
/// <summary>
/// The internal type name of the FilterExpression
/// The internal type name of the FilterExpression<br/>
/// This is what you give the API, not actually the internal type (it is the internal type without the word Expression)
/// </summary>
[Required]
Expand All @@ -222,16 +222,16 @@ public class SortingCriteriaHelp
}

/// <summary>
/// Sorting Criteria hold info on how Group Filters sort their items.
/// Sorting Criteria hold info on how Group Filters sort their items.<br/>
/// It is in a List to follow an OrderBy().ThenBy().ThenBy(), allowing
/// consistent results with fallbacks.
/// </summary>
public class SortingCriteria
{
/// <summary>
/// The sorting type. What it is sorted on.
/// This is not the GroupFilterSorting, but the type of the SortingExpression, with 'Expression' removed.
/// ex. And, Or, Not, HasAudioLanguage
/// The sorting type. What it is sorted on.<br/>
/// This is not the GroupFilterSorting, but the type of the SortingExpression, with 'Expression' removed.<br/>
/// ex. And, Or, Not, HasAudioLanguage<br/>
/// </summary>
[Required]
public string Type { get; set; }
Expand Down
3 changes: 2 additions & 1 deletion Shoko.Server/Filters/Info/InSeasonExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public InSeasonExpression() { }
public AnimeSeason Season { get; set; }
public override bool TimeDependent => false;
public override bool UserDependent => false;
public override string HelpDescription => "This passes if any of the anime aired in the season given in the parameters";
public override string HelpDescription => "This passes if any of the anime aired in the season given in the parameters." +
"The first parameter is the Year, while the second parameter is the Season.";
public override string[] HelpPossibleSecondParameters => new[]
{
AnimeSeason.Winter.ToString(), AnimeSeason.Spring.ToString(),
Expand Down

0 comments on commit 9765698

Please sign in to comment.