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,102 @@
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using FinlyticBackend.Database;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace FinlyticBackend.Controllers;
[ApiController]
[Route("api/v1/user/preferences")]
[Authorize]
public class UserPreferencesController : ControllerBase
{
private readonly BackendDbContext _context;
public UserPreferencesController(BackendDbContext context)
{
_context = context;
}
/// <summary>
/// Request payload for updating the user's theme.
/// Supported IDs for FluentAvalonia: fluent_dark, fluent_light, fluent_accent, dark_classic.
/// </summary>
public record UpdateThemeRequest(string ThemeId);
/// <summary>
/// Gets current user preferences including FluentAvalonia theme preference.
/// </summary>
[HttpGet]
public async Task<IActionResult> GetPreferences()
{
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub");
if (!Guid.TryParse(userIdStr, out var userId))
{
return Unauthorized(new { message = "Invalid user claims." });
}
var user = await _context.Users.AsNoTracking().FirstOrDefaultAsync(u => u.Id == userId);
if (user == null)
{
return NotFound(new { message = "User not found." });
}
// Default logic for FluentAvaloniaTheme integration
string theme = string.IsNullOrWhiteSpace(user.ThemePreference) ? "fluent_dark" : user.ThemePreference;
return Ok(new
{
userId = user.Id,
email = user.Email,
fullName = user.FullName,
role = user.Role,
themePreference = theme
});
}
/// <summary>
/// Updates current user theme preference in PostgreSQL database.
/// </summary>
[HttpPut("theme")]
public async Task<IActionResult> UpdateThemePreference([FromBody] UpdateThemeRequest request)
{
if (request == null || string.IsNullOrWhiteSpace(request.ThemeId))
{
return BadRequest(new { message = "ThemeId is required." });
}
var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub");
if (!Guid.TryParse(userIdStr, out var userId))
{
return Unauthorized(new { message = "Invalid user claims." });
}
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
if (user == null)
{
return NotFound(new { message = "User not found." });
}
string cleanTheme = request.ThemeId.Trim().ToLowerInvariant();
// Normalize theme names for FluentAvaloniaTheme support
user.ThemePreference = cleanTheme switch
{
"dark" => "fluent_dark",
"light" => "fluent_light",
_ => cleanTheme
};
await _context.SaveChangesAsync();
return Ok(new
{
message = "Theme preference updated successfully.",
themePreference = user.ThemePreference
});
}
}