Merge branch 'netcore/feature/use-request-cache-instead-of-httpcontext-items' into netcore/feature/move-files-after-umbraco-context-abstractions

This commit is contained in:
Bjarke Berg
2020-02-13 11:40:56 +01:00
52 changed files with 330 additions and 220 deletions

View File

@@ -1,25 +0,0 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.Editors;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models
{
[DataContract(Name = "contentTypeImportModel")]
public class ContentTypeImportModel : INotificationModel, IHaveUploadedFiles
{
[DataMember(Name = "alias")]
public string Alias { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notifications")]
public List<BackOfficeNotification> Notifications { get; } = new List<BackOfficeNotification>();
[DataMember(Name = "tempFileName")]
public string TempFileName { get; set; }
public List<ContentPropertyFile> UploadedFiles => new List<ContentPropertyFile>();
}
}

View File

@@ -1,64 +0,0 @@
using System.Globalization;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Models;
namespace Umbraco.Web.Models
{
internal class ImageProcessorImageUrlGenerator : IImageUrlGenerator
{
public string GetImageUrl(ImageUrlGenerationOptions options)
{
if (options == null) return null;
var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty);
if (options.FocalPoint != null) AppendFocalPoint(imageProcessorUrl, options);
else if (options.Crop != null) AppendCrop(imageProcessorUrl, options);
else if (options.DefaultCrop) imageProcessorUrl.Append("?anchor=center&mode=crop");
else
{
imageProcessorUrl.Append("?mode=").Append((options.ImageCropMode ?? "crop").ToLower());
if (options.ImageCropAnchor != null) imageProcessorUrl.Append("&anchor=").Append(options.ImageCropAnchor.ToLower());
}
var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&format=");
//Only put quality here, if we don't have a format specified.
//Otherwise we need to put quality at the end to avoid it being overridden by the format.
if (options.Quality != null && hasFormat == false) imageProcessorUrl.Append("&quality=").Append(options.Quality);
if (options.HeightRatio != null) imageProcessorUrl.Append("&heightratio=").Append(options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture));
if (options.WidthRatio != null) imageProcessorUrl.Append("&widthratio=").Append(options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture));
if (options.Width != null) imageProcessorUrl.Append("&width=").Append(options.Width);
if (options.Height != null) imageProcessorUrl.Append("&height=").Append(options.Height);
if (options.UpScale == false) imageProcessorUrl.Append("&upscale=false");
if (options.AnimationProcessMode != null) imageProcessorUrl.Append("&animationprocessmode=").Append(options.AnimationProcessMode);
if (options.FurtherOptions != null) imageProcessorUrl.Append(options.FurtherOptions);
//If furtherOptions contains a format, we need to put the quality after the format.
if (options.Quality != null && hasFormat) imageProcessorUrl.Append("&quality=").Append(options.Quality);
if (options.CacheBusterValue != null) imageProcessorUrl.Append("&rnd=").Append(options.CacheBusterValue);
return imageProcessorUrl.ToString();
}
private void AppendFocalPoint(StringBuilder imageProcessorUrl, ImageUrlGenerationOptions options)
{
imageProcessorUrl.Append("?center=");
imageProcessorUrl.Append(options.FocalPoint.Top.ToString(CultureInfo.InvariantCulture)).Append(",");
imageProcessorUrl.Append(options.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
imageProcessorUrl.Append("&mode=crop");
}
private void AppendCrop(StringBuilder imageProcessorUrl, ImageUrlGenerationOptions options)
{
imageProcessorUrl.Append("?crop=");
imageProcessorUrl.Append(options.Crop.X1.ToString(CultureInfo.InvariantCulture)).Append(",");
imageProcessorUrl.Append(options.Crop.Y1.ToString(CultureInfo.InvariantCulture)).Append(",");
imageProcessorUrl.Append(options.Crop.X2.ToString(CultureInfo.InvariantCulture)).Append(",");
imageProcessorUrl.Append(options.Crop.Y2.ToString(CultureInfo.InvariantCulture));
imageProcessorUrl.Append("&cropmode=percentage");
}
}
}

View File

@@ -1,97 +0,0 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.Editors;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models
{
/// <summary>
/// A model that represents uploading a local package
/// </summary>
[DataContract(Name = "localPackageInstallModel")]
public class LocalPackageInstallModel : PackageInstallModel, IHaveUploadedFiles, INotificationModel
{
public List<ContentPropertyFile> UploadedFiles { get; } = new List<ContentPropertyFile>();
[DataMember(Name = "notifications")]
public List<BackOfficeNotification> Notifications { get; } = new List<BackOfficeNotification>();
/// <summary>
/// A flag to determine if this package is compatible to be installed
/// </summary>
[DataMember(Name = "isCompatible")]
public bool IsCompatible { get; set; }
/// <summary>
/// The minimum umbraco version that this package is pinned to
/// </summary>
[DataMember(Name = "umbracoVersion")]
public string UmbracoVersion { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "version")]
public string Version { get; set; }
/// <summary>
/// If this is not null then it means the package is being from this version
/// </summary>
[DataMember(Name = "originalVersion")]
public string OriginalVersion { get; set; }
[DataMember(Name = "containsUnsecureFiles")]
public bool ContainsUnsecureFiles { get; set; }
[DataMember(Name = "containsTemplateConflicts")]
public bool ContainsTemplateConflicts => ConflictingTemplateAliases != null && ConflictingTemplateAliases.Count > 0;
[DataMember(Name = "containsStyleSheetConflicts")]
public bool ContainsStyleSheetConflicts => ConflictingStyleSheetNames != null && ConflictingStyleSheetNames.Count > 0;
[DataMember(Name = "containsMacroConflict")]
public bool ContainsMacroConflict => ConflictingMacroAliases != null && ConflictingMacroAliases.Count > 0;
/// <summary>
/// Key value of name + alias
/// </summary>
[DataMember(Name = "conflictingTemplateAliases")]
public IDictionary<string, string> ConflictingTemplateAliases { get; set; }
/// <summary>
/// Key value of name + alias
/// </summary>
[DataMember(Name = "conflictingStyleSheetNames")]
public IDictionary<string, string> ConflictingStyleSheetNames { get; set; }
/// <summary>
/// Key value of name + alias
/// </summary>
[DataMember(Name = "conflictingMacroAliases")]
public IDictionary<string, string> ConflictingMacroAliases { get; set; }
[DataMember(Name = "readme")]
public string Readme { get; set; }
[DataMember(Name = "licenseUrl")]
public string LicenseUrl { get; set; }
[DataMember(Name = "license")]
public string License { get; set; }
[DataMember(Name = "authorUrl")]
public string AuthorUrl { get; set; }
[DataMember(Name = "author")]
public string Author { get; set; }
[DataMember(Name = "contributors")]
public IList<string> Contributors { get; set; }
[DataMember(Name = "iconUrl")]
public string IconUrl { get; set; }
}
}

View File

@@ -1,28 +0,0 @@
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models.PublishedContent
{
/// <summary>
/// Implements <see cref="IVariationContextAccessor"/> on top of <see cref="IHttpContextAccessor"/>.
/// </summary>
public class HttpContextVariationContextAccessor : IVariationContextAccessor
{
public const string ContextKey = "Umbraco.Web.Models.PublishedContent.DefaultVariationContextAccessor";
public readonly IHttpContextAccessor HttpContextAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="HttpContextVariationContextAccessor"/> class.
/// </summary>
public HttpContextVariationContextAccessor(IHttpContextAccessor httpContextAccessor)
{
HttpContextAccessor = httpContextAccessor;
}
/// <inheritdoc />
public VariationContext VariationContext
{
get => (VariationContext) HttpContextAccessor.HttpContext?.Items[ContextKey];
set => HttpContextAccessor.HttpContext.Items[ContextKey] = value;
}
}
}

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models.PublishedContent
{
@@ -7,8 +8,8 @@ namespace Umbraco.Web.Models.PublishedContent
/// </summary>
internal class HybridVariationContextAccessor : HybridAccessorBase<VariationContext>, IVariationContextAccessor
{
public HybridVariationContextAccessor(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
public HybridVariationContextAccessor(IRequestCache requestCache)
: base(requestCache)
{ }
/// <inheritdoc />
@@ -23,4 +24,4 @@ namespace Umbraco.Web.Models.PublishedContent
set => Value = value;
}
}
}
}

View File

@@ -1,298 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.PublishedContent
{
/// <summary>
/// Provides a default implementation for <see cref="IPublishedValueFallback"/>.
/// </summary>
public class PublishedValueFallback : IPublishedValueFallback
{
private readonly ILocalizationService _localizationService;
private readonly IVariationContextAccessor _variationContextAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedValueFallback"/> class.
/// </summary>
public PublishedValueFallback(ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor)
{
_localizationService = serviceContext.LocalizationService;
_variationContextAccessor = variationContextAccessor;
}
/// <inheritdoc />
public bool TryGetValue(IPublishedProperty property, string culture, string segment, Fallback fallback, object defaultValue, out object value)
{
return TryGetValue<object>(property, culture, segment, fallback, defaultValue, out value);
}
/// <inheritdoc />
public bool TryGetValue<T>(IPublishedProperty property, string culture, string segment, Fallback fallback, T defaultValue, out T value)
{
_variationContextAccessor.ContextualizeVariation(property.PropertyType.Variations, ref culture, ref segment);
foreach (var f in fallback)
{
switch (f)
{
case Fallback.None:
continue;
case Fallback.DefaultValue:
value = defaultValue;
return true;
case Fallback.Language:
if (TryGetValueWithLanguageFallback(property, culture, segment, out value))
return true;
break;
default:
throw NotSupportedFallbackMethod(f, "property");
}
}
value = default;
return false;
}
/// <inheritdoc />
public bool TryGetValue(IPublishedElement content, string alias, string culture, string segment, Fallback fallback, object defaultValue, out object value)
{
return TryGetValue<object>(content, alias, culture, segment, fallback, defaultValue, out value);
}
/// <inheritdoc />
public bool TryGetValue<T>(IPublishedElement content, string alias, string culture, string segment, Fallback fallback, T defaultValue, out T value)
{
var propertyType = content.ContentType.GetPropertyType(alias);
if (propertyType == null)
{
value = default;
return false;
}
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
foreach (var f in fallback)
{
switch (f)
{
case Fallback.None:
continue;
case Fallback.DefaultValue:
value = defaultValue;
return true;
case Fallback.Language:
if (TryGetValueWithLanguageFallback(content, alias, culture, segment, out value))
return true;
break;
default:
throw NotSupportedFallbackMethod(f, "element");
}
}
value = default;
return false;
}
/// <inheritdoc />
public bool TryGetValue(IPublishedContent content, string alias, string culture, string segment, Fallback fallback, object defaultValue, out object value, out IPublishedProperty noValueProperty)
{
return TryGetValue<object>(content, alias, culture, segment, fallback, defaultValue, out value, out noValueProperty);
}
/// <inheritdoc />
public virtual bool TryGetValue<T>(IPublishedContent content, string alias, string culture, string segment, Fallback fallback, T defaultValue, out T value, out IPublishedProperty noValueProperty)
{
noValueProperty = default;
var propertyType = content.ContentType.GetPropertyType(alias);
if (propertyType != null)
{
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
noValueProperty = content.GetProperty(alias);
}
// note: we don't support "recurse & language" which would walk up the tree,
// looking at languages at each level - should someone need it... they'll have
// to implement it.
foreach (var f in fallback)
{
switch (f)
{
case Fallback.None:
continue;
case Fallback.DefaultValue:
value = defaultValue;
return true;
case Fallback.Language:
if (propertyType == null)
continue;
if (TryGetValueWithLanguageFallback(content, alias, culture, segment, out value))
return true;
break;
case Fallback.Ancestors:
if (TryGetValueWithAncestorsFallback(content, alias, culture, segment, out value, ref noValueProperty))
return true;
break;
default:
throw NotSupportedFallbackMethod(f, "content");
}
}
value = default;
return false;
}
private NotSupportedException NotSupportedFallbackMethod(int fallback, string level)
{
return new NotSupportedException($"Fallback {GetType().Name} does not support fallback code '{fallback}' at {level} level.");
}
// tries to get a value, recursing the tree
// because we recurse, content may not even have the a property with the specified alias (but only some ancestor)
// in case no value was found, noValueProperty contains the first property that was found (which does not have a value)
private bool TryGetValueWithAncestorsFallback<T>(IPublishedContent content, string alias, string culture, string segment, out T value, ref IPublishedProperty noValueProperty)
{
IPublishedProperty property; // if we are here, content's property has no value
do
{
content = content.Parent;
var propertyType = content?.ContentType.GetPropertyType(alias);
if (propertyType != null)
{
culture = null;
segment = null;
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
}
property = content?.GetProperty(alias);
if (property != null && noValueProperty == null)
{
noValueProperty = property;
}
}
while (content != null && (property == null || property.HasValue(culture, segment) == false));
// if we found a content with the property having a value, return that property value
if (property != null && property.HasValue(culture, segment))
{
value = property.Value<T>(culture, segment);
return true;
}
value = default;
return false;
}
// tries to get a value, falling back onto other languages
private bool TryGetValueWithLanguageFallback<T>(IPublishedProperty property, string culture, string segment, out T value)
{
value = default;
if (culture.IsNullOrWhiteSpace()) return false;
var visited = new HashSet<int>();
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language == null) return false;
while (true)
{
if (language.FallbackLanguageId == null) return false;
var language2Id = language.FallbackLanguageId.Value;
if (visited.Contains(language2Id)) return false;
visited.Add(language2Id);
var language2 = _localizationService.GetLanguageById(language2Id);
if (language2 == null) return false;
var culture2 = language2.IsoCode;
if (property.HasValue(culture2, segment))
{
value = property.Value<T>(culture2, segment);
return true;
}
language = language2;
}
}
// tries to get a value, falling back onto other languages
private bool TryGetValueWithLanguageFallback<T>(IPublishedElement content, string alias, string culture, string segment, out T value)
{
value = default;
if (culture.IsNullOrWhiteSpace()) return false;
var visited = new HashSet<int>();
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language == null) return false;
while (true)
{
if (language.FallbackLanguageId == null) return false;
var language2Id = language.FallbackLanguageId.Value;
if (visited.Contains(language2Id)) return false;
visited.Add(language2Id);
var language2 = _localizationService.GetLanguageById(language2Id);
if (language2 == null) return false;
var culture2 = language2.IsoCode;
if (content.HasValue(alias, culture2, segment))
{
value = content.Value<T>(alias, culture2, segment);
return true;
}
language = language2;
}
}
// tries to get a value, falling back onto other languages
private bool TryGetValueWithLanguageFallback<T>(IPublishedContent content, string alias, string culture, string segment, out T value)
{
value = default;
if (culture.IsNullOrWhiteSpace()) return false;
var visited = new HashSet<int>();
// TODO: _localizationService.GetXxx() is expensive, it deep clones objects
// we want _localizationService.GetReadOnlyXxx() returning IReadOnlyLanguage which cannot be saved back = no need to clone
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language == null) return false;
while (true)
{
if (language.FallbackLanguageId == null) return false;
var language2Id = language.FallbackLanguageId.Value;
if (visited.Contains(language2Id)) return false;
visited.Add(language2Id);
var language2 = _localizationService.GetLanguageById(language2Id);
if (language2 == null) return false;
var culture2 = language2.IsoCode;
if (content.HasValue(alias, culture2, segment))
{
value = content.Value<T>(alias, culture2, segment);
return true;
}
language = language2;
}
}
}
}

View File

@@ -1,27 +0,0 @@
using Umbraco.Core.Services;
using Umbraco.Web.Actions;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// Represents the refresh node menu item
/// </summary>
public sealed class CreateChildEntity : ActionMenuItem
{
public override string AngularServiceName => "umbracoMenuActions";
public CreateChildEntity(string name, bool separatorBefore = false)
: base(ActionNew.ActionAlias, name)
{
Icon = "add"; Name = name;
SeparatorBefore = separatorBefore;
}
public CreateChildEntity(ILocalizedTextService textService, bool separatorBefore = false)
: base(ActionNew.ActionAlias, textService)
{
Icon = "add";
SeparatorBefore = separatorBefore;
}
}
}

View File

@@ -1,17 +0,0 @@
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// Represents the export member menu item
/// </summary>
public sealed class ExportMember : ActionMenuItem
{
public override string AngularServiceName => "umbracoMenuActions";
public ExportMember(ILocalizedTextService textService) : base("export", textService)
{
Icon = "download-alt";
}
}
}