using Management.Data; using Management.Security; using Microsoft.AspNetCore.Mvc; using System.Text.Json; namespace Management.Controllers; /// /// Onboarding endpoints for new user/client registration. /// Requires JWT authentication (user may not have session yet). /// /// ENDPOINTS: /// GET /api/onboarding/status - Check registration status /// POST /api/onboarding/register - Register new organization /// [ApiController] [Route("api/onboarding")] public sealed class OnboardingController : ControllerBase { private readonly SqlService _sql; private readonly ClientContext _client; private readonly ILogger _log; public OnboardingController(SqlService sql, ClientContext client, ILogger log) { _sql = sql; _client = client; _log = log; } /// /// Check registration status for authenticated user. /// [HttpGet("status")] public async Task Status(CancellationToken ct) { if (!_client.IsAuthenticated) return Unauthorized(new { ok = false, error = "Valid Entra authentication required" }); var rqst = JsonSerializer.Serialize(new { provider = "EntraExternalId", subject = _client.ClientId, email = _client.Email }); try { var resp = await _sql.ExecProcAsync("dbo.spOnboarding", "status", rqst, ct: ct); if (string.IsNullOrWhiteSpace(resp)) return StatusCode(500, new { ok = false, error = "Service unavailable" }); return Content(resp, "application/json"); } catch (Exception ex) { _log.LogError(ex, "[Onboarding] Status error"); return StatusCode(500, new { ok = false, error = "Status check failed", detail = ex.Message }); } } /// /// Register a new organization. /// [HttpPost("register")] public async Task Register([FromBody] RegisterRequest request, CancellationToken ct) { if (!_client.IsAuthenticated) return Unauthorized(new { ok = false, error = "Valid Entra authentication required" }); if (string.IsNullOrWhiteSpace(request?.ClientName)) return BadRequest(new { ok = false, error = "clientName is required" }); _log.LogWarning("[Onboarding] Register | Subject={Subject} ClientName={ClientName}", _client.ClientId, request.ClientName); var rqst = JsonSerializer.Serialize(new { provider = "EntraExternalId", subject = _client.ClientId, email = _client.Email, displayName = _client.ClientName, clientName = request.ClientName.Trim() }); try { var resp = await _sql.ExecProcAsync("dbo.spOnboarding", "register", rqst, ct: ct); if (string.IsNullOrWhiteSpace(resp)) return StatusCode(500, new { ok = false, error = "Registration service unavailable" }); using var doc = JsonDocument.Parse(resp); var root = doc.RootElement; if (root.TryGetProperty("ok", out var okProp) && okProp.GetBoolean()) return Content(resp, "application/json"); var error = root.TryGetProperty("error", out var errProp) ? errProp.GetString() : "Registration failed"; return BadRequest(new { ok = false, error }); } catch (Exception ex) { _log.LogError(ex, "[Onboarding] Register error"); return StatusCode(500, new { ok = false, error = "Registration failed", detail = ex.Message }); } } } public sealed class RegisterRequest { public string? ClientName { get; set; } }