feat(Backend): update API gateway and websocket hubs
This commit is contained in:
@@ -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>());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user