using CMSBLL.Site; using CMSBLL.SiteDocument; using CMSBLL.SitePage; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using static GB5Shared.GB5Constant.Constant; namespace CMSSL.Endpoints.Cms; // The designer-agnostic rendering/compose contract (Site/Page platform Phases 2 + 5): resolves // an anonymous public request's Host header + path to a Site/Page, then hands back a // SiteDocumentDTO — the page plus the site's header/footer (if authored), each already // resolved to the same ContentFullDocumentDTO tree (Content -> Containers -> Blocks) the // existing designer already consumes, with any COMPONENT_REF blocks inlined — no GrapesJS- or // any other designer-specific shape appears here or ever will. public class GetSiteDocument : BaseEndpoint { private readonly ISiteResolverBLL _resolver; private readonly ISitePageBLL _sitePageBll; private readonly ISiteDocumentBLL _siteDocumentBll; public GetSiteDocument(ISiteResolverBLL resolver, ISitePageBLL sitePageBll, ISiteDocumentBLL siteDocumentBll) { _resolver = resolver; _sitePageBll = sitePageBll; _siteDocumentBll = siteDocumentBll; } public override void Configure() { Get("/CMS/GetSiteDocument"); AllowAnonymous(); } public record Parameters( [property: QueryParam] string Domain, [property: QueryParam] string Path, [property: FromHeader] string Login ); protected override async Task> ExecuteAsync(Parameters req, LoginDTO login, CancellationToken ct) { try { // Domain is the ONLY trusted source of tenant/site context here — never resolved // from a client-supplied TenantId/SiteId field, exactly mirroring the SignalR rule // of always reconstructing identity server-side (see SiteResolverBLL). var site = await _resolver.ResolveByDomainAsync(req.Domain, login, ct); if (site is null) return await GB5Shared.ResponseStandard.Response.CreateExceptionError( new Exception("Site not found."), CacheKeyLevel.NOT_REQUIRED, login, "Site not found.", 404); var urlPath = string.IsNullOrWhiteSpace(req.Path) ? "/" : req.Path; var route = await _sitePageBll.GetRouteAsync(site.SiteId, urlPath, login, ct); if (route is null) return await GB5Shared.ResponseStandard.Response.CreateExceptionError( new Exception("Page not found."), CacheKeyLevel.NOT_REQUIRED, login, "Page not found.", 404); var document = await _siteDocumentBll.ComposeAsync(site.SiteId, site.TenantId, route.ContentId, login, ct); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse(document, CacheKeyLevel.CLIENT_LEVEL, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } }