using System.Threading; using System.Threading.Tasks; namespace RecruitmentBLL.Integration { /// Outcome of a DXP Auth call. Unlike EcpIntegrationService's fire-and-forget /// notification calls, Register/Login are user-facing — a failure here must propagate a real /// error back to the caller (401/400), never silently no-op. public class DxpAuthOutcome { public bool Success { get; set; } public string? Error { get; set; } public int DxpUserId { get; set; } = -1; } /// Login additionally carries FullName back — DXP's own MDXPUSER row is the only /// place this candidate's display name is known until Recruitment provisions/links its own /// MCANDIDATE row for them (see CandidatePortalBLL.EnsureCandidateAsync). public class DxpLoginOutcome : DxpAuthOutcome { public string FullName { get; set; } = string.Empty; } /// /// Cross-host HTTP integration with DXP's real Auth surface (hosted by PlatformHost, a /// different process than Recruitment's HRFinanceHost) — thin wrappers over /// POST /DXP/Auth/Register and POST /DXP/Auth/Login, following the exact /// IHttpClientFactory named-client pattern established by /// RecruitmentBLL.Integration.EcpIntegrationService / DXPBLL.VendorPo.MmIntegrationService. /// /// Verified real request/response shapes (read from DXPSL/Endpoints/Auth/Register.cs, /// DXPSL/Endpoints/Auth/Login.cs, DXPSL/Parameters/Auth/*.cs, DXPBLL/Auth/AuthBLL.cs — /// 2026-09-04): /// POST /DXP/Auth/Register — plain JSON body { FullName, Email, Mobile?, Password }, /// NOT wrapped, no Login header (Register/Login are plain FastEndpoints Endpoint<,>, /// not BaseEndpoint — DXP resolves its own "system" LoginDTO internally via /// IDXPSystemContext, so callers never supply one). Success: ResponseStandardDTO.Body is /// "{SuccessResponse.SaveSuccessMessage} {DxpUserId}" (200). Failure (duplicate email / /// bad password length): ResponseStandardDTO.ErrorBody carries the message (400). /// POST /DXP/Auth/Login — plain JSON body { Email, Password, DeviceInfo? }. Success (200): /// ResponseStandardDTO.Body is a serialized DXPLoginResultDTO { DxpUserId, FullName, /// Contexts[], Tokens (DXPTokenPair, null unless the account has exactly one /// Party/Role/tenant-link context), IntermediateToken (string, populated only when /// Contexts.Count != 1) }. A candidate account has NO DXP Party/Role at all (DXP's /// PartyType model doesn't fit an individual candidate — see the plan's Phase 3 note), /// so Contexts is always empty and Tokens is always null; only IntermediateToken would be /// populated, carrying nothing but a bare `dxp_user_id` claim (RoleCode/TenantId/etc are /// zero/empty — see DXPBLL.Auth.AuthBLL.LoginAsync's zero/one-context branch). This class /// does NOT relay that token — see CandidatePortalBLL for why Recruitment mints its own /// token instead. Failure (bad credentials / locked account): ResponseStandardDTO.ErrorBody /// carries a deliberately generic message (401). /// /// Every method here degrades to a clear failure result (Success=false + Error) on a non-2xx /// response or thrown exception — it never throws back into CandidatePortalBLL uncaught, but /// (unlike Ecp/Mm's fire-and-forget calls) that failure is always surfaced to the end user as /// a real 400/401, never swallowed into a silent success. /// public interface IDxpAuthIntegrationService { Task RegisterCandidateUserAsync( string fullName, string email, string? mobile, string password, CancellationToken ct); Task LoginCandidateAsync( string email, string password, CancellationToken ct); } }