using Management.Data; using Management.Security; using Microsoft.AspNetCore.Mvc; using System.Text.Json; namespace Management.Controllers.Admin; /// /// Client-planet user management — tbClientUser / tbClientUserRole. /// No admin-plane concepts here whatsoever. /// /// ENDPOINTS: /// GET /api/admin/client-users - List client users /// GET /api/admin/client-users/{userId} - Get single user /// PUT /api/admin/client-users/{userId} - Update display name / status /// DELETE /api/admin/client-users/{userId} - Deactivate /// POST /api/admin/client-users/{userId}/link - Link to a client /// DELETE /api/admin/client-users/{userId}/link/{clientId} - Unlink from a client /// [ApiController] [Route("api/admin/client-users")] public sealed class AdminClientUsersController : AdminControllerBase { private const string Proc = "spClientUsers"; public AdminClientUsersController(SqlService sql, ClientContext client, ILogger log) : base(sql, client, log) { } [HttpPost("list")] public Task List([FromBody] JsonElement body, CancellationToken ct) => CallProc(Proc, "list", body.ToString(), ct); [HttpGet("{userId}")] public Task Get(string userId, CancellationToken ct) => CallProc(Proc, "get", new { userId }, ct); [HttpPut("{userId}")] public Task Update(string userId, [FromBody] JsonElement body, CancellationToken ct) { Logger.LogInformation("[ClientUsers] Update {Id} by {User}", userId, Client.Email); return CallProc(Proc, "update", new { userId, displayName = Str(body, "displayName"), status = Str(body, "status") }, ct); } [HttpDelete("{userId}")] public Task Deactivate(string userId, CancellationToken ct) { Logger.LogWarning("[ClientUsers] Deactivate {Id} by {User}", userId, Client.Email); return CallProc(Proc, "deactivate", new { userId }, ct); } [HttpPost("{userId}/link")] public Task LinkToClient(string userId, [FromBody] JsonElement body, CancellationToken ct) { var clientId = Str(body, "clientId"); if (string.IsNullOrWhiteSpace(clientId)) return Task.FromResult(ValidationError("clientId is required")); Logger.LogInformation("[ClientUsers] Link user {UserId} → client {ClientId} by {User}", userId, clientId, Client.Email); return CallProc(Proc, "linkToClient", new { userId, clientId, role = Str(body, "role") ?? "User" }, ct); } [HttpDelete("{userId}/link/{clientId}")] public Task UnlinkFromClient(string userId, string clientId, CancellationToken ct) { Logger.LogInformation("[ClientUsers] Unlink user {UserId} from client {ClientId} by {User}", userId, clientId, Client.Email); return CallProc(Proc, "unlinkFromClient", new { userId, clientId }, ct); } private static string? Str(JsonElement el, string key) => el.TryGetProperty(key, out var p) && p.ValueKind == JsonValueKind.String ? p.GetString() : null; }