Add swagger, tidy up, fix docker, and add docker-compose.yml

This commit is contained in:
Mike 2024-11-17 11:59:08 +00:00
parent ba9f063fd6
commit 1c597e2115
7 changed files with 93 additions and 19 deletions

View file

@ -4,20 +4,30 @@ WORKDIR /app
EXPOSE 8080 EXPOSE 8080
EXPOSE 8081 EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG TARGETARCH
ARG BUILDPLATFORM
ARG BUILD_CONFIGURATION=Release ARG BUILD_CONFIGURATION=Release
WORKDIR /src WORKDIR /src
COPY ["Galaeth.CoreApi/Galaeth.CoreApi.csproj", "Galaeth.CoreApi/"]
RUN dotnet restore "Galaeth.CoreApi/Galaeth.CoreApi.csproj" COPY ["Galaeth.ApiServer/Galaeth.ApiServer.csproj", "Galaeth.ApiServer/"]
COPY ["Galaeth.Core/Galaeth.Core.csproj", "Galaeth.Core/"]
COPY ["Galaeth.Services/Galaeth.Services.csproj", "Galaeth.Services/"]
COPY ["Galaeth.DAL/Galaeth.DAL.csproj", "Galaeth.DAL/"]
RUN dotnet restore "Galaeth.ApiServer/Galaeth.ApiServer.csproj"
COPY . . COPY . .
WORKDIR "/src/Galaeth.CoreApi" WORKDIR "/src/Galaeth.ApiServer"
RUN dotnet build "Galaeth.CoreApi.csproj" -c $BUILD_CONFIGURATION -o /app/build RUN dotnet build "Galaeth.ApiServer.csproj" -c $BUILD_CONFIGURATION -a $TARGETARCH -o /app/build
FROM build AS publish FROM build AS publish
ARG TARGETARCH
ARG BUILD_CONFIGURATION=Release ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "Galaeth.CoreApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
RUN dotnet publish "Galaeth.ApiServer.csproj" --no-restore -c $BUILD_CONFIGURATION -a $TARGETARCH -o /app/publish /p:UseAppHost=false
FROM base AS final FROM base AS final
WORKDIR /app WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Galaeth.CoreApi.dll"] ENTRYPOINT ["dotnet", "Galaeth.ApiServer.dll"]

View file

@ -5,7 +5,6 @@ using Galaeth.Services.Interfaces;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using MyCSharp.HttpUserAgentParser.AspNetCore; using MyCSharp.HttpUserAgentParser.AspNetCore;
using Toycloud.AspNetCore.Mvc.ModelBinding;
namespace Galaeth.ApiServer.Controllers; namespace Galaeth.ApiServer.Controllers;
@ -40,7 +39,7 @@ public class AuthenticationController : ApiController
/// <returns>If successful, instance of <see cref="AccessTokensDto"/>.</returns> /// <returns>If successful, instance of <see cref="AccessTokensDto"/>.</returns>
[AllowAnonymous] [AllowAnonymous]
[HttpPost("login")] [HttpPost("login")]
public async Task<IActionResult> Authenticate([FromBodyOrDefault] AuthenticateRequest request) public async Task<IActionResult> Authenticate(AuthenticateRequest request)
{ {
if (request is null) if (request is null)
{ {
@ -72,7 +71,7 @@ public class AuthenticationController : ApiController
/// <returns>If successful, instance of <see cref="AccessTokensDto"/>.</returns> /// <returns>If successful, instance of <see cref="AccessTokensDto"/>.</returns>
[AllowAnonymous] [AllowAnonymous]
[HttpPost("refresh")] [HttpPost("refresh")]
public async Task<IActionResult> RefreshSession([FromBodyOrDefault] RefreshUserAuthRequest userAuthRequest) public async Task<IActionResult> RefreshSession(RefreshUserAuthRequest userAuthRequest)
{ {
if (userAuthRequest is null) if (userAuthRequest is null)
{ {
@ -101,7 +100,7 @@ public class AuthenticationController : ApiController
/// </summary> /// </summary>
/// <param name="request">Instance of <see cref="ChangePasswordRequest"/>.</param> /// <param name="request">Instance of <see cref="ChangePasswordRequest"/>.</param>
[HttpPost("pwd")] [HttpPost("pwd")]
public async Task<IActionResult> ChangePassword([FromBodyOrDefault] ChangePasswordRequest request) public async Task<IActionResult> ChangePassword(ChangePasswordRequest request)
{ {
if (request is null) if (request is null)
{ {

View file

@ -11,17 +11,17 @@ namespace Galaeth.ApiServer.Controllers;
[ApiController] [ApiController]
[Authorize] [Authorize]
[Route("v1/me")] [Route("v1/me")]
public class UserSelfController : ApiController public class MeController : ApiController
{ {
private readonly IIdentityProvider _identityProvider; private readonly IIdentityProvider _identityProvider;
private readonly IUserService _userService; private readonly IUserService _userService;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserSelfController"/> class. /// Initializes a new instance of the <see cref="MeController"/> class.
/// </summary> /// </summary>
/// <param name="identityProvider">Instance of <see cref="IIdentityProvider"/>.</param> /// <param name="identityProvider">Instance of <see cref="IIdentityProvider"/>.</param>
/// <param name="userService">Instance of <see cref="IUserService"/>.</param> /// <param name="userService">Instance of <see cref="IUserService"/>.</param>
public UserSelfController( public MeController(
IIdentityProvider identityProvider, IIdentityProvider identityProvider,
IUserService userService) IUserService userService)
{ {

View file

@ -24,7 +24,9 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Toycloud.AspNetCore.Mvc.ModelBinding.BodyOrDefaultBinding" Version="1.2.1" /> <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,3 +1,5 @@
using System.Text.Json.Serialization;
namespace Galaeth.ApiServer.Models; namespace Galaeth.ApiServer.Models;
/// <summary> /// <summary>
@ -8,10 +10,12 @@ public class ChangePasswordRequest
/// <summary> /// <summary>
/// The user's old password. /// The user's old password.
/// </summary> /// </summary>
[JsonPropertyName("oldPassword")]
public string OldPassword { get; set; } public string OldPassword { get; set; }
/// <summary> /// <summary>
/// The user's new password. /// The user's new password.
/// </summary> /// </summary>
[JsonPropertyName("newPassword")]
public string NewPassword { get; set; } public string NewPassword { get; set; }
} }

View file

@ -5,10 +5,10 @@ using Galaeth.Core.Configuration;
using Galaeth.Services.Configuration; using Galaeth.Services.Configuration;
using Galaeth.Services.Profiles; using Galaeth.Services.Profiles;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using MyCSharp.HttpUserAgentParser.AspNetCore.DependencyInjection; using MyCSharp.HttpUserAgentParser.AspNetCore.DependencyInjection;
using MyCSharp.HttpUserAgentParser.MemoryCache.DependencyInjection; using MyCSharp.HttpUserAgentParser.MemoryCache.DependencyInjection;
using Serilog; using Serilog;
using Serilog.Events;
namespace Galaeth.ApiServer; namespace Galaeth.ApiServer;
@ -32,9 +32,6 @@ internal static class Program
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext() .Enrich.FromLogContext()
.MinimumLevel.Override("Default", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.WriteTo.Console() .WriteTo.Console()
.CreateLogger(); .CreateLogger();
@ -56,6 +53,32 @@ internal static class Program
builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpContextAccessor();
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(setup =>
{
var jwtSecurityScheme = new OpenApiSecurityScheme
{
BearerFormat = "JWT",
Name = "JWT Authentication",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = JwtBearerDefaults.AuthenticationScheme,
Description = "Paste your access token below",
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme,
},
};
setup.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme);
setup.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ jwtSecurityScheme, Array.Empty<string>() },
});
});
// Setup authentication. // Setup authentication.
var jwtConfig = new JwtConfiguration(); var jwtConfig = new JwtConfiguration();
builder.Configuration.Bind("JWT", jwtConfig); builder.Configuration.Bind("JWT", jwtConfig);
@ -83,6 +106,12 @@ internal static class Program
app.UseMiddleware<ExceptionMiddleware>(); app.UseMiddleware<ExceptionMiddleware>();
app.UseMiddleware<StatusCodeMiddleware>(); app.UseMiddleware<StatusCodeMiddleware>();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization(); app.UseAuthorization();
app.MapControllers(); app.MapControllers();

30
docker-compose.yml Normal file
View file

@ -0,0 +1,30 @@
services:
api-server:
image: forge.alveus.dev/misc/galaeth-api:latest
build: .
container_name: "galaeth-api-server"
restart: on-failure
ports:
- 8080:8080
environment:
ASPNETCORE_ENVIRONMENT: 'Development'
EmailDomainBlacklist__Enabled: false
Database__ConnectionString: 'Server=postgres;Port=5432;User Id=postgres;Password=postgres;Database=galaeth'
InitialUser__Username: 'admin'
InitialUser__Email: 'admin@change.me'
InitialUser__Password: 'Change!Me1234'
JWT__SecretKey: "11ca143299193d9968d31cb85cb30991820ed9dc231aac902ba38abf25b7b6f904e1d614391001e49d8b8af28c4f79b48bb7853ef20bf06a38c17cf8c3f694c0"
JWT__Issuer: 'localdev'
JWT__Audience: 'localdev'
db:
image: postgres:17.1-bookworm
container_name: postgres
restart: on-failure
environment:
POSTGRES_USER: 'postgres'
POSTGRES_PASSWORD: 'postgres'
POSTGRES_DB: 'galaeth'