From c58c31c6bd1d6df8b65a46506973cdd7a80229d7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 13 Nov 2019 16:33:40 +1100 Subject: [PATCH 1/3] Split Udi into UdiParser & UdiParserServiceConnectors, remove GuidUdi and StringUdi Parse methods (makes no sense), adds generic parse method to UdiParser, simplifies tests, removes Current usage --- src/Umbraco.Core/GuidUdi.cs | 23 -- .../ConvertRelatedLinksToMultiUrlPicker.cs | 2 +- .../KnownTypeUdiJsonConverter.cs | 2 +- .../Serialization/UdiJsonConverter.cs | 2 +- src/Umbraco.Core/StringUdi.cs | 23 -- src/Umbraco.Core/Udi.cs | 232 +----------------- src/Umbraco.Core/UdiParser.cs | 179 ++++++++++++++ .../UdiParserServiceConnectors.cs | 82 +++++++ src/Umbraco.Core/UdiTypeConverter.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 3 + src/Umbraco.Core/UnknownTypeUdi.cs | 16 ++ src/Umbraco.Tests/CoreThings/UdiTests.cs | 63 ++--- .../Web/TemplateUtilitiesTests.cs | 52 +--- src/Umbraco.Tests/Web/UmbracoHelperTests.cs | 8 +- src/Umbraco.Web/Editors/EntityController.cs | 2 +- src/Umbraco.Web/Editors/MediaController.cs | 3 +- .../RedirectUrlManagementController.cs | 2 +- .../MediaPickerValueConverter.cs | 2 +- .../MultiNodeTreePickerValueConverter.cs | 2 +- src/Umbraco.Web/Search/UmbracoTreeSearcher.cs | 2 +- .../Templates/TemplateUtilities.cs | 4 +- .../Trees/ContentTreeControllerBase.cs | 4 +- src/Umbraco.Web/UmbracoHelper.cs | 2 +- ...EnsureUserPermissionForContentAttribute.cs | 2 +- 24 files changed, 338 insertions(+), 376 deletions(-) create mode 100644 src/Umbraco.Core/UdiParser.cs create mode 100644 src/Umbraco.Core/UdiParserServiceConnectors.cs create mode 100644 src/Umbraco.Core/UnknownTypeUdi.cs diff --git a/src/Umbraco.Core/GuidUdi.cs b/src/Umbraco.Core/GuidUdi.cs index d78a33a435..8acac61b32 100644 --- a/src/Umbraco.Core/GuidUdi.cs +++ b/src/Umbraco.Core/GuidUdi.cs @@ -39,29 +39,6 @@ namespace Umbraco.Core Guid = guid; } - /// - /// Converts the string representation of an entity identifier into the equivalent GuidUdi instance. - /// - /// The string to convert. - /// A GuidUdi instance that contains the value that was parsed. - public new static GuidUdi Parse(string s) - { - var udi = Udi.Parse(s); - if (udi is GuidUdi == false) - throw new FormatException("String \"" + s + "\" is not a guid entity id."); - - return (GuidUdi) udi; - } - - public static bool TryParse(string s, out GuidUdi udi) - { - Udi tmp; - udi = null; - if (TryParse(s, out tmp) == false) return false; - udi = tmp as GuidUdi; - return udi != null; - } - public override bool Equals(object obj) { var other = obj as GuidUdi; diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs index 1956876402..343557e3f5 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs @@ -64,7 +64,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 GuidUdi udi = null; if (relatedLink.IsInternal) { - var linkIsUdi = GuidUdi.TryParse(relatedLink.Link, out udi); + var linkIsUdi = UdiParser.TryParse(relatedLink.Link, out udi); if (linkIsUdi == false) { // oh no.. probably an integer, yikes! diff --git a/src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs b/src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs index e6473e7f8e..79ff90c734 100644 --- a/src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs +++ b/src/Umbraco.Core/Serialization/KnownTypeUdiJsonConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Serialization { var jo = JToken.ReadFrom(reader); var val = jo.ToObject(); - return val == null ? null : Udi.Parse(val, true); + return val == null ? null : UdiParser.Parse(val, true); } } } diff --git a/src/Umbraco.Core/Serialization/UdiJsonConverter.cs b/src/Umbraco.Core/Serialization/UdiJsonConverter.cs index 134faf3d1d..eac5dd8c26 100644 --- a/src/Umbraco.Core/Serialization/UdiJsonConverter.cs +++ b/src/Umbraco.Core/Serialization/UdiJsonConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Serialization { var jo = JToken.ReadFrom(reader); var val = jo.ToObject(); - return val == null ? null : Udi.Parse(val); + return val == null ? null : UdiParser.Parse(val); } } } diff --git a/src/Umbraco.Core/StringUdi.cs b/src/Umbraco.Core/StringUdi.cs index 7b32399599..7e067ad6f9 100644 --- a/src/Umbraco.Core/StringUdi.cs +++ b/src/Umbraco.Core/StringUdi.cs @@ -49,29 +49,6 @@ namespace Umbraco.Core return string.Join("/", s.Split('/').Select(Uri.EscapeDataString)); } - /// - /// Converts the string representation of an entity identifier into the equivalent StringUdi instance. - /// - /// The string to convert. - /// A StringUdi instance that contains the value that was parsed. - public new static StringUdi Parse(string s) - { - var udi = Udi.Parse(s); - if (udi is StringUdi == false) - throw new FormatException("String \"" + s + "\" is not a string entity id."); - - return (StringUdi) udi; - } - - public static bool TryParse(string s, out StringUdi udi) - { - udi = null; - Udi tmp; - if (TryParse(s, out tmp) == false || tmp is StringUdi == false) return false; - udi = (StringUdi) tmp; - return true; - } - /// public override bool IsRoot { diff --git a/src/Umbraco.Core/Udi.cs b/src/Umbraco.Core/Udi.cs index 444cbda6f5..0da549f498 100644 --- a/src/Umbraco.Core/Udi.cs +++ b/src/Umbraco.Core/Udi.cs @@ -1,30 +1,17 @@ using System; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using Umbraco.Core.Deploy; -using Umbraco.Core.Composing; namespace Umbraco.Core { + /// /// Represents an entity identifier. /// /// An Udi can be fully qualified or "closed" eg umb://document/{guid} or "open" eg umb://document. [TypeConverter(typeof(UdiTypeConverter))] public abstract class Udi : IComparable - { - // notes - see U4-10409 - // if this class is used during application pre-start it cannot scans the assemblies, - // this is addressed by lazily-scanning, with the following caveats: - // - parsing a root udi still requires a scan and therefore still breaks - // - parsing an invalid udi ("umb://should-be-guid/") corrupts KnowUdiTypes - - private static volatile bool _scanned; - private static readonly object ScanLocker = new object(); - private static ConcurrentDictionary _udiTypes; - private static readonly ConcurrentDictionary RootUdis = new ConcurrentDictionary(); + { internal readonly Uri UriValue; // internal for UdiRange /// @@ -48,19 +35,7 @@ namespace Umbraco.Core UriValue = uriValue; } - static Udi() - { - // initialize with known (built-in) Udi types - // we will add scanned types later on - _udiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); - } - - // for tests, totally unsafe - internal static void ResetUdiTypes() - { - _udiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); - _scanned = false; - } + /// /// Gets the entity type part of the identifier. @@ -79,181 +54,7 @@ namespace Umbraco.Core return UriValue.AbsoluteUri; } - /// - /// Converts the string representation of an entity identifier into the equivalent Udi instance. - /// - /// The string to convert. - /// An Udi instance that contains the value that was parsed. - public static Udi Parse(string s) - { - Udi udi; - ParseInternal(s, false, false, out udi); - return udi; - } - - /// - /// Converts the string representation of an entity identifier into the equivalent Udi instance. - /// - /// The string to convert. - /// A value indicating whether to only deal with known types. - /// An Udi instance that contains the value that was parsed. - /// - /// If is true, and the string could not be parsed because - /// the entity type was not known, the method succeeds but sets udito an - /// value. - /// If is true, assemblies are not scanned for types, - /// and therefore only builtin types may be known. Unless scanning already took place. - /// - public static Udi Parse(string s, bool knownTypes) - { - Udi udi; - ParseInternal(s, false, knownTypes, out udi); - return udi; - } - - /// - /// Converts the string representation of an entity identifier into the equivalent Udi instance. - /// - /// The string to convert. - /// An Udi instance that contains the value that was parsed. - /// A boolean value indicating whether the string could be parsed. - public static bool TryParse(string s, out Udi udi) - { - return ParseInternal(s, true, false, out udi); - } - - /// - /// Converts the string representation of an entity identifier into the equivalent Udi instance. - /// - /// The string to convert. - /// A value indicating whether to only deal with known types. - /// An Udi instance that contains the value that was parsed. - /// A boolean value indicating whether the string could be parsed. - /// - /// If is true, and the string could not be parsed because - /// the entity type was not known, the method returns false but still sets udi - /// to an value. - /// If is true, assemblies are not scanned for types, - /// and therefore only builtin types may be known. Unless scanning already took place. - /// - public static bool TryParse(string s, bool knownTypes, out Udi udi) - { - return ParseInternal(s, true, knownTypes, out udi); - } - - private static bool ParseInternal(string s, bool tryParse, bool knownTypes, out Udi udi) - { - if (knownTypes == false) - EnsureScanForUdiTypes(); - - udi = null; - Uri uri; - - if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false - || Uri.TryCreate(s, UriKind.Absolute, out uri) == false) - { - if (tryParse) return false; - throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); - } - - var entityType = uri.Host; - UdiType udiType; - if (_udiTypes.TryGetValue(entityType, out udiType) == false) - { - if (knownTypes) - { - // not knowing the type is not an error - // just return the unknown type udi - udi = UnknownTypeUdi.Instance; - return false; - } - if (tryParse) return false; - throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType)); - } - - var path = uri.AbsolutePath.TrimStart('/'); - - if (udiType == UdiType.GuidUdi) - { - if (path == string.Empty) - { - udi = GetRootUdi(uri.Host); - return true; - } - Guid guid; - if (Guid.TryParse(path, out guid) == false) - { - if (tryParse) return false; - throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); - } - udi = new GuidUdi(uri.Host, guid); - return true; - } - - if (udiType == UdiType.StringUdi) - { - udi = path == string.Empty ? GetRootUdi(uri.Host) : new StringUdi(uri.Host, Uri.UnescapeDataString(path)); - return true; - } - - if (tryParse) return false; - throw new InvalidOperationException(string.Format("Invalid udi type \"{0}\".", udiType)); - } - - private static Udi GetRootUdi(string entityType) - { - EnsureScanForUdiTypes(); - - return RootUdis.GetOrAdd(entityType, x => - { - UdiType udiType; - if (_udiTypes.TryGetValue(x, out udiType) == false) - throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType)); - return udiType == UdiType.StringUdi - ? (Udi)new StringUdi(entityType, string.Empty) - : new GuidUdi(entityType, Guid.Empty); - }); - } - - /// - /// When required scan assemblies for known UDI types based on instances - /// - /// - /// This is only required when needing to resolve root udis - /// - private static void EnsureScanForUdiTypes() - { - if (_scanned) return; - - lock (ScanLocker) - { - // Scan for unknown UDI types - // there is no way we can get the "registered" service connectors, as registration - // happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we - // just pick every service connectors - just making sure that not two of them - // would register the same entity type, with different udi types (would not make - // much sense anyways). - var connectors = Current.TypeLoader.GetTypes(); - var result = new Dictionary(); - foreach (var connector in connectors) - { - var attrs = connector.GetCustomAttributes(false); - foreach (var attr in attrs) - { - UdiType udiType; - if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType) - throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType)); - result[attr.EntityType] = attr.UdiType; - } - } - - // merge these into the known list - foreach (var item in result) - _udiTypes.TryAdd(item.Key, item.Value); - - _scanned = true; - } - } + /// /// Creates a root Udi for an entity type. @@ -262,7 +63,7 @@ namespace Umbraco.Core /// The root Udi for the entity type. public static Udi Create(string entityType) { - return GetRootUdi(entityType); + return UdiParser.GetRootUdi(entityType); } /// @@ -273,8 +74,7 @@ namespace Umbraco.Core /// The string Udi for the entity type and identifier. public static Udi Create(string entityType, string id) { - UdiType udiType; - if (_udiTypes.TryGetValue(entityType, out udiType) == false) + if (UdiParser.UdiTypes.TryGetValue(entityType, out var udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType"); if (string.IsNullOrWhiteSpace(id)) @@ -293,8 +93,7 @@ namespace Umbraco.Core /// The Guid Udi for the entity type and identifier. public static Udi Create(string entityType, Guid id) { - UdiType udiType; - if (_udiTypes.TryGetValue(entityType, out udiType) == false) + if (UdiParser.UdiTypes.TryGetValue(entityType, out var udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType"); if (udiType != UdiType.GuidUdi) @@ -310,8 +109,7 @@ namespace Umbraco.Core // if it's a know type go fast and use ctors // else fallback to parsing the string (and guess the type) - UdiType udiType; - if (_udiTypes.TryGetValue(uri.Host, out udiType) == false) + if (UdiParser.UdiTypes.TryGetValue(uri.Host, out var udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", uri.Host), "uri"); if (udiType == UdiType.GuidUdi) @@ -368,18 +166,6 @@ namespace Umbraco.Core return (udi1 == udi2) == false; } - private class UnknownTypeUdi : Udi - { - private UnknownTypeUdi() - : base("unknown", "umb://unknown/") - { } - - public static readonly UnknownTypeUdi Instance = new UnknownTypeUdi(); - - public override bool IsRoot - { - get { return false; } - } - } + } } diff --git a/src/Umbraco.Core/UdiParser.cs b/src/Umbraco.Core/UdiParser.cs new file mode 100644 index 0000000000..20002a79e0 --- /dev/null +++ b/src/Umbraco.Core/UdiParser.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Concurrent; + +namespace Umbraco.Core +{ + public sealed class UdiParser + { + private static readonly ConcurrentDictionary RootUdis = new ConcurrentDictionary(); + internal static ConcurrentDictionary UdiTypes { get; private set; } + + static UdiParser() + { + // initialize with known (built-in) Udi types + // we will add scanned types later on + UdiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); + } + + // for tests, totally unsafe + internal static void ResetUdiTypes() + { + UdiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); + } + + /// + /// Converts the string representation of an entity identifier into the equivalent Udi instance. + /// + /// The string to convert. + /// An Udi instance that contains the value that was parsed. + public static Udi Parse(string s) + { + ParseInternal(s, false, false, out var udi); + return udi; + } + + /// + /// Converts the string representation of an entity identifier into the equivalent Udi instance. + /// + /// The string to convert. + /// A value indicating whether to only deal with known types. + /// An Udi instance that contains the value that was parsed. + /// + /// If is true, and the string could not be parsed because + /// the entity type was not known, the method succeeds but sets udito an + /// value. + /// If is true, assemblies are not scanned for types, + /// and therefore only builtin types may be known. Unless scanning already took place. + /// + public static Udi Parse(string s, bool knownTypes) + { + ParseInternal(s, false, knownTypes, out var udi); + return udi; + } + + /// + /// Converts the string representation of an entity identifier into the equivalent Udi instance. + /// + /// The string to convert. + /// An Udi instance that contains the value that was parsed. + /// A boolean value indicating whether the string could be parsed. + public static bool TryParse(string s, out Udi udi) + { + return ParseInternal(s, true, false, out udi); + } + + /// + /// Converts the string representation of an entity identifier into the equivalent Udi instance. + /// + /// The string to convert. + /// An Udi instance that contains the value that was parsed. + /// A boolean value indicating whether the string could be parsed. + public static bool TryParse(string s, out T udi) + where T : Udi + { + var result = ParseInternal(s, true, false, out var parsed); + if (result && parsed is T) + { + udi = (T)parsed; + return true; + } + + udi = null; + return false; + } + + /// + /// Converts the string representation of an entity identifier into the equivalent Udi instance. + /// + /// The string to convert. + /// A value indicating whether to only deal with known types. + /// An Udi instance that contains the value that was parsed. + /// A boolean value indicating whether the string could be parsed. + /// + /// If is true, and the string could not be parsed because + /// the entity type was not known, the method returns false but still sets udi + /// to an value. + /// If is true, assemblies are not scanned for types, + /// and therefore only builtin types may be known. Unless scanning already took place. + /// + public static bool TryParse(string s, bool knownTypes, out Udi udi) + { + return ParseInternal(s, true, knownTypes, out udi); + } + + private static bool ParseInternal(string s, bool tryParse, bool knownTypes, out Udi udi) + { + udi = null; + Uri uri; + + if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false + || Uri.TryCreate(s, UriKind.Absolute, out uri) == false) + { + if (tryParse) return false; + throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); + } + + var entityType = uri.Host; + if (UdiTypes.TryGetValue(entityType, out var udiType) == false) + { + if (knownTypes) + { + // not knowing the type is not an error + // just return the unknown type udi + udi = UnknownTypeUdi.Instance; + return false; + } + if (tryParse) return false; + throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType)); + } + + var path = uri.AbsolutePath.TrimStart('/'); + + if (udiType == UdiType.GuidUdi) + { + if (path == string.Empty) + { + udi = GetRootUdi(uri.Host); + return true; + } + if (Guid.TryParse(path, out var guid) == false) + { + if (tryParse) return false; + throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s)); + } + udi = new GuidUdi(uri.Host, guid); + return true; + } + + if (udiType == UdiType.StringUdi) + { + udi = path == string.Empty ? GetRootUdi(uri.Host) : new StringUdi(uri.Host, Uri.UnescapeDataString(path)); + return true; + } + + if (tryParse) return false; + throw new InvalidOperationException(string.Format("Invalid udi type \"{0}\".", udiType)); + } + + internal static Udi GetRootUdi(string entityType) + { + return RootUdis.GetOrAdd(entityType, x => + { + if (UdiTypes.TryGetValue(x, out var udiType) == false) + throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType)); + return udiType == UdiType.StringUdi + ? (Udi)new StringUdi(entityType, string.Empty) + : new GuidUdi(entityType, Guid.Empty); + }); + } + + + + /// + /// Registers a custom entity type. + /// + /// + /// + public static void RegisterUdiType(string entityType, UdiType udiType) => UdiTypes.TryAdd(entityType, udiType); + } +} diff --git a/src/Umbraco.Core/UdiParserServiceConnectors.cs b/src/Umbraco.Core/UdiParserServiceConnectors.cs new file mode 100644 index 0000000000..6137b0bde9 --- /dev/null +++ b/src/Umbraco.Core/UdiParserServiceConnectors.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Deploy; +using Umbraco.Core.Composing; + +namespace Umbraco.Core +{ + public static class UdiParserServiceConnectors + { + // notes - see U4-10409 + // if this class is used during application pre-start it cannot scans the assemblies, + // this is addressed by lazily-scanning, with the following caveats: + // - parsing a root udi still requires a scan and therefore still breaks + // - parsing an invalid udi ("umb://should-be-guid/") corrupts KnowUdiTypes + + private static volatile bool _scanned; + private static readonly object ScanLocker = new object(); + + /// + /// Scan for deploy in assemblies for known UDI types. + /// + /// + public static void ScanDeployServiceConnectorsForUdiTypes(TypeLoader typeLoader) + { + if (typeLoader is null) + throw new ArgumentNullException(nameof(typeLoader)); + + if (_scanned) return; + + lock (ScanLocker) + { + // Scan for unknown UDI types + // there is no way we can get the "registered" service connectors, as registration + // happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we + // just pick every service connectors - just making sure that not two of them + // would register the same entity type, with different udi types (would not make + // much sense anyways) + var connectors = typeLoader.GetTypes(); + var result = new Dictionary(); + foreach (var connector in connectors) + { + var attrs = connector.GetCustomAttributes(false); + foreach (var attr in attrs) + { + if (result.TryGetValue(attr.EntityType, out var udiType) && udiType != attr.UdiType) + throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType)); + result[attr.EntityType] = attr.UdiType; + } + } + + // merge these into the known list + foreach (var item in result) + UdiParser.RegisterUdiType(item.Key, item.Value); + + _scanned = true; + } + } + + /// + /// Registers a single to add it's UDI type. + /// + /// + public static void RegisterServiceConnector() + where T: IServiceConnector + { + var result = new Dictionary(); + var connector = typeof(T); + var attrs = connector.GetCustomAttributes(false); + foreach (var attr in attrs) + { + if (result.TryGetValue(attr.EntityType, out var udiType) && udiType != attr.UdiType) + throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType)); + result[attr.EntityType] = attr.UdiType; + } + + // merge these into the known list + foreach (var item in result) + UdiParser.RegisterUdiType(item.Key, item.Value); + } + } +} diff --git a/src/Umbraco.Core/UdiTypeConverter.cs b/src/Umbraco.Core/UdiTypeConverter.cs index e63aa7f786..8da1b7bb5f 100644 --- a/src/Umbraco.Core/UdiTypeConverter.cs +++ b/src/Umbraco.Core/UdiTypeConverter.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core if (value is string) { Udi udi; - if (Udi.TryParse((string)value, out udi)) + if (UdiParser.TryParse((string)value, out udi)) { return udi; } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 5ca4efc67d..0b0992fa98 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1104,8 +1104,11 @@ + + + diff --git a/src/Umbraco.Core/UnknownTypeUdi.cs b/src/Umbraco.Core/UnknownTypeUdi.cs new file mode 100644 index 0000000000..ac42205cbc --- /dev/null +++ b/src/Umbraco.Core/UnknownTypeUdi.cs @@ -0,0 +1,16 @@ +namespace Umbraco.Core +{ + internal class UnknownTypeUdi : Udi + { + private UnknownTypeUdi() + : base("unknown", "umb://unknown/") + { } + + public static readonly UnknownTypeUdi Instance = new UnknownTypeUdi(); + + public override bool IsRoot + { + get { return false; } + } + } +} diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests/CoreThings/UdiTests.cs index dc2265eac2..641587ebe7 100644 --- a/src/Umbraco.Tests/CoreThings/UdiTests.cs +++ b/src/Umbraco.Tests/CoreThings/UdiTests.cs @@ -24,21 +24,7 @@ namespace Umbraco.Tests.CoreThings [SetUp] public void SetUp() { - // FIXME: bad in a unit test - but Udi has a static ctor that wants it?! - var container = new Mock(); - var ioHelper = IOHelper.Default; - var typeFinder = new TypeFinder(Mock.Of()); - container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns( - new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), new ProfilingLogger(Mock.Of(), Mock.Of()))); - Current.Factory = container.Object; - - Udi.ResetUdiTypes(); - } - - [TearDown] - public void TearDown() - { - Current.Reset(); + UdiParser.ResetUdiTypes(); } [Test] @@ -53,7 +39,7 @@ namespace Umbraco.Tests.CoreThings [Test] public void StringUdiParseTest() { - var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id"); + var udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id"); Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.IsInstanceOf(udi); var stringEntityId = udi as StringUdi; @@ -61,7 +47,7 @@ namespace Umbraco.Tests.CoreThings Assert.AreEqual("test-id", stringEntityId.Id); Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString()); - udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/DA845952BE474EE9BD6F6194272AC750"); + udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/DA845952BE474EE9BD6F6194272AC750"); Assert.IsInstanceOf(udi); } @@ -78,7 +64,7 @@ namespace Umbraco.Tests.CoreThings Assert.AreEqual("%2Fthis%20is%20a%20test", Uri.EscapeDataString("/this is a test")); Assert.AreEqual("/this%20is%20a%20test", Uri.EscapeUriString("/this is a test")); - var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test"); + var udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test"); Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.IsInstanceOf(udi); var stringEntityId = udi as StringUdi; @@ -112,7 +98,7 @@ namespace Umbraco.Tests.CoreThings // with the proper fix in StringUdi this should work: var udi1 = new StringUdi("partial-view-macro", "path/to/View[1].cshtml"); Assert.AreEqual("umb://partial-view-macro/path/to/View%5B1%5D.cshtml", udi1.ToString()); - var udi2 = Udi.Parse("umb://partial-view-macro/path/to/View%5B1%5D.cshtml"); + var udi2 = UdiParser.Parse("umb://partial-view-macro/path/to/View%5B1%5D.cshtml"); Assert.AreEqual("path/to/View[1].cshtml", ((StringUdi) udi2).Id); } @@ -131,7 +117,7 @@ namespace Umbraco.Tests.CoreThings { var guid = Guid.NewGuid(); var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"); - var udi = Udi.Parse(s); + var udi = UdiParser.Parse(s); Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.IsInstanceOf(udi); var gudi = udi as GuidUdi; @@ -198,15 +184,15 @@ namespace Umbraco.Tests.CoreThings Assert.IsTrue(guidUdi.IsRoot); Assert.AreEqual("umb://any-guid/00000000000000000000000000000000", guidUdi.ToString()); - var udi = Udi.Parse("umb://any-string/"); + var udi = UdiParser.Parse("umb://any-string/"); Assert.IsTrue(udi.IsRoot); Assert.IsInstanceOf(udi); - udi = Udi.Parse("umb://any-guid/00000000000000000000000000000000"); + udi = UdiParser.Parse("umb://any-guid/00000000000000000000000000000000"); Assert.IsTrue(udi.IsRoot); Assert.IsInstanceOf(udi); - udi = Udi.Parse("umb://any-guid/"); + udi = UdiParser.Parse("umb://any-guid/"); Assert.IsTrue(udi.IsRoot); Assert.IsInstanceOf(udi); } @@ -217,13 +203,13 @@ namespace Umbraco.Tests.CoreThings // can parse open string udi var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString; Udi stringUdi; - Assert.IsTrue(Udi.TryParse(stringUdiString, out stringUdi)); + Assert.IsTrue(UdiParser.TryParse(stringUdiString, out stringUdi)); Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id); // can parse open guid udi var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid; Udi guidUdi; - Assert.IsTrue(Udi.TryParse(guidUdiString, out guidUdi)); + Assert.IsTrue(UdiParser.TryParse(guidUdiString, out guidUdi)); Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid); // can create a range @@ -294,33 +280,34 @@ namespace Umbraco.Tests.CoreThings // cannot parse an unknown type, udi is null // this will scan - Assert.IsFalse(Udi.TryParse("umb://whatever/1234", out udi)); + Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", out udi)); Assert.IsNull(udi); - Udi.ResetUdiTypes(); - + UdiParser.ResetUdiTypes(); + // unless we want to know - Assert.IsFalse(Udi.TryParse("umb://whatever/1234", true, out udi)); + Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", true, out udi)); Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType); - Assert.AreEqual("Umbraco.Core.Udi+UnknownTypeUdi", udi.GetType().FullName); - - Udi.ResetUdiTypes(); + Assert.AreEqual("Umbraco.Core.UnknownTypeUdi", udi.GetType().FullName); + UdiParser.ResetUdiTypes(); + // not known - Assert.IsFalse(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); + Assert.IsFalse(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType); - Assert.AreEqual("Umbraco.Core.Udi+UnknownTypeUdi", udi.GetType().FullName); + Assert.AreEqual("Umbraco.Core.UnknownTypeUdi", udi.GetType().FullName); - // scanned - Assert.IsTrue(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", out udi)); + // scanned + UdiParserServiceConnectors.RegisterServiceConnector(); // this is the equivalent of scanning but we'll just manually register this one + Assert.IsTrue(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", out udi)); Assert.IsInstanceOf(udi); // known - Assert.IsTrue(Udi.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); + Assert.IsTrue(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); Assert.IsInstanceOf(udi); // can get method for Deploy compatibility - var method = typeof(Udi).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(bool) }, null); + var method = typeof(UdiParser).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(bool) }, null); Assert.IsNotNull(method); } diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index e3678a1db5..b13532b824 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -1,14 +1,10 @@ using System; -using System.IO; using System.Linq; using System.Web; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -17,10 +13,7 @@ using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Web.Security; using Umbraco.Web.Templates; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; namespace Umbraco.Tests.Web { @@ -30,37 +23,9 @@ namespace Umbraco.Tests.Web [SetUp] public void SetUp() { - Current.Reset(); - - // FIXME: now UrlProvider depends on EntityService for GetUrl(guid) - this is bad - // should not depend on more than IdkMap maybe - fix this! - var entityService = new Mock(); - entityService.Setup(x => x.GetId(It.IsAny(), It.IsAny())).Returns(Attempt.Fail()); - var serviceContext = ServiceContext.CreatePartial(entityService: entityService.Object); - - // FIXME: bad in a unit test - but Udi has a static ctor that wants it?! - var factory = new Mock(); - var typeFinder = new TypeFinder(Mock.Of()); - var ioHelper = IOHelper.Default; - factory.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns( - new TypeLoader(ioHelper, typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), new ProfilingLogger(Mock.Of(), Mock.Of()))); - factory.Setup(x => x.GetInstance(typeof (ServiceContext))).Returns(serviceContext); - - var settings = SettingsForTests.GetDefaultUmbracoSettings(); - factory.Setup(x => x.GetInstance(typeof(IUmbracoSettingsSection))).Returns(settings); - - Current.Factory = factory.Object; - - Umbraco.Web.Composing.Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - - Udi.ResetUdiTypes(); + UdiParser.ResetUdiTypes(); } - [TearDown] - public void TearDown() - { - Current.Reset(); - } [TestCase("", "")] [TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")] @@ -71,17 +36,7 @@ namespace Umbraco.Tests.Web [TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")] [TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")] public void ParseLocalLinks(string input, string result) - { - var serviceCtxMock = new TestObjects(null).GetServiceContextMock(); - - //setup a mock entity service from the service context to return an integer for a GUID - var entityService = Mock.Get(serviceCtxMock.EntityService); - //entityService.Setup(x => x.GetId(It.IsAny(), It.IsAny())) - // .Returns((Guid id, UmbracoObjectTypes objType) => - // { - // return Attempt.Succeed(1234); - // }); - + { //setup a mock url provider which we'll use for testing var testUrlProvider = new Mock(); testUrlProvider @@ -106,8 +61,9 @@ namespace Umbraco.Tests.Web var mediaCache = Mock.Of(); Mock.Get(mediaCache).Setup(x => x.GetById(It.IsAny())).Returns(media); + var umbracoContextAccessor = new TestUmbracoContextAccessor(); var umbracoContextFactory = new UmbracoContextFactory( - Umbraco.Web.Composing.Current.UmbracoContextAccessor, + umbracoContextAccessor, snapshotService, new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), diff --git a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs index cdf17e12e9..425f24be41 100644 --- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs +++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs @@ -176,7 +176,7 @@ namespace Umbraco.Tests.Web public static void Converting_Boxed_Udi_To_A_Udi_Returns_Original_Udi_Value() { // Arrange - Udi.ResetUdiTypes(); + UdiParser.ResetUdiTypes(); Udi sample = new GuidUdi(Constants.UdiEntityType.AnyGuid, Guid.NewGuid()); // Act @@ -198,7 +198,7 @@ namespace Umbraco.Tests.Web { // Arrange SetUpDependencyContainer(); - Udi.ResetUdiTypes(); + UdiParser.ResetUdiTypes(); Udi sample = new GuidUdi(Constants.UdiEntityType.AnyGuid, Guid.NewGuid()); // Act @@ -220,7 +220,7 @@ namespace Umbraco.Tests.Web { // Arrange SetUpDependencyContainer(); - Udi.ResetUdiTypes(); + UdiParser.ResetUdiTypes(); const string sample = "Hello"; // Act @@ -241,7 +241,7 @@ namespace Umbraco.Tests.Web public static void Converting_Unsupported_Object_To_A_Udi_Returns_False() { // Arrange - Udi.ResetUdiTypes(); + UdiParser.ResetUdiTypes(); var clearlyWillNotConvertToGuid = new StringBuilder(0); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index aa8f735cf2..2381867616 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -509,7 +509,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - if (Udi.TryParse(id, out _)) + if (UdiParser.TryParse(id, out _)) { //Not supported currently throw new HttpResponseException(HttpStatusCode.NotFound); diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 2cab9f4ebc..315abaa8ce 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -793,10 +793,9 @@ namespace Umbraco.Web.Editors private int GetParentIdAsInt(string parentId, bool validatePermissions) { int intParentId; - GuidUdi parentUdi; // test for udi - if (GuidUdi.TryParse(parentId, out parentUdi)) + if (UdiParser.TryParse(parentId, out GuidUdi parentUdi)) { parentId = parentUdi.Guid.ToString(); } diff --git a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs index 4a3f6b43c3..9252899027 100644 --- a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs @@ -67,7 +67,7 @@ namespace Umbraco.Web.Editors public RedirectUrlSearchResult RedirectUrlsForContentItem(string contentUdi) { var redirectsResult = new RedirectUrlSearchResult(); - if (GuidUdi.TryParse(contentUdi, out var guidIdi)) + if (UdiParser.TryParse(contentUdi, out GuidUdi guidIdi)) { var redirectUrlService = Services.RedirectUrlService; var redirects = redirectUrlService.GetContentRedirectUrls(guidIdi.Guid); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index a56630d7c5..cf0e872c1a 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -58,7 +58,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters var nodeIds = source.ToString() .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) - .Select(Udi.Parse) + .Select(UdiParser.Parse) .ToArray(); return nodeIds; } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs index 47f8797295..46ebbd0abb 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs @@ -55,7 +55,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var nodeIds = source.ToString() .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) - .Select(Udi.Parse) + .Select(UdiParser.Parse) .ToArray(); return nodeIds; } diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs index b351cca972..c1844655a9 100644 --- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs @@ -326,7 +326,7 @@ namespace Umbraco.Web.Search if (sb == null) throw new ArgumentNullException(nameof(sb)); if (entityService == null) throw new ArgumentNullException(nameof(entityService)); - Udi.TryParse(searchFrom, true, out var udi); + UdiParser.TryParse(searchFrom, true, out var udi); searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString(); var entityPath = int.TryParse(searchFrom, out var searchFromId) && searchFromId > 0 diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index 0f291a3c35..b98fedccbd 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web.Templates var id = tag.Groups[1].Value; //.Remove(tag.Groups[1].Value.Length - 1, 1); //The id could be an int or a UDI - if (Udi.TryParse(id, out var udi)) + if (UdiParser.TryParse(id, out var udi)) { var guidUdi = udi as GuidUdi; if (guidUdi != null) @@ -166,7 +166,7 @@ namespace Umbraco.Web.Templates // - 4 = the data-udi attribute value // - 5 = anything after group 4 until the image tag is closed var udi = match.Groups[4].Value; - if(udi.IsNullOrWhiteSpace() || GuidUdi.TryParse(udi, out var guidUdi) == false) + if(udi.IsNullOrWhiteSpace() || UdiParser.TryParse(udi, out GuidUdi guidUdi) == false) { return match.Value; } diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 4efbc2adc8..faa6f56d2b 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -491,7 +491,7 @@ namespace Umbraco.Web.Trees { return new Tuple(null, idInt); } - if (Udi.TryParse(id, out idUdi)) + if (UdiParser.TryParse(id, out idUdi)) { var guidUdi = idUdi as GuidUdi; if (guidUdi != null) @@ -523,7 +523,7 @@ namespace Umbraco.Web.Trees { entity = Services.EntityService.Get(idInt, UmbracoObjectType); } - else if (Udi.TryParse(s, out var idUdi)) + else if (UdiParser.TryParse(s, out var idUdi)) { var guidUdi = idUdi as GuidUdi; entity = guidUdi != null ? Services.EntityService.Get(guidUdi.Guid, UmbracoObjectType) : null; diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 705d72f3dd..070e57ca5c 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -621,7 +621,7 @@ namespace Umbraco.Web switch (id) { case string s: - return Udi.TryParse(s, out guidId); + return UdiParser.TryParse(s, out guidId); case Udi u: guidId = u; diff --git a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs index efee045890..9f163f553a 100644 --- a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs @@ -87,7 +87,7 @@ namespace Umbraco.Web.WebApi.Filters { nodeId = parsedId; } - else if (Udi.TryParse(argument, true, out Udi udi)) + else if (UdiParser.TryParse(argument, true, out Udi udi)) { // TODO: inject? we can't because this is an attribute but we could provide ctors and empty ctors that pass in the required services nodeId = Current.Services.EntityService.GetId(udi).Result; From c97b156eafb36d1e88ee566b85468466b4f9a31d Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 13 Nov 2019 16:44:40 +1100 Subject: [PATCH 2/3] Moves Udi, UriParser and others to abstractions --- .../GuidUdi.cs | 0 .../StringUdi.cs | 0 .../Udi.cs | 4 +- .../UdiParser.cs | 51 +++++++++++++++++-- .../UdiTypeConverter.cs | 0 .../UnknownTypeUdi.cs | 0 src/Umbraco.Core/Models/UmbracoObjectTypes.cs | 4 +- src/Umbraco.Core/UdiEntityTypeHelper.cs | 38 +------------- src/Umbraco.Core/Umbraco.Core.csproj | 6 --- src/Umbraco.Tests/CoreThings/UdiTests.cs | 2 +- 10 files changed, 52 insertions(+), 53 deletions(-) rename src/{Umbraco.Core => Umbraco.Abstractions}/GuidUdi.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/StringUdi.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/Udi.cs (98%) rename src/{Umbraco.Core => Umbraco.Abstractions}/UdiParser.cs (72%) rename src/{Umbraco.Core => Umbraco.Abstractions}/UdiTypeConverter.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/UnknownTypeUdi.cs (100%) diff --git a/src/Umbraco.Core/GuidUdi.cs b/src/Umbraco.Abstractions/GuidUdi.cs similarity index 100% rename from src/Umbraco.Core/GuidUdi.cs rename to src/Umbraco.Abstractions/GuidUdi.cs diff --git a/src/Umbraco.Core/StringUdi.cs b/src/Umbraco.Abstractions/StringUdi.cs similarity index 100% rename from src/Umbraco.Core/StringUdi.cs rename to src/Umbraco.Abstractions/StringUdi.cs diff --git a/src/Umbraco.Core/Udi.cs b/src/Umbraco.Abstractions/Udi.cs similarity index 98% rename from src/Umbraco.Core/Udi.cs rename to src/Umbraco.Abstractions/Udi.cs index 0da549f498..80e58b2f86 100644 --- a/src/Umbraco.Core/Udi.cs +++ b/src/Umbraco.Abstractions/Udi.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core [TypeConverter(typeof(UdiTypeConverter))] public abstract class Udi : IComparable { - internal readonly Uri UriValue; // internal for UdiRange + public Uri UriValue { get; } /// /// Initializes a new instance of the Udi class. @@ -104,7 +104,7 @@ namespace Umbraco.Core return new GuidUdi(entityType, id); } - internal static Udi Create(Uri uri) + public static Udi Create(Uri uri) { // if it's a know type go fast and use ctors // else fallback to parsing the string (and guess the type) diff --git a/src/Umbraco.Core/UdiParser.cs b/src/Umbraco.Abstractions/UdiParser.cs similarity index 72% rename from src/Umbraco.Core/UdiParser.cs rename to src/Umbraco.Abstractions/UdiParser.cs index 20002a79e0..08af2bf0cd 100644 --- a/src/Umbraco.Core/UdiParser.cs +++ b/src/Umbraco.Abstractions/UdiParser.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; namespace Umbraco.Core { @@ -12,13 +14,16 @@ namespace Umbraco.Core { // initialize with known (built-in) Udi types // we will add scanned types later on - UdiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); + UdiTypes = new ConcurrentDictionary(GetKnownUdiTypes()); } - // for tests, totally unsafe - internal static void ResetUdiTypes() + /// + /// Internal API for tests to resets all udi types back to only the known udi types. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void ResetUdiTypes() { - UdiTypes = new ConcurrentDictionary(UdiEntityTypeHelper.GetTypes()); + UdiTypes = new ConcurrentDictionary(GetKnownUdiTypes()); } /// @@ -175,5 +180,43 @@ namespace Umbraco.Core /// /// public static void RegisterUdiType(string entityType, UdiType udiType) => UdiTypes.TryAdd(entityType, udiType); + + public static Dictionary GetKnownUdiTypes() => + new Dictionary + { + { Constants.UdiEntityType.Unknown, UdiType.Unknown }, + + { Constants.UdiEntityType.AnyGuid, UdiType.GuidUdi }, + { Constants.UdiEntityType.Document, UdiType.GuidUdi }, + { Constants.UdiEntityType.DocumentBlueprint, UdiType.GuidUdi }, + { Constants.UdiEntityType.Media, UdiType.GuidUdi }, + { Constants.UdiEntityType.Member, UdiType.GuidUdi }, + { Constants.UdiEntityType.DictionaryItem, UdiType.GuidUdi }, + { Constants.UdiEntityType.Macro, UdiType.GuidUdi }, + { Constants.UdiEntityType.Template, UdiType.GuidUdi }, + { Constants.UdiEntityType.DocumentType, UdiType.GuidUdi }, + { Constants.UdiEntityType.DocumentTypeContainer, UdiType.GuidUdi }, + { Constants.UdiEntityType.DocumentTypeBluePrints, UdiType.GuidUdi }, + { Constants.UdiEntityType.MediaType, UdiType.GuidUdi }, + { Constants.UdiEntityType.MediaTypeContainer, UdiType.GuidUdi }, + { Constants.UdiEntityType.DataType, UdiType.GuidUdi }, + { Constants.UdiEntityType.DataTypeContainer, UdiType.GuidUdi }, + { Constants.UdiEntityType.MemberType, UdiType.GuidUdi }, + { Constants.UdiEntityType.MemberGroup, UdiType.GuidUdi }, + { Constants.UdiEntityType.RelationType, UdiType.GuidUdi }, + { Constants.UdiEntityType.FormsForm, UdiType.GuidUdi }, + { Constants.UdiEntityType.FormsPreValue, UdiType.GuidUdi }, + { Constants.UdiEntityType.FormsDataSource, UdiType.GuidUdi }, + + { Constants.UdiEntityType.AnyString, UdiType.StringUdi }, + { Constants.UdiEntityType.Language, UdiType.StringUdi }, + { Constants.UdiEntityType.MacroScript, UdiType.StringUdi }, + { Constants.UdiEntityType.MediaFile, UdiType.StringUdi }, + { Constants.UdiEntityType.TemplateFile, UdiType.StringUdi }, + { Constants.UdiEntityType.Script, UdiType.StringUdi }, + { Constants.UdiEntityType.PartialView, UdiType.StringUdi }, + { Constants.UdiEntityType.PartialViewMacro, UdiType.StringUdi }, + { Constants.UdiEntityType.Stylesheet, UdiType.StringUdi } + }; } } diff --git a/src/Umbraco.Core/UdiTypeConverter.cs b/src/Umbraco.Abstractions/UdiTypeConverter.cs similarity index 100% rename from src/Umbraco.Core/UdiTypeConverter.cs rename to src/Umbraco.Abstractions/UdiTypeConverter.cs diff --git a/src/Umbraco.Core/UnknownTypeUdi.cs b/src/Umbraco.Abstractions/UnknownTypeUdi.cs similarity index 100% rename from src/Umbraco.Core/UnknownTypeUdi.cs rename to src/Umbraco.Abstractions/UnknownTypeUdi.cs diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs index 5449318e7a..a9bcbc2b65 100644 --- a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs +++ b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs @@ -1,6 +1,4 @@ -using System; -using System.ComponentModel; -using Umbraco.Core.CodeAnnotations; +using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.Models { diff --git a/src/Umbraco.Core/UdiEntityTypeHelper.cs b/src/Umbraco.Core/UdiEntityTypeHelper.cs index 6504ddc674..12e934b9ec 100644 --- a/src/Umbraco.Core/UdiEntityTypeHelper.cs +++ b/src/Umbraco.Core/UdiEntityTypeHelper.cs @@ -6,43 +6,7 @@ namespace Umbraco.Core { public static class UdiEntityTypeHelper { - internal static Dictionary GetTypes() => - new Dictionary - { - { Constants.UdiEntityType.Unknown, UdiType.Unknown }, - - { Constants.UdiEntityType.AnyGuid, UdiType.GuidUdi }, - { Constants.UdiEntityType.Document, UdiType.GuidUdi }, - { Constants.UdiEntityType.DocumentBlueprint, UdiType.GuidUdi }, - { Constants.UdiEntityType.Media, UdiType.GuidUdi }, - { Constants.UdiEntityType.Member, UdiType.GuidUdi }, - { Constants.UdiEntityType.DictionaryItem, UdiType.GuidUdi }, - { Constants.UdiEntityType.Macro, UdiType.GuidUdi }, - { Constants.UdiEntityType.Template, UdiType.GuidUdi }, - { Constants.UdiEntityType.DocumentType, UdiType.GuidUdi }, - { Constants.UdiEntityType.DocumentTypeContainer, UdiType.GuidUdi }, - { Constants.UdiEntityType.DocumentTypeBluePrints, UdiType.GuidUdi }, - { Constants.UdiEntityType.MediaType, UdiType.GuidUdi }, - { Constants.UdiEntityType.MediaTypeContainer, UdiType.GuidUdi }, - { Constants.UdiEntityType.DataType, UdiType.GuidUdi }, - { Constants.UdiEntityType.DataTypeContainer, UdiType.GuidUdi }, - { Constants.UdiEntityType.MemberType, UdiType.GuidUdi }, - { Constants.UdiEntityType.MemberGroup, UdiType.GuidUdi }, - { Constants.UdiEntityType.RelationType, UdiType.GuidUdi }, - { Constants.UdiEntityType.FormsForm, UdiType.GuidUdi }, - { Constants.UdiEntityType.FormsPreValue, UdiType.GuidUdi }, - { Constants.UdiEntityType.FormsDataSource, UdiType.GuidUdi }, - - { Constants.UdiEntityType.AnyString, UdiType.StringUdi }, - { Constants.UdiEntityType.Language, UdiType.StringUdi }, - { Constants.UdiEntityType.MacroScript, UdiType.StringUdi }, - { Constants.UdiEntityType.MediaFile, UdiType.StringUdi }, - { Constants.UdiEntityType.TemplateFile, UdiType.StringUdi }, - { Constants.UdiEntityType.Script, UdiType.StringUdi }, - { Constants.UdiEntityType.PartialView, UdiType.StringUdi }, - { Constants.UdiEntityType.PartialViewMacro, UdiType.StringUdi }, - { Constants.UdiEntityType.Stylesheet, UdiType.StringUdi } - }; + public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType) { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0b0992fa98..b53e43266c 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -527,7 +527,6 @@ - @@ -1095,20 +1094,15 @@ - - - - - diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests/CoreThings/UdiTests.cs index 641587ebe7..df5d5363e5 100644 --- a/src/Umbraco.Tests/CoreThings/UdiTests.cs +++ b/src/Umbraco.Tests/CoreThings/UdiTests.cs @@ -250,7 +250,7 @@ namespace Umbraco.Tests.CoreThings [Test] public void ValidateUdiEntityType() { - var types = UdiEntityTypeHelper.GetTypes(); + var types = UdiParser.GetKnownUdiTypes(); foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static)) { From 1a6a31e3371733631ce5cedef1c1ea28a476c5b5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 13 Nov 2019 16:51:07 +1100 Subject: [PATCH 3/3] Moves more Udi things --- src/{Umbraco.Core => Umbraco.Abstractions}/NamedUdiRange.cs | 0 .../UdiDefinitionAttribute.cs | 0 src/{Umbraco.Core => Umbraco.Abstractions}/UdiRange.cs | 0 src/Umbraco.Core/Umbraco.Core.csproj | 3 --- 4 files changed, 3 deletions(-) rename src/{Umbraco.Core => Umbraco.Abstractions}/NamedUdiRange.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/UdiDefinitionAttribute.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/UdiRange.cs (100%) diff --git a/src/Umbraco.Core/NamedUdiRange.cs b/src/Umbraco.Abstractions/NamedUdiRange.cs similarity index 100% rename from src/Umbraco.Core/NamedUdiRange.cs rename to src/Umbraco.Abstractions/NamedUdiRange.cs diff --git a/src/Umbraco.Core/UdiDefinitionAttribute.cs b/src/Umbraco.Abstractions/UdiDefinitionAttribute.cs similarity index 100% rename from src/Umbraco.Core/UdiDefinitionAttribute.cs rename to src/Umbraco.Abstractions/UdiDefinitionAttribute.cs diff --git a/src/Umbraco.Core/UdiRange.cs b/src/Umbraco.Abstractions/UdiRange.cs similarity index 100% rename from src/Umbraco.Core/UdiRange.cs rename to src/Umbraco.Abstractions/UdiRange.cs diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b53e43266c..ab5198f677 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -657,7 +657,6 @@ - @@ -1098,11 +1097,9 @@ - -