Skip to content

Commit a428851

Browse files
authored
Merge pull request #650 from bcgov/yj
Yj
2 parents 2ea0c0a + ba70ade commit a428851

File tree

7 files changed

+185
-6
lines changed

7 files changed

+185
-6
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Microsoft.Extensions.Options;
2+
using Microsoft.OpenApi.Models;
3+
using Swashbuckle.AspNetCore.SwaggerGen;
4+
5+
namespace StrDss.Api
6+
{
7+
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
8+
{
9+
/// <summary>
10+
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
11+
/// </summary>
12+
/// <param name="options">The options specified by <see cref="SwaggerGenOptions"/> object</param>
13+
/// <inheritdoc />
14+
public void Configure(SwaggerGenOptions options)
15+
{
16+
17+
// Create Swagger documents per version and consumer
18+
options.SwaggerDoc(Common.ApiTags.Default, CreateInfoForApiVersion(Common.ApiTags.Default, "StrData"));
19+
options.SwaggerDoc(Common.ApiTags.Aps, CreateInfoForApiVersion(Common.ApiTags.Aps, $"StrData {Common.ApiTags.Aps}"));
20+
21+
// Include all paths
22+
options.DocInclusionPredicate((name, api) => true);
23+
24+
// Filter endpoints based on consumer
25+
options.DocumentFilter<SwaggerDocumentFilter>();
26+
27+
// Take first description on any conflict
28+
options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
29+
}
30+
31+
static OpenApiInfo CreateInfoForApiVersion(string version, string title)
32+
{
33+
var info = new OpenApiInfo()
34+
{
35+
Title = title,
36+
Version = version
37+
};
38+
39+
return info;
40+
}
41+
}
42+
}

server/StrDss.Api/Controllers/OrganizationsController.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using StrDss.Model;
77
using StrDss.Model.OrganizationDtos;
88
using StrDss.Service;
9+
using Swashbuckle.AspNetCore.Annotations;
910

1011
namespace StrDss.Api.Controllers
1112
{
@@ -44,7 +45,15 @@ public async Task<ActionResult<List<DropdownNumDto>>> GetOrganizationsDropdown(s
4445
return Ok(await _orgService.GetOrganizationsDropdownAsync(type));
4546
}
4647

47-
[ApiAuthorize]
48+
/// <summary>
49+
/// Retrieves the Short-Term Rental (STR) requirements for a specified location based on longitude and latitude coordinates.
50+
/// Validates the geographical boundaries of the input values to ensure they fall within acceptable ranges.
51+
/// </summary>
52+
/// <param name="longitude">The longitude of the location, must be between -180 and 180 degrees.</param>
53+
/// <param name="latitude">The latitude of the location, must be between -90 and 90 degrees.</param>
54+
/// <returns>An object containing STR requirements for the given location, or a validation error if the input is invalid.</returns>
55+
[ApiAuthorize] //todo: specify permission
56+
[SwaggerOperation(Tags = new string[] { Common.ApiTags.Aps })]
4857
[HttpGet("strrequirements", Name = "GetStrRequirements")]
4958
public async Task<ActionResult<StrRequirementsDto>> GetStrRequirements(double longitude, double latitude)
5059
{

server/StrDss.Api/Program.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
using StrDss.Service.Bceid;
1919
using Npgsql;
2020
using Serilog;
21-
using Microsoft.AspNetCore.Authentication;
21+
using Microsoft.Extensions.Options;
22+
using Swashbuckle.AspNetCore.SwaggerGen;
23+
using StrDss.Common;
2224

2325
var builder = WebApplication.CreateBuilder(args);
2426

@@ -158,7 +160,15 @@
158160

159161
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
160162
builder.Services.AddEndpointsApiExplorer();
161-
builder.Services.AddSwaggerGen();
163+
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
164+
builder.Services.AddSwaggerGen(options =>
165+
{
166+
options.EnableAnnotations();
167+
options.UseAllOfToExtendReferenceSchemas();
168+
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
169+
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
170+
options.IncludeXmlComments(xmlPath);
171+
});
162172

163173
var healthCheck = new HealthCheck(connString);
164174
builder.Services.AddHealthChecks().AddCheck("DbConnection", healthCheck);
@@ -168,8 +178,18 @@
168178
// Configure the HTTP request pipeline.
169179
if (app.Environment.IsDevelopment())
170180
{
171-
app.UseSwagger();
172-
app.UseSwaggerUI();
181+
app.UseSwagger(option =>
182+
{
183+
option.RouteTemplate = "api/swagger/{documentName}/swagger.json";
184+
});
185+
186+
app.UseSwaggerUI(option =>
187+
{
188+
option.SwaggerEndpoint($"/api/swagger/{ApiTags.Default}/swagger.json", ApiTags.Default);
189+
option.SwaggerEndpoint($"/api/swagger/{ApiTags.Aps}/swagger.json", ApiTags.Aps);
190+
191+
option.RoutePrefix = "api/swagger";
192+
});
173193
}
174194

175195
app.UseHealthChecks("/healthz");

server/StrDss.Api/StrDss.Api.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFramework>net7.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>True</GenerateDocumentationFile>
78
</PropertyGroup>
89

910
<ItemGroup>
@@ -19,6 +20,7 @@
1920
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
2021
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
2122
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
23+
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.7.3" />
2224
</ItemGroup>
2325

2426
<ItemGroup>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using Microsoft.OpenApi.Models;
2+
using Swashbuckle.AspNetCore.SwaggerGen;
3+
4+
namespace StrDss.Api
5+
{
6+
public class SwaggerDocumentFilter : IDocumentFilter
7+
{
8+
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
9+
{
10+
var filteredPaths = new OpenApiPaths();
11+
var referencedSchemas = new HashSet<string>();
12+
13+
if (swaggerDoc.Info.Version == Common.ApiTags.Aps)
14+
{
15+
foreach (var path in swaggerDoc.Paths)
16+
{
17+
var operation = path.Value?.Operations?.Values?.FirstOrDefault();
18+
19+
if (operation != null && operation.Tags.Any(t => Common.ApiTags.ApsTagList.Contains(t.Name)))
20+
{
21+
filteredPaths.Add(path.Key, path.Value);
22+
TrackSchemasInOperations(operation, referencedSchemas);
23+
}
24+
}
25+
}
26+
else
27+
{
28+
foreach (var path in swaggerDoc.Paths)
29+
{
30+
if (path.Key != null && path.Value != null)
31+
{
32+
filteredPaths.Add(path.Key, path.Value);
33+
34+
foreach (var operation in path.Value.Operations.Values)
35+
{
36+
TrackSchemasInOperations(operation, referencedSchemas);
37+
}
38+
}
39+
}
40+
}
41+
42+
swaggerDoc.Paths = filteredPaths;
43+
44+
// Filter schemas in components to only include those that are referenced
45+
var filteredSchemas = new Dictionary<string, OpenApiSchema>();
46+
foreach (var schemaKey in swaggerDoc.Components.Schemas.Keys)
47+
{
48+
if (referencedSchemas.Contains(schemaKey))
49+
{
50+
filteredSchemas.Add(schemaKey, swaggerDoc.Components.Schemas[schemaKey]);
51+
}
52+
}
53+
54+
// Update the document's components with filtered schemas
55+
swaggerDoc.Components.Schemas = filteredSchemas;
56+
}
57+
58+
/// <summary>
59+
/// Tracks the schemas used in the operation's parameters, request bodies, and responses.
60+
/// </summary>
61+
private void TrackSchemasInOperations(OpenApiOperation operation, HashSet<string> referencedSchemas)
62+
{
63+
// Track schemas from parameters
64+
foreach (var parameter in operation.Parameters)
65+
{
66+
if (parameter.Schema?.Reference != null)
67+
{
68+
referencedSchemas.Add(parameter.Schema.Reference.Id);
69+
}
70+
}
71+
72+
// Track schemas from request bodies
73+
if (operation.RequestBody?.Content != null)
74+
{
75+
foreach (var content in operation.RequestBody.Content.Values)
76+
{
77+
if (content.Schema?.Reference != null)
78+
{
79+
referencedSchemas.Add(content.Schema.Reference.Id);
80+
}
81+
}
82+
}
83+
84+
// Track schemas from responses
85+
foreach (var response in operation.Responses.Values)
86+
{
87+
foreach (var content in response.Content.Values)
88+
{
89+
if (content.Schema?.Reference != null)
90+
{
91+
referencedSchemas.Add(content.Schema.Reference.Id);
92+
}
93+
}
94+
}
95+
}
96+
97+
98+
}
99+
}

server/StrDss.Common/Constants.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,11 @@ public static class ListingExportFileNames
356356
public const string All = "BC";
357357
public const string AllPr = "BC_PR";
358358
}
359+
360+
public static class ApiTags
361+
{
362+
public const string Default = "stadata";
363+
public const string Aps = "aps";
364+
public static readonly string[] ApsTagList = { "aps" };
365+
}
359366
}

server/StrDss.Data/Repositories/OrganizationRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ FROM dss_organization
140140
OrganizationNm = o.OrganizationNm,
141141
IsPrincipalResidenceRequired = o.IsPrincipalResidenceRequired,
142142
IsBusinessLicenceRequired = o.IsBusinessLicenceRequired,
143-
IsStrProhibited = null
143+
IsStrProhibited = null //todo: map with the new column
144144
})
145145
.OrderBy(o => o.OrganizationNm)
146146
.FirstOrDefaultAsync();

0 commit comments

Comments
 (0)