using FastEndpoints; using GB5Shared.DTO.Framework.Enum; using GB5Shared.DTO.Framework.ResponseStandard; using Newtonsoft.Json; using PartnerSL.Services; namespace PartnerSL.EndPoints.ClientDomain { // Public endpoint — no Login header required. // Resolves a hostname to ClientId + DatabaseName before authentication. // Angular shell calls this on load to pre-populate the database selector // and apply partner branding on custom-domain deployments. // // DatabaseName in the response is actually the ConnectionName — feed it straight into // GetPublicBrandByConnection?ConnectionName=... (and into VersionCheck/boot) to resolve // this domain's white-label branding dynamically, with no hardcoded ConnectionName // anywhere on the FE. This is the missing link between "browser loaded on custom domain" // and "which tenant/branding to show" — see ClientDomainDTO.DatabaseName for why the // field is still named DatabaseName. public class GetDomainTenant : Endpoint> { private readonly DomainCacheService _domainCache; public GetDomainTenant(DomainCacheService domainCache) => _domainCache = domainCache; public override void Configure() { Get("/ClientDomain/GetDomainTenant"); AllowAnonymous(); } public class GetDomainTenantRequest { [QueryParam] public string DomainName { get; set; } = ""; } public override async Task HandleAsync(GetDomainTenantRequest req, CancellationToken ct) { if (string.IsNullOrWhiteSpace(req.DomainName)) { await Send.ResponseAsync(new ResponseStandardDTO { Body = "", ErrorBody = "DomainName is required.", Status = FrameworkEnumDTO.ResponseStatus.Failed }, 400, ct); return; } var dto = await _domainCache.GetOrLoadAsync(req.DomainName.Trim().ToLowerInvariant(), ct); if (dto != null) { await Send.ResponseAsync(new ResponseStandardDTO { Body = JsonConvert.SerializeObject(dto), Status = FrameworkEnumDTO.ResponseStatus.Ok }, 200, ct); return; } await Send.ResponseAsync(new ResponseStandardDTO { Body = "", ErrorBody = "Domain not mapped.", Status = FrameworkEnumDTO.ResponseStatus.Failed }, 404, ct); } } }