using System.Collections.Generic; using System.Linq; using System.Security.Claims; using RecruitmentBLL.CandidatePortal; namespace RecruitmentSL.Common { /// /// Everything a CandidatePortal endpoint knows about the calling candidate, taken ONLY from /// validated JWT claims (HttpContext.User.Claims, populated by the "CandidatePortal" /// JwtBearer scheme after verifying the signature — see RecruitmentSL/Program.cs). Mirrors /// EntitlementSL.Common.ClientCallerContext.FromClaims exactly — the established precedent in /// this codebase for "internet-facing, non-employee caller identity must come only from /// verified claims," never request body/headers. /// /// LoginDTO (from the "Login" header every BaseEndpoint already reconstructs) stays what it /// always is in this module: DB-routing context (which tenant/database a query targets), not /// an identity/authorization mechanism — CandidateId here is what every CandidatePortal /// endpoint uses to scope data to the calling candidate and nothing else. /// public class CandidatePortalCallerContext { public int DxpUserId { get; set; } public int CandidateId { get; set; } public string Email { get; set; } = string.Empty; public static CandidatePortalCallerContext FromClaims(IEnumerable claims) { var dict = claims.ToDictionary(c => c.Type, c => c.Value); int GetInt(string key) => dict.TryGetValue(key, out var v) && int.TryParse(v, out var i) ? i : 0; string GetStr(string key) => dict.TryGetValue(key, out var v) ? v : string.Empty; return new CandidatePortalCallerContext { DxpUserId = GetInt(CandidatePortalClaimTypes.DxpUserId), CandidateId = GetInt(CandidatePortalClaimTypes.CandidateId), Email = GetStr(CandidatePortalClaimTypes.Email) }; } } }