using System; using System.Collections.Generic; using System.IO; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using GB5Shared.Auth.Jwt; using GB5Shared.DTO.ECM; using GB5Shared.DTO.Framework.Login; namespace RecruitmentBLL.CandidatePortal { /// /// Claim type names for the CandidatePortal access token — read on the RecruitmentSL side by /// CandidatePortalCallerContext.FromClaims after the "CandidatePortal" JwtBearer scheme has /// verified the token's signature (see RecruitmentSL/Program.cs). /// public static class CandidatePortalClaimTypes { public const string DxpUserId = "dxp_user_id"; public const string CandidateId = "candidate_id"; public const string Email = "email"; } /// /// Claims embedded in every CandidatePortal access token, minted by /// CandidatePortalBLL.LoginAsync — see that class's doc comment for why Recruitment mints /// this token itself (using DXP's own signing key/issuer/audience) instead of relaying DXP's /// raw Login-issued token verbatim. /// public class CandidatePortalAccessTokenClaims : IJwtClaimsSource { public int DxpUserId { get; set; } public int CandidateId { get; set; } public string Email { get; set; } = string.Empty; public IEnumerable ToClaims() => new[] { new Claim(CandidatePortalClaimTypes.DxpUserId, DxpUserId.ToString()), new Claim(CandidatePortalClaimTypes.CandidateId, CandidateId.ToString()), new Claim(CandidatePortalClaimTypes.Email, Email) }; } public class CandidatePortalLoginResultDTO { public bool Success { get; set; } public string? Error { get; set; } public int CandidateId { get; set; } = -1; public string Email { get; set; } = string.Empty; public string AccessToken { get; set; } = string.Empty; public DateTime AccessTokenExpiresOn { get; set; } } public interface ICandidatePortalBLL { /// Thin passthrough to DXP's real /DXP/Auth/Register, then eagerly ensures a /// matching MCANDIDATE row exists for this email (see EnsureCandidateAsync) so a first /// Login right after registering never has to create one mid-request. Task RegisterAsync(string fullName, string email, string? mobile, string password, LoginDTO login, CancellationToken ct); /// Validates credentials against DXP, resolves/creates the matching /// MCANDIDATE.CandidateId by email, and mints a CandidatePortal access token carrying it. /// Success=false (never an exception) on bad credentials — callers must return a real /// 401, not a silent no-op. Task LoginAsync(string email, string password, LoginDTO login, CancellationToken ct); Task GetMyApplicationsAsync(int candidateId, LoginDTO login, CancellationToken ct); Task UploadDocumentAsync( int candidateId, Stream fileStream, string fileName, string contentType, string? remarks, LoginDTO login, CancellationToken ct); } }