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();