using EntitlementBLL.Interfaces; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using static GB5Shared.GB5Constant.Constant; namespace EntitlementSL.Endpoints.Feature; // AllowAnonymous — but only ever surfaces the ISEXPOSEDTOPIE=1 subset to an unauthenticated // caller (needed by the public QuickStart wizard's module list). The existing GOODBOOKS_ADMIN // full-catalog path keeps working unchanged: a caller with a verified GOODBOOKS_ADMIN role gets // the full list by default, or the PIE-only subset if it explicitly passes isExposedToPie=true. // The admin/anonymous distinction is resolved from the verified request principal // (HttpContext.User.IsInRole), never from a client-supplied flag — enforced again, explicitly, // in FeatureBLL.GetListAsync so a caller can never bypass this by lying about the query param. public class GetFeatureList : BaseEndpoint> { private const string AdminRole = "GOODBOOKS_ADMIN"; private readonly IFeatureBLL _FeatureBLL; public GetFeatureList(IFeatureBLL featureBLL) => _FeatureBLL = featureBLL; public override void Configure() { Get("/lic/Feature.svc/GetList"); AllowAnonymous(); } public record Params( [property: FromHeader] string Login, [property: QueryParam] bool? IsExposedToPie ); private bool IsAdminAuthenticated() => HttpContext.User?.IsInRole(AdminRole) == true; protected override string? GetCacheKey(Params req, LoginDTO loginDTO) { // pieOnly (not the raw request flag) determines cache-key identity — otherwise a // PIE-only anonymous response and a full admin response could collide on the same key. bool pieOnly = IsAdminAuthenticated() ? req.IsExposedToPie == true : true; return KeyGenerator.KeyGeneration(pieOnly ? 1 : -1, EntityConstant.OBJECTENTITLEMENTFEATURE, CacheKeyLevel.CLIENT_LEVEL, loginDTO); } protected override async Task> ExecuteAsync(Params req, LoginDTO loginDTO, CancellationToken ct) { var result = await _FeatureBLL.GetListAsync(IsAdminAuthenticated(), req.IsExposedToPie, loginDTO, ct); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponseEnumerable(result, CacheKeyLevel.CLIENT_LEVEL, loginDTO); } }