feat(Backend): update API gateway and websocket hubs

This commit is contained in:
2026-08-09 21:32:52 +02:00
parent fdf4b6efcb
commit a9553e9fbf
66 changed files with 188878 additions and 0 deletions
@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using FinlyticAssets.Models;
using FinlyticBackend.Util;
using FinlyticCore.Dtos;
using FinlyticCore.Dtos.Fundamentals;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace FinlyticBackend.Controllers;
/// <summary>
/// Response DTO for corporate calendar events (AOT-compliant).
/// </summary>
public record CalendarEventResponseDto(
[property: JsonPropertyName("id")] string Id,
[property: JsonPropertyName("symbol")] string Symbol,
[property: JsonPropertyName("companyName")]
string CompanyName,
[property: JsonPropertyName("eventType")]
string EventType,
[property: JsonPropertyName("eventDate")]
DateTime EventDate,
[property: JsonPropertyName("date")] string Date,
[property: JsonPropertyName("isin")] string Isin,
[property: JsonPropertyName("ticker")] string Ticker,
[property: JsonPropertyName("description")]
string Description,
[property: JsonPropertyName("details")]
string Details,
[property: JsonPropertyName("image")] string Image
);
[ApiController]
[Authorize]
[Route("api/v1/calendar")]
public class CalendarController : ControllerBase
{
private readonly WebMqttClient _mqttClient;
private readonly ILogger<CalendarController> _logger;
public CalendarController(WebMqttClient mqttClient, ILogger<CalendarController> logger)
{
_mqttClient = mqttClient;
_logger = logger;
}
/// <summary>
/// Retrieves corporate calendar events with optional filters.
/// </summary>
[HttpGet("events")]
public async Task<IActionResult> GetCorporateCalendar(
[FromQuery] string? category = null,
[FromQuery] DateTime? date = null,
[FromQuery] string? symbol = null,
[FromQuery] string? isin = null)
{
string? activeSymbol = !string.IsNullOrWhiteSpace(symbol) ? symbol.Trim() : isin?.Trim();
try
{
if (_mqttClient.IsConnected)
{
var rawEvents = await _mqttClient.SendRpcRequestAsync<List<CorporateEventDto>, EmptyRequest>(
"events_GetAll",
new EmptyRequest(),
TimeSpan.FromSeconds(4)
);
if (rawEvents != null && rawEvents.Count > 0)
{
var allAssets = AssetsController.LoadAssetsFromIndexJson() ?? new List<AssetIndex>();
var isinLookup = allAssets
.Where(a => !string.IsNullOrEmpty(a.Isin))
.GroupBy(a => a.Isin, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
var parsedEvents = rawEvents.Select(e =>
{
string eventIsin = e.Isin ?? string.Empty;
string ticker = e.Ticker ?? string.Empty;
string companyName = e.CompanyName ?? string.Empty;
string eventType = e.EventType ?? string.Empty;
DateTime eventDate = e.Date;
string image = $"/api/v1/logo/{eventIsin}";
if (!string.IsNullOrEmpty(eventIsin) && isinLookup.TryGetValue(eventIsin, out var matchedAsset))
{
if (!string.IsNullOrWhiteSpace(matchedAsset.Name))
{
companyName = matchedAsset.Name;
}
if (!string.IsNullOrWhiteSpace(matchedAsset.Image))
{
image = matchedAsset.Image;
}
}
return new CalendarEventResponseDto(
Id: $"evt-{eventIsin}-{eventDate:yyyyMMdd}-{eventType}",
Symbol: string.IsNullOrWhiteSpace(ticker) ? eventIsin : ticker,
CompanyName: companyName,
EventType: eventType,
EventDate: eventDate,
Date: eventDate.ToString("o"),
Isin: eventIsin,
Ticker: ticker,
Description: $"{eventType} - {companyName}",
Details: $"Termin für {companyName} am {eventDate:dd.MM.yyyy}",
Image: image
);
});
// Optionales Filtern
var filtered = parsedEvents;
if (!string.IsNullOrWhiteSpace(category) &&
!string.Equals(category, "Alle", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(category, "all", StringComparison.OrdinalIgnoreCase))
{
filtered = filtered.Where(e =>
string.Equals(e.EventType, category, StringComparison.OrdinalIgnoreCase));
}
if (date.HasValue)
{
filtered = filtered.Where(e => e.EventDate.Date == date.Value.Date);
}
if (!string.IsNullOrWhiteSpace(activeSymbol))
{
filtered = filtered.Where(e =>
string.Equals(e.Isin, activeSymbol, StringComparison.OrdinalIgnoreCase) ||
string.Equals(e.Ticker, activeSymbol, StringComparison.OrdinalIgnoreCase) ||
string.Equals(e.Symbol, activeSymbol, StringComparison.OrdinalIgnoreCase)
);
}
return Ok(filtered.OrderBy(e => e.EventDate).ToList());
}
}
else
{
_logger.LogWarning("[CalendarController] MQTT client is NOT connected to broker.");
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[CalendarController] Failed to retrieve corporate events via MQTT RPC.");
}
return Ok(new List<CalendarEventResponseDto>());
}
}