diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor index fd5f981b..363c9a67 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor @@ -17,6 +17,7 @@ + diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/UserPreferencesController.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/UserPreferencesController.cs index 47f84b27..4ef2771a 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/UserPreferencesController.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/UserPreferencesController.cs @@ -10,24 +10,37 @@ namespace EnvelopeGenerator.Server.Controllers; /// /// Manages per-user UI preferences (theme, dark mode, grid layouts). /// Preferences are stored in the distributed cache (dbo.TBDD_CACHE). +/// Accessible by both Sender and Receiver roles. /// [ApiController] [Route("api/[controller]")] -[Authorize(Policy = AuthPolicy.Sender)] +[Authorize(Policy = AuthPolicy.SenderOrReceiver)] public class UserPreferencesController(IUserPreferencesService preferencesService) : ControllerBase { private static readonly HashSet AllowedThemes = - ["blazing-berry", "fluent", "purple"]; + ["blazing-berry", "blazing-dark", "purple"]; /// /// Returns the current user's UI preferences. /// Always returns 200 with defaults if no preferences have been saved yet. + /// DisplayName is populated from JWT claims for senders only. /// [HttpGet] public async Task> Get(CancellationToken ct) { - var username = User.GetUsername(); - var prefs = await preferencesService.GetAsync(username, ct); + bool isReceiver = User.IsReceiver(); + + var userId = isReceiver ? User.ReceiverMail() : User.GetUsername(); + + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var prefs = await preferencesService.GetOrCreateAsync(userId, ct); + + // Populate DisplayName for sender only (receiver has no given/surname claims) + if (!isReceiver) + prefs.DisplayName = $"{User.GetPrename()} {User.GetName()}".Trim(); + return Ok(prefs); } @@ -42,8 +55,12 @@ public class UserPreferencesController(IUserPreferencesService preferencesServic if (!AllowedThemes.Contains(dto.ThemeName)) return BadRequest($"Invalid theme '{dto.ThemeName}'. Allowed: {string.Join(", ", AllowedThemes)}."); - var username = User.GetUsername(); - await preferencesService.SaveAsync(username, dto, ct); + var userId = User.IsReceiver() ? User.ReceiverMail() : User.GetUsername(); + + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + await preferencesService.SaveAsync(userId, dto, ct); return Ok(dto); } } diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Extensions/ReceiverClaimExtensions.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Extensions/ReceiverClaimExtensions.cs index cc2611ab..e4b29df9 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Extensions/ReceiverClaimExtensions.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Extensions/ReceiverClaimExtensions.cs @@ -1,4 +1,6 @@ using DigitalData.Auth.Claims; +using DigitalData.UserManager.Domain.Entities; +using EnvelopeGenerator.Domain.Constants; using Microsoft.IdentityModel.JsonWebTokens; using System.Security.Claims; @@ -93,4 +95,14 @@ public static class ReceiverClaimExtensions else throw new InvalidOperationException($"Claim '{EnvelopeClaimNames.ReceiverId}' is not a valid integer."); } + + /// + /// + /// + /// + /// + public static bool IsReceiver(this ClaimsPrincipal user) + { + return Role.Receiver.Authorized.Any(user.IsInRole); + } } \ No newline at end of file diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs index fc25e496..d8aadebd 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs @@ -271,7 +271,12 @@ try .AddAuthenticationSchemes(AuthScheme.Receiver) .RequireAuthenticatedUser() .RequireRole(Role.Receiver.Full, "receiver")) - .AddPolicy(AuthPolicy.ReceiverTFA, policy => policy.RequireRole(Role.Receiver.TFA)); + .AddPolicy(AuthPolicy.ReceiverTFA, policy => policy.RequireRole(Role.Receiver.TFA)) + // Combined policy: accepts both Sender and Receiver tokens. + // Used by endpoints accessible to both roles (e.g. UserPreferences). + .AddPolicy(AuthPolicy.SenderOrReceiver, policy => policy + .AddAuthenticationSchemes(AuthScheme.Sender, AuthScheme.Receiver) + .RequireAuthenticatedUser()); // User Manager #pragma warning disable CS0618