From 993d9cfea054b25b5d2560dcbc2f3265ef8017eb Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 17 Aug 2026 16:05:43 +0200 Subject: [PATCH] refactor(api): inject IEmailSyncService into SyncController; change OAuth2 authorize route to username param; add Swagger UI metadata and description links --- .../Controllers/OAuth2Controller.cs | 8 +-- .../Controllers/SyncController.cs | 16 ++---- .../Program.cs | 50 +++++++++++++++++-- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/presentation/DigitalData.MessagingService.API/Controllers/OAuth2Controller.cs b/src/presentation/DigitalData.MessagingService.API/Controllers/OAuth2Controller.cs index 13a9a7d..d7b3b78 100644 --- a/src/presentation/DigitalData.MessagingService.API/Controllers/OAuth2Controller.cs +++ b/src/presentation/DigitalData.MessagingService.API/Controllers/OAuth2Controller.cs @@ -20,20 +20,20 @@ public class OAuth2Controller(IMediator mediator, IHttpContextAccessor httpConte /// Step 1: Redirects the user to Google's consent screen for the specified email account. /// After consent, Google redirects to /api/oauth2/google/callback with an authorization code. /// - /// ID of the email account to authorize. + /// the email account to authorize. /// Cancellation token. /// HTTP 302 redirect to Google consent screen. - [HttpGet("google/authorize/{accountId:int}")] + [HttpGet("google/authorize/{username}")] [ProducesResponseType(StatusCodes.Status302Found)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task AuthorizeGoogle(int accountId, CancellationToken cancellationToken) + public async Task AuthorizeGoogle([FromRoute] string username, CancellationToken cancellationToken) { var redirectUri = BuildCallbackUri(); var authUrl = await mediator.Send(new GetOAuth2AuthorizationUrlQuery { - AccountId = accountId, + Username = username, RedirectUri = redirectUri }, cancellationToken); diff --git a/src/presentation/DigitalData.MessagingService.API/Controllers/SyncController.cs b/src/presentation/DigitalData.MessagingService.API/Controllers/SyncController.cs index c5e59be..c29581d 100644 --- a/src/presentation/DigitalData.MessagingService.API/Controllers/SyncController.cs +++ b/src/presentation/DigitalData.MessagingService.API/Controllers/SyncController.cs @@ -1,6 +1,5 @@ -using DigitalData.MessagingService.Infrastructure.Services.Background; +using DigitalData.MessagingService.Application.Common.Interfaces; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Hosting; namespace DigitalData.MessagingService.API.Controllers; @@ -9,7 +8,7 @@ namespace DigitalData.MessagingService.API.Controllers; /// [ApiController] [Route("api/[controller]")] -public class SyncController(IEnumerable hostedServices) : ControllerBase +public class SyncController(IEmailSyncService emailSyncService) : ControllerBase { /// /// Triggers an immediate email sync cycle for all configured accounts, @@ -22,14 +21,7 @@ public class SyncController(IEnumerable hostedServices) : Contro [ProducesResponseType(StatusCodes.Status503ServiceUnavailable)] public IActionResult TriggerSync() { - var syncWorker = hostedServices.OfType().FirstOrDefault(); - - if (syncWorker is null) - return StatusCode(StatusCodes.Status503ServiceUnavailable, - new { Message = "EmailSyncWorker is not running." }); - - syncWorker.TriggerSync(); - - return Accepted(new { Message = "Sync triggered. The next cycle will start immediately." }); + var syncTime = emailSyncService.ForceTriggerSync(); + return Accepted(new { syncTime }); } } diff --git a/src/presentation/DigitalData.MessagingService.API/Program.cs b/src/presentation/DigitalData.MessagingService.API/Program.cs index 2e37be9..65a1537 100644 --- a/src/presentation/DigitalData.MessagingService.API/Program.cs +++ b/src/presentation/DigitalData.MessagingService.API/Program.cs @@ -69,7 +69,35 @@ try builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); - builder.Services.AddSwaggerGen(); + builder.Services.AddSwaggerGen(options => + { + options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo + { + Title = "DigitalData MessagingService API", + Version = "v1", + Description = """ + Die **DigitalData MessagingService API** stellt Endpunkte zur Verwaltung von E-Mail-Konten, + E-Mail-Profilen sowie zur Verarbeitung und Nachverfolgung eingehender und ausgehender Nachrichten bereit. + + --- + + ## Authentifizierung + + Für OAuth2-geschützte Endpunkte ist eine Authentifizierung erforderlich. + Rufen Sie den folgenden Endpunkt auf und ersetzen Sie `{E-Mail-Adresse}` durch die zu authentifizierende E-Mail-Adresse: + + `/api/OAuth2/google/authorize/{E-Mail-Adresse}` + + **Beispiel:** **[/api/OAuth2/google/authorize/htek0100@gmail.com →](/api/OAuth2/google/authorize/htek0100@gmail.com)** + + --- + + ## Weiterführende Links + + - [Serilog Log-Viewer ↗](/serilog-ui) + """ + }); + }); // Required by OAuth2Controller to build callback URIs builder.Services.AddHttpContextAccessor(); @@ -92,14 +120,30 @@ try // Add Serilog request logging app.UseSerilogRequestLogging(); - // Configure Swagger — enabled in Development always, and in other environments based on appsettings + // Configure Swagger � enabled in Development always, and in other environments based on appsettings var swaggerEnabled = app.Environment.IsDevelopment() || app.Configuration.GetValue("Swagger:Enabled"); if (swaggerEnabled) { app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwaggerUI(ui => + { + ui.SwaggerEndpoint("/swagger/v1/swagger.json", "DigitalData MessagingService API v1"); + // Inject CSS so all description links open in a new tab + ui.InjectStylesheet("data:text/css,.renderedMarkdown a{target:_blank}"); + ui.InjectJavascript("data:text/javascript," + Uri.EscapeDataString(""" + window.addEventListener('load', () => { + const observer = new MutationObserver(() => { + document.querySelectorAll('.renderedMarkdown a').forEach(a => { + a.setAttribute('target', '_blank'); + a.setAttribute('rel', 'noopener noreferrer'); + }); + }); + observer.observe(document.body, { childList: true, subtree: true }); + }); + """)); + }); } app.UseHttpsRedirection();