Skip to content

Commit 7e23b3a

Browse files
author
Warren Buckley
authored
Merge pull request #47 from skttl/our-self-host
Adds our-self-host
2 parents 09b25f5 + c99c6a1 commit 7e23b3a

File tree

10 files changed

+556
-9
lines changed

10 files changed

+556
-9
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Microsoft.AspNetCore.Hosting;
2+
using Microsoft.Extensions.Options;
3+
using Moq;
4+
using NUnit.Framework;
5+
using Our.Umbraco.TagHelpers.Configuration;
6+
using Our.Umbraco.TagHelpers.Services;
7+
using System;
8+
using Umbraco.Cms.Core.Cache;
9+
using Umbraco.Cms.Core.Logging;
10+
11+
namespace Our.Umbraco.TagHelpers.Tests
12+
{
13+
public class SelfHostServiceTests
14+
{
15+
private Mock<IProfilingLogger> _loggerMock;
16+
private Mock<IAppPolicyCache> _runtimeCacheMock;
17+
private Mock<IWebHostEnvironment> _hostingEnvironmentMock;
18+
private Mock<IOptions<OurUmbracoTagHelpersConfiguration>> _globalSettingsMock;
19+
private SelfHostService _service;
20+
21+
[SetUp]
22+
public void SetUp()
23+
{
24+
_loggerMock = new Mock<IProfilingLogger>();
25+
_runtimeCacheMock = new Mock<IAppPolicyCache>();
26+
_hostingEnvironmentMock = new Mock<IWebHostEnvironment>();
27+
_globalSettingsMock = new Mock<IOptions<OurUmbracoTagHelpersConfiguration>>();
28+
_globalSettingsMock.SetupGet(x => x.Value).Returns(new OurUmbracoTagHelpersConfiguration
29+
{
30+
OurSelfHost = new SelfHostTagHelperConfiguration
31+
{
32+
RootFolder = "/self-hosted/"
33+
}
34+
});
35+
_service = new SelfHostService(
36+
_loggerMock.Object,
37+
_runtimeCacheMock.Object,
38+
_hostingEnvironmentMock.Object,
39+
_globalSettingsMock.Object
40+
);
41+
}
42+
43+
[Test]
44+
public void GetRemoteFolderPath_GivenUriWithMoreThanTwoSegments_ReturnsFolderPath()
45+
{
46+
// Arrange
47+
var uri = new Uri("http://www.example.com/folder/subfolder/file.jpg");
48+
var expectedFolderPath = "/folder/subfolder";
49+
50+
// Act
51+
var result = _service.GetRemoteFolderPath(uri);
52+
53+
// Assert
54+
Assert.AreEqual(expectedFolderPath, result);
55+
}
56+
57+
[Test]
58+
public void GetRemoteFolderPath_GivenUriWithLessThanTwoSegments_ReturnsEmptyString()
59+
{
60+
// Arrange
61+
var uri = new Uri("http://www.example.com/");
62+
var expectedFolderPath = string.Empty;
63+
64+
// Act
65+
var result = _service.GetRemoteFolderPath(uri);
66+
67+
// Assert
68+
Assert.AreEqual(expectedFolderPath, result);
69+
}
70+
}
71+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using Microsoft.AspNetCore.Razor.TagHelpers;
2+
using Moq;
3+
using NUnit.Framework;
4+
using Our.Umbraco.TagHelpers.Models;
5+
using Our.Umbraco.TagHelpers.Services;
6+
using Our.Umbraco.TagHelpers.Tests.Helpers;
7+
using System.Threading.Tasks;
8+
9+
namespace Our.Umbraco.TagHelpers.Tests
10+
{
11+
[TestFixture]
12+
public class SelfHostTagHelperTests
13+
{
14+
[Test]
15+
public async Task ProcessAsync_SrcAttribute_SetsSrcAttribute()
16+
{
17+
// Arrange
18+
var selfHostServiceMock = new Mock<ISelfHostService>();
19+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
20+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });
21+
22+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
23+
tagHelper.SrcAttribute = "https://example.com/test.jpg";
24+
var id = "unique-id";
25+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
26+
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
27+
28+
// Act
29+
await tagHelper.ProcessAsync(tagHelperContext, output);
30+
31+
// Assert
32+
Assert.AreEqual("/media/test.jpg", output.Attributes["src"].Value);
33+
}
34+
35+
[Test]
36+
public async Task ProcessAsync_HrefAttribute_SetsHrefAttribute()
37+
{
38+
// Arrange
39+
var selfHostServiceMock = new Mock<ISelfHostService>();
40+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
41+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.pdf" });
42+
43+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
44+
tagHelper.HrefAttribute = "https://example.com/test.pdf";
45+
var id = "unique-id";
46+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
47+
var output = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
48+
49+
// Act
50+
await tagHelper.ProcessAsync(tagHelperContext, output);
51+
52+
// Assert
53+
Assert.AreEqual("/media/test.pdf", output.Attributes["href"].Value);
54+
}
55+
56+
[Test]
57+
public async Task ProcessAsync_RemovesOurSelfHostAttribute()
58+
{
59+
// Arrange
60+
var selfHostServiceMock = new Mock<ISelfHostService>();
61+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
62+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });
63+
64+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
65+
tagHelper.SrcAttribute = "https://example.com/test.jpg";
66+
var id = "unique-id";
67+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
68+
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
69+
70+
// Act
71+
await tagHelper.ProcessAsync(tagHelperContext, output);
72+
73+
// Assert
74+
Assert.IsFalse(output.Attributes.ContainsName("our-self-host"));
75+
}
76+
77+
[Test]
78+
public async Task ProcessAsync_RemovesFolderAttribute()
79+
{
80+
// Arrange
81+
var selfHostServiceMock = new Mock<ISelfHostService>();
82+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
83+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });
84+
85+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
86+
tagHelper.SrcAttribute = "https://example.com/test.jpg";
87+
tagHelper.FolderName = "test-folder";
88+
var id = "unique-id";
89+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
90+
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
91+
92+
// Act
93+
await tagHelper.ProcessAsync(tagHelperContext, output);
94+
95+
// Assert
96+
Assert.IsFalse(output.Attributes.ContainsName("folder"));
97+
}
98+
99+
[Test]
100+
public async Task ProcessAsync_RemovesExtAttribute()
101+
{
102+
// Arrange
103+
var selfHostServiceMock = new Mock<ISelfHostService>();
104+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
105+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });
106+
107+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
108+
tagHelper.SrcAttribute = "https://example.com/test";
109+
tagHelper.Extension = "jpg";
110+
var id = "unique-id";
111+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
112+
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
113+
114+
// Act
115+
await tagHelper.ProcessAsync(tagHelperContext, output);
116+
117+
// Assert
118+
Assert.IsFalse(output.Attributes.ContainsName("ext"));
119+
}
120+
121+
[Test]
122+
public async Task ProcessAsync_SrcAttribute_EnforcesExtAttribute()
123+
{
124+
// Arrange
125+
var selfHostServiceMock = new Mock<ISelfHostService>();
126+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
127+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.jpg" });
128+
129+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
130+
tagHelper.SrcAttribute = "https://example.com/test";
131+
tagHelper.Extension = "jpg";
132+
var id = "unique-id";
133+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
134+
var output = new TagHelperOutput("img", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
135+
136+
// Act
137+
await tagHelper.ProcessAsync(tagHelperContext, output);
138+
139+
// Assert
140+
Assert.IsTrue(output.Attributes.ContainsName("src") && output.Attributes["src"].Value.ToString().EndsWith(tagHelper.Extension));
141+
}
142+
143+
[Test]
144+
public async Task ProcessAsync_HrefAttribute_EnforcesExtAttribute()
145+
{
146+
// Arrange
147+
var selfHostServiceMock = new Mock<ISelfHostService>();
148+
selfHostServiceMock.Setup(x => x.SelfHostFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
149+
.ReturnsAsync(new SelfHostedFile { Url = "/media/test.pdf" });
150+
151+
var tagHelper = new SelfHostTagHelper(selfHostServiceMock.Object);
152+
tagHelper.HrefAttribute = "https://example.com/test";
153+
tagHelper.Extension = "pdf";
154+
var id = "unique-id";
155+
var tagHelperContext = TestContextHelpers.GetTagHelperContext(id);
156+
var output = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
157+
158+
// Act
159+
await tagHelper.ProcessAsync(tagHelperContext, output);
160+
161+
// Assert
162+
Assert.IsTrue(output.Attributes.ContainsName("href") && output.Attributes["href"].Value.ToString().EndsWith(tagHelper.Extension));
163+
}
164+
}
165+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Our.Umbraco.TagHelpers.Services;
3+
using Umbraco.Cms.Core.Composing;
4+
using Umbraco.Cms.Core.DependencyInjection;
5+
6+
namespace Our.Umbraco.TagHelpers.Composing
7+
{
8+
public class SelfHostServiceComposer : IComposer
9+
{
10+
public void Compose(IUmbracoBuilder builder)
11+
{
12+
builder.Services.AddSingleton<ISelfHostService, SelfHostService>();
13+
}
14+
}
15+
}

Our.Umbraco.TagHelpers/Configuration/OurUmbracoTagHelpersConfiguration.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ namespace Our.Umbraco.TagHelpers.Configuration
55
public class OurUmbracoTagHelpersConfiguration
66
{
77
public InlineSvgTagHelperConfiguration OurSVG { get; set; } = new InlineSvgTagHelperConfiguration();
8-
public ImgTagHelperConfiguration OurImg { get; set; } = new ImgTagHelperConfiguration();
8+
public ImgTagHelperConfiguration OurImg { get; set; } = new ImgTagHelperConfiguration();
9+
10+
public SelfHostTagHelperConfiguration OurSelfHost { get; set; } = new SelfHostTagHelperConfiguration();
911
}
1012

1113
public class InlineSvgTagHelperConfiguration
@@ -14,33 +16,33 @@ public class InlineSvgTagHelperConfiguration
1416
public bool Cache { get; set; } = false;
1517
public int CacheMinutes { get; set; } = 180;
1618
}
17-
18-
public class ImgTagHelperConfiguration
19+
20+
public class ImgTagHelperConfiguration
1921
{
2022
/// <summary>
2123
/// Define the typical responsive breakpoints (S,M,L,XL,XXL) in which your website uses during screen resize
2224
/// </summary>
2325
public MediaQuerySizes MediaQueries { get; set; } = new MediaQuerySizes();
24-
26+
2527
/// <summary>
2628
/// If true, let the browser handle image lazy loading, otherwise disable to use a 3rd party JavaScript based library
2729
/// </summary>
2830
public bool UseNativeLazyLoading { get; set; } = true;
29-
31+
3032
/// <summary>
3133
/// Applicable if UseNativeLazyLoading is false
3234
/// </summary>
3335
public string LazyLoadCssClass { get; set; } = "lazyload";
34-
36+
3537
/// <summary>
3638
/// Applicable if UseNativeLazyLoading is false
3739
/// </summary>
3840
public ImagePlaceholderType LazyLoadPlaceholder { get; set; } = ImagePlaceholderType.SVG;
39-
41+
4042
/// <summary>
4143
/// Applicable if UseNativeLazyLoading is false & LazyLoadPlaceholder is LowQualityImage
4244
/// </summary>
43-
public int LazyLoadPlaceholderLowQualityImageQuality { get; set; } = 5;
45+
public int LazyLoadPlaceholderLowQualityImageQuality { get; set; } = 5;
4446
public bool ApplyAspectRatio { get; set; } = false;
4547
public bool MobileFirst { get; set; } = true;
4648

@@ -57,4 +59,9 @@ public class MediaQuerySizes
5759
public int ExtraLarge { get; set; } = 1200;
5860
public int ExtraExtraLarge { get; set; } = 1400;
5961
}
62+
63+
public class SelfHostTagHelperConfiguration
64+
{
65+
public string RootFolder { get; set; } = "~/assets";
66+
}
6067
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Microsoft.AspNetCore.Hosting;
2+
using System;
3+
using System.IO;
4+
using Umbraco.Cms.Core;
5+
6+
namespace Our.Umbraco.TagHelpers.Extensions
7+
{
8+
[Obsolete("This should be removed, when the package gets upgraded past Umbraco 10")]
9+
public static class WebHostEnvironmentExtensions
10+
{
11+
12+
/// <summary>
13+
/// Maps a virtual path to a physical path to the application's web root
14+
/// </summary>
15+
/// <remarks>
16+
/// Depending on the runtime 'web root', this result can vary. For example in Net Framework the web root and the
17+
/// content root are the same, however
18+
/// in netcore the web root is /wwwroot therefore this will Map to a physical path within wwwroot.
19+
/// </remarks>
20+
21+
[Obsolete("This should be removed, when the package gets upgraded past Umbraco 10")]
22+
public static string MapPathWebRoot(this IWebHostEnvironment webHostEnvironment, string path)
23+
{
24+
var root = webHostEnvironment.WebRootPath;
25+
26+
// Create if missing
27+
if (string.IsNullOrWhiteSpace(root))
28+
{
29+
root = webHostEnvironment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
30+
}
31+
32+
var newPath = path.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
33+
34+
// TODO: This is a temporary error because we switched from IOHelper.MapPath to HostingEnvironment.MapPathXXX
35+
// IOHelper would check if the path passed in started with the root, and not prepend the root again if it did,
36+
// however if you are requesting a path be mapped, it should always assume the path is relative to the root, not
37+
// absolute in the file system. This error will help us find and fix improper uses, and should be removed once
38+
// all those uses have been found and fixed
39+
if (newPath.StartsWith(root))
40+
{
41+
throw new ArgumentException(
42+
"The path appears to already be fully qualified. Please remove the call to MapPathWebRoot");
43+
}
44+
45+
return Path.Combine(root, newPath.TrimStart(Constants.CharArrays.TildeForwardSlashBackSlash));
46+
}
47+
}
48+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Our.Umbraco.TagHelpers.Models
2+
{
3+
public class SelfHostedFile
4+
{
5+
public string? ExternalUrl { get; set; }
6+
public string? FileName { get; set; }
7+
public string? FolderPath { get; set; }
8+
public string? Url { get; set; }
9+
10+
public override string? ToString()
11+
{
12+
return Url;
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)