diff --git a/source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs b/source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs index e10d29188..5acf2e787 100644 --- a/source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs +++ b/source/DasBlog.Services/ConfigFile/Interfaces/ISiteConfig.cs @@ -61,9 +61,12 @@ public interface ISiteConfig string Root { get; set; } - string Copyright { get; set; } + string CdnFrom { get; set; } + string CdnTo { get; set; } - int RssDayCount { get; set; } + string Copyright { get; set; } + + int RssDayCount { get; set; } int RssMainEntryCount { get; set; } diff --git a/source/DasBlog.Services/ConfigFile/SiteConfig.cs b/source/DasBlog.Services/ConfigFile/SiteConfig.cs index a4b060717..b4f9b8b02 100644 --- a/source/DasBlog.Services/ConfigFile/SiteConfig.cs +++ b/source/DasBlog.Services/ConfigFile/SiteConfig.cs @@ -52,8 +52,10 @@ namespace DasBlog.Services.ConfigFile public class SiteConfig : ISiteConfig { private string _root; + private string _cdnFrom; + private string _cdnTo; - public SiteConfig() { } + public SiteConfig() { } public string Title { get; set; } public string Subtitle { get; set; } @@ -77,6 +79,9 @@ public string Root { } } } + public string CdnFrom { get; set; } + public string CdnTo { get; set; } + public string AllowedHosts { get; set; } public string Copyright { get; set; } public int RssDayCount { get; set; } diff --git a/source/DasBlog.Tests/UnitTests/SiteConfigTest.cs b/source/DasBlog.Tests/UnitTests/SiteConfigTest.cs index 494d51b5f..91363d389 100644 --- a/source/DasBlog.Tests/UnitTests/SiteConfigTest.cs +++ b/source/DasBlog.Tests/UnitTests/SiteConfigTest.cs @@ -3,8 +3,6 @@ using DasBlog.Services.ConfigFile.Interfaces; using newtelligence.DasBlog.Runtime; using System; -using System.Collections.Generic; -using System.Text; using System.Xml; namespace DasBlog.Tests.UnitTests @@ -17,10 +15,11 @@ public class SiteConfigTest : ISiteConfig public string Description { get => "Description"; set => throw new NotImplementedException(); } public string Contact { get => "Contact"; set => throw new NotImplementedException(); } public string Root { get => "http://www.poppastring.com/"; set => throw new NotImplementedException(); } + public string CdnFrom{ get => ""; set => throw new NotImplementedException(); } + public string CdnTo{ get => ""; set => throw new NotImplementedException(); } public string Copyright { get => "CopyRight"; set => throw new NotImplementedException(); } public int RssDayCount { get => 100; set => throw new NotImplementedException(); } public bool ShowCommentCount { get => true; set => throw new NotImplementedException(); } - public int RssMainEntryCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public int RssEntryCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public bool EnableRssItemFooters { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } diff --git a/source/DasBlog.Web.Repositories/FileSystemBinaryManager.cs b/source/DasBlog.Web.Repositories/FileSystemBinaryManager.cs index db56883e4..75f72c46f 100644 --- a/source/DasBlog.Web.Repositories/FileSystemBinaryManager.cs +++ b/source/DasBlog.Web.Repositories/FileSystemBinaryManager.cs @@ -1,7 +1,6 @@ using DasBlog.Managers.Interfaces; using DasBlog.Services; using DasBlog.Services.ConfigFile; -using DasBlog.Services.ConfigFile.Interfaces; using DasBlog.Services.FileManagement; using DasBlog.Services.FileManagement.Interfaces; using Microsoft.Extensions.Options; @@ -36,7 +35,9 @@ public FileSystemBinaryManager(IDasBlogSettings dasBlogSettings, IConfigFileServ var loggingDataService = LoggingDataServiceFactory.GetService(Path.Combine(dasBlogSettings.WebRootDirectory, dasBlogSettings.SiteConfiguration.LogDir)); - this.binaryDataService = BinaryDataServiceFactory.GetService(options.BinaryFolder, physBinaryPathUrl, loggingDataService); + var cdnManager = CdnManagerFactory.GetService(dasBlogSettings.SiteConfiguration.CdnFrom, dasBlogSettings.SiteConfiguration.CdnTo); + + binaryDataService = BinaryDataServiceFactory.GetService(options.BinaryFolder, physBinaryPathUrl, loggingDataService, cdnManager); } public string SaveFile(Stream inputFile, string fileName) diff --git a/source/DasBlog.Web.UI/Config/site.config b/source/DasBlog.Web.UI/Config/site.config index 371dcec8e..8998da6e0 100644 --- a/source/DasBlog.Web.UI/Config/site.config +++ b/source/DasBlog.Web.UI/Config/site.config @@ -56,6 +56,16 @@ logs content/binary + + + + + + true false false diff --git a/source/DasBlog.Web.UI/Models/AdminViewModels/SiteViewModel.cs b/source/DasBlog.Web.UI/Models/AdminViewModels/SiteViewModel.cs index 9e72f3c32..3fc1b87f2 100644 --- a/source/DasBlog.Web.UI/Models/AdminViewModels/SiteViewModel.cs +++ b/source/DasBlog.Web.UI/Models/AdminViewModels/SiteViewModel.cs @@ -240,9 +240,16 @@ public class SiteViewModel [DisplayName("Time zone index")] [Description("")] - public int DisplayTimeZoneIndex { get; set; } + [DisplayName("CDN from")] + [Description("The part of your Root URL to replace with the CDN URL. (optional)")] + public string CdnFrom { get; set; } + + [DisplayName("CDN to")] + [Description("The CDN URL that will replace 'CDN from'. (optional)")] + public string CdnTo { get; set; } + [DisplayName("Comments require approval")] [Description("")] public bool CommentsRequireApproval { get; set; } diff --git a/source/DasBlog.Web.UI/Views/Admin/Settings.cshtml b/source/DasBlog.Web.UI/Views/Admin/Settings.cshtml index 7dcf36689..cf3b0df0e 100644 --- a/source/DasBlog.Web.UI/Views/Admin/Settings.cshtml +++ b/source/DasBlog.Web.UI/Views/Admin/Settings.cshtml @@ -694,6 +694,22 @@ @Html.ValidationMessageFor(m => m.SiteConfig.DisplayTimeZoneIndex, null, new { @class = "text-danger" }) + +
+ + @Html.LabelFor(m => @Model.SiteConfig.CdnFrom, null, new { @class = "col-form-label col-sm-2" }) +
+ @Html.TextBoxFor(m => @Model.SiteConfig.CdnFrom, null, new { @class = "form-control sm-10" }) +
+ @Html.ValidationMessageFor(m => m.SiteConfig.CdnFrom, null, new { @class = "text-danger" }) + + @Html.LabelFor(m => @Model.SiteConfig.CdnTo, null, new { @class = "col-form-label col-sm-2" }) +
+ @Html.TextBoxFor(m => @Model.SiteConfig.CdnTo, null, new { @class = "form-control sm-10" }) +
+ @Html.ValidationMessageFor(m => m.SiteConfig.CdnTo, null, new { @class = "text-danger" }) + +

Security

diff --git a/source/newtelligence.DasBlog.Runtime/CdnManager.cs b/source/newtelligence.DasBlog.Runtime/CdnManager.cs new file mode 100644 index 000000000..586f9f501 --- /dev/null +++ b/source/newtelligence.DasBlog.Runtime/CdnManager.cs @@ -0,0 +1,35 @@ +using System; + +namespace newtelligence.DasBlog.Runtime +{ + public static class CdnManagerFactory + { + public static ICdnManager GetService(string cdnFrom, string cdnTo) + { + return new CdnManager(cdnFrom, cdnTo); + } + } + + internal sealed class CdnManager : ICdnManager + { + private readonly string cdnFrom; + private readonly string cdnTo; + + /// + /// Setting up the cdn manager to return cdn uris when that is configured. + /// + /// The binary hosting path to be replaced. + /// The cdn binary hosting path to change to. + public CdnManager(string cdnFrom, string cdnTo) + { + this.cdnFrom = string.IsNullOrWhiteSpace(cdnFrom) ? null : cdnFrom; + this.cdnTo = string.IsNullOrWhiteSpace(cdnTo) || this.cdnFrom == null ? null : cdnTo; + } + + public string ApplyCdnUri(string uri) + { + // If the cdnUri is null then we can just return the uri. + return cdnTo == null ? uri : uri.Replace(cdnFrom, cdnTo); + } + } +} diff --git a/source/newtelligence.DasBlog.Runtime/FileSystemBinaryDataService.cs b/source/newtelligence.DasBlog.Runtime/FileSystemBinaryDataService.cs index 2f54ac70e..78f47402b 100644 --- a/source/newtelligence.DasBlog.Runtime/FileSystemBinaryDataService.cs +++ b/source/newtelligence.DasBlog.Runtime/FileSystemBinaryDataService.cs @@ -19,7 +19,7 @@ public static class BinaryDataServiceFactory /// /// /// - public static IBinaryDataService GetService(string contentLocation, Uri rootUrl, ILoggingDataService loggingService) + public static IBinaryDataService GetService(string contentLocation, Uri rootUrl, ILoggingDataService loggingService, ICdnManager cdnManager) { IBinaryDataService service; @@ -27,7 +27,7 @@ public static IBinaryDataService GetService(string contentLocation, Uri rootUrl, { if (!services.TryGetValue(contentLocation, out service)) { - service = new FileSystemBinaryDataService(contentLocation, rootUrl, loggingService); + service = new FileSystemBinaryDataService(contentLocation, rootUrl, loggingService, cdnManager); services.Add(contentLocation, service); } } @@ -50,14 +50,14 @@ public static bool RemoveService(string contentLocation) internal sealed class FileSystemBinaryDataService : IBinaryDataService { - - /// - /// - /// - /// The location of the content on disk. - /// The relative url to the binary content from the root of the site. - /// The logging service. - internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl, ILoggingDataService loggingService) + /// + /// + /// + /// The location of the content on disk. + /// The relative url to the binary content from the root of the site. + /// The logging service. + /// Creates content URis for CDN locations. + internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl, ILoggingDataService loggingService, ICdnManager cdnManager) { // parameter validation if (string.IsNullOrEmpty(contentLocation)) @@ -82,6 +82,7 @@ internal FileSystemBinaryDataService(string contentLocation, Uri binaryRootUrl, this.contentLocation = contentLocation; this.loggingService = loggingService; + this.cdnManager = cdnManager; this.binaryRoot = binaryRootUrl; } @@ -144,9 +145,11 @@ public string SaveFile(System.IO.Stream inputFile, ref string fileName) string absUri = GetAbsoluteFileUri(file.FullName, out relUri); - fileName = relUri; + fileName = relUri; + + absUri = cdnManager.ApplyCdnUri(absUri); - return absUri; + return absUri; } private string GetAbsoluteFileUri(string fullPath, out string relFileUri) @@ -218,6 +221,6 @@ private bool EqualBuffers(byte[] buf1, byte[] buf2) private string contentLocation; private Uri binaryRoot; private ILoggingDataService loggingService; - + private readonly ICdnManager cdnManager; } } diff --git a/source/newtelligence.DasBlog.Runtime/ICdnManager.cs b/source/newtelligence.DasBlog.Runtime/ICdnManager.cs new file mode 100644 index 000000000..21e1059b5 --- /dev/null +++ b/source/newtelligence.DasBlog.Runtime/ICdnManager.cs @@ -0,0 +1,16 @@ +namespace newtelligence.DasBlog.Runtime +{ + /// + /// When the site is configured with a "CdnRoot" setting, + /// this manager is used to create content URIs for the CDN location. + /// + public interface ICdnManager + { + /// + /// Manages URI creation for resources when CDN is configured. + /// + /// The URI of a file hosted locally. + /// The URI of a file when it is hosted in CDN. + string ApplyCdnUri(string uri); + } +}