Skip to content

Commit

Permalink
Merge pull request #47 from skttl/our-self-host
Browse files Browse the repository at this point in the history
Adds our-self-host
  • Loading branch information
Warren Buckley authored May 12, 2023
2 parents 09b25f5 + c99c6a1 commit 7e23b3a
Show file tree
Hide file tree
Showing 10 changed files with 556 additions and 9 deletions.
71 changes: 71 additions & 0 deletions Our.Umbraco.TagHelpers.Tests/SelfHostServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Our.Umbraco.TagHelpers.Configuration;
using Our.Umbraco.TagHelpers.Services;
using System;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Logging;

namespace Our.Umbraco.TagHelpers.Tests
{
public class SelfHostServiceTests
{
private Mock<IProfilingLogger> _loggerMock;
private Mock<IAppPolicyCache> _runtimeCacheMock;
private Mock<IWebHostEnvironment> _hostingEnvironmentMock;
private Mock<IOptions<OurUmbracoTagHelpersConfiguration>> _globalSettingsMock;
private SelfHostService _service;

[SetUp]
public void SetUp()
{
_loggerMock = new Mock<IProfilingLogger>();
_runtimeCacheMock = new Mock<IAppPolicyCache>();
_hostingEnvironmentMock = new Mock<IWebHostEnvironment>();
_globalSettingsMock = new Mock<IOptions<OurUmbracoTagHelpersConfiguration>>();
_globalSettingsMock.SetupGet(x => x.Value).Returns(new OurUmbracoTagHelpersConfiguration
{
OurSelfHost = new SelfHostTagHelperConfiguration
{
RootFolder = "/self-hosted/"
}
});
_service = new SelfHostService(
_loggerMock.Object,
_runtimeCacheMock.Object,
_hostingEnvironmentMock.Object,
_globalSettingsMock.Object
);
}

[Test]
public void GetRemoteFolderPath_GivenUriWithMoreThanTwoSegments_ReturnsFolderPath()
{
// Arrange
var uri = new Uri("http://www.example.com/folder/subfolder/file.jpg");
var expectedFolderPath = "/folder/subfolder";

// Act
var result = _service.GetRemoteFolderPath(uri);

// Assert
Assert.AreEqual(expectedFolderPath, result);
}

[Test]
public void GetRemoteFolderPath_GivenUriWithLessThanTwoSegments_ReturnsEmptyString()
{
// Arrange
var uri = new Uri("http://www.example.com/");
var expectedFolderPath = string.Empty;

// Act
var result = _service.GetRemoteFolderPath(uri);

// Assert
Assert.AreEqual(expectedFolderPath, result);
}
}
}
165 changes: 165 additions & 0 deletions Our.Umbraco.TagHelpers.Tests/SelfHostTagHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Moq;
using NUnit.Framework;
using Our.Umbraco.TagHelpers.Models;
using Our.Umbraco.TagHelpers.Services;
using Our.Umbraco.TagHelpers.Tests.Helpers;
using System.Threading.Tasks;

namespace Our.Umbraco.TagHelpers.Tests
{
[TestFixture]
public class SelfHostTagHelperTests
{
[Test]
public async Task ProcessAsync_SrcAttribute_SetsSrcAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.SrcAttribute = "https://example.com/test.jpg";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.AreEqual("/media/test.jpg", output.Attributes["src"].Value);
}

[Test]
public async Task ProcessAsync_HrefAttribute_SetsHrefAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.pdf" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.HrefAttribute = "https://example.com/test.pdf";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.AreEqual("/media/test.pdf", output.Attributes["href"].Value);
}

[Test]
public async Task ProcessAsync_RemovesOurSelfHostAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.SrcAttribute = "https://example.com/test.jpg";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.IsFalse(output.Attributes.ContainsName("our-self-host"));
}

[Test]
public async Task ProcessAsync_RemovesFolderAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.SrcAttribute = "https://example.com/test.jpg";
tagHelper.FolderName = "test-folder";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.IsFalse(output.Attributes.ContainsName("folder"));
}

[Test]
public async Task ProcessAsync_RemovesExtAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.SrcAttribute = "https://example.com/test";
tagHelper.Extension = "jpg";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.IsFalse(output.Attributes.ContainsName("ext"));
}

[Test]
public async Task ProcessAsync_SrcAttribute_EnforcesExtAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.SrcAttribute = "https://example.com/test";
tagHelper.Extension = "jpg";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.IsTrue(output.Attributes.ContainsName("src") && output.Attributes["src"].Value.ToString().EndsWith(tagHelper.Extension));
}

[Test]
public async Task ProcessAsync_HrefAttribute_EnforcesExtAttribute()
{
// Arrange
var selfHostServiceMock = new Mock<ISelfHostService>();
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.pdf" });

var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
tagHelper.HrefAttribute = "https://example.com/test";
tagHelper.Extension = "pdf";
var id = "unique-id";
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
var output = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));

// Act
await tagHelper.ProcessAsync(tagHelperContext, output);

// Assert
Assert.IsTrue(output.Attributes.ContainsName("href") && output.Attributes["href"].Value.ToString().EndsWith(tagHelper.Extension));
}
}
}
15 changes: 15 additions & 0 deletions Our.Umbraco.TagHelpers/Composing/SelfHostServiceComposer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Our.Umbraco.TagHelpers.Services;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

namespace Our.Umbraco.TagHelpers.Composing
{
public class SelfHostServiceComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.AddSingleton<ISelfHostService, SelfHostService>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ namespace Our.Umbraco.TagHelpers.Configuration
public class OurUmbracoTagHelpersConfiguration
{
public InlineSvgTagHelperConfiguration OurSVG { get; set; } = new InlineSvgTagHelperConfiguration();
public ImgTagHelperConfiguration OurImg { get; set; } = new ImgTagHelperConfiguration();
public ImgTagHelperConfiguration OurImg { get; set; } = new ImgTagHelperConfiguration();

public SelfHostTagHelperConfiguration OurSelfHost { get; set; } = new SelfHostTagHelperConfiguration();
}

public class InlineSvgTagHelperConfiguration
Expand All @@ -14,33 +16,33 @@ public class InlineSvgTagHelperConfiguration
public bool Cache { get; set; } = false;
public int CacheMinutes { get; set; } = 180;
}
public class ImgTagHelperConfiguration

public class ImgTagHelperConfiguration
{
/// <summary>
/// Define the typical responsive breakpoints (S,M,L,XL,XXL) in which your website uses during screen resize
/// </summary>
public MediaQuerySizes MediaQueries { get; set; } = new MediaQuerySizes();

/// <summary>
/// If true, let the browser handle image lazy loading, otherwise disable to use a 3rd party JavaScript based library
/// </summary>
public bool UseNativeLazyLoading { get; set; } = true;

/// <summary>
/// Applicable if UseNativeLazyLoading is false
/// </summary>
public string LazyLoadCssClass { get; set; } = "lazyload";

/// <summary>
/// Applicable if UseNativeLazyLoading is false
/// </summary>
public ImagePlaceholderType LazyLoadPlaceholder { get; set; } = ImagePlaceholderType.SVG;

/// <summary>
/// Applicable if UseNativeLazyLoading is false & LazyLoadPlaceholder is LowQualityImage
/// </summary>
public int LazyLoadPlaceholderLowQualityImageQuality { get; set; } = 5;
public int LazyLoadPlaceholderLowQualityImageQuality { get; set; } = 5;
public bool ApplyAspectRatio { get; set; } = false;
public bool MobileFirst { get; set; } = true;

Expand All @@ -57,4 +59,9 @@ public class MediaQuerySizes
public int ExtraLarge { get; set; } = 1200;
public int ExtraExtraLarge { get; set; } = 1400;
}

public class SelfHostTagHelperConfiguration
{
public string RootFolder { get; set; } = "~/assets";
}
}
48 changes: 48 additions & 0 deletions Our.Umbraco.TagHelpers/Extensions/WebHostEnvironmentExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Hosting;
using System;
using System.IO;
using Umbraco.Cms.Core;

namespace Our.Umbraco.TagHelpers.Extensions
{
[Obsolete("This should be removed, when the package gets upgraded past Umbraco 10")]
public static class WebHostEnvironmentExtensions
{

/// <summary>
/// Maps a virtual path to a physical path to the application's web root
/// </summary>
/// <remarks>
/// Depending on the runtime 'web root', this result can vary. For example in Net Framework the web root and the
/// content root are the same, however
/// in netcore the web root is /wwwroot therefore this will Map to a physical path within wwwroot.
/// </remarks>

[Obsolete("This should be removed, when the package gets upgraded past Umbraco 10")]
public static string MapPathWebRoot(this IWebHostEnvironment webHostEnvironment, string path)
{
var root = webHostEnvironment.WebRootPath;

// Create if missing
if (string.IsNullOrWhiteSpace(root))
{
root = webHostEnvironment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}

var newPath = path.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);

// TODO: This is a temporary error because we switched from IOHelper.MapPath to HostingEnvironment.MapPathXXX
// IOHelper would check if the path passed in started with the root, and not prepend the root again if it did,
// however if you are requesting a path be mapped, it should always assume the path is relative to the root, not
// absolute in the file system. This error will help us find and fix improper uses, and should be removed once
// all those uses have been found and fixed
if (newPath.StartsWith(root))
{
throw new ArgumentException(
"The path appears to already be fully qualified. Please remove the call to MapPathWebRoot");
}

return Path.Combine(root, newPath.TrimStart(Constants.CharArrays.TildeForwardSlashBackSlash));
}
}
}
15 changes: 15 additions & 0 deletions Our.Umbraco.TagHelpers/Models/SelfHostedFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Our.Umbraco.TagHelpers.Models
{
public class SelfHostedFile
{
public string? ExternalUrl { get; set; }
public string? FileName { get; set; }
public string? FolderPath { get; set; }
public string? Url { get; set; }

public override string? ToString()
{
return Url;
}
}
}
Loading

0 comments on commit 7e23b3a

Please sign in to comment.