diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/IndexedArrayItem.cs b/src/Umbraco.Abstractions/Models/PublishedContent/IndexedArrayItem.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/PublishedContent/IndexedArrayItem.cs rename to src/Umbraco.Abstractions/Models/PublishedContent/IndexedArrayItem.cs diff --git a/src/Umbraco.Abstractions/PublishedContentExtensions.cs b/src/Umbraco.Abstractions/PublishedContentExtensions.cs index 53618ea632..aa432459dd 100644 --- a/src/Umbraco.Abstractions/PublishedContentExtensions.cs +++ b/src/Umbraco.Abstractions/PublishedContentExtensions.cs @@ -9,6 +9,56 @@ namespace Umbraco.Core { public static class PublishedContentExtensions { + #region Name + + /// + /// Gets the name of the content item. + /// + /// The content item. + /// + /// The specific culture to get the name for. If null is used the current culture is used (Default is null). + public static string Name(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + // invariant has invariant value (whatever the requested culture) + if (!content.ContentType.VariesByCulture()) + return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.Name : null; + + // handle context culture for variant + if (culture == null) + culture = variationContextAccessor?.VariationContext?.Culture ?? ""; + + // get + return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Name : null; + } + + #endregion + + #region Url segment + + /// + /// Gets the url segment of the content item. + /// + /// The content item. + /// + /// The specific culture to get the url segment for. If null is used the current culture is used (Default is null). + public static string UrlSegment(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + // invariant has invariant value (whatever the requested culture) + if (!content.ContentType.VariesByCulture()) + return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.UrlSegment : null; + + // handle context culture for variant + if (culture == null) + culture = variationContextAccessor?.VariationContext?.Culture ?? ""; + + // get + return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.UrlSegment : null; + } + + #endregion + + #region Culture + /// /// Determines whether the content has a culture. /// @@ -40,47 +90,6 @@ namespace Umbraco.Core return contents.Where(x => !x.ContentType.VariesByCulture() || HasCulture(x, culture)); } - /// - /// Gets the name of the content item. - /// - /// The content item. - /// - /// The specific culture to get the name for. If null is used the current culture is used (Default is null). - public static string Name(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) - { - // invariant has invariant value (whatever the requested culture) - if (!content.ContentType.VariesByCulture()) - return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.Name : null; - - // handle context culture for variant - if (culture == null) - culture = variationContextAccessor?.VariationContext?.Culture ?? ""; - - // get - return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Name : null; - } - - - /// - /// Gets the url segment of the content item. - /// - /// The content item. - /// - /// The specific culture to get the url segment for. If null is used the current culture is used (Default is null). - public static string UrlSegment(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) - { - // invariant has invariant value (whatever the requested culture) - if (!content.ContentType.VariesByCulture()) - return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.UrlSegment : null; - - // handle context culture for variant - if (culture == null) - culture = variationContextAccessor?.VariationContext?.Culture ?? ""; - - // get - return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.UrlSegment : null; - } - /// /// Gets the culture date of the content item. /// @@ -101,53 +110,211 @@ namespace Umbraco.Core return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Date : DateTime.MinValue; } + #endregion + + #region IsComposedOf + /// - /// Gets the children of the content item. + /// Gets a value indicating whether the content is of a content type composed of the given alias /// - /// The content item. - /// - /// - /// The specific culture to get the url children for. Default is null which will use the current culture in - /// - /// - /// Gets children that are available for the specified culture. - /// Children are sorted by their sortOrder. - /// - /// For culture, - /// if null is used the current culture is used. - /// If an empty string is used only invariant children are returned. - /// If "*" is used all children are returned. - /// - /// - /// If a variant culture is specified or there is a current culture in the then the Children returned - /// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture. - /// However, if an empty string is specified only invariant children are returned. - /// - /// - public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + /// The content. + /// The content type alias. + /// A value indicating whether the content is of a content type composed of a content type identified by the alias. + public static bool IsComposedOf(this IPublishedContent content, string alias) { - // handle context culture for variant - if (culture == null) - culture = variationContextAccessor?.VariationContext?.Culture ?? ""; - - var children = content.ChildrenForAllCultures; - return culture == "*" - ? children - : children.Where(x => x.IsInvariantOrHasCulture(culture)); + return content.ContentType.CompositionAliases.InvariantContains(alias); } - #region Writer and creator + #endregion - public static string GetCreatorName(this IPublishedContent content, IUserService userService) + #region Template + + /// + /// Returns the current template Alias + /// + /// Empty string if none is set. + public static string GetTemplateAlias(this IPublishedContent content, IFileService fileService) { - var user = userService.GetProfileById(content.CreatorId); - return user?.Name; + if (content.TemplateId.HasValue == false) + { + return string.Empty; + } + + var template = fileService.GetTemplate(content.TemplateId.Value); + return template == null ? string.Empty : template.Alias; } - public static string GetWriterName(this IPublishedContent content, IUserService userService) + public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService, bool disableAlternativeTemplates, bool validateAlternativeTemplates, int templateId) { - var user = userService.GetProfileById(content.WriterId); - return user?.Name; + if (disableAlternativeTemplates) + return content.TemplateId == templateId; + + if (content.TemplateId == templateId || !validateAlternativeTemplates) + return true; + + var publishedContentContentType = contentTypeService.Get(content.ContentType.Id); + if (publishedContentContentType == null) + throw new NullReferenceException("No content type returned for published content (contentType='" + content.ContentType.Id + "')"); + + return publishedContentContentType.IsAllowedTemplate(templateId); + + } + public static bool IsAllowedTemplate(this IPublishedContent content, IFileService fileService, IContentTypeService contentTypeService, bool disableAlternativeTemplates, bool validateAlternativeTemplates, string templateAlias) + { + var template = fileService.GetTemplate(templateAlias); + return template != null && content.IsAllowedTemplate(contentTypeService, disableAlternativeTemplates, validateAlternativeTemplates, template.Id); + } + + #endregion + + #region HasValue, Value, Value + + /// + /// Gets a value indicating whether the content has a value for a property identified by its alias. + /// + /// The content. + /// The published value fallback implementation. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// A value indicating whether the content has a value for the property identified by the alias. + /// Returns true if HasValue is true, or a fallback strategy can provide a value. + public static bool HasValue(this IPublishedContent content, IPublishedValueFallback publishedValueFallback, string alias, string culture = null, string segment = null, Fallback fallback = default) + { + var property = content.GetProperty(alias); + + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return true; + + // else let fallback try to get a value + return publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, null, out _, out _); + } + + /// + /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. + /// + /// The content. + /// The published value fallback implementation. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, if it exists, otherwise a default value. + public static object Value(this IPublishedContent content, IPublishedValueFallback publishedValueFallback, string alias, string culture = null, string segment = null, Fallback fallback = default, object defaultValue = default) + { + var property = content.GetProperty(alias); + + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return property.GetValue(culture, segment); + + // else let fallback try to get a value + if (publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value, out property)) + return value; + + // else... if we have a property, at least let the converter return its own + // vision of 'no value' (could be an empty enumerable) + return property?.GetValue(culture, segment); + } + + /// + /// Gets the value of a content's property identified by its alias, converted to a specified type. + /// + /// The target property type. + /// The content. + /// The published value fallback implementation. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, converted to the specified type. + public static T Value(this IPublishedContent content, IPublishedValueFallback publishedValueFallback, string alias, string culture = null, string segment = null, Fallback fallback = default, T defaultValue = default) + { + var property = content.GetProperty(alias); + + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return property.Value(publishedValueFallback, culture, segment); + + // else let fallback try to get a value + if (publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value, out property)) + return value; + + // else... if we have a property, at least let the converter return its own + // vision of 'no value' (could be an empty enumerable) - otherwise, default + return property == null ? default : property.Value(publishedValueFallback, culture, segment); + } + + #endregion + + #region IsSomething: misc. + + /// + /// Determines whether the specified content is a specified content type. + /// + /// The content to determine content type of. + /// The alias of the content type to test against. + /// True if the content is of the specified content type; otherwise false. + public static bool IsDocumentType(this IPublishedContent content, string docTypeAlias) + { + return content.ContentType.Alias.InvariantEquals(docTypeAlias); + } + + /// + /// Determines whether the specified content is a specified content type or it's derived types. + /// + /// The content to determine content type of. + /// The alias of the content type to test against. + /// When true, recurses up the content type tree to check inheritance; when false just calls IsDocumentType(this IPublishedContent content, string docTypeAlias). + /// True if the content is of the specified content type or a derived content type; otherwise false. + public static bool IsDocumentType(this IPublishedContent content, string docTypeAlias, bool recursive) + { + if (content.IsDocumentType(docTypeAlias)) + return true; + + return recursive && content.IsComposedOf(docTypeAlias); + } + + #endregion + + #region IsSomething: equality + + public static bool IsEqual(this IPublishedContent content, IPublishedContent other) + { + return content.Id == other.Id; + } + + public static bool IsNotEqual(this IPublishedContent content, IPublishedContent other) + { + return content.IsEqual(other) == false; + } + + #endregion + + #region IsSomething: ancestors and descendants + + public static bool IsDescendant(this IPublishedContent content, IPublishedContent other) + { + return other.Level < content.Level && content.Path.InvariantStartsWith(other.Path.EnsureEndsWith(',')); + } + + public static bool IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other) + { + return content.Path.InvariantEquals(other.Path) || content.IsDescendant(other); + } + + public static bool IsAncestor(this IPublishedContent content, IPublishedContent other) + { + return content.Level < other.Level && other.Path.InvariantStartsWith(content.Path.EnsureEndsWith(',')); + } + + public static bool IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other) + { + return other.Path.InvariantEquals(content.Path) || content.IsAncestor(other); } #endregion @@ -639,6 +806,41 @@ namespace Umbraco.Core #region Axes: children + /// + /// Gets the children of the content item. + /// + /// The content item. + /// + /// + /// The specific culture to get the url children for. Default is null which will use the current culture in + /// + /// + /// Gets children that are available for the specified culture. + /// Children are sorted by their sortOrder. + /// + /// For culture, + /// if null is used the current culture is used. + /// If an empty string is used only invariant children are returned. + /// If "*" is used all children are returned. + /// + /// + /// If a variant culture is specified or there is a current culture in the then the Children returned + /// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture. + /// However, if an empty string is specified only invariant children are returned. + /// + /// + public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + // handle context culture for variant + if (culture == null) + culture = variationContextAccessor?.VariationContext?.Culture ?? ""; + + var children = content.ChildrenForAllCultures; + return culture == "*" + ? children + : children.Where(x => x.IsInvariantOrHasCulture(culture)); + } + /// /// Gets the children of the content, filtered by a predicate. /// @@ -741,7 +943,7 @@ namespace Umbraco.Core #endregion - #region Axes: Siblings + #region Axes: siblings /// /// Gets the siblings of the content. @@ -857,5 +1059,21 @@ namespace Umbraco.Core } #endregion + + #region Writer and creator + + public static string GetCreatorName(this IPublishedContent content, IUserService userService) + { + var user = userService.GetProfileById(content.CreatorId); + return user?.Name; + } + + public static string GetWriterName(this IPublishedContent content, IUserService userService) + { + var user = userService.GetProfileById(content.WriterId); + return user?.Name; + } + + #endregion } } diff --git a/src/Umbraco.Abstractions/PublishedElementExtensions.cs b/src/Umbraco.Abstractions/PublishedElementExtensions.cs index 77b6b1516a..4b529147e3 100644 --- a/src/Umbraco.Abstractions/PublishedElementExtensions.cs +++ b/src/Umbraco.Abstractions/PublishedElementExtensions.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core @@ -23,5 +22,158 @@ namespace Umbraco.Core } #endregion + + #region IsComposedOf + + /// + /// Gets a value indicating whether the content is of a content type composed of the given alias + /// + /// The content. + /// The content type alias. + /// A value indicating whether the content is of a content type composed of a content type identified by the alias. + public static bool IsComposedOf(this IPublishedElement content, string alias) + { + return content.ContentType.CompositionAliases.InvariantContains(alias); + } + + #endregion + + #region HasProperty + + /// + /// Gets a value indicating whether the content has a property identified by its alias. + /// + /// The content. + /// The property alias. + /// A value indicating whether the content has the property identified by the alias. + /// The content may have a property, and that property may not have a value. + public static bool HasProperty(this IPublishedElement content, string alias) + { + return content.ContentType.GetPropertyType(alias) != null; + } + + #endregion + + #region HasValue + + /// + /// Gets a value indicating whether the content has a value for a property identified by its alias. + /// + /// Returns true if GetProperty(alias) is not null and GetProperty(alias).HasValue is true. + public static bool HasValue(this IPublishedElement content, string alias, string culture = null, string segment = null) + { + var prop = content.GetProperty(alias); + return prop != null && prop.HasValue(culture, segment); + } + + #endregion + + #region Value + + /// + /// Gets the value of a content's property identified by its alias. + /// + /// The content. + /// The published value fallback implementation. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, if it exists, otherwise a default value. + /// + /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. + /// If no property with the specified alias exists, or if the property has no value, returns . + /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. + /// The alias is case-insensitive. + /// + public static object Value(this IPublishedElement content, IPublishedValueFallback publishedValueFallback, string alias, string culture = null, string segment = null, Fallback fallback = default, object defaultValue = default) + { + var property = content.GetProperty(alias); + + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return property.GetValue(culture, segment); + + // else let fallback try to get a value + if (publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value)) + return value; + + // else... if we have a property, at least let the converter return its own + // vision of 'no value' (could be an empty enumerable) - otherwise, default + return property?.GetValue(culture, segment); + } + + #endregion + + #region Value + + /// + /// Gets the value of a content's property identified by its alias, converted to a specified type. + /// + /// The target property type. + /// The content. + /// The published value fallback implementation. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, converted to the specified type. + /// + /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. + /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns default(T). + /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. + /// The alias is case-insensitive. + /// + public static T Value(this IPublishedElement content, IPublishedValueFallback publishedValueFallback, string alias, string culture = null, string segment = null, Fallback fallback = default, T defaultValue = default) + { + var property = content.GetProperty(alias); + + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return property.Value(publishedValueFallback, culture, segment); + + // else let fallback try to get a value + if (publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value)) + return value; + + // else... if we have a property, at least let the converter return its own + // vision of 'no value' (could be an empty enumerable) - otherwise, default + return property == null ? default : property.Value(publishedValueFallback, culture, segment); + } + + #endregion + + #region ToIndexedArray + + public static IndexedArrayItem[] ToIndexedArray(this IEnumerable source) + where TContent : class, IPublishedElement + { + var set = source.Select((content, index) => new IndexedArrayItem(content, index)).ToArray(); + foreach (var setItem in set) setItem.TotalCount = set.Length; + return set; + } + + #endregion + + #region IsSomething + + /// + /// Gets a value indicating whether the content is visible. + /// + /// The content. + /// The published value fallback implementation. + /// A value indicating whether the content is visible. + /// A content is not visible if it has an umbracoNaviHide property with a value of "1". Otherwise, + /// the content is visible. + public static bool IsVisible(this IPublishedElement content, IPublishedValueFallback publishedValueFallback) + { + // rely on the property converter - will return default bool value, ie false, if property + // is not defined, or has no value, else will return its value. + return content.Value(publishedValueFallback, Constants.Conventions.Content.NaviHide) == false; + } + + #endregion } } diff --git a/src/Umbraco.Abstractions/PublishedPropertyExtension.cs b/src/Umbraco.Abstractions/PublishedPropertyExtension.cs new file mode 100644 index 0000000000..259a2714d3 --- /dev/null +++ b/src/Umbraco.Abstractions/PublishedPropertyExtension.cs @@ -0,0 +1,59 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Core +{ + /// + /// Provides extension methods for IPublishedProperty. + /// + public static class PublishedPropertyExtension + { + #region Value + + public static object Value(this IPublishedProperty property, IPublishedValueFallback publishedValueFallback, string culture = null, string segment = null, Fallback fallback = default, object defaultValue = default) + { + if (property.HasValue(culture, segment)) + return property.GetValue(culture, segment); + + return publishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var value) + ? value + : property.GetValue(culture, segment); // give converter a chance to return it's own vision of "no value" + } + + #endregion + + #region Value + + public static T Value(this IPublishedProperty property, IPublishedValueFallback publishedValueFallback, string culture = null, string segment = null, Fallback fallback = default, T defaultValue = default) + { + if (property.HasValue(culture, segment)) + { + // we have a value + // try to cast or convert it + var value = property.GetValue(culture, segment); + if (value is T valueAsT) return valueAsT; + var valueConverted = value.TryConvertTo(); + if (valueConverted) return valueConverted.Result; + + // cannot cast nor convert the value, nothing we can return but 'default' + // note: we don't want to fallback in that case - would make little sense + return default; + } + + // we don't have a value, try fallback + if (publishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var fallbackValue)) + return fallbackValue; + + // we don't have a value - neither direct nor fallback + // give a chance to the converter to return something (eg empty enumerable) + var noValue = property.GetValue(culture, segment); + if (noValue is T noValueAsT) return noValueAsT; + var noValueConverted = noValue.TryConvertTo(); + if (noValueConverted) return noValueConverted.Result; + + // cannot cast noValue nor convert it, nothing we can return but 'default' + return default; + } + + #endregion + } +} diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 36f0c6f6b3..36d78adf10 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -77,7 +77,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _umbracoContext = new UmbracoContext( _httpContextFactory.HttpContext, publishedSnapshotService.Object, - new WebSecurity(_httpContextFactory.HttpContext, Mock.Of(), globalSettings), + new WebSecurity(_httpContextFactory.HttpContext, Mock.Of(), globalSettings, IOHelper), umbracoSettings, Enumerable.Empty(), Enumerable.Empty(), diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs index 5812fde11c..c058c9ac48 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs @@ -5,6 +5,7 @@ using System.Xml; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Composing; namespace Umbraco.Tests.LegacyXmlPublishedCache @@ -108,7 +109,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _previewXml = _xmlStore.GetPreviewXml(contentId, includeSubs); // make sure the preview folder exists - var dir = new DirectoryInfo(Current.IOHelper.MapPath(Constants.SystemDirectories.Preview)); + var dir = new DirectoryInfo(TestHelper.IOHelper.MapPath(Constants.SystemDirectories.Preview)); if (dir.Exists == false) dir.Create(); @@ -122,7 +123,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // get the full path to the preview set private static string GetPreviewSetPath(int userId, Guid previewSet) { - return Current.IOHelper.MapPath(Path.Combine(Constants.SystemDirectories.Preview, userId + "_" + previewSet + ".config")); + return TestHelper.IOHelper.MapPath(Path.Combine(Constants.SystemDirectories.Preview, userId + "_" + previewSet + ".config")); } // deletes files for the user, and files accessed more than one hour ago diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs index df46ab755f..238da68370 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs @@ -22,6 +22,7 @@ using Umbraco.Core.Services.Changes; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Xml; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Cache; using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; @@ -94,7 +95,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _hostingEnvironment = hostingEnvironment; _shortStringHelper = shortStringHelper; - _xmlFileName = Current.IOHelper.MapPath(SystemFiles.GetContentCacheXml(_hostingEnvironment)); + _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(_hostingEnvironment)); if (testing) { @@ -118,7 +119,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _mediaRepository = mediaRepository; _memberRepository = memberRepository; _xmlFileEnabled = false; - _xmlFileName = Current.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); + _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); // do not plug events, we may not have what it takes to handle them } @@ -132,7 +133,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _memberRepository = memberRepository; GetXmlDocument = getXmlDocument ?? throw new ArgumentNullException(nameof(getXmlDocument)); _xmlFileEnabled = false; - _xmlFileName = Current.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); + _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); // do not plug events, we may not have what it takes to handle them } diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 19adf28528..7a456f427a 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -15,13 +15,14 @@ using Umbraco.Core.Strings; using Umbraco.Tests.Components; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class ConvertersTests + public class ConvertersTests : UmbracoTestBase { #region SimpleConverter1 diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs index 1b79b65b19..3bb2c0a5e4 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests/Published/NestedContentTests.cs @@ -17,16 +17,15 @@ using Umbraco.Web; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; +using Umbraco.Tests.Testing; namespace Umbraco.Tests.Published { [TestFixture] - public class NestedContentTests + public class NestedContentTests : UmbracoTestBase { private (IPublishedContentType, IPublishedContentType) CreateContentTypes() { - Current.Reset(); - var logger = Mock.Of(); var profiler = Mock.Of(); var proflog = new ProfilingLogger(logger, profiler); diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs index 8f8e4ae7a9..d3e6dae26b 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs @@ -12,13 +12,14 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class PropertyCacheLevelTests + public class PropertyCacheLevelTests : UmbracoTestBase { [TestCase(PropertyCacheLevel.None, 2)] [TestCase(PropertyCacheLevel.Element, 1)] diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs index fdf9863c78..65da377071 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using NUnit.Framework; using Umbraco.Web.Composing; +using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 89995ebf73..a1592a57d0 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -71,7 +71,7 @@ namespace Umbraco.Tests.PublishedContent var umbracoContext = new UmbracoContext( httpContext, publishedSnapshotService.Object, - new WebSecurity(httpContext, Current.Services.UserService, globalSettings), + new WebSecurity(httpContext, Current.Services.UserService, globalSettings, IOHelper), TestObjects.GetUmbracoSettings(), Enumerable.Empty(), Enumerable.Empty(), diff --git a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs index 4079ea6c84..bedd8a8744 100644 --- a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs +++ b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.Routing public void Is_Reserved_Path_Or_Url(string url) { var globalSettings = TestObjects.GetGlobalSettings(); - var routableDocFilter = new RoutableDocumentFilter(globalSettings); + var routableDocFilter = new RoutableDocumentFilter(globalSettings, IOHelper); Assert.IsTrue(routableDocFilter.IsReservedPathOrUrl(url)); } @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Routing public void Is_Not_Reserved_Path_Or_Url(string url) { var globalSettings = TestObjects.GetGlobalSettings(); - var routableDocFilter = new RoutableDocumentFilter(globalSettings); + var routableDocFilter = new RoutableDocumentFilter(globalSettings, IOHelper); Assert.IsFalse(routableDocFilter.IsReservedPathOrUrl(url)); } @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Routing globalSettingsMock.Setup(x => x.ReservedPaths).Returns(""); globalSettingsMock.Setup(x => x.ReservedUrls).Returns(""); - var routableDocFilter = new RoutableDocumentFilter(globalSettingsMock.Object); + var routableDocFilter = new RoutableDocumentFilter(globalSettingsMock.Object, IOHelper); var routes = new RouteCollection(); diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index bfb3bc6ac0..d4c242a762 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -42,7 +42,7 @@ namespace Umbraco.Tests.Routing logger, null, // FIXME: PublishedRouter complexities... Mock.Of(), - new RoutableDocumentFilter(globalSettings) + new RoutableDocumentFilter(globalSettings, IOHelper) ); runtime.Level = RuntimeLevel.Run; diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index d4d00f60ef..ed25764201 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -122,7 +122,7 @@ namespace Umbraco.Tests.Scoping var umbracoContext = new UmbracoContext( httpContext, service, - new WebSecurity(httpContext, Current.Services.UserService, globalSettings), + new WebSecurity(httpContext, Current.Services.UserService, globalSettings, IOHelper), umbracoSettings ?? SettingsForTests.GetDefaultUmbracoSettings(), urlProviders ?? Enumerable.Empty(), Enumerable.Empty(), diff --git a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs index 9ac45ae87a..7ff0776ba8 100644 --- a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs @@ -33,7 +33,7 @@ namespace Umbraco.Tests.Security var umbracoContext = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService, globalSettings), + new WebSecurity(Mock.Of(), Current.Services.UserService, globalSettings, IOHelper), TestObjects.GetUmbracoSettings(), new List(), Enumerable.Empty(), globalSettings, new TestVariationContextAccessor(), IOHelper); @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Security var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService, globalSettings), + new WebSecurity(Mock.Of(), Current.Services.UserService, globalSettings, IOHelper), TestObjects.GetUmbracoSettings(), new List(), Enumerable.Empty(), globalSettings, new TestVariationContextAccessor(), IOHelper); diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index e7abec5ee2..9365c710b6 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -11,6 +11,7 @@ using Moq; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Dictionary; +using Umbraco.Core.IO; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Security; diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 82cc0b196e..5f6467abc4 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -385,7 +385,7 @@ namespace Umbraco.Tests.TestHelpers httpContext, service, new WebSecurity(httpContext, Factory.GetInstance(), - Factory.GetInstance()), + Factory.GetInstance(), IOHelper), umbracoSettings ?? Factory.GetInstance(), urlProviders ?? Enumerable.Empty(), mediaUrlProviders ?? Enumerable.Empty(), diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 7999898c4e..a1d50e54c1 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -49,13 +49,11 @@ using Umbraco.Web.Templates; using Umbraco.Web.PropertyEditors; using Umbraco.Core.Dictionary; using Umbraco.Core.Models.Identity; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Net; using Umbraco.Web.Security; using Current = Umbraco.Web.Composing.Current; - namespace Umbraco.Tests.Testing { /// @@ -297,7 +295,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); - + Composition.RegisterUnique(); } protected virtual void ComposeMisc() diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index 3705d23162..7753b0495f 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -33,6 +33,7 @@ using Umbraco.Web.Features; using Umbraco.Web.Models.ContentEditing; using IUser = Umbraco.Core.Models.Membership.IUser; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; namespace Umbraco.Tests.Web.Controllers { @@ -87,7 +88,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), helper, Factory.GetInstance(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance()); return usersController; } diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs index 31ee27d399..0c9b4f428f 100644 --- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs @@ -89,7 +89,9 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance() + ); return usersController; } @@ -157,7 +159,9 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance() + ); return usersController; } @@ -196,7 +200,9 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance() + ); return usersController; } @@ -270,7 +276,9 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), ShortStringHelper, Factory.GetInstance(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance() + ); return usersController; } diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index c99d2cd943..6fa54e34cb 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -440,7 +440,7 @@ namespace Umbraco.Tests.Web.Mvc var ctx = new UmbracoContext( http, _service, - new WebSecurity(http, Current.Services.UserService, globalSettings), + new WebSecurity(http, Current.Services.UserService, globalSettings, IOHelper), TestObjects.GetUmbracoSettings(), Enumerable.Empty(), Enumerable.Empty(), diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index bb3db7273c..cb125fa851 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings(), IOHelper), TestObjects.GetUmbracoSettings(), new List(), Enumerable.Empty(), @@ -49,7 +49,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings(), IOHelper), TestObjects.GetUmbracoSettings(), new List(), Enumerable.Empty(), @@ -79,7 +79,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings(), IOHelper), TestObjects.GetUmbracoSettings(), new List(), Enumerable.Empty(), diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Breadcrumb.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Breadcrumb.cshtml index 335987f542..94519f53da 100755 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Breadcrumb.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Breadcrumb.cshtml @@ -18,7 +18,7 @@ @* For each page in the ancestors collection which have been ordered by Level (so we start with the highest top node first) *@ @foreach (var item in selection.OrderBy(x => x.Level)) { -
  • @item.Name /
  • +
  • @item.Name /
  • } @* Display the current page as the last item in the list *@ diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml index fa86862c9a..7ff9d0bb94 100755 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml @@ -45,7 +45,7 @@ @helper Render(IPublishedContent item) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/ListAncestorsFromCurrentPage.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/ListAncestorsFromCurrentPage.cshtml index e067ef6376..070f67ff23 100755 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/ListAncestorsFromCurrentPage.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/ListAncestorsFromCurrentPage.cshtml @@ -18,7 +18,7 @@ @* For each page in the ancestors collection which have been ordered by Level (so we start with the highest top node first) *@ @foreach (var item in selection.OrderBy(x => x.Level)) { -
  • @item.Name »
  • +
  • @item.Name »
  • } @* Display the current page as the last item in the list *@ diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Navigation.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Navigation.cshtml index 363352c148..15427f4b3c 100755 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Navigation.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Navigation.cshtml @@ -16,7 +16,7 @@ @foreach (var item in selection) {
  • - @item.Name + @item.Name
  • } diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/SiteMap.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/SiteMap.cshtml index d6b12bbd78..a4127a9636 100755 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/SiteMap.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/SiteMap.cshtml @@ -33,7 +33,7 @@ @foreach (var item in selection) {
  • - @item.Name + @item.Name @* Run the traverse helper again for any child pages *@ @Traverse(item) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml index 040913cd1d..e95057efe9 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml @@ -48,7 +48,7 @@ redirectUrl = Url.Action("AuthorizeUpgrade", "BackOffice") }); } - @Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection) + @Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection)