using System; using System.Collections.Generic; using System.Linq; using System.Net; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Services; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing { public class PublishedRequestBuilder : IPublishedRequestBuilder { private readonly IFileService _fileService; private IReadOnlyDictionary _headers; private bool _cacheability; private IReadOnlyList _cacheExtensions; private string _redirectUrl; private HttpStatusCode? _responseStatus; private IPublishedContent _publishedContent; private bool _ignorePublishedContentCollisions; /// /// Initializes a new instance of the class. /// public PublishedRequestBuilder(Uri uri, IFileService fileService) { Uri = uri; AbsolutePathDecoded = uri.GetAbsolutePathDecoded(); _fileService = fileService; } /// public Uri Uri { get; } /// public string AbsolutePathDecoded { get; } /// public DomainAndUri Domain { get; private set; } /// public string Culture { get; private set; } /// public ITemplate Template { get; private set; } /// public bool IsInternalRedirect { get; private set; } /// public int? ResponseStatusCode => _responseStatus.HasValue ? (int?)_responseStatus : null; /// public IPublishedContent PublishedContent { get => _publishedContent; private set { _publishedContent = value; IsInternalRedirect = false; Template = null; } } /// public IPublishedRequest Build() => new PublishedRequest( Uri, AbsolutePathDecoded, PublishedContent, IsInternalRedirect, Template, Domain, Culture, _redirectUrl, _responseStatus.HasValue ? (int?)_responseStatus : null, _cacheExtensions, _headers, _cacheability, _ignorePublishedContentCollisions); /// public IPublishedRequestBuilder SetNoCacheHeader(bool cacheability) { _cacheability = cacheability; return this; } /// public IPublishedRequestBuilder SetCacheExtensions(IEnumerable cacheExtensions) { _cacheExtensions = cacheExtensions.ToList(); return this; } /// public IPublishedRequestBuilder SetCulture(string culture) { Culture = culture; return this; } /// public IPublishedRequestBuilder SetDomain(DomainAndUri domain) { Domain = domain; SetCulture(domain.Culture); return this; } /// public IPublishedRequestBuilder SetHeaders(IReadOnlyDictionary headers) { _headers = headers; return this; } /// public IPublishedRequestBuilder SetInternalRedirect(IPublishedContent content) { // unless a template has been set already by the finder, // template should be null at that point. // redirecting to self if (PublishedContent != null && content.Id == PublishedContent.Id) { // no need to set PublishedContent, we're done IsInternalRedirect = true; return this; } // else // set published content - this resets the template, and sets IsInternalRedirect to false PublishedContent = content; IsInternalRedirect = true; return this; } /// public IPublishedRequestBuilder SetPublishedContent(IPublishedContent content) { PublishedContent = content; IsInternalRedirect = false; return this; } /// public IPublishedRequestBuilder SetRedirect(string url, int status = (int)HttpStatusCode.Redirect) { _redirectUrl = url; _responseStatus = (HttpStatusCode)status; return this; } /// public IPublishedRequestBuilder SetRedirectPermanent(string url) { _redirectUrl = url; _responseStatus = HttpStatusCode.Moved; return this; } /// public IPublishedRequestBuilder SetResponseStatus(int code) { _responseStatus = (HttpStatusCode)code; return this; } /// public IPublishedRequestBuilder SetTemplate(ITemplate template) { Template = template; return this; } /// public bool TrySetTemplate(string alias) { if (string.IsNullOrWhiteSpace(alias)) { Template = null; return true; } // NOTE - can we still get it with whitespaces in it due to old legacy bugs? alias = alias.Replace(" ", string.Empty); ITemplate model = _fileService.GetTemplate(alias); if (model == null) { return false; } Template = model; return true; } /// public void IgnorePublishedContentCollisions() => _ignorePublishedContentCollisions = true; } }