Merge branch 'v8/dev' into v8-fix-media-picker-create-folder

This commit is contained in:
elitsa
2019-04-24 09:41:48 +02:00
704 changed files with 14897 additions and 11551 deletions

View File

@@ -1,10 +1,10 @@
using System;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using Umbraco.Core;
[assembly: PreApplicationStartMethod(typeof(BindingRedirects), "Initialize")]
// no binding redirect for now = de-activate
//[assembly: PreApplicationStartMethod(typeof(BindingRedirects), "Initialize")]
namespace Umbraco.Core
{
@@ -18,7 +18,7 @@ namespace Umbraco.Core
// this only gets called when an assembly can't be resolved
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
/// <summary>
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
/// </summary>
@@ -27,14 +27,19 @@ namespace Umbraco.Core
/// <returns></returns>
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// When an assembly can't be resolved. In here we can do magic with the assembly name and try loading another.
// keep here for reference - we don't use AutoMapper
/*
//AutoMapper:
// this is used for loading a signed assembly of AutoMapper (v. 3.1+) without having to recompile old code.
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
*/
return null;
}
}
}

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
@@ -13,11 +12,6 @@ namespace Umbraco.Core.Cache
public static NoCacheRepositoryCachePolicy<TEntity, TId> Instance { get; } = new NoCacheRepositoryCachePolicy<TEntity, TId>();
public IRepositoryCachePolicy<TEntity, TId> Scoped(IAppPolicyCache runtimeCache, IScope scope)
{
throw new NotImplementedException();
}
public TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
return performGet(id);

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Compose
private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContent.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContentString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias;
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Compose
private static void MediaService_Moved(IMediaService sender, MoveEventArgs<IMedia> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMedia.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMediaString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias;

View File

@@ -70,7 +70,23 @@ namespace Umbraco.Core.Composing
}
}
private IEnumerable<Type> PrepareComposerTypes()
internal IEnumerable<Type> PrepareComposerTypes()
{
var requirements = GetRequirements();
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
var sortedComposerTypes = SortComposers(requirements);
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
internal Dictionary<Type, List<Type>> GetRequirements(bool throwOnMissing = true)
{
// create a list, remove those that cannot be enabled due to runtime level
var composerTypeList = _composerTypes
@@ -89,25 +105,69 @@ namespace Umbraco.Core.Composing
// enable or disable composers
EnableDisableComposers(composerTypeList);
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList) requirements[type] = null;
foreach (var type in composerTypeList)
void GatherInterfaces<TAttribute>(Type type, Func<TAttribute, Type> getTypeInAttribute, HashSet<Type> iset, List<Type> set2)
where TAttribute : Attribute
{
GatherRequirementsFromRequireAttribute(type, composerTypeList, requirements);
GatherRequirementsFromRequiredByAttribute(type, composerTypeList, requirements);
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
{
var typeInAttribute = getTypeInAttribute(attribute);
if (typeInAttribute != null && // if the attribute references a type ...
typeInAttribute.IsInterface && // ... which is an interface ...
typeof(IComposer).IsAssignableFrom(typeInAttribute) && // ... which implements IComposer ...
!iset.Contains(typeInAttribute)) // ... which is not already in the list
{
// add it to the new list
iset.Add(typeInAttribute);
set2.Add(typeInAttribute);
// add all its interfaces implementing IComposer
foreach (var i in typeInAttribute.GetInterfaces().Where(x => typeof(IComposer).IsAssignableFrom(x)))
{
iset.Add(i);
set2.Add(i);
}
}
}
}
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
// gather interfaces too
var interfaces = new HashSet<Type>(composerTypeList.SelectMany(x => x.GetInterfaces().Where(y => typeof(IComposer).IsAssignableFrom(y))));
composerTypeList.AddRange(interfaces);
var list1 = composerTypeList;
while (list1.Count > 0)
{
var list2 = new List<Type>();
foreach (var t in list1)
{
GatherInterfaces<ComposeAfterAttribute>(t, a => a.RequiredType, interfaces, list2);
GatherInterfaces<ComposeBeforeAttribute>(t, a => a.RequiringType, interfaces, list2);
}
composerTypeList.AddRange(list2);
list1 = list2;
}
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList)
requirements[type] = null;
foreach (var type in composerTypeList)
{
GatherRequirementsFromAfterAttribute(type, composerTypeList, requirements, throwOnMissing);
GatherRequirementsFromBeforeAttribute(type, composerTypeList, requirements);
}
return requirements;
}
internal IEnumerable<Type> SortComposers(Dictionary<Type, List<Type>> requirements)
{
// sort composers
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
graph.AddItems(requirements);
List<Type> sortedComposerTypes;
try
{
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).Where(x => !x.IsInterface).ToList();
}
catch (Exception e)
{
@@ -117,40 +177,37 @@ namespace Umbraco.Core.Composing
throw;
}
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
private static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
internal static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
{
var text = new StringBuilder();
text.AppendLine("Composers & Dependencies:");
text.AppendLine(" < compose before");
text.AppendLine(" > compose after");
text.AppendLine(" : implements");
text.AppendLine(" = depends");
text.AppendLine();
bool HasReq(IEnumerable<Type> types, Type type)
=> types.Any(x => type.IsAssignableFrom(x) && !x.IsInterface);
foreach (var kvp in requirements)
{
var type = kvp.Key;
text.AppendLine(type.FullName);
foreach (var attribute in type.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
{
text.AppendLine(" : " + i.FullName);
foreach (var attribute in i.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in i.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
var weak = !(attribute.RequiredType.IsInterface ? attribute.Weak == false : attribute.Weak != true);
text.AppendLine(" > " + attribute.RequiredType +
(weak ? " (weak" : " (strong") + (HasReq(requirements.Keys, attribute.RequiredType) ? ", found" : ", missing") + ")");
}
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" < " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
text.AppendLine(" : " + i.FullName);
if (kvp.Value != null)
foreach (var t in kvp.Value)
text.AppendLine(" = " + t);
@@ -221,16 +278,16 @@ namespace Umbraco.Core.Composing
types.Remove(kvp.Key);
}
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromAfterAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements, bool throwOnMissing = true)
{
// get 'require' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requireAttributes = type
var afterAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeAfterAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeAfterAttribute>()); // those marking the composer
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
foreach (var attr in requireAttributes)
foreach (var attr in afterAttributes)
{
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
@@ -238,13 +295,13 @@ namespace Umbraco.Core.Composing
// unless strong, and then require at least one enabled composer implementing that interface
if (attr.RequiredType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x) && !x.IsInterface).ToList();
if (implems.Count > 0)
{
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].AddRange(implems);
}
else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak
else if (attr.Weak == false && throwOnMissing) // if explicitly set to !weak, is strong, else is weak
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
// requiring a class = require that the composer is enabled
@@ -256,28 +313,28 @@ namespace Umbraco.Core.Composing
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].Add(attr.RequiredType);
}
else if (attr.Weak != true) // if not explicitly set to weak, is strong
else if (attr.Weak != true && throwOnMissing) // if not explicitly set to weak, is strong
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
}
}
private static void GatherRequirementsFromRequiredByAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromBeforeAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
{
// get 'required' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requiredAttributes = type
var beforeAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeBeforeAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeBeforeAttribute>()); // those marking the composer
foreach (var attr in requiredAttributes)
foreach (var attr in beforeAttributes)
{
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
// required by an interface = by any enabled composer implementing this that interface
if (attr.RequiringType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x) && !x.IsInterface).ToList();
foreach (var implem in implems)
{
if (requirements[implem] == null) requirements[implem] = new List<Type>();

View File

@@ -133,7 +133,11 @@ namespace Umbraco.Core.Composing
Configs.RegisterWith(_register);
return _register.CreateFactory();
IFactory factory = null;
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
factory = _register.CreateFactory();
return factory;
}
/// <summary>

View File

@@ -1,4 +1,4 @@
using AutoMapper;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.Identity;
namespace Umbraco.Core.Composing.CompositionExtensions
@@ -8,7 +8,9 @@ namespace Umbraco.Core.Composing.CompositionExtensions
{
public static Composition ComposeCoreMappingProfiles(this Composition composition)
{
composition.Register<Profile, IdentityMapperProfile>();
composition.RegisterUnique<UmbracoMapper>();
composition.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<IdentityMapDefinition>();
return composition;
}
}

View File

@@ -46,6 +46,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
composition.RegisterUnique<IPartialViewRepository, PartialViewRepository>();
composition.RegisterUnique<IScriptRepository, ScriptRepository>();
composition.RegisterUnique<IStylesheetRepository, StylesheetRepository>();
composition.RegisterUnique<IContentTypeCommonRepository, ContentTypeCommonRepository>();
return composition;
}

View File

@@ -98,7 +98,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
: appPlugins.GetDirectories()
.SelectMany(x => x.GetDirectories("Lang"))
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 5)
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
//user defined langs that overwrite the default, these should not be used by plugin creators
@@ -106,7 +105,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
: configLangFolder
.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 10)
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true));
return new LocalizedTextServiceFileSources(

View File

@@ -4,6 +4,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PackageActions;
using Umbraco.Core.Packaging;
@@ -103,6 +104,9 @@ namespace Umbraco.Core.Composing
#region Getters
public static UmbracoMapper Mapper
=> _factory.GetInstance<UmbracoMapper>();
public static IShortStringHelper ShortStringHelper
=> _shortStringHelper ?? (_shortStringHelper = _factory?.TryGetInstance<IShortStringHelper>()
?? new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(Configs.Settings())));

View File

@@ -8,7 +8,6 @@
/// <summary>
/// Compose.
/// </summary>
/// <param name="composition"></param>
void Compose(Composition composition);
}
}
}

View File

@@ -4,10 +4,8 @@
/// Represents a core <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All core composers are required by (compose before) all user composers,
/// and require (compose after) all runtime composers.</para>
/// <para>Core composers compose after the initial composer, and before user composers.</para>
/// </remarks>
[ComposeAfter(typeof(IRuntimeComposer))]
public interface ICoreComposer : IComposer
{ }
}
}

View File

@@ -1,11 +0,0 @@
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a runtime <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All runtime composers are required by (compose before) all core composers</para>
/// </remarks>
public interface IRuntimeComposer : IComposer
{ }
}

View File

@@ -4,9 +4,9 @@
/// Represents a user <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All user composers require (compose after) all core composers.</para>
/// <para>User composers compose after core composers, and before the final composer.</para>
/// </remarks>
[ComposeAfter(typeof(ICoreComposer))]
public interface IUserComposer : IComposer
{ }
}
}

View File

@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Implements an un-ordered collection builder.
/// </summary>
/// <typeparam name="TBuilder">The type of the builder.</typeparam>
/// <typeparam name="TCollection">The type of the collection.</typeparam>
/// <typeparam name="TItem">The type of the items.</typeparam>
/// <remarks>
/// <para>A set collection builder is the most basic collection builder,
/// where items are not ordered.</para>
/// </remarks>
public abstract class SetCollectionBuilderBase<TBuilder, TCollection, TItem> : CollectionBuilderBase<TBuilder, TCollection, TItem>
where TBuilder : SetCollectionBuilderBase<TBuilder, TCollection, TItem>
where TCollection : class, IBuilderCollection<TItem>
{
protected abstract TBuilder This { get; }
/// <summary>
/// Clears all types in the collection.
/// </summary>
/// <returns>The builder.</returns>
public TBuilder Clear()
{
Configure(types => types.Clear());
return This;
}
/// <summary>
/// Adds a type to the collection.
/// </summary>
/// <typeparam name="T">The type to append.</typeparam>
/// <returns>The builder.</returns>
public TBuilder Add<T>()
where T : TItem
{
Configure(types =>
{
var type = typeof(T);
if (types.Contains(type)) types.Remove(type);
types.Add(type);
});
return This;
}
/// <summary>
/// Adds a type to the collection.
/// </summary>
/// <param name="type">The type to append.</param>
/// <returns>The builder.</returns>
public TBuilder Add(Type type)
{
Configure(types =>
{
EnsureType(type, "register");
if (types.Contains(type)) types.Remove(type);
types.Add(type);
});
return This;
}
/// <summary>
/// Adds types to the collections.
/// </summary>
/// <param name="types">The types to append.</param>
/// <returns>The builder.</returns>
public TBuilder Add(IEnumerable<Type> types)
{
Configure(list =>
{
foreach (var type in types)
{
// would be detected by CollectionBuilderBase when registering, anyways, but let's fail fast
EnsureType(type, "register");
if (list.Contains(type)) list.Remove(type);
list.Add(type);
}
});
return This;
}
/// <summary>
/// Removes a type from the collection.
/// </summary>
/// <typeparam name="T">The type to remove.</typeparam>
/// <returns>The builder.</returns>
public TBuilder Remove<T>()
where T : TItem
{
Configure(types =>
{
var type = typeof(T);
if (types.Contains(type)) types.Remove(type);
});
return This;
}
/// <summary>
/// Removes a type from the collection.
/// </summary>
/// <param name="type">The type to remove.</param>
/// <returns>The builder.</returns>
public TBuilder Remove(Type type)
{
Configure(types =>
{
EnsureType(type, "remove");
if (types.Contains(type)) types.Remove(type);
});
return This;
}
/// <summary>
/// Replaces a type in the collection.
/// </summary>
/// <typeparam name="TReplaced">The type to replace.</typeparam>
/// <typeparam name="T">The type to insert.</typeparam>
/// <returns>The builder.</returns>
/// <remarks>Throws if the type to replace does not already belong to the collection.</remarks>
public TBuilder Replace<TReplaced, T>()
where TReplaced : TItem
where T : TItem
{
Configure(types =>
{
var typeReplaced = typeof(TReplaced);
var type = typeof(T);
if (typeReplaced == type) return;
var index = types.IndexOf(typeReplaced);
if (index < 0) throw new InvalidOperationException();
if (types.Contains(type)) types.Remove(type);
index = types.IndexOf(typeReplaced); // in case removing type changed index
types.Insert(index, type);
types.Remove(typeReplaced);
});
return This;
}
/// <summary>
/// Replaces a type in the collection.
/// </summary>
/// <param name="typeReplaced">The type to replace.</param>
/// <param name="type">The type to insert.</param>
/// <returns>The builder.</returns>
/// <remarks>Throws if the type to replace does not already belong to the collection.</remarks>
public TBuilder Replace(Type typeReplaced, Type type)
{
Configure(types =>
{
EnsureType(typeReplaced, "find");
EnsureType(type, "register");
if (typeReplaced == type) return;
var index = types.IndexOf(typeReplaced);
if (index < 0) throw new InvalidOperationException();
if (types.Contains(type)) types.Remove(type);
index = types.IndexOf(typeReplaced); // in case removing type changed index
types.Insert(index, type);
types.Remove(typeReplaced);
});
return This;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides a base class for collections of types.
/// </summary>
public abstract class TypeCollectionBuilderBase<TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
where TCollection : class, IBuilderCollection<Type>
{
private readonly HashSet<Type> _types = new HashSet<Type>();
private Type Validate(Type type, string action)
{
if (!typeof(TConstraint).IsAssignableFrom(type))
throw new InvalidOperationException($"Cannot {action} type {type.FullName} as it does not inherit from/implement {typeof(TConstraint).FullName}.");
return type;
}
public void Add(Type type) => _types.Add(Validate(type, "add"));
public void Add<T>() => Add(typeof(T));
public void Add(IEnumerable<Type> types)
{
foreach (var type in types) Add(type);
}
public void Remove(Type type) => _types.Remove(Validate(type, "remove"));
public void Remove<T>() => Remove(typeof(T));
public TCollection CreateCollection(IFactory factory)
{
return factory.CreateInstance<TCollection>(_types);
}
public void RegisterWith(IRegister register)
{
register.Register(CreateCollection, Lifetime.Singleton);
}
}
}

View File

@@ -203,6 +203,28 @@ namespace Umbraco.Core
composition.RegisterUnique(_ => registrar);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="factory">A function creating the options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, Func<IFactory, DatabaseServerMessengerOptions> factory)
{
composition.RegisterUnique(factory);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="options">Options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, DatabaseServerMessengerOptions options)
{
composition.RegisterUnique(_ => options);
}
/// <summary>
/// Sets the short string helper.
/// </summary>

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Net.Configuration;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Xml.Linq;
using Umbraco.Core.IO;
@@ -17,16 +18,15 @@ namespace Umbraco.Core.Configuration
/// </summary>
public class GlobalSettings : IGlobalSettings
{
private string _localTempPath;
#region Private static fields
// TODO these should not be static
private static string _reservedPaths;
private static string _reservedUrls;
//ensure the built on (non-changeable) reserved paths are there at all times
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
#endregion
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
@@ -131,7 +131,7 @@ namespace Umbraco.Core.Configuration
: "~/App_Data/umbraco.config";
}
}
/// <summary>
/// Gets the path to umbraco's root directory (/umbraco by default).
/// </summary>
@@ -163,7 +163,7 @@ namespace Umbraco.Core.Configuration
SaveSetting(Constants.AppSettings.ConfigurationStatus, value);
}
}
/// <summary>
/// Saves a setting into the configuration file.
/// </summary>
@@ -206,7 +206,7 @@ namespace Umbraco.Core.Configuration
ConfigurationManager.RefreshSection("appSettings");
}
}
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
@@ -250,7 +250,7 @@ namespace Umbraco.Core.Configuration
}
}
}
/// <summary>
/// Returns the number of days that should take place between version checks.
/// </summary>
@@ -269,7 +269,7 @@ namespace Umbraco.Core.Configuration
}
}
}
/// <inheritdoc />
public LocalTempStorage LocalTempStorageLocation
{
@@ -288,25 +288,43 @@ namespace Umbraco.Core.Configuration
{
get
{
if (_localTempPath != null)
return _localTempPath;
switch (LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
return _localTempPath = System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
case LocalTempStorage.EnvironmentTemp:
// include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId
var appDomainHash = HttpRuntime.AppDomainAppId.GenerateHash();
return System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash);
// environment temp is unique, we need a folder per site
// use a hash
// combine site name and application id
// site name is a Guid on Cloud
// application id is eg /LM/W3SVC/123456/ROOT
// the combination is unique on one server
// and, if a site moves from worker A to B and then back to A...
// hopefully it gets a new Guid or new application id?
var siteName = HostingEnvironment.SiteName;
var applicationId = HostingEnvironment.ApplicationID; // ie HttpRuntime.AppDomainAppId
var hashString = siteName + "::" + applicationId;
var hash = hashString.GenerateHash();
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
return _localTempPath = siteTemp;
//case LocalTempStorage.Default:
//case LocalTempStorage.Unknown:
default:
return IOHelper.MapPath("~/App_Data/TEMP");
return _localTempPath = IOHelper.MapPath("~/App_Data/TEMP");
}
}
}
/// <summary>
/// Gets the default UI language.
/// </summary>

View File

@@ -93,7 +93,6 @@ namespace Umbraco.Core
/// </summary>
public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer";
/// <summary>
/// Debug specific web.config AppSetting keys for Umbraco
/// </summary>

View File

@@ -145,11 +145,11 @@
public const string PartialViewMacros = "partialViewMacros";
public const string LogViewer = "logViewer";
public const string LogViewer = "logViewer";
public static class Groups
{
public const string Settings = "settingsGroup";
public const string Settings = "settingsGroup";
public const string Templating = "templatingGroup";

View File

@@ -92,10 +92,10 @@ namespace Umbraco.Core
/// </summary>
public const string Extension = "umbracoExtension";
/// <summary>
/// The default height/width of an image file if the size can't be determined from the metadata
/// </summary>
public const int DefaultSize = 200;
/// <summary>
/// The default height/width of an image file if the size can't be determined from the metadata
/// </summary>
public const int DefaultSize = 200;
}
/// <summary>
@@ -209,71 +209,71 @@ namespace Umbraco.Core
public static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
{
return new Dictionary<string, PropertyType>
{
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Name = CommentsLabel
}
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
Name = CommentsLabel
}
};
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
}
};
}
}

View File

@@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
public static class Icons
{
/// <summary>
/// System contenttype icon
/// </summary>
@@ -42,12 +34,10 @@ namespace Umbraco.Core
/// </summary>
public const string MemberType = "icon-users";
/// <summary>
/// System member icon
/// </summary>
public const string Template = "icon-layout";
}
}
}

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{

View File

@@ -123,7 +123,6 @@ namespace Umbraco.Core
public static readonly Guid Template = new Guid(Strings.Template);
public static readonly Guid ContentItem = new Guid(Strings.ContentItem);
}
}
}

View File

@@ -3,7 +3,7 @@
public static partial class Constants
{
/// <summary>
/// Defines the constants used for the Umbraco package repository
/// Defines the constants used for the Umbraco package repository
/// </summary>
public static class PackageRepository
{

View File

@@ -34,7 +34,6 @@ namespace Umbraco.Core
/// </summary>
public const string ContentPicker = "Umbraco.ContentPicker";
/// <summary>
/// DateTime.
/// </summary>

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
@@ -22,7 +19,6 @@ namespace Umbraco.Core
public const string PreviewCookieName = "UMB_PREVIEW";
public const string InstallerCookieName = "umb_installId";
}
}
}

View File

@@ -7,6 +7,7 @@ using System.Web;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPoco.Expressions;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -52,8 +53,8 @@ namespace Umbraco.Core
return ContentStatus.Unpublished;
}
#endregion
/// <summary>
@@ -134,9 +135,14 @@ namespace Umbraco.Core
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
/// <remarks>This really is for FileUpload fields only, and should be obsoleted. For anything else,
/// you need to store the file by yourself using Store and then figure out
/// how to deal with auto-fill properties (if any) and thumbnails (if any) by yourself.</remarks>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, HttpPostedFileBase postedFile, string culture = null, string segment = null)
{
content.SetValue(contentTypeBaseServiceProvider, propertyTypeAlias, postedFile.FileName, postedFile.InputStream, culture, segment);
}
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
if (filename == null || filestream == null) return;

View File

@@ -10,6 +10,18 @@ namespace Umbraco.Core
///</summary>
public static class EnumerableExtensions
{
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
{
var hs = new HashSet<T>();
foreach (var item in items)
{
if ((item != null || includeNull) && !hs.Add(item))
return true;
}
return false;
}
/// <summary>
/// Wraps this object instance into an IEnumerable{T} consisting of a single item.
/// </summary>
@@ -100,7 +112,7 @@ namespace Umbraco.Core
}
}
/// <summary>
/// Returns true if all items in the other collection exist in this collection
/// </summary>

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Serilog.Events;
using Serilog.Formatting.Compact.Reader;
@@ -10,13 +11,15 @@ namespace Umbraco.Core.Logging.Viewer
internal class JsonLogViewer : LogViewerSourceBase
{
private readonly string _logsPath;
private readonly ILogger _logger;
public JsonLogViewer(string logsPath = "", string searchPath = "") : base(searchPath)
public JsonLogViewer(ILogger logger, string logsPath = "", string searchPath = "") : base(searchPath)
{
if (string.IsNullOrEmpty(logsPath))
logsPath = $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\";
_logsPath = logsPath;
_logger = logger;
}
private const int FileSizeCap = 100;
@@ -77,8 +80,14 @@ namespace Umbraco.Core.Logging.Viewer
using (var stream = new StreamReader(fs))
{
var reader = new LogEventReader(stream);
while (reader.TryRead(out var evt))
while (TryRead(reader, out var evt))
{
//We may get a null if log line is malformed
if (evt == null)
{
continue;
}
if (count > skip + take)
{
break;
@@ -105,5 +114,21 @@ namespace Umbraco.Core.Logging.Viewer
return logs;
}
private bool TryRead(LogEventReader reader, out LogEvent evt)
{
try
{
return reader.TryRead(out evt);
}
catch (JsonReaderException ex)
{
// As we are reading/streaming one line at a time in the JSON file
// Thus we can not report the line number, as it will always be 1
_logger.Error<JsonLogViewer>(ex, "Unable to parse a line in the JSON log file");
evt = null;
return true;
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace Umbraco.Core.Logging.Viewer
{
public void Compose(Composition composition)
{
composition.SetLogViewer(_ => new JsonLogViewer());
composition.SetLogViewer(_ => new JsonLogViewer(composition.Logger));
}
}
}

View File

@@ -0,0 +1,13 @@
namespace Umbraco.Core.Mapping
{
/// <summary>
/// Defines maps for <see cref="UmbracoMapper"/>.
/// </summary>
public interface IMapDefinition
{
/// <summary>
/// Defines maps.
/// </summary>
void DefineMaps(UmbracoMapper mapper);
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Mapping
{
public class MapDefinitionCollection : BuilderCollectionBase<IMapDefinition>
{
public MapDefinitionCollection(IEnumerable<IMapDefinition> items)
: base(items)
{ }
}
}

View File

@@ -0,0 +1,11 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Mapping
{
public class MapDefinitionCollectionBuilder : SetCollectionBuilderBase<MapDefinitionCollectionBuilder, MapDefinitionCollection, IMapDefinition>
{
protected override MapDefinitionCollectionBuilder This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient;
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Mapping
{
/// <summary>
/// Represents a mapper context.
/// </summary>
public class MapperContext
{
private readonly UmbracoMapper _mapper;
private IDictionary<string, object> _items;
/// <summary>
/// Initializes a new instance of the <see cref="MapperContext"/> class.
/// </summary>
public MapperContext(UmbracoMapper mapper)
{
_mapper = mapper;
}
/// <summary>
/// Gets a value indicating whether the context has items.
/// </summary>
public bool HasItems => _items != null;
/// <summary>
/// Gets the context items.
/// </summary>
public IDictionary<string, object> Items => _items ?? (_items = new Dictionary<string, object>());
#region Map
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TTarget>(object source)
=> _mapper.Map<TTarget>(source, this);
// let's say this is a bad (dangerous) idea, and leave it out for now
/*
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TTarget>(object source, Action<MapperContext> f)
{
f(this);
return _mapper.Map<TTarget>(source, this);
}
*/
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source)
=> _mapper.Map<TSource, TTarget>(source, this);
// let's say this is a bad (dangerous) idea, and leave it out for now
/*
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, Action<MapperContext> f)
{
f(this);
return _mapper.Map<TSource, TTarget>(source, this);
}
*/
/// <summary>
/// Maps a source object to an existing target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="target">The target object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, TTarget target)
=> _mapper.Map(source, target, this);
// let's say this is a bad (dangerous) idea, and leave it out for now
/*
/// <summary>
/// Maps a source object to an existing target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="target">The target object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, TTarget target, Action<MapperContext> f)
{
f(this);
return _mapper.Map(source, target, this);
}
*/
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
{
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
}
#endregion
}
}

View File

@@ -0,0 +1,424 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Mapping
{
// notes:
// AutoMapper maps null to empty arrays, lists, etc
// TODO:
// when mapping from TSource, and no map is found, consider the actual source.GetType()?
// when mapping to TTarget, and no map is found, consider the actual target.GetType()?
// not sure we want to add magic to this simple mapper class, though
/// <summary>
/// Umbraco Mapper.
/// </summary>
/// <remarks>
/// <para>When a map is defined from TSource to TTarget, the mapper automatically knows how to map
/// from IEnumerable{TSource} to IEnumerable{TTarget} (using a List{TTarget}) and to TTarget[].</para>
/// <para>When a map is defined from TSource to TTarget, the mapper automatically uses that map
/// for any source type that inherits from, or implements, TSource.</para>
/// <para>When a map is defined from TSource to TTarget, the mapper can map to TTarget exclusively
/// and cannot re-use that map for types that would inherit from, or implement, TTarget.</para>
/// <para>When using the Map{TSource, TTarget}(TSource source, ...) overloads, TSource is explicit. When
/// using the Map{TTarget}(object source, ...) TSource is defined as source.GetType().</para>
/// <para>In both cases, TTarget is explicit and not typeof(target).</para>
/// </remarks>
public class UmbracoMapper
{
private readonly Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
= new Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>>();
private readonly Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
= new Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoMapper"/> class.
/// </summary>
/// <param name="profiles"></param>
public UmbracoMapper(MapDefinitionCollection profiles)
{
foreach (var profile in profiles)
profile.DefineMaps(this);
}
#region Define
private static TTarget ThrowCtor<TSource, TTarget>(TSource source, MapperContext context)
=> throw new InvalidOperationException($"Don't know how to create {typeof(TTarget).FullName} instances.");
private static void Identity<TSource, TTarget>(TSource source, TTarget target, MapperContext context)
{ }
/// <summary>
/// Defines a mapping.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
public void Define<TSource, TTarget>()
=> Define<TSource, TTarget>(ThrowCtor<TSource, TTarget>, Identity);
/// <summary>
/// Defines a mapping.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="map">A mapping method.</param>
public void Define<TSource, TTarget>(Action<TSource, TTarget, MapperContext> map)
=> Define(ThrowCtor<TSource, TTarget>, map);
/// <summary>
/// Defines a mapping.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="ctor">A constructor method.</param>
public void Define<TSource, TTarget>(Func<TSource, MapperContext, TTarget> ctor)
=> Define(ctor, Identity);
/// <summary>
/// Defines a mapping.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="ctor">A constructor method.</param>
/// <param name="map">A mapping method.</param>
public void Define<TSource, TTarget>(Func<TSource, MapperContext, TTarget> ctor, Action<TSource, TTarget, MapperContext> map)
{
var sourceType = typeof(TSource);
var targetType = typeof(TTarget);
var sourceCtors = DefineCtors(sourceType);
if (ctor != null)
sourceCtors[targetType] = (source, context) => ctor((TSource)source, context);
var sourceMaps = DefineMaps(sourceType);
sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context);
}
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType)
{
if (!_ctors.TryGetValue(sourceType, out var sourceCtor))
sourceCtor = _ctors[sourceType] = new Dictionary<Type, Func<object, MapperContext, object>>();
return sourceCtor;
}
private Dictionary<Type, Action<object, object, MapperContext>> DefineMaps(Type sourceType)
{
if (!_maps.TryGetValue(sourceType, out var sourceMap))
sourceMap = _maps[sourceType] = new Dictionary<Type, Action<object, object, MapperContext>>();
return sourceMap;
}
#endregion
#region Map
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TTarget>(object source)
=> Map<TTarget>(source, new MapperContext(this));
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TTarget>(object source, Action<MapperContext> f)
{
var context = new MapperContext(this);
f(context);
return Map<TTarget>(source, context);
}
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="context">A mapper context.</param>
/// <returns>The target object.</returns>
public TTarget Map<TTarget>(object source, MapperContext context)
=> Map<TTarget>(source, source?.GetType(), context);
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source)
=> Map<TSource, TTarget>(source, new MapperContext(this));
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, Action<MapperContext> f)
{
var context = new MapperContext(this);
f(context);
return Map<TSource, TTarget>(source, context);
}
/// <summary>
/// Maps a source object to a new target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="context">A mapper context.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, MapperContext context)
=> Map<TTarget>(source, typeof(TSource), context);
private TTarget Map<TTarget>(object source, Type sourceType, MapperContext context)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
var targetType = typeof(TTarget);
var ctor = GetCtor(sourceType, targetType);
var map = GetMap(sourceType, targetType);
// if there is a direct constructor, map
if (ctor != null && map != null)
{
var target = ctor(source, context);
map(source, target, context);
return (TTarget)target;
}
// otherwise, see if we can deal with enumerable
var ienumerableOfT = typeof(IEnumerable<>);
bool IsIEnumerableOfT(Type type) =>
type.IsGenericType &&
type.GenericTypeArguments.Length == 1 &&
type.GetGenericTypeDefinition() == ienumerableOfT;
// try to get source as an IEnumerable<T>
var sourceIEnumerable = IsIEnumerableOfT(sourceType) ? sourceType : sourceType.GetInterfaces().FirstOrDefault(IsIEnumerableOfT);
// if source is an IEnumerable<T> and target is T[] or IEnumerable<T>, we can create a map
if (sourceIEnumerable != null && IsEnumerableOrArrayOfType(targetType))
{
var sourceGenericArg = sourceIEnumerable.GenericTypeArguments[0];
var targetGenericArg = GetEnumerableOrArrayTypeArgument(targetType);
ctor = GetCtor(sourceGenericArg, targetGenericArg);
map = GetMap(sourceGenericArg, targetGenericArg);
// if there is a constructor for the underlying type, create & invoke the map
if (ctor != null && map != null)
{
// register (for next time) and do it now (for this time)
object NCtor(object s, MapperContext c) => MapEnumerableInternal<TTarget>((IEnumerable) s, targetGenericArg, ctor, map, c);
DefineCtors(sourceType)[targetType] = NCtor;
DefineMaps(sourceType)[targetType] = Identity;
return (TTarget) NCtor(source, context);
}
throw new InvalidOperationException($"Don't know how to map {sourceGenericArg.FullName} to {targetGenericArg.FullName}, so don't know how to map {sourceType.FullName} to {targetType.FullName}.");
}
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
}
private TTarget MapEnumerableInternal<TTarget>(IEnumerable source, Type targetGenericArg, Func<object, MapperContext, object> ctor, Action<object, object, MapperContext> map, MapperContext context)
{
var targetList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetGenericArg));
foreach (var sourceItem in source)
{
var targetItem = ctor(sourceItem, context);
map(sourceItem, targetItem, context);
targetList.Add(targetItem);
}
object target = targetList;
if (typeof(TTarget).IsArray)
{
var elementType = typeof(TTarget).GetElementType();
if (elementType == null) throw new Exception("panic");
var targetArray = Array.CreateInstance(elementType, targetList.Count);
targetList.CopyTo(targetArray, 0);
target = targetArray;
}
return (TTarget) target;
}
/// <summary>
/// Maps a source object to an existing target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="target">The target object.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, TTarget target)
=> Map(source, target, new MapperContext(this));
/// <summary>
/// Maps a source object to an existing target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="target">The target object.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, TTarget target, Action<MapperContext> f)
{
var context = new MapperContext(this);
f(context);
return Map(source, target, context);
}
/// <summary>
/// Maps a source object to an existing target object.
/// </summary>
/// <typeparam name="TSource">The source type.</typeparam>
/// <typeparam name="TTarget">The target type.</typeparam>
/// <param name="source">The source object.</param>
/// <param name="target">The target object.</param>
/// <param name="context">A mapper context.</param>
/// <returns>The target object.</returns>
public TTarget Map<TSource, TTarget>(TSource source, TTarget target, MapperContext context)
{
var sourceType = typeof(TSource);
var targetType = typeof(TTarget);
var map = GetMap(sourceType, targetType);
// if there is a direct map, map
if (map != null)
{
map(source, target, context);
return target;
}
// we cannot really map to an existing enumerable - give up
throw new InvalidOperationException($"Don't know how to map {typeof(TSource).FullName} to {typeof(TTarget).FullName}.");
}
private Func<object, MapperContext, object> GetCtor(Type sourceType, Type targetType)
{
if (_ctors.TryGetValue(sourceType, out var sourceCtor) && sourceCtor.TryGetValue(targetType, out var ctor))
return ctor;
ctor = null;
foreach (var (stype, sctors) in _ctors)
{
if (!stype.IsAssignableFrom(sourceType)) continue;
if (!sctors.TryGetValue(targetType, out ctor)) continue;
sourceCtor = sctors;
break;
}
if (ctor == null) return null;
_ctors[sourceType] = sourceCtor;
return ctor;
}
private Action<object, object, MapperContext> GetMap(Type sourceType, Type targetType)
{
if (_maps.TryGetValue(sourceType, out var sourceMap) && sourceMap.TryGetValue(targetType, out var map))
return map;
map = null;
foreach (var (stype, smap) in _maps)
{
if (!stype.IsAssignableFrom(sourceType)) continue;
// TODO: consider looking for assignable types for target too?
if (!smap.TryGetValue(targetType, out map)) continue;
sourceMap = smap;
break;
}
if (map == null) return null;
_maps[sourceType] = sourceMap;
return map;
}
private static bool IsEnumerableOrArrayOfType(Type type)
{
if (type.IsArray && type.GetArrayRank() == 1) return true;
if (type.IsGenericType && type.GenericTypeArguments.Length == 1) return true;
return false;
}
private static Type GetEnumerableOrArrayTypeArgument(Type type)
{
if (type.IsArray) return type.GetElementType();
if (type.IsGenericType) return type.GenericTypeArguments[0];
throw new Exception("panic");
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
{
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, Action<MapperContext> f)
{
var context = new MapperContext(this);
f(context);
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <param name="context">A mapper context.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, MapperContext context)
{
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
}
#endregion
}
}

View File

@@ -83,17 +83,25 @@ namespace Umbraco.Core.Migrations.Expressions.Create
}
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey()
public ICreateConstraintOnTableBuilder PrimaryKey() => PrimaryKey(true);
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(bool clustered)
{
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
expression.Constraint.IsPrimaryKeyClustered = clustered;
return new CreateConstraintBuilder(expression);
}
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName)
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName) => PrimaryKey(primaryKeyName, true);
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered)
{
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
expression.Constraint.ConstraintName = primaryKeyName;
expression.Constraint.IsPrimaryKeyClustered = clustered;
return new CreateConstraintBuilder(expression);
}

View File

@@ -19,7 +19,7 @@ namespace Umbraco.Core.Migrations.Expressions.Create.Expressions
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
if (Constraint.IsPrimaryKeyConstraint && SqlSyntax.SupportsClustered())
constraintType += " CLUSTERED";
constraintType += Constraint.IsPrimaryKeyClustered ? " CLUSTERED" : " NONCLUSTERED";
if (Constraint.IsNonUniqueConstraint)
constraintType = string.Empty;

View File

@@ -68,6 +68,16 @@ namespace Umbraco.Core.Migrations.Expressions.Create
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName);
/// <summary>
/// Builds a Create Primary Key expression.
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(bool clustered);
/// <summary>
/// Builds a Create Primary Key expression.
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered);
/// <summary>
/// Builds a Create Unique Constraint expression.
/// </summary>

View File

@@ -226,6 +226,8 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
}

View File

@@ -47,7 +47,7 @@ namespace Umbraco.Core.Migrations.Install
typeof (LogDto),
typeof (MacroDto),
typeof (MacroPropertyDto),
typeof (MemberTypeDto),
typeof (MemberPropertyTypeDto),
typeof (MemberDto),
typeof (Member2MemberGroupDto),
typeof (PropertyTypeGroupDto),

View File

@@ -5,6 +5,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
namespace Umbraco.Core.Migrations.Upgrade
{
@@ -137,6 +138,8 @@ namespace Umbraco.Core.Migrations.Upgrade
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
//FINAL
@@ -167,7 +170,7 @@ namespace Umbraco.Core.Migrations.Upgrade
From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
// 7.14.0 has migrations, handle it...
// clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
// clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),

View File

@@ -13,8 +13,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.MemberType) && x.ColumnName.InvariantEquals("isSensitive")) == false)
AddColumn<MemberTypeDto>("isSensitive");
if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.MemberPropertyType) && x.ColumnName.InvariantEquals("isSensitive")) == false)
AddColumn<MemberPropertyTypeDto>("isSensitive");
}
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_1
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}

View File

@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Composing;
using Umbraco.Core.Exceptions;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
@@ -170,23 +166,23 @@ namespace Umbraco.Core.Models
/// Sets the publishing values for names and properties.
/// </summary>
/// <param name="content"></param>
/// <param name="culture"></param>
/// <param name="impact"></param>
/// <returns>A value indicating whether it was possible to publish the names and values for the specified
/// culture(s). The method may fail if required names are not set, but it does NOT validate property data</returns>
public static bool PublishCulture(this IContent content, string culture = "*")
public static bool PublishCulture(this IContent content, CultureImpact impact)
{
culture = culture.NullOrWhiteSpaceAsNull();
if (impact == null) throw new ArgumentNullException(nameof(impact));
// the variation should be supported by the content type properties
// if the content type is invariant, only '*' and 'null' is ok
// if the content type varies, everything is ok because some properties may be invariant
if (!content.ContentType.SupportsPropertyVariation(culture, "*", true))
throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\".");
if (!content.ContentType.SupportsPropertyVariation(impact.Culture, "*", true))
throw new NotSupportedException($"Culture \"{impact.Culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\".");
var alsoInvariant = false;
if (culture == "*") // all cultures
// set names
if (impact.ImpactsAllCultures)
{
foreach (var c in content.AvailableCultures)
foreach (var c in content.AvailableCultures) // does NOT contain the invariant culture
{
var name = content.GetCultureName(c);
if (string.IsNullOrWhiteSpace(name))
@@ -194,26 +190,31 @@ namespace Umbraco.Core.Models
content.SetPublishInfo(c, name, DateTime.Now);
}
}
else if (culture == null) // invariant culture
else if (impact.ImpactsOnlyInvariantCulture)
{
if (string.IsNullOrWhiteSpace(content.Name))
return false;
// PublishName set by repository - nothing to do here
}
else // one single culture
else if (impact.ImpactsExplicitCulture)
{
var name = content.GetCultureName(culture);
var name = content.GetCultureName(impact.Culture);
if (string.IsNullOrWhiteSpace(name))
return false;
content.SetPublishInfo(culture, name, DateTime.Now);
alsoInvariant = true; // we also want to publish invariant values
content.SetPublishInfo(impact.Culture, name, DateTime.Now);
}
// property.PublishValues only publishes what is valid, variation-wise
// set values
// property.PublishValues only publishes what is valid, variation-wise,
// but accepts any culture arg: null, all, specific
foreach (var property in content.Properties)
{
property.PublishValues(culture);
if (alsoInvariant)
// for the specified culture (null or all or specific)
property.PublishValues(impact.Culture);
// maybe the specified culture did not impact the invariant culture, so PublishValues
// above would skip it, yet it *also* impacts invariant properties
if (impact.ImpactsAlsoInvariantProperties)
property.PublishValues(null);
}

View File

@@ -95,6 +95,21 @@ namespace Umbraco.Core.Models
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//enable this to detect duplicate property aliases. We do want this, however making this change in a
//patch release might be a little dangerous
////detect if there are any duplicate aliases - this cannot be allowed
//if (e.Action == NotifyCollectionChangedAction.Add
// || e.Action == NotifyCollectionChangedAction.Replace)
//{
// var allAliases = _noGroupPropertyTypes.Concat(PropertyGroups.SelectMany(x => x.PropertyTypes)).Select(x => x.Alias);
// if (allAliases.HasDuplicates(false))
// {
// var newAliases = string.Join(", ", e.NewItems.Cast<PropertyType>().Select(x => x.Alias));
// throw new InvalidOperationException($"Other property types already exist with the aliases: {newAliases}");
// }
//}
OnPropertyChanged(nameof(PropertyTypes));
}
@@ -210,9 +225,7 @@ namespace Umbraco.Core.Models
return Variations.ValidateVariation(culture, segment, false, true, false);
}
/// <summary>
/// List of PropertyGroups available on this ContentType
/// </summary>
/// <inheritdoc />
/// <remarks>
/// <para>A PropertyGroup corresponds to a Tab in the UI</para>
/// <para>Marked DoNotClone because we will manually deal with cloning and the event handlers</para>
@@ -230,9 +243,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets all property types, across all property groups.
/// </summary>
/// <inheritdoc />
[IgnoreDataMember]
[DoNotClone]
public IEnumerable<PropertyType> PropertyTypes
@@ -243,12 +254,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets the property types that are not in a group.
/// </summary>
/// <remarks>
/// Marked DoNotClone because we will manually deal with cloning and the event handlers
/// </remarks>
/// <inheritdoc />
[DoNotClone]
public IEnumerable<PropertyType> NoGroupPropertyTypes
{
@@ -397,15 +403,16 @@ namespace Umbraco.Core.Models
var group = PropertyGroups[propertyGroupName];
if (group == null) return;
// re-assign the group's properties to no group
// first remove the group
PropertyGroups.RemoveItem(propertyGroupName);
// Then re-assign the group's properties to no group
foreach (var property in group.PropertyTypes)
{
property.PropertyGroupId = null;
_noGroupPropertyTypes.Add(property);
}
// actually remove the group
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(nameof(PropertyGroups));
}

View File

@@ -43,9 +43,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets the property groups for the entire composition.
/// </summary>
/// <inheritdoc />
[IgnoreDataMember]
public IEnumerable<PropertyGroup> CompositionPropertyGroups
{
@@ -76,9 +74,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets the property types for the entire composition.
/// </summary>
/// <inheritdoc />
[IgnoreDataMember]
public IEnumerable<PropertyType> CompositionPropertyTypes
{

View File

@@ -0,0 +1,257 @@
using System;
using System.Linq;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents the impact of a culture set.
/// </summary>
/// <remarks>
/// <para>A set of cultures can be either all cultures (including the invariant culture), or
/// the invariant culture, or a specific culture.</para>
/// </remarks>
internal class CultureImpact
{
/// <summary>
/// Utility method to return the culture used for invariant property errors based on what cultures are being actively saved,
/// the default culture and the state of the current content item
/// </summary>
/// <param name="content"></param>
/// <param name="savingCultures"></param>
/// <param name="defaultCulture"></param>
/// <returns></returns>
public static string GetCultureForInvariantErrors(IContent content, string[] savingCultures, string defaultCulture)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (savingCultures == null) throw new ArgumentNullException(nameof(savingCultures));
if (savingCultures.Length == 0) throw new ArgumentException(nameof(savingCultures));
var cultureForInvariantErrors = savingCultures.Any(x => x.InvariantEquals(defaultCulture))
//the default culture is being flagged for saving so use it
? defaultCulture
//If the content has no published version, we need to affiliate validation with the first variant being saved.
//If the content has a published version we will not affiliate the validation with any culture (null)
: !content.Published ? savingCultures[0] : null;
return cultureForInvariantErrors;
}
/// <summary>
/// Initializes a new instance of the <see cref="CultureImpact"/> class.
/// </summary>
/// <param name="culture">The culture code.</param>
/// <param name="isDefault">A value indicating whether the culture is the default culture.</param>
private CultureImpact(string culture, bool isDefault = false)
{
if (culture != null && culture.IsNullOrWhiteSpace())
throw new ArgumentException("Culture \"\" is not valid here.");
Culture = culture;
if ((culture == null || culture == "*") && isDefault)
throw new ArgumentException("The invariant or 'all' culture can not be the default culture.");
ImpactsOnlyDefaultCulture = isDefault;
}
/// <summary>
/// Gets the impact of 'all' cultures (including the invariant culture).
/// </summary>
public static CultureImpact All { get; } = new CultureImpact("*");
/// <summary>
/// Gets the impact of the invariant culture.
/// </summary>
public static CultureImpact Invariant { get; } = new CultureImpact(null);
/// <summary>
/// Creates an impact instance representing the impact of a specific culture.
/// </summary>
/// <param name="culture">The culture code.</param>
/// <param name="isDefault">A value indicating whether the culture is the default culture.</param>
public static CultureImpact Explicit(string culture, bool isDefault)
{
if (culture == null)
throw new ArgumentException("Culture <null> is not explicit.");
if (culture.IsNullOrWhiteSpace())
throw new ArgumentException("Culture \"\" is not explicit.");
if (culture == "*")
throw new ArgumentException("Culture \"*\" is not explicit.");
return new CultureImpact(culture, isDefault);
}
/// <summary>
/// Creates an impact instance representing the impact of a culture set,
/// in the context of a content item variation.
/// </summary>
/// <param name="culture">The culture code.</param>
/// <param name="isDefault">A value indicating whether the culture is the default culture.</param>
/// <param name="content">The content item.</param>
/// <remarks>
/// <para>Validates that the culture is compatible with the variation.</para>
/// </remarks>
public static CultureImpact Create(string culture, bool isDefault, IContent content)
{
// throws if not successful
TryCreate(culture, isDefault, content.ContentType.Variations, true, out var impact);
return impact;
}
/// <summary>
/// Tries to create an impact instance representing the impact of a culture set,
/// in the context of a content item variation.
/// </summary>
/// <param name="culture">The culture code.</param>
/// <param name="isDefault">A value indicating whether the culture is the default culture.</param>
/// <param name="variation">A content variation.</param>
/// <param name="throwOnFail">A value indicating whether to throw if the impact cannot be created.</param>
/// <param name="impact">The impact if it could be created, otherwise null.</param>
/// <returns>A value indicating whether the impact could be created.</returns>
/// <remarks>
/// <para>Validates that the culture is compatible with the variation.</para>
/// </remarks>
internal static bool TryCreate(string culture, bool isDefault, ContentVariation variation, bool throwOnFail, out CultureImpact impact)
{
impact = null;
// if culture is invariant...
if (culture == null)
{
// ... then variation must not vary by culture ...
if (variation.VariesByCulture())
{
if (throwOnFail)
throw new InvalidOperationException("The invariant culture is not compatible with a varying variation.");
return false;
}
// ... and it cannot be default
if (isDefault)
{
if (throwOnFail)
throw new InvalidOperationException("The invariant culture can not be the default culture.");
return false;
}
impact = Invariant;
return true;
}
// if culture is 'all'...
if (culture == "*")
{
// ... it cannot be default
if (isDefault)
{
if (throwOnFail)
throw new InvalidOperationException("The 'all' culture can not be the default culture.");
return false;
}
// if variation does not vary by culture, then impact is invariant
impact = variation.VariesByCulture() ? All : Invariant;
return true;
}
// neither null nor "*" - cannot be the empty string
if (culture.IsNullOrWhiteSpace())
{
if (throwOnFail)
throw new ArgumentException("Cannot be the empty string.", nameof(culture));
return false;
}
// if culture is specific, then variation must vary
if (!variation.VariesByCulture())
{
if (throwOnFail)
throw new InvalidOperationException($"The variant culture {culture} is not compatible with an invariant variation.");
return false;
}
// return specific impact
impact = new CultureImpact(culture, isDefault);
return true;
}
/// <summary>
/// Gets the culture code.
/// </summary>
/// <remarks>
/// <para>Can be null (invariant) or * (all cultures) or a specific culture code.</para>
/// </remarks>
public string Culture { get; }
/// <summary>
/// Gets a value indicating whether this impact impacts all cultures, including,
/// indirectly, the invariant culture.
/// </summary>
public bool ImpactsAllCultures => Culture == "*";
/// <summary>
/// Gets a value indicating whether this impact impacts only the invariant culture,
/// directly, not because all cultures are impacted.
/// </summary>
public bool ImpactsOnlyInvariantCulture => Culture == null;
/// <summary>
/// Gets a value indicating whether this impact impacts an implicit culture.
/// </summary>
/// <remarks>And then it does not impact the invariant culture. The impacted
/// explicit culture could be the default culture.</remarks>
public bool ImpactsExplicitCulture => Culture != null && Culture != "*";
/// <summary>
/// Gets a value indicating whether this impact impacts the default culture, directly,
/// not because all cultures are impacted.
/// </summary>
public bool ImpactsOnlyDefaultCulture {get; }
/// <summary>
/// Gets a value indicating whether this impact impacts the invariant properties, either
/// directly, or because all cultures are impacted, or because the default culture is impacted.
/// </summary>
public bool ImpactsInvariantProperties => Culture == null || Culture == "*" || ImpactsOnlyDefaultCulture;
/// <summary>
/// Gets a value indicating whether this also impact impacts the invariant properties,
/// even though it does not impact the invariant culture, neither directly (ImpactsInvariantCulture)
/// nor indirectly (ImpactsAllCultures).
/// </summary>
public bool ImpactsAlsoInvariantProperties => !ImpactsOnlyInvariantCulture &&
!ImpactsAllCultures &&
ImpactsOnlyDefaultCulture;
public Behavior CultureBehavior
{
get
{
//null can only be invariant
if (Culture == null) return Behavior.InvariantCulture | Behavior.InvariantProperties;
// * is All which means its also invariant properties since this will include the default language
if (Culture == "*") return (Behavior.AllCultures | Behavior.InvariantProperties);
//else it's explicit
var result = Behavior.ExplicitCulture;
//if the explicit culture is the default, then the behavior is also InvariantProperties
if (ImpactsOnlyDefaultCulture)
result |= Behavior.InvariantProperties;
return result;
}
}
[Flags]
public enum Behavior : byte
{
AllCultures = 1,
InvariantCulture = 2,
ExplicitCulture = 4,
InvariantProperties = 8
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Umbraco.Core.Models
/// * when the setter performs additional required logic other than just setting the underlying field
///
/// </remarks>
internal class DoNotCloneAttribute : Attribute
public class DoNotCloneAttribute : Attribute
{
}

View File

@@ -96,17 +96,17 @@ namespace Umbraco.Core.Models
IEnumerable<ContentTypeSort> AllowedContentTypes { get; set; }
/// <summary>
/// Gets or Sets a collection of Property Groups
/// Gets or sets the local property groups.
/// </summary>
PropertyGroupCollection PropertyGroups { get; set; }
/// <summary>
/// Gets all property types, across all property groups.
/// Gets all local property types belonging to a group, across all local property groups.
/// </summary>
IEnumerable<PropertyType> PropertyTypes { get; }
/// <summary>
/// Gets or sets the property types that are not in a group.
/// Gets or sets the local property types that do not belong to a group.
/// </summary>
IEnumerable<PropertyType> NoGroupPropertyTypes { get; set; }

View File

@@ -41,7 +41,7 @@ namespace Umbraco.Core.Models.Identity
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(username));
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture));
var user = new BackOfficeIdentityUser();
var user = new BackOfficeIdentityUser(Array.Empty<IReadOnlyUserGroup>());
user.DisableChangeTracking();
user._userName = username;
user._email = email;
@@ -54,16 +54,19 @@ namespace Umbraco.Core.Models.Identity
return user;
}
private BackOfficeIdentityUser()
private BackOfficeIdentityUser(IReadOnlyUserGroup[] groups)
{
_startMediaIds = new int[] { };
_startContentIds = new int[] { };
_groups = new IReadOnlyUserGroup[] { };
_allowedSections = new string[] { };
_startMediaIds = Array.Empty<int>();
_startContentIds = Array.Empty<int>();
_allowedSections = Array.Empty<string>();
_culture = Current.Configs.Global().DefaultUILanguage; // TODO: inject
_groups = new IReadOnlyUserGroup[0];
// must initialize before setting groups
_roles = new ObservableCollection<IdentityUserRole<string>>();
_roles.CollectionChanged += _roles_CollectionChanged;
// use the property setters - they do more than just setting a field
Groups = groups;
}
/// <summary>
@@ -72,19 +75,10 @@ namespace Umbraco.Core.Models.Identity
/// <param name="userId"></param>
/// <param name="groups"></param>
public BackOfficeIdentityUser(int userId, IEnumerable<IReadOnlyUserGroup> groups)
: this(groups.ToArray())
{
_startMediaIds = new int[] { };
_startContentIds = new int[] { };
_groups = new IReadOnlyUserGroup[] { };
_allowedSections = new string[] { };
_culture = Current.Configs.Global().DefaultUILanguage; // TODO: inject
_groups = groups.ToArray();
_roles = new ObservableCollection<IdentityUserRole<string>>(_groups.Select(x => new IdentityUserRole<string>
{
RoleId = x.Alias,
UserId = userId.ToString()
}));
_roles.CollectionChanged += _roles_CollectionChanged;
// use the property setters - they do more than just setting a field
Id = userId;
}
/// <summary>
@@ -226,6 +220,8 @@ namespace Umbraco.Core.Models.Identity
//so they recalculate
_allowedSections = null;
_groups = value;
//now clear all roles and re-add them
_roles.CollectionChanged -= _roles_CollectionChanged;
_roles.Clear();

View File

@@ -0,0 +1,80 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models.Identity
{
public class IdentityMapDefinition : IMapDefinition
{
private readonly ILocalizedTextService _textService;
private readonly IEntityService _entityService;
private readonly IGlobalSettings _globalSettings;
public IdentityMapDefinition(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings)
{
_textService = textService;
_entityService = entityService;
_globalSettings = globalSettings;
}
public void DefineMaps(UmbracoMapper mapper)
{
mapper.Define<IUser, BackOfficeIdentityUser>(
(source, context) =>
{
var target = new BackOfficeIdentityUser(source.Id, source.Groups);
target.DisableChangeTracking();
return target;
},
(source, target, context) =>
{
Map(source, target);
target.ResetDirtyProperties(true);
target.EnableChangeTracking();
});
}
// Umbraco.Code.MapAll -Id -Groups -LockoutEnabled -PhoneNumber -PhoneNumberConfirmed -TwoFactorEnabled
private void Map(IUser source, BackOfficeIdentityUser target)
{
// well, the ctor has been fixed
/*
// these two are already set in ctor but BackOfficeIdentityUser ctor is CompletelyBroken
target.Id = source.Id;
target.Groups = source.Groups.ToArray();
*/
target.CalculatedMediaStartNodeIds = source.CalculateMediaStartNodeIds(_entityService);
target.CalculatedContentStartNodeIds = source.CalculateContentStartNodeIds(_entityService);
target.Email = source.Email;
target.UserName = source.Username;
target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate.ToUniversalTime();
target.LastLoginDateUtc = source.LastLoginDate.ToUniversalTime();
target.EmailConfirmed = source.EmailConfirmedDate.HasValue;
target.Name = source.Name;
target.AccessFailedCount = source.FailedPasswordAttempts;
target.PasswordHash = GetPasswordHash(source.RawPasswordValue);
target.StartContentIds = source.StartContentIds;
target.StartMediaIds = source.StartMediaIds;
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString(); // project CultureInfo to string
target.IsApproved = source.IsApproved;
target.SecurityStamp = source.SecurityStamp;
target.LockoutEndDateUtc = source.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?) null;
// this was in AutoMapper but does not have a setter anyways
//target.AllowedSections = source.AllowedSections.ToArray(),
// these were marked as ignored for AutoMapper but don't have a setter anyways
//target.Logins =;
//target.Claims =;
//target.Roles =;
}
private static string GetPasswordHash(string storedPass)
{
return storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass;
}
}
}

View File

@@ -1,58 +0,0 @@
using System;
using System.Linq;
using AutoMapper;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models.Identity
{
public class IdentityMapperProfile : Profile
{
public IdentityMapperProfile(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings)
{
CreateMap<IUser, BackOfficeIdentityUser>()
.BeforeMap((src, dest) =>
{
dest.DisableChangeTracking();
})
.ConstructUsing(src => new BackOfficeIdentityUser(src.Id, src.Groups))
.ForMember(dest => dest.LastLoginDateUtc, opt => opt.MapFrom(src => src.LastLoginDate.ToUniversalTime()))
.ForMember(user => user.LastPasswordChangeDateUtc, expression => expression.MapFrom(user => user.LastPasswordChangeDate.ToUniversalTime()))
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
.ForMember(dest => dest.EmailConfirmed, opt => opt.MapFrom(src => src.EmailConfirmedDate.HasValue))
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.LockoutEndDateUtc, opt => opt.MapFrom(src => src.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?) null))
.ForMember(dest => dest.IsApproved, opt => opt.MapFrom(src => src.IsApproved))
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Username))
.ForMember(dest => dest.PasswordHash, opt => opt.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
.ForMember(dest => dest.Culture, opt => opt.MapFrom(src => src.GetUserCulture(textService, globalSettings)))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
.ForMember(dest => dest.StartMediaIds, opt => opt.MapFrom(src => src.StartMediaIds))
.ForMember(dest => dest.StartContentIds, opt => opt.MapFrom(src => src.StartContentIds))
.ForMember(dest => dest.AccessFailedCount, opt => opt.MapFrom(src => src.FailedPasswordAttempts))
.ForMember(dest => dest.CalculatedContentStartNodeIds, opt => opt.MapFrom(src => src.CalculateContentStartNodeIds(entityService)))
.ForMember(dest => dest.CalculatedMediaStartNodeIds, opt => opt.MapFrom(src => src.CalculateMediaStartNodeIds(entityService)))
.ForMember(dest => dest.AllowedSections, opt => opt.MapFrom(src => src.AllowedSections.ToArray()))
.ForMember(dest => dest.LockoutEnabled, opt => opt.Ignore())
.ForMember(dest => dest.Logins, opt => opt.Ignore())
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore())
.ForMember(dest => dest.PhoneNumber, opt => opt.Ignore())
.ForMember(dest => dest.PhoneNumberConfirmed, opt => opt.Ignore())
.ForMember(dest => dest.TwoFactorEnabled, opt => opt.Ignore())
.ForMember(dest => dest.Roles, opt => opt.Ignore())
.ForMember(dest => dest.Claims, opt => opt.Ignore())
.AfterMap((src, dest) =>
{
dest.ResetDirtyProperties(true);
dest.EnableChangeTracking();
});
}
private static string GetPasswordHash(string storedPass)
{
return storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
{
private readonly object _addLocker = new object();
internal Action OnAdd;
internal Func<Property, bool> AdditionValidator { get; set; }
/// <summary>
@@ -49,10 +49,12 @@ namespace Umbraco.Core.Models
/// </summary>
internal void Reset(IEnumerable<Property> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
@@ -60,8 +62,9 @@ namespace Umbraco.Core.Models
/// </summary>
protected override void SetItem(int index, Property property)
{
var oldItem = index >= 0 ? this[index] : property;
base.SetItem(index, property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, property, oldItem));
}
/// <summary>
@@ -120,10 +123,8 @@ namespace Umbraco.Core.Models
}
}
//collection events will be raised in InsertItem with Add
base.Add(property);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property));
}
}

View File

@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: this doesn't seem to be used anywhere
internal Action OnAdd;
internal PropertyGroupCollection()
{ }
@@ -37,16 +34,19 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyGroup> groups)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var group in groups)
Add(group);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void SetItem(int index, PropertyGroup item)
{
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
}
protected override void RemoveItem(int index)
@@ -84,6 +84,7 @@ namespace Umbraco.Core.Models
if (keyExists)
throw new Exception($"Naming conflict: Changing the name of PropertyGroup '{item.Name}' would result in duplicates");
//collection events will be raised in SetItem
SetItem(IndexOfKey(item.Id), item);
return;
}
@@ -96,16 +97,14 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
}
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{

View File

@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: This doesn't seem to be used
[IgnoreDataMember]
internal Action OnAdd;
internal PropertyTypeCollection(bool supportsPublishing)
{
@@ -43,36 +40,44 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyType> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
Add(property);
}
protected override void SetItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void RemoveItem(int index)
{
var removed = this[index];
base.RemoveItem(index);
removed.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void InsertItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.InsertItem(index, item);
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void ClearItems()
{
base.ClearItems();
foreach (var item in this)
item.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
@@ -91,6 +96,7 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
@@ -103,10 +109,8 @@ namespace Umbraco.Core.Models
item.SortOrder = this.Max(x => x.SortOrder) + 1;
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{
@@ -115,6 +119,17 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Occurs when a property changes on a PropertyType that exists in this collection
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var propType = (PropertyType)sender;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, propType, propType));
}
/// <summary>
/// Determines whether this collection contains a <see cref="Property"/> whose alias matches the specified PropertyType.
/// </summary>

View File

@@ -11,14 +11,14 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Initializes a new instance of the <see cref="PublishedCultureInfo"/> class.
/// </summary>
public PublishedCultureInfo(string culture, string name, DateTime date)
public PublishedCultureInfo(string culture, string name, string urlSegment, DateTime date)
{
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentNullOrEmptyException(nameof(culture));
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
Culture = culture;
Name = name;
UrlSegment = name.ToUrlSegment(culture);
UrlSegment = urlSegment;
Date = date;
}

View File

@@ -151,22 +151,22 @@ namespace Umbraco.Core.Models
internal static bool HasContentRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasContentBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContent.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContentString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMedia.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMediaString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService)
@@ -327,7 +327,7 @@ namespace Umbraco.Core.Models
? entityService.GetAllPaths(objectType, asn).ToDictionary(x => x.Id, x => x.Path)
: new Dictionary<int, string>();
paths[Constants.System.Root] = Constants.System.Root.ToString(); // entityService does not get that one
paths[Constants.System.Root] = Constants.System.RootString; // entityService does not get that one
var binPath = GetBinPath(objectType);

View File

@@ -57,7 +57,7 @@ namespace Umbraco.Core
public const string MacroProperty = /*TableNamePrefix*/ "cms" + "MacroProperty";
public const string Member = /*TableNamePrefix*/ "cms" + "Member";
public const string MemberType = /*TableNamePrefix*/ "cms" + "MemberType";
public const string MemberPropertyType = /*TableNamePrefix*/ "cms" + "MemberType";
public const string Member2MemberGroup = /*TableNamePrefix*/ "cms" + "Member2MemberGroup";
public const string Access = TableNamePrefix + "Access";
@@ -69,7 +69,7 @@ namespace Umbraco.Core
public const string Tag = /*TableNamePrefix*/ "cms" + "Tags";
public const string TagRelationship = /*TableNamePrefix*/ "cms" + "TagRelationship";
public const string KeyValue = TableNamePrefix + "KeyValue";
public const string AuditEntry = TableNamePrefix + "Audit";

View File

@@ -18,5 +18,6 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
public string ConstraintName { get; set; }
public string TableName { get; set; }
public ICollection<string> Columns = new HashSet<string>();
public bool IsPrimaryKeyClustered { get; set; }
}
}

View File

@@ -54,6 +54,7 @@ namespace Umbraco.Core.Persistence.Dtos
public byte Variations { get; set; }
[ResultColumn]
[Reference(ReferenceType.OneToOne, ColumnName = "NodeId")]
public NodeDto NodeDto { get; set; }
}
}

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Dtos
public string Configuration { get; set; }
[ResultColumn]
[Reference(ReferenceType.OneToOne, ColumnName = "DataTypeId")]
[Reference(ReferenceType.OneToOne, ColumnName = "NodeId")]
public NodeDto NodeDto { get; set; }
}
}

View File

@@ -3,10 +3,10 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Persistence.Dtos
{
[TableName(Constants.DatabaseSchema.Tables.MemberType)]
[TableName(Constants.DatabaseSchema.Tables.MemberPropertyType)]
[PrimaryKey("pk")]
[ExplicitColumns]
internal class MemberTypeDto
internal class MemberPropertyTypeDto
{
[Column("pk")]
[PrimaryKeyColumn]

View File

@@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using NPoco;
namespace Umbraco.Core.Persistence.Dtos
{
[TableName(Constants.DatabaseSchema.Tables.Node)]
[PrimaryKey("id")]
[ExplicitColumns]
internal class MemberTypeReadOnlyDto
{
/* from umbracoNode */
[Column("id")]
public int NodeId { get; set; }
[Column("trashed")]
public bool Trashed { get; set; }
[Column("parentID")]
public int ParentId { get; set; }
[Column("nodeUser")]
public int? UserId { get; set; }
[Column("level")]
public short Level { get; set; }
[Column("path")]
public string Path { get; set; }
[Column("sortOrder")]
public int SortOrder { get; set; }
[Column("uniqueID")]
public Guid? UniqueId { get; set; }
[Column("text")]
public string Text { get; set; }
[Column("nodeObjectType")]
public Guid? NodeObjectType { get; set; }
[Column("createDate")]
public DateTime CreateDate { get; set; }
/* cmsContentType */
[Column("pk")]
public int PrimaryKey { get; set; }
[Column("alias")]
public string Alias { get; set; }
[Column("icon")]
public string Icon { get; set; }
[Column("thumbnail")]
public string Thumbnail { get; set; }
[Column("description")]
public string Description { get; set; }
[Column("isContainer")]
public bool IsContainer { get; set; }
[Column("allowAtRoot")]
public bool AllowAtRoot { get; set; }
/* PropertyTypes */
// TODO: Add PropertyTypeDto (+MemberTypeDto and DataTypeDto as one) ReadOnly list
[ResultColumn]
[Reference(ReferenceType.Many, ReferenceMemberName = "ContentTypeId")]
public List<PropertyTypeReadOnlyDto> PropertyTypes { get; set; }
/* PropertyTypeGroups */
// TODO: Add PropertyTypeGroupDto ReadOnly list
[ResultColumn]
[Reference(ReferenceType.Many, ReferenceMemberName = "ContentTypeNodeId")]
public List<PropertyTypeGroupReadOnlyDto> PropertyTypeGroups { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using NPoco;
namespace Umbraco.Core.Persistence.Dtos
{
// this is PropertyTypeDto + the special property type fields for members
// it is used for querying everything needed for a property type, at once
internal class PropertyTypeCommonDto : PropertyTypeDto
{
[Column("memberCanEdit")]
public bool CanEdit { get; set; }
[Column("viewOnProfile")]
public bool ViewOnProfile { get; set; }
[Column("isSensitive")]
public bool IsSensitive { get; set; }
}
}

View File

@@ -67,16 +67,28 @@ namespace Umbraco.Core.Persistence.Factories
public static IMemberType BuildMemberTypeEntity(ContentTypeDto dto)
{
throw new NotImplementedException();
var contentType = new MemberType(dto.NodeDto.ParentId);
try
{
contentType.DisableChangeTracking();
BuildCommonEntity(contentType, dto, false);
contentType.ResetDirtyProperties(false);
}
finally
{
contentType.EnableChangeTracking();
}
return contentType;
}
public static IEnumerable<MemberTypeDto> BuildMemberTypeDtos(IMemberType entity)
public static IEnumerable<MemberPropertyTypeDto> BuildMemberPropertyTypeDtos(IMemberType entity)
{
var memberType = entity as MemberType;
if (memberType == null || memberType.PropertyTypes.Any() == false)
return Enumerable.Empty<MemberTypeDto>();
return Enumerable.Empty<MemberPropertyTypeDto>();
var dtos = memberType.PropertyTypes.Select(x => new MemberTypeDto
var dtos = memberType.PropertyTypes.Select(x => new MemberPropertyTypeDto
{
NodeId = entity.Id,
PropertyTypeId = x.Id,
@@ -91,7 +103,7 @@ namespace Umbraco.Core.Persistence.Factories
#region Common
private static void BuildCommonEntity(ContentTypeBase entity, ContentTypeDto dto)
private static void BuildCommonEntity(ContentTypeBase entity, ContentTypeDto dto, bool setVariations = true)
{
entity.Id = dto.NodeDto.NodeId;
entity.Key = dto.NodeDto.UniqueId;
@@ -102,6 +114,7 @@ namespace Umbraco.Core.Persistence.Factories
entity.SortOrder = dto.NodeDto.SortOrder;
entity.Description = dto.Description;
entity.CreateDate = dto.NodeDto.CreateDate;
entity.UpdateDate = dto.NodeDto.CreateDate;
entity.Path = dto.NodeDto.Path;
entity.Level = dto.NodeDto.Level;
entity.CreatorId = dto.NodeDto.UserId ?? Constants.Security.UnknownUserId;
@@ -109,7 +122,9 @@ namespace Umbraco.Core.Persistence.Factories
entity.IsContainer = dto.IsContainer;
entity.IsElement = dto.IsElement;
entity.Trashed = dto.NodeDto.Trashed;
entity.Variations = (ContentVariation) dto.Variations;
if (setVariations)
entity.Variations = (ContentVariation) dto.Variations;
}
public static ContentTypeDto BuildContentTypeDto(IContentTypeBase entity)

View File

@@ -1,194 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Repositories.Implement;
namespace Umbraco.Core.Persistence.Factories
{
internal static class MemberTypeReadOnlyFactory
{
public static IMemberType BuildEntity(MemberTypeReadOnlyDto dto, out bool needsSaving)
{
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
needsSaving = false;
var memberType = new MemberType(dto.ParentId);
try
{
memberType.DisableChangeTracking();
memberType.Alias = dto.Alias;
memberType.AllowedAsRoot = dto.AllowAtRoot;
memberType.CreateDate = dto.CreateDate;
memberType.CreatorId = dto.UserId.HasValue ? dto.UserId.Value : 0;
memberType.Description = dto.Description;
memberType.Icon = dto.Icon;
memberType.Id = dto.NodeId;
memberType.IsContainer = dto.IsContainer;
memberType.Key = dto.UniqueId.Value;
memberType.Level = dto.Level;
memberType.Name = dto.Text;
memberType.Path = dto.Path;
memberType.SortOrder = dto.SortOrder;
memberType.Thumbnail = dto.Thumbnail;
memberType.Trashed = dto.Trashed;
memberType.UpdateDate = dto.CreateDate;
memberType.AllowedContentTypes = Enumerable.Empty<ContentTypeSort>();
var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType, standardPropertyTypes);
memberType.PropertyGroups = propertyTypeGroupCollection;
var propertyTypes = GetPropertyTypes(dto, memberType, standardPropertyTypes);
//By Convention we add 9 standard PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
foreach (var standardPropertyType in standardPropertyTypes)
{
if (dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue;
// beware!
// means that we can return a memberType "from database" that has some property types
// that do *not* come from the database and therefore are incomplete eg have no key,
// no id, no dataTypeDefinitionId - ouch! - better notify caller of the situation
needsSaving = true;
//Add the standard PropertyType to the current list
propertyTypes.Add(standardPropertyType.Value);
//Internal dictionary for adding "MemberCanEdit", "VisibleOnProfile", "IsSensitive" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key,
new MemberTypePropertyProfileAccess(false, false, false));
}
memberType.NoGroupPropertyTypes = propertyTypes;
return memberType;
}
finally
{
memberType.EnableChangeTracking();
}
}
private static PropertyGroupCollection GetPropertyTypeGroupCollection(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
{
// see PropertyGroupFactory, repeating code here...
var propertyGroups = new PropertyGroupCollection();
foreach (var groupDto in dto.PropertyTypeGroups.Where(x => x.Id.HasValue))
{
var group = new PropertyGroup(MemberType.SupportsPublishingConst);
// if the group is defined on the current member type,
// assign its identifier, else it will be zero
if (groupDto.ContentTypeNodeId == memberType.Id)
{
// note: no idea why Id is nullable here, but better check
if (groupDto.Id.HasValue == false)
throw new Exception("GroupDto.Id has no value.");
group.Id = groupDto.Id.Value;
}
group.Key = groupDto.UniqueId;
group.Name = groupDto.Text;
group.SortOrder = groupDto.SortOrder;
group.PropertyTypes = new PropertyTypeCollection(MemberType.SupportsPublishingConst);
//Because we are likely to have a group with no PropertyTypes we need to ensure that these are excluded
var localGroupDto = groupDto;
var typeDtos = dto.PropertyTypes.Where(x => x.Id.HasValue && x.Id > 0 && x.PropertyTypeGroupId.HasValue && x.PropertyTypeGroupId.Value == localGroupDto.Id.Value);
foreach (var typeDto in typeDtos)
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit, typeDto.IsSensitive));
var tempGroupDto = groupDto;
//ensures that any built-in membership properties have their correct dbtype assigned no matter
//what the underlying data type is
var propDbType = MemberTypeRepository.GetDbTypeForBuiltInProperty(
typeDto.Alias,
typeDto.DbType.EnumParse<ValueStorageType>(true),
standardProps);
var propertyType = new PropertyType(
typeDto.PropertyEditorAlias,
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success,
typeDto.Alias)
{
DataTypeId = typeDto.DataTypeId,
Description = typeDto.Description,
Id = typeDto.Id.Value,
Name = typeDto.Name,
Mandatory = typeDto.Mandatory,
SortOrder = typeDto.SortOrder,
ValidationRegExp = typeDto.ValidationRegExp,
PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id.Value),
CreateDate = memberType.CreateDate,
UpdateDate = memberType.UpdateDate,
Key = typeDto.UniqueId
};
// reset dirty initial properties (U4-1946)
propertyType.ResetDirtyProperties(false);
group.PropertyTypes.Add(propertyType);
}
// reset dirty initial properties (U4-1946)
group.ResetDirtyProperties(false);
propertyGroups.Add(group);
}
return propertyGroups;
}
private static List<PropertyType> GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
{
//Find PropertyTypes that does not belong to a PropertyTypeGroup
var propertyTypes = new List<PropertyType>();
foreach (var typeDto in dto.PropertyTypes.Where(x => (x.PropertyTypeGroupId.HasValue == false || x.PropertyTypeGroupId.Value == 0) && x.Id.HasValue))
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit, typeDto.IsSensitive));
//ensures that any built-in membership properties have their correct dbtype assigned no matter
//what the underlying data type is
var propDbType = MemberTypeRepository.GetDbTypeForBuiltInProperty(
typeDto.Alias,
typeDto.DbType.EnumParse<ValueStorageType>(true),
standardProps);
var propertyType = new PropertyType(
typeDto.PropertyEditorAlias,
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success,
typeDto.Alias)
{
DataTypeId = typeDto.DataTypeId,
Description = typeDto.Description,
Id = typeDto.Id.Value,
Mandatory = typeDto.Mandatory,
Name = typeDto.Name,
SortOrder = typeDto.SortOrder,
ValidationRegExp = typeDto.ValidationRegExp,
PropertyGroupId = null,
CreateDate = dto.CreateDate,
UpdateDate = dto.CreateDate,
Key = typeDto.UniqueId
};
propertyTypes.Add(propertyType);
}
return propertyTypes;
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -7,18 +8,18 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(PublicAccessEntry))]
public sealed class AccessMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public AccessMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<PublicAccessEntry, AccessDto>(src => src.Key, dto => dto.Id);
CacheMap<PublicAccessEntry, AccessDto>(src => src.LoginNodeId, dto => dto.LoginNodeId);
CacheMap<PublicAccessEntry, AccessDto>(src => src.NoAccessNodeId, dto => dto.NoAccessNodeId);
CacheMap<PublicAccessEntry, AccessDto>(src => src.ProtectedNodeId, dto => dto.NodeId);
CacheMap<PublicAccessEntry, AccessDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<PublicAccessEntry, AccessDto>(src => src.UpdateDate, dto => dto.UpdateDate);
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.Key), nameof(AccessDto.Id));
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.LoginNodeId), nameof(AccessDto.LoginNodeId));
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.NoAccessNodeId), nameof(AccessDto.NoAccessNodeId));
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.ProtectedNodeId), nameof(AccessDto.NodeId));
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.CreateDate), nameof(AccessDto.CreateDate));
DefineMap<PublicAccessEntry, AccessDto>(nameof(PublicAccessEntry.UpdateDate), nameof(AccessDto.UpdateDate));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -11,21 +12,21 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(AuditEntry))]
public sealed class AuditEntryMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public AuditEntryMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.Id, dto => dto.Id);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingUserId, dto => dto.PerformingUserId);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingDetails, dto => dto.PerformingDetails);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingIp, dto => dto.PerformingIp);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventDateUtc, dto => dto.EventDateUtc);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.AffectedUserId, dto => dto.AffectedUserId);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.AffectedDetails, dto => dto.AffectedDetails);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventType, dto => dto.EventType);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventDetails, dto => dto.EventDetails);
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.Id), nameof(AuditEntryDto.Id));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.PerformingUserId), nameof(AuditEntryDto.PerformingUserId));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.PerformingDetails), nameof(AuditEntryDto.PerformingDetails));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.PerformingIp), nameof(AuditEntryDto.PerformingIp));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.EventDateUtc), nameof(AuditEntryDto.EventDateUtc));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.AffectedUserId), nameof(AuditEntryDto.AffectedUserId));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.AffectedDetails), nameof(AuditEntryDto.AffectedDetails));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.EventType), nameof(AuditEntryDto.EventType));
DefineMap<AuditEntry, AuditEntryDto>(nameof(AuditEntry.EventDetails), nameof(AuditEntryDto.EventDetails));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,17 +9,17 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IAuditItem))]
public sealed class AuditItemMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public AuditItemMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<AuditItem, LogDto>(src => src.Id, dto => dto.NodeId);
CacheMap<AuditItem, LogDto>(src => src.CreateDate, dto => dto.Datestamp);
CacheMap<AuditItem, LogDto>(src => src.UserId, dto => dto.UserId);
CacheMap<AuditItem, LogDto>(src => src.AuditType, dto => dto.Header);
CacheMap<AuditItem, LogDto>(src => src.Comment, dto => dto.Comment);
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Id), nameof(LogDto.NodeId));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.CreateDate), nameof(LogDto.Datestamp));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.UserId), nameof(LogDto.UserId));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.AuditType), nameof(LogDto.Header));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Comment), nameof(LogDto.Comment));
}
}
}

View File

@@ -1,69 +1,81 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
using NPoco;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Persistence.Mappers
{
public abstract class BaseMapper : IDiscoverable
public abstract class BaseMapper
{
protected BaseMapper()
// note: using a Lazy<ISqlContext> here because during installs, we are resolving the
// mappers way before we have a configured IUmbracoDatabaseFactory, ie way before we
// have an ISqlContext - this is some nasty temporal coupling which we might want to
// cleanup eventually.
private readonly Lazy<ISqlContext> _sqlContext;
private readonly object _definedLock = new object();
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> _maps;
private ISqlSyntaxProvider _sqlSyntax;
private bool _defined;
protected BaseMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
{
Build();
_sqlContext = sqlContext;
_maps = maps;
}
internal abstract ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache { get; }
protected abstract void DefineMaps();
private void Build()
internal string Map(string propertyName)
{
BuildMap();
}
protected abstract void BuildMap();
internal string Map(ISqlSyntaxProvider sqlSyntax, string propertyName, bool throws = false)
{
if (PropertyInfoCache.TryGetValue(propertyName, out var dtoTypeProperty))
return GetColumnName(sqlSyntax, dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
if (throws)
throw new InvalidOperationException("Could not get the value with the key " + propertyName + " from the property info cache, keys available: " + string.Join(", ", PropertyInfoCache.Keys));
return string.Empty;
}
internal void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
internal DtoMapModel ResolveMapping<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var source = ExpressionHelper.FindProperty(sourceMember);
var destination = (PropertyInfo) ExpressionHelper.FindProperty(destinationMember).Item1;
if (destination == null)
lock (_definedLock)
{
throw new InvalidOperationException("The 'destination' returned was null, cannot resolve the mapping");
if (!_defined)
{
var sqlContext = _sqlContext.Value;
if (sqlContext == null)
throw new InvalidOperationException("Could not get an ISqlContext.");
_sqlSyntax = sqlContext.SqlSyntax;
DefineMaps();
_defined = true;
}
}
return new DtoMapModel(typeof(TDestination), destination, source.Item1.Name);
if (!_maps.TryGetValue(GetType(), out var mapperMaps))
throw new InvalidOperationException($"No maps defined for mapper {GetType().FullName}.");
if (!mapperMaps.TryGetValue(propertyName, out var mappedName))
throw new InvalidOperationException($"No map defined by mapper {GetType().FullName} for property {propertyName}.");
return mappedName;
}
internal virtual string GetColumnName(ISqlSyntaxProvider sqlSyntax, Type dtoType, PropertyInfo dtoProperty)
protected void DefineMap<TSource, TTarget>(string sourceName, string targetName)
{
var tableNameAttribute = dtoType.FirstAttribute<TableNameAttribute>();
if (_sqlSyntax == null)
throw new InvalidOperationException("Do not define maps outside of DefineMaps.");
var targetType = typeof(TTarget);
// TODO ensure that sourceName is a valid sourceType property (but, slow?)
var tableNameAttribute = targetType.FirstAttribute<TableNameAttribute>();
if (tableNameAttribute == null) throw new InvalidOperationException($"Type {targetType.FullName} is not marked with a TableName attribute.");
var tableName = tableNameAttribute.Value;
var columnAttribute = dtoProperty.FirstAttribute<ColumnAttribute>();
var columnName = columnAttribute.Name;
// TODO maybe get all properties once and then index them
var targetProperty = targetType.GetProperty(targetName);
if (targetProperty == null) throw new InvalidOperationException($"Type {targetType.FullName} does not have a property named {targetName}.");
var columnAttribute = targetProperty.FirstAttribute<ColumnAttribute>();
if (columnAttribute == null) throw new InvalidOperationException($"Property {targetType.FullName}.{targetName} is not marked with a Column attribute.");
var columnMap = sqlSyntax.GetQuotedTableName(tableName) + "." + sqlSyntax.GetQuotedColumnName(columnName);
return columnMap;
var columnName = columnAttribute.Name;
var columnMap = _sqlSyntax.GetQuotedTableName(tableName) + "." + _sqlSyntax.GetQuotedColumnName(columnName);
var mapperMaps = _maps.GetOrAdd(GetType(), type => new ConcurrentDictionary<string, string>());
mapperMaps[sourceName] = columnMap;
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -11,20 +12,20 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Consent))]
public sealed class ConsentMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public ConsentMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Consent, ConsentDto>(entity => entity.Id, dto => dto.Id);
CacheMap<Consent, ConsentDto>(entity => entity.Current, dto => dto.Current);
CacheMap<Consent, ConsentDto>(entity => entity.CreateDate, dto => dto.CreateDate);
CacheMap<Consent, ConsentDto>(entity => entity.Source, dto => dto.Source);
CacheMap<Consent, ConsentDto>(entity => entity.Context, dto => dto.Context);
CacheMap<Consent, ConsentDto>(entity => entity.Action, dto => dto.Action);
CacheMap<Consent, ConsentDto>(entity => entity.State, dto => dto.State);
CacheMap<Consent, ConsentDto>(entity => entity.Comment, dto => dto.Comment);
DefineMap<Consent, ConsentDto>(nameof(Consent.Id), nameof(ConsentDto.Id));
DefineMap<Consent, ConsentDto>(nameof(Consent.Current), nameof(ConsentDto.Current));
DefineMap<Consent, ConsentDto>(nameof(Consent.CreateDate), nameof(ConsentDto.CreateDate));
DefineMap<Consent, ConsentDto>(nameof(Consent.Source), nameof(ConsentDto.Source));
DefineMap<Consent, ConsentDto>(nameof(Consent.Context), nameof(ConsentDto.Context));
DefineMap<Consent, ConsentDto>(nameof(Consent.Action), nameof(ConsentDto.Action));
DefineMap<Consent, ConsentDto>(nameof(Consent.State), nameof(ConsentDto.State));
DefineMap<Consent, ConsentDto>(nameof(Consent.Comment), nameof(ConsentDto.Comment));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,36 +13,34 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IContent))]
public sealed class ContentMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public ContentMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
DefineMap<Content, NodeDto>(nameof(Content.Id), nameof(NodeDto.NodeId));
DefineMap<Content, NodeDto>(nameof(Content.Key), nameof(NodeDto.UniqueId));
CacheMap<Content, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<Content, NodeDto>(src => src.Key, dto => dto.UniqueId);
DefineMap<Content, ContentVersionDto>(nameof(Content.VersionId), nameof(ContentVersionDto.Id));
DefineMap<Content, ContentVersionDto>(nameof(Content.Name), nameof(ContentVersionDto.Text));
CacheMap<Content, ContentVersionDto>(src => src.VersionId, dto => dto.Id);
CacheMap<Content, ContentVersionDto>(src => src.Name, dto => dto.Text);
DefineMap<Content, NodeDto>(nameof(Content.ParentId), nameof(NodeDto.ParentId));
DefineMap<Content, NodeDto>(nameof(Content.Level), nameof(NodeDto.Level));
DefineMap<Content, NodeDto>(nameof(Content.Path), nameof(NodeDto.Path));
DefineMap<Content, NodeDto>(nameof(Content.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<Content, NodeDto>(nameof(Content.Trashed), nameof(NodeDto.Trashed));
CacheMap<Content, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<Content, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<Content, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<Content, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<Content, NodeDto>(src => src.Trashed, dto => dto.Trashed);
DefineMap<Content, NodeDto>(nameof(Content.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<Content, NodeDto>(nameof(Content.CreatorId), nameof(NodeDto.UserId));
DefineMap<Content, ContentDto>(nameof(Content.ContentTypeId), nameof(ContentDto.ContentTypeId));
CacheMap<Content, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<Content, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<Content, ContentDto>(src => src.ContentTypeId, dto => dto.ContentTypeId);
DefineMap<Content, ContentVersionDto>(nameof(Content.UpdateDate), nameof(ContentVersionDto.VersionDate));
DefineMap<Content, DocumentDto>(nameof(Content.Published), nameof(DocumentDto.Published));
CacheMap<Content, ContentVersionDto>(src => src.UpdateDate, dto => dto.VersionDate);
CacheMap<Content, DocumentDto>(src => src.Published, dto => dto.Published);
//CacheMap<Content, DocumentDto>(src => src.Name, dto => dto.Alias);
//DefineMap<Content, DocumentDto>(nameof(Content.Name), nameof(DocumentDto.Alias));
//CacheMap<Content, DocumentDto>(src => src, dto => dto.Newest);
//CacheMap<Content, DocumentDto>(src => src.Template, dto => dto.TemplateId);
//DefineMap<Content, DocumentDto>(nameof(Content.Template), nameof(DocumentDto.TemplateId));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,31 +13,29 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IContentType))]
public sealed class ContentTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public ContentTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<ContentType, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<ContentType, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<ContentType, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<ContentType, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<ContentType, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<ContentType, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<ContentType, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<ContentType, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<ContentType, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<ContentType, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<ContentType, ContentTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<ContentType, ContentTypeDto>(src => src.AllowedAsRoot, dto => dto.AllowAtRoot);
CacheMap<ContentType, ContentTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<ContentType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
CacheMap<ContentType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
CacheMap<ContentType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
CacheMap<ContentType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
DefineMap<ContentType, NodeDto>(nameof(ContentType.Id), nameof(NodeDto.NodeId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Level), nameof(NodeDto.Level));
DefineMap<ContentType, NodeDto>(nameof(ContentType.ParentId), nameof(NodeDto.ParentId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Path), nameof(NodeDto.Path));
DefineMap<ContentType, NodeDto>(nameof(ContentType.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Name), nameof(NodeDto.Text));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Trashed), nameof(NodeDto.Trashed));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Key), nameof(NodeDto.UniqueId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.CreatorId), nameof(NodeDto.UserId));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Alias), nameof(ContentTypeDto.Alias));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.AllowedAsRoot), nameof(ContentTypeDto.AllowAtRoot));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Description), nameof(ContentTypeDto.Description));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Icon), nameof(ContentTypeDto.Icon));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.IsContainer), nameof(ContentTypeDto.IsContainer));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.IsElement), nameof(ContentTypeDto.IsElement));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Thumbnail), nameof(ContentTypeDto.Thumbnail));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,25 +13,24 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDataType))]
public sealed class DataTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public DataTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<DataType, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<DataType, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<DataType, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<DataType, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<DataType, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<DataType, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<DataType, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<DataType, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<DataType, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<DataType, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<DataType, DataTypeDto>(src => src.EditorAlias, dto => dto.EditorAlias);
CacheMap<DataType, DataTypeDto>(src => src.DatabaseType, dto => dto.DbType);
DefineMap<DataType, NodeDto>(nameof(DataType.Id), nameof(NodeDto.NodeId));
DefineMap<DataType, NodeDto>(nameof(DataType.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<DataType, NodeDto>(nameof(DataType.Level), nameof(NodeDto.Level));
DefineMap<DataType, NodeDto>(nameof(DataType.ParentId), nameof(NodeDto.ParentId));
DefineMap<DataType, NodeDto>(nameof(DataType.Path), nameof(NodeDto.Path));
DefineMap<DataType, NodeDto>(nameof(DataType.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<DataType, NodeDto>(nameof(DataType.Name), nameof(NodeDto.Text));
DefineMap<DataType, NodeDto>(nameof(DataType.Trashed), nameof(NodeDto.Trashed));
DefineMap<DataType, NodeDto>(nameof(DataType.Key), nameof(NodeDto.UniqueId));
DefineMap<DataType, NodeDto>(nameof(DataType.CreatorId), nameof(NodeDto.UserId));
DefineMap<DataType, DataTypeDto>(nameof(DataType.EditorAlias), nameof(DataTypeDto.EditorAlias));
DefineMap<DataType, DataTypeDto>(nameof(DataType.DatabaseType), nameof(DataTypeDto.DbType));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,16 +13,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDictionaryItem))]
public sealed class DictionaryMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public DictionaryMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<DictionaryItem, DictionaryDto>(src => src.Id, dto => dto.PrimaryKey);
CacheMap<DictionaryItem, DictionaryDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<DictionaryItem, DictionaryDto>(src => src.ItemKey, dto => dto.Key);
CacheMap<DictionaryItem, DictionaryDto>(src => src.ParentId, dto => dto.Parent);
DefineMap<DictionaryItem, DictionaryDto>(nameof(DictionaryItem.Id), nameof(DictionaryDto.PrimaryKey));
DefineMap<DictionaryItem, DictionaryDto>(nameof(DictionaryItem.Key), nameof(DictionaryDto.UniqueId));
DefineMap<DictionaryItem, DictionaryDto>(nameof(DictionaryItem.ItemKey), nameof(DictionaryDto.Key));
DefineMap<DictionaryItem, DictionaryDto>(nameof(DictionaryItem.ParentId), nameof(DictionaryDto.Parent));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,16 +13,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDictionaryTranslation))]
public sealed class DictionaryTranslationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public DictionaryTranslationMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Id, dto => dto.PrimaryKey);
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Language, dto => dto.LanguageId);
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Value, dto => dto.Value);
DefineMap<DictionaryTranslation, LanguageTextDto>(nameof(DictionaryTranslation.Id), nameof(LanguageTextDto.PrimaryKey));
DefineMap<DictionaryTranslation, LanguageTextDto>(nameof(DictionaryTranslation.Key), nameof(LanguageTextDto.UniqueId));
DefineMap<DictionaryTranslation, LanguageTextDto>(nameof(DictionaryTranslation.Language), nameof(LanguageTextDto.LanguageId));
DefineMap<DictionaryTranslation, LanguageTextDto>(nameof(DictionaryTranslation.Value), nameof(LanguageTextDto.Value));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,16 +9,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(UmbracoDomain))]
public sealed class DomainMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public DomainMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<UmbracoDomain, DomainDto>(src => src.Id, dto => dto.Id);
CacheMap<UmbracoDomain, DomainDto>(src => src.RootContentId, dto => dto.RootStructureId);
CacheMap<UmbracoDomain, DomainDto>(src => src.LanguageId, dto => dto.DefaultLanguage);
CacheMap<UmbracoDomain, DomainDto>(src => src.DomainName, dto => dto.DomainName);
DefineMap<UmbracoDomain, DomainDto>(nameof(UmbracoDomain.Id), nameof(DomainDto.Id));
DefineMap<UmbracoDomain, DomainDto>(nameof(UmbracoDomain.RootContentId), nameof(DomainDto.RootStructureId));
DefineMap<UmbracoDomain, DomainDto>(nameof(UmbracoDomain.LanguageId), nameof(DomainDto.DefaultLanguage));
DefineMap<UmbracoDomain, DomainDto>(nameof(UmbracoDomain.DomainName), nameof(DomainDto.DomainName));
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
using System.Reflection;
namespace Umbraco.Core.Persistence.Mappers
{
internal class DtoMapModel
{
public DtoMapModel(Type type, PropertyInfo propertyInfo, string sourcePropertyName)
{
Type = type;
PropertyInfo = propertyInfo;
SourcePropertyName = sourcePropertyName;
}
public string SourcePropertyName { get; private set; }
public Type Type { get; private set; }
public PropertyInfo PropertyInfo { get; private set; }
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Persistence.Dtos;
@@ -8,25 +9,17 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IdentityUserLogin))]
public sealed class ExternalLoginMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public ExternalLoginMapper()
public ExternalLoginMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
protected override void DefineMaps()
{
BuildMap();
DefineMap<IdentityUserLogin, ExternalLoginDto>(nameof(IdentityUserLogin.Id), nameof(ExternalLoginDto.Id));
DefineMap<IdentityUserLogin, ExternalLoginDto>(nameof(IdentityUserLogin.CreateDate), nameof(ExternalLoginDto.CreateDate));
DefineMap<IdentityUserLogin, ExternalLoginDto>(nameof(IdentityUserLogin.LoginProvider), nameof(ExternalLoginDto.LoginProvider));
DefineMap<IdentityUserLogin, ExternalLoginDto>(nameof(IdentityUserLogin.ProviderKey), nameof(ExternalLoginDto.ProviderKey));
DefineMap<IdentityUserLogin, ExternalLoginDto>(nameof(IdentityUserLogin.UserId), nameof(ExternalLoginDto.UserId));
}
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
{
CacheMap<IdentityUserLogin, ExternalLoginDto>(src => src.Id, dto => dto.Id);
CacheMap<IdentityUserLogin, ExternalLoginDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<IdentityUserLogin, ExternalLoginDto>(src => src.LoginProvider, dto => dto.LoginProvider);
CacheMap<IdentityUserLogin, ExternalLoginDto>(src => src.ProviderKey, dto => dto.ProviderKey);
CacheMap<IdentityUserLogin, ExternalLoginDto>(src => src.UserId, dto => dto.UserId);
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,15 +13,15 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Language))]
public sealed class LanguageMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public LanguageMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Language, LanguageDto>(src => src.Id, dto => dto.Id);
CacheMap<Language, LanguageDto>(src => src.IsoCode, dto => dto.IsoCode);
CacheMap<Language, LanguageDto>(src => src.CultureName, dto => dto.CultureName);
DefineMap<Language, LanguageDto>(nameof(Language.Id), nameof(LanguageDto.Id));
DefineMap<Language, LanguageDto>(nameof(Language.IsoCode), nameof(LanguageDto.IsoCode));
DefineMap<Language, LanguageDto>(nameof(Language.CultureName), nameof(LanguageDto.CultureName));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,22 +9,22 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IMacro))]
internal sealed class MacroMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MacroMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Macro, MacroDto>(src => src.Id, dto => dto.Id);
CacheMap<Macro, MacroDto>(src => src.Alias, dto => dto.Alias);
CacheMap<Macro, MacroDto>(src => src.CacheByPage, dto => dto.CacheByPage);
CacheMap<Macro, MacroDto>(src => src.CacheByMember, dto => dto.CachePersonalized);
CacheMap<Macro, MacroDto>(src => src.MacroType, dto => dto.MacroType);
CacheMap<Macro, MacroDto>(src => src.DontRender, dto => dto.DontRender);
CacheMap<Macro, MacroDto>(src => src.Name, dto => dto.Name);
CacheMap<Macro, MacroDto>(src => src.CacheDuration, dto => dto.RefreshRate);
CacheMap<Macro, MacroDto>(src => src.MacroSource, dto => dto.MacroSource);
CacheMap<Macro, MacroDto>(src => src.UseInEditor, dto => dto.UseInEditor);
DefineMap<Macro, MacroDto>(nameof(Macro.Id), nameof(MacroDto.Id));
DefineMap<Macro, MacroDto>(nameof(Macro.Alias), nameof(MacroDto.Alias));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheByPage), nameof(MacroDto.CacheByPage));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheByMember), nameof(MacroDto.CachePersonalized));
DefineMap<Macro, MacroDto>(nameof(Macro.MacroType), nameof(MacroDto.MacroType));
DefineMap<Macro, MacroDto>(nameof(Macro.DontRender), nameof(MacroDto.DontRender));
DefineMap<Macro, MacroDto>(nameof(Macro.Name), nameof(MacroDto.Name));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheDuration), nameof(MacroDto.RefreshRate));
DefineMap<Macro, MacroDto>(nameof(Macro.MacroSource), nameof(MacroDto.MacroSource));
DefineMap<Macro, MacroDto>(nameof(Macro.UseInEditor), nameof(MacroDto.UseInEditor));
}
}
}

View File

@@ -1,9 +1,14 @@
using Umbraco.Core.Composing;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Persistence.Mappers
{
public class MapperCollectionBuilder : LazyCollectionBuilderBase<MapperCollectionBuilder, MapperCollection, BaseMapper>
public class MapperCollectionBuilder : SetCollectionBuilderBase<MapperCollectionBuilder, MapperCollection, BaseMapper>
{
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> _maps
= new ConcurrentDictionary<Type, ConcurrentDictionary<string, string>>();
protected override MapperCollectionBuilder This => this;
public override void RegisterWith(IRegister register)
@@ -19,6 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
register.Register<IMapperCollection>(factory => factory.GetInstance<MapperCollection>());
}
protected override BaseMapper CreateItem(IFactory factory, Type itemType)
{
return (BaseMapper) factory.CreateInstance(itemType, _maps);
}
public MapperCollectionBuilder AddCoreMappers()
{
Add<AccessMapper>();

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,29 +13,27 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Umbraco.Core.Models.Media))]
public sealed class MediaMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MediaMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Id), nameof(NodeDto.NodeId));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Key), nameof(NodeDto.UniqueId));
CacheMap<Models.Media, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<Models.Media, NodeDto>(src => src.Key, dto => dto.UniqueId);
DefineMap<Content, ContentVersionDto>(nameof(Content.VersionId), nameof(ContentVersionDto.Id));
CacheMap<Content, ContentVersionDto>(src => src.VersionId, dto => dto.Id);
CacheMap<Models.Media, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<Models.Media, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<Models.Media, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<Models.Media, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<Models.Media, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<Models.Media, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<Models.Media, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<Models.Media, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<Models.Media, ContentDto>(src => src.ContentTypeId, dto => dto.ContentTypeId);
CacheMap<Models.Media, ContentVersionDto>(src => src.UpdateDate, dto => dto.VersionDate);
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Level), nameof(NodeDto.Level));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.ParentId), nameof(NodeDto.ParentId));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Path), nameof(NodeDto.Path));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Name), nameof(NodeDto.Text));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.Trashed), nameof(NodeDto.Trashed));
DefineMap<Models.Media, NodeDto>(nameof(Models.Media.CreatorId), nameof(NodeDto.UserId));
DefineMap<Models.Media, ContentDto>(nameof(Models.Media.ContentTypeId), nameof(ContentDto.ContentTypeId));
DefineMap<Models.Media, ContentVersionDto>(nameof(Models.Media.UpdateDate), nameof(ContentVersionDto.VersionDate));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,31 +13,29 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(MediaType))]
public sealed class MediaTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MediaTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<MediaType, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<MediaType, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<MediaType, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<MediaType, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<MediaType, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<MediaType, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<MediaType, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<MediaType, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<MediaType, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<MediaType, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<MediaType, ContentTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<MediaType, ContentTypeDto>(src => src.AllowedAsRoot, dto => dto.AllowAtRoot);
CacheMap<MediaType, ContentTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<MediaType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
CacheMap<MediaType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
CacheMap<MediaType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
CacheMap<MediaType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
DefineMap<MediaType, NodeDto>(nameof(MediaType.Id), nameof(NodeDto.NodeId));
DefineMap<MediaType, NodeDto>(nameof(MediaType.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<MediaType, NodeDto>(nameof(MediaType.Level), nameof(NodeDto.Level));
DefineMap<MediaType, NodeDto>(nameof(MediaType.ParentId), nameof(NodeDto.ParentId));
DefineMap<MediaType, NodeDto>(nameof(MediaType.Path), nameof(NodeDto.Path));
DefineMap<MediaType, NodeDto>(nameof(MediaType.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<MediaType, NodeDto>(nameof(MediaType.Name), nameof(NodeDto.Text));
DefineMap<MediaType, NodeDto>(nameof(MediaType.Trashed), nameof(NodeDto.Trashed));
DefineMap<MediaType, NodeDto>(nameof(MediaType.Key), nameof(NodeDto.UniqueId));
DefineMap<MediaType, NodeDto>(nameof(MediaType.CreatorId), nameof(NodeDto.UserId));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.Alias), nameof(ContentTypeDto.Alias));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.AllowedAsRoot), nameof(ContentTypeDto.AllowAtRoot));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.Description), nameof(ContentTypeDto.Description));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.Icon), nameof(ContentTypeDto.Icon));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.IsContainer), nameof(ContentTypeDto.IsContainer));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.IsElement), nameof(ContentTypeDto.IsElement));
DefineMap<MediaType, ContentTypeDto>(nameof(MediaType.Thumbnail), nameof(ContentTypeDto.Thumbnail));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,17 +9,17 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof (MemberGroup))]
public sealed class MemberGroupMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MemberGroupMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<MemberGroup, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<MemberGroup, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<MemberGroup, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<MemberGroup, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<MemberGroup, NodeDto>(src => src.Key, dto => dto.UniqueId);
DefineMap<MemberGroup, NodeDto>(nameof(MemberGroup.Id), nameof(NodeDto.NodeId));
DefineMap<MemberGroup, NodeDto>(nameof(MemberGroup.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<MemberGroup, NodeDto>(nameof(MemberGroup.CreatorId), nameof(NodeDto.UserId));
DefineMap<MemberGroup, NodeDto>(nameof(MemberGroup.Name), nameof(NodeDto.Text));
DefineMap<MemberGroup, NodeDto>(nameof(MemberGroup.Key), nameof(NodeDto.UniqueId));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
@@ -13,47 +14,47 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Member))]
public sealed class MemberMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MemberMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Member, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<Member, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<Member, NodeDto>(src => ((IUmbracoEntity)src).Level, dto => dto.Level);
CacheMap<Member, NodeDto>(src => ((IUmbracoEntity)src).ParentId, dto => dto.ParentId);
CacheMap<Member, NodeDto>(src => ((IUmbracoEntity)src).Path, dto => dto.Path);
CacheMap<Member, NodeDto>(src => ((IUmbracoEntity)src).SortOrder, dto => dto.SortOrder);
CacheMap<Member, NodeDto>(src => ((IUmbracoEntity)src).CreatorId, dto => dto.UserId);
CacheMap<Member, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<Member, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<Member, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<Member, ContentDto>(src => src.ContentTypeId, dto => dto.ContentTypeId);
CacheMap<Member, ContentTypeDto>(src => src.ContentTypeAlias, dto => dto.Alias);
CacheMap<Member, ContentVersionDto>(src => src.UpdateDate, dto => dto.VersionDate);
DefineMap<Member, NodeDto>(nameof(Member.Id), nameof(NodeDto.NodeId));
DefineMap<Member, NodeDto>(nameof(Member.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<Member, NodeDto>(nameof(Member.Level), nameof(NodeDto.Level));
DefineMap<Member, NodeDto>(nameof(Member.ParentId), nameof(NodeDto.ParentId));
DefineMap<Member, NodeDto>(nameof(Member.Path), nameof(NodeDto.Path));
DefineMap<Member, NodeDto>(nameof(Member.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<Member, NodeDto>(nameof(Member.CreatorId), nameof(NodeDto.UserId));
DefineMap<Member, NodeDto>(nameof(Member.Name), nameof(NodeDto.Text));
DefineMap<Member, NodeDto>(nameof(Member.Trashed), nameof(NodeDto.Trashed));
DefineMap<Member, NodeDto>(nameof(Member.Key), nameof(NodeDto.UniqueId));
DefineMap<Member, ContentDto>(nameof(Member.ContentTypeId), nameof(ContentDto.ContentTypeId));
DefineMap<Member, ContentTypeDto>(nameof(Member.ContentTypeAlias), nameof(ContentTypeDto.Alias));
DefineMap<Member, ContentVersionDto>(nameof(Member.UpdateDate), nameof(ContentVersionDto.VersionDate));
CacheMap<Member, MemberDto>(src => src.Email, dto => dto.Email);
CacheMap<Member, MemberDto>(src => src.Username, dto => dto.LoginName);
CacheMap<Member, MemberDto>(src => src.RawPasswordValue, dto => dto.Password);
DefineMap<Member, MemberDto>(nameof(Member.Email), nameof(MemberDto.Email));
DefineMap<Member, MemberDto>(nameof(Member.Username), nameof(MemberDto.LoginName));
DefineMap<Member, MemberDto>(nameof(Member.RawPasswordValue), nameof(MemberDto.Password));
CacheMap<Member, PropertyDataDto>(src => src.IsApproved, dto => dto.IntegerValue);
CacheMap<Member, PropertyDataDto>(src => src.IsLockedOut, dto => dto.IntegerValue);
CacheMap<Member, PropertyDataDto>(src => src.Comments, dto => dto.TextValue);
CacheMap<Member, PropertyDataDto>(src => src.RawPasswordAnswerValue, dto => dto.VarcharValue);
CacheMap<Member, PropertyDataDto>(src => src.PasswordQuestion, dto => dto.VarcharValue);
CacheMap<Member, PropertyDataDto>(src => src.FailedPasswordAttempts, dto => dto.IntegerValue);
CacheMap<Member, PropertyDataDto>(src => src.LastLockoutDate, dto => dto.DateValue);
CacheMap<Member, PropertyDataDto>(src => src.LastLoginDate, dto => dto.DateValue);
CacheMap<Member, PropertyDataDto>(src => src.LastPasswordChangeDate, dto => dto.DateValue);
DefineMap<Member, PropertyDataDto>(nameof(Member.IsApproved), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.IsLockedOut), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.Comments), nameof(PropertyDataDto.TextValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.RawPasswordAnswerValue), nameof(PropertyDataDto.VarcharValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.PasswordQuestion), nameof(PropertyDataDto.VarcharValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.FailedPasswordAttempts), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLockoutDate), nameof(PropertyDataDto.DateValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLoginDate), nameof(PropertyDataDto.DateValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LastPasswordChangeDate), nameof(PropertyDataDto.DateValue));
/* Internal experiment */
CacheMap<Member, PropertyDataDto>(src => src.DateTimePropertyValue, dto => dto.DateValue);
CacheMap<Member, PropertyDataDto>(src => src.IntegerPropertyValue, dto => dto.IntegerValue);
CacheMap<Member, PropertyDataDto>(src => src.BoolPropertyValue, dto => dto.IntegerValue);
CacheMap<Member, PropertyDataDto>(src => src.LongStringPropertyValue, dto => dto.TextValue);
CacheMap<Member, PropertyDataDto>(src => src.ShortStringPropertyValue, dto => dto.VarcharValue);
CacheMap<Member, PropertyTypeDto>(src => src.PropertyTypeAlias, dto => dto.Alias);
DefineMap<Member, PropertyDataDto>(nameof(Member.DateTimePropertyValue), nameof(PropertyDataDto.DateValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.IntegerPropertyValue), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.BoolPropertyValue), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LongStringPropertyValue), nameof(PropertyDataDto.TextValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.ShortStringPropertyValue), nameof(PropertyDataDto.VarcharValue));
DefineMap<Member, PropertyTypeDto>(nameof(Member.PropertyTypeAlias), nameof(PropertyTypeDto.Alias));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,31 +13,29 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof (IMemberType))]
public sealed class MemberTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public MemberTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<MemberType, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<MemberType, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<MemberType, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<MemberType, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<MemberType, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<MemberType, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<MemberType, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<MemberType, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<MemberType, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<MemberType, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<MemberType, ContentTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<MemberType, ContentTypeDto>(src => src.AllowedAsRoot, dto => dto.AllowAtRoot);
CacheMap<MemberType, ContentTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<MemberType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
CacheMap<MemberType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
CacheMap<MemberType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
CacheMap<MemberType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
DefineMap<MemberType, NodeDto>(nameof(MemberType.Id), nameof(NodeDto.NodeId));
DefineMap<MemberType, NodeDto>(nameof(MemberType.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<MemberType, NodeDto>(nameof(MemberType.Level), nameof(NodeDto.Level));
DefineMap<MemberType, NodeDto>(nameof(MemberType.ParentId), nameof(NodeDto.ParentId));
DefineMap<MemberType, NodeDto>(nameof(MemberType.Path), nameof(NodeDto.Path));
DefineMap<MemberType, NodeDto>(nameof(MemberType.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<MemberType, NodeDto>(nameof(MemberType.Name), nameof(NodeDto.Text));
DefineMap<MemberType, NodeDto>(nameof(MemberType.Trashed), nameof(NodeDto.Trashed));
DefineMap<MemberType, NodeDto>(nameof(MemberType.Key), nameof(NodeDto.UniqueId));
DefineMap<MemberType, NodeDto>(nameof(MemberType.CreatorId), nameof(NodeDto.UserId));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.Alias), nameof(ContentTypeDto.Alias));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.AllowedAsRoot), nameof(ContentTypeDto.AllowAtRoot));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.Description), nameof(ContentTypeDto.Description));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.Icon), nameof(ContentTypeDto.Icon));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.IsContainer), nameof(ContentTypeDto.IsContainer));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.IsElement), nameof(ContentTypeDto.IsElement));
DefineMap<MemberType, ContentTypeDto>(nameof(MemberType.Thumbnail), nameof(ContentTypeDto.Thumbnail));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -11,16 +12,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(PropertyGroup))]
public sealed class PropertyGroupMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public PropertyGroupMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.Id, dto => dto.Id);
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.Name, dto => dto.Text);
DefineMap<PropertyGroup, PropertyTypeGroupDto>(nameof(PropertyGroup.Id), nameof(PropertyTypeGroupDto.Id));
DefineMap<PropertyGroup, PropertyTypeGroupDto>(nameof(PropertyGroup.Key), nameof(PropertyTypeGroupDto.UniqueId));
DefineMap<PropertyGroup, PropertyTypeGroupDto>(nameof(PropertyGroup.SortOrder), nameof(PropertyTypeGroupDto.SortOrder));
DefineMap<PropertyGroup, PropertyTypeGroupDto>(nameof(PropertyGroup.Name), nameof(PropertyTypeGroupDto.Text));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -7,14 +8,14 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Property))]
public sealed class PropertyMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public PropertyMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Property, PropertyDataDto>(src => src.Id, dto => dto.Id);
CacheMap<Property, PropertyDataDto>(src => src.PropertyTypeId, dto => dto.PropertyTypeId);
DefineMap<Property, PropertyDataDto>(nameof(Property.Id), nameof(PropertyDataDto.Id));
DefineMap<Property, PropertyDataDto>(nameof(Property.PropertyTypeId), nameof(PropertyDataDto.PropertyTypeId));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -11,25 +12,23 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(PropertyType))]
public sealed class PropertyTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public PropertyTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<PropertyType, PropertyTypeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Id, dto => dto.Id);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<PropertyType, PropertyTypeDto>(src => src.DataTypeId, dto => dto.DataTypeId);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Mandatory, dto => dto.Mandatory);
CacheMap<PropertyType, PropertyTypeDto>(src => src.Name, dto => dto.Name);
CacheMap<PropertyType, PropertyTypeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<PropertyType, PropertyTypeDto>(src => src.ValidationRegExp, dto => dto.ValidationRegExp);
CacheMap<PropertyType, DataTypeDto>(src => src.PropertyEditorAlias, dto => dto.EditorAlias);
CacheMap<PropertyType, DataTypeDto>(src => src.ValueStorageType, dto => dto.DbType);
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Key), nameof(PropertyTypeDto.UniqueId));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Id), nameof(PropertyTypeDto.Id));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Alias), nameof(PropertyTypeDto.Alias));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.DataTypeId), nameof(PropertyTypeDto.DataTypeId));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Description), nameof(PropertyTypeDto.Description));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Mandatory), nameof(PropertyTypeDto.Mandatory));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Name), nameof(PropertyTypeDto.Name));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder));
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp));
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias));
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,18 +13,18 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Relation))]
public sealed class RelationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public RelationMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<Relation, RelationDto>(src => src.Id, dto => dto.Id);
CacheMap<Relation, RelationDto>(src => src.ChildId, dto => dto.ChildId);
CacheMap<Relation, RelationDto>(src => src.Comment, dto => dto.Comment);
CacheMap<Relation, RelationDto>(src => src.CreateDate, dto => dto.Datetime);
CacheMap<Relation, RelationDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<Relation, RelationDto>(src => src.RelationTypeId, dto => dto.RelationType);
DefineMap<Relation, RelationDto>(nameof(Relation.Id), nameof(RelationDto.Id));
DefineMap<Relation, RelationDto>(nameof(Relation.ChildId), nameof(RelationDto.ChildId));
DefineMap<Relation, RelationDto>(nameof(Relation.Comment), nameof(RelationDto.Comment));
DefineMap<Relation, RelationDto>(nameof(Relation.CreateDate), nameof(RelationDto.Datetime));
DefineMap<Relation, RelationDto>(nameof(Relation.ParentId), nameof(RelationDto.ParentId));
DefineMap<Relation, RelationDto>(nameof(Relation.RelationTypeId), nameof(RelationDto.RelationType));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,18 +13,18 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IRelationType))]
public sealed class RelationTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public RelationTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<RelationType, RelationTypeDto>(src => src.Id, dto => dto.Id);
CacheMap<RelationType, RelationTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<RelationType, RelationTypeDto>(src => src.ChildObjectType, dto => dto.ChildObjectType);
CacheMap<RelationType, RelationTypeDto>(src => src.IsBidirectional, dto => dto.Dual);
CacheMap<RelationType, RelationTypeDto>(src => src.Name, dto => dto.Name);
CacheMap<RelationType, RelationTypeDto>(src => src.ParentObjectType, dto => dto.ParentObjectType);
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.Id), nameof(RelationTypeDto.Id));
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.Alias), nameof(RelationTypeDto.Alias));
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.ChildObjectType), nameof(RelationTypeDto.ChildObjectType));
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.IsBidirectional), nameof(RelationTypeDto.Dual));
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.Name), nameof(RelationTypeDto.Name));
DefineMap<RelationType, RelationTypeDto>(nameof(RelationType.ParentObjectType), nameof(RelationTypeDto.ParentObjectType));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,19 +9,19 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IServerRegistration))]
internal sealed class ServerRegistrationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public ServerRegistrationMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.Id, dto => dto.Id);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.IsActive, dto => dto.IsActive);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.IsMaster, dto => dto.IsMaster);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.ServerAddress, dto => dto.ServerAddress);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.CreateDate, dto => dto.DateRegistered);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.UpdateDate, dto => dto.DateAccessed);
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.ServerIdentity, dto => dto.ServerIdentity);
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.Id), nameof(ServerRegistrationDto.Id));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.IsActive), nameof(ServerRegistrationDto.IsActive));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.IsMaster), nameof(ServerRegistrationDto.IsMaster));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.ServerAddress), nameof(ServerRegistrationDto.ServerAddress));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.CreateDate), nameof(ServerRegistrationDto.DateRegistered));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.UpdateDate), nameof(ServerRegistrationDto.DateAccessed));
DefineMap<ServerRegistration, ServerRegistrationDto>(nameof(ServerRegistration.ServerIdentity), nameof(ServerRegistrationDto.ServerIdentity));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -8,31 +9,29 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(SimpleContentType))]
public sealed class SimpleContentTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public SimpleContentTypeMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<ContentType, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<ContentType, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<ContentType, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<ContentType, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<ContentType, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<ContentType, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<ContentType, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<ContentType, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<ContentType, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<ContentType, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<ContentType, ContentTypeDto>(src => src.Alias, dto => dto.Alias);
CacheMap<ContentType, ContentTypeDto>(src => src.AllowedAsRoot, dto => dto.AllowAtRoot);
CacheMap<ContentType, ContentTypeDto>(src => src.Description, dto => dto.Description);
CacheMap<ContentType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
CacheMap<ContentType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
CacheMap<ContentType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
CacheMap<ContentType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
DefineMap<ContentType, NodeDto>(nameof(ContentType.Id), nameof(NodeDto.NodeId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Level), nameof(NodeDto.Level));
DefineMap<ContentType, NodeDto>(nameof(ContentType.ParentId), nameof(NodeDto.ParentId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Path), nameof(NodeDto.Path));
DefineMap<ContentType, NodeDto>(nameof(ContentType.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Name), nameof(NodeDto.Text));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Trashed), nameof(NodeDto.Trashed));
DefineMap<ContentType, NodeDto>(nameof(ContentType.Key), nameof(NodeDto.UniqueId));
DefineMap<ContentType, NodeDto>(nameof(ContentType.CreatorId), nameof(NodeDto.UserId));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Alias), nameof(ContentTypeDto.Alias));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.AllowedAsRoot), nameof(ContentTypeDto.AllowAtRoot));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Description), nameof(ContentTypeDto.Description));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Icon), nameof(ContentTypeDto.Icon));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.IsContainer), nameof(ContentTypeDto.IsContainer));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.IsElement), nameof(ContentTypeDto.IsElement));
DefineMap<ContentType, ContentTypeDto>(nameof(ContentType.Thumbnail), nameof(ContentTypeDto.Thumbnail));
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,18 +13,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(ITag))]
public sealed class TagMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public TagMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<Tag, TagDto>(src => src.Id, dto => dto.Id);
CacheMap<Tag, TagDto>(src => src.Text, dto => dto.Text);
CacheMap<Tag, TagDto>(src => src.Group, dto => dto.Group);
CacheMap<Tag, TagDto>(src => src.LanguageId, dto => dto.LanguageId);
DefineMap<Tag, TagDto>(nameof(Tag.Id), nameof(TagDto.Id));
DefineMap<Tag, TagDto>(nameof(Tag.Text), nameof(TagDto.Text));
DefineMap<Tag, TagDto>(nameof(Tag.Group), nameof(TagDto.Group));
DefineMap<Tag, TagDto>(nameof(Tag.LanguageId), nameof(TagDto.LanguageId));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
@@ -12,18 +13,16 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(ITemplate))]
public sealed class TemplateMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public TemplateMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
if (PropertyInfoCache.IsEmpty == false) return;
CacheMap<Template, TemplateDto>(src => src.Id, dto => dto.NodeId);
CacheMap<Template, NodeDto>(src => src.MasterTemplateId, dto => dto.ParentId);
CacheMap<Template, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<Template, TemplateDto>(src => src.Alias, dto => dto.Alias);
DefineMap<Template, TemplateDto>(nameof(Template.Id), nameof(TemplateDto.NodeId));
DefineMap<Template, NodeDto>(nameof(Template.MasterTemplateId), nameof(NodeDto.ParentId));
DefineMap<Template, NodeDto>(nameof(Template.Key), nameof(NodeDto.UniqueId));
DefineMap<Template, TemplateDto>(nameof(Template.Alias), nameof(TemplateDto.Alias));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
@@ -7,22 +8,22 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof (IUmbracoEntity))]
public sealed class UmbracoEntityMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public UmbracoEntityMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<IUmbracoEntity, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<IUmbracoEntity, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<IUmbracoEntity, NodeDto>(src => src.Level, dto => dto.Level);
CacheMap<IUmbracoEntity, NodeDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<IUmbracoEntity, NodeDto>(src => src.Path, dto => dto.Path);
CacheMap<IUmbracoEntity, NodeDto>(src => src.SortOrder, dto => dto.SortOrder);
CacheMap<IUmbracoEntity, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<IUmbracoEntity, NodeDto>(src => src.Trashed, dto => dto.Trashed);
CacheMap<IUmbracoEntity, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<IUmbracoEntity, NodeDto>(src => src.CreatorId, dto => dto.UserId);
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Id), nameof(NodeDto.NodeId));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.CreateDate), nameof(NodeDto.CreateDate));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Level), nameof(NodeDto.Level));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.ParentId), nameof(NodeDto.ParentId));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Path), nameof(NodeDto.Path));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.SortOrder), nameof(NodeDto.SortOrder));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Name), nameof(NodeDto.Text));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Trashed), nameof(NodeDto.Trashed));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.Key), nameof(NodeDto.UniqueId));
DefineMap<IUmbracoEntity, NodeDto>(nameof(IUmbracoEntity.CreatorId), nameof(NodeDto.UserId));
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Dtos;
@@ -12,29 +13,18 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(UserGroup))]
public sealed class UserGroupMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public UserGroupMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
public UserGroupMapper()
protected override void DefineMaps()
{
BuildMap();
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Id), nameof(UserGroupDto.Id));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Alias), nameof(UserGroupDto.Alias));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Name), nameof(UserGroupDto.Name));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.Icon), nameof(UserGroupDto.Icon));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.StartContentId), nameof(UserGroupDto.StartContentId));
DefineMap<UserGroup, UserGroupDto>(nameof(UserGroup.StartMediaId), nameof(UserGroupDto.StartMediaId));
}
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
{
CacheMap<UserGroup, UserGroupDto>(src => src.Id, dto => dto.Id);
CacheMap<UserGroup, UserGroupDto>(src => src.Alias, dto => dto.Alias);
CacheMap<UserGroup, UserGroupDto>(src => src.Name, dto => dto.Name);
CacheMap<UserGroup, UserGroupDto>(src => src.Icon, dto => dto.Icon);
CacheMap<UserGroup, UserGroupDto>(src => src.StartContentId, dto => dto.StartContentId);
CacheMap<UserGroup, UserGroupDto>(src => src.StartMediaId, dto => dto.StartMediaId);
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Dtos;
@@ -8,28 +9,28 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(User))]
public sealed class UserMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public UserMapper(Lazy<ISqlContext> sqlContext, ConcurrentDictionary<Type, ConcurrentDictionary<string, string>> maps)
: base(sqlContext, maps)
{ }
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
protected override void BuildMap()
protected override void DefineMaps()
{
CacheMap<User, UserDto>(src => src.Id, dto => dto.Id);
CacheMap<User, UserDto>(src => src.Email, dto => dto.Email);
CacheMap<User, UserDto>(src => src.Username, dto => dto.Login);
CacheMap<User, UserDto>(src => src.RawPasswordValue, dto => dto.Password);
CacheMap<User, UserDto>(src => src.Name, dto => dto.UserName);
DefineMap<User, UserDto>(nameof(User.Id), nameof(UserDto.Id));
DefineMap<User, UserDto>(nameof(User.Email), nameof(UserDto.Email));
DefineMap<User, UserDto>(nameof(User.Username), nameof(UserDto.Login));
DefineMap<User, UserDto>(nameof(User.RawPasswordValue), nameof(UserDto.Password));
DefineMap<User, UserDto>(nameof(User.Name), nameof(UserDto.UserName));
//NOTE: This column in the db is *not* used!
//CacheMap<User, UserDto>(src => src.DefaultPermissions, dto => dto.DefaultPermissions);
CacheMap<User, UserDto>(src => src.IsApproved, dto => dto.Disabled);
CacheMap<User, UserDto>(src => src.IsLockedOut, dto => dto.NoConsole);
CacheMap<User, UserDto>(src => src.Language, dto => dto.UserLanguage);
CacheMap<User, UserDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<User, UserDto>(src => src.UpdateDate, dto => dto.UpdateDate);
CacheMap<User, UserDto>(src => src.LastLockoutDate, dto => dto.LastLockoutDate);
CacheMap<User, UserDto>(src => src.LastLoginDate, dto => dto.LastLoginDate);
CacheMap<User, UserDto>(src => src.LastPasswordChangeDate, dto => dto.LastPasswordChangeDate);
CacheMap<User, UserDto>(src => src.SecurityStamp, dto => dto.SecurityStampToken);
//DefineMap<User, UserDto>(nameof(User.DefaultPermissions), nameof(UserDto.DefaultPermissions));
DefineMap<User, UserDto>(nameof(User.IsApproved), nameof(UserDto.Disabled));
DefineMap<User, UserDto>(nameof(User.IsLockedOut), nameof(UserDto.NoConsole));
DefineMap<User, UserDto>(nameof(User.Language), nameof(UserDto.UserLanguage));
DefineMap<User, UserDto>(nameof(User.CreateDate), nameof(UserDto.CreateDate));
DefineMap<User, UserDto>(nameof(User.UpdateDate), nameof(UserDto.UpdateDate));
DefineMap<User, UserDto>(nameof(User.LastLockoutDate), nameof(UserDto.LastLockoutDate));
DefineMap<User, UserDto>(nameof(User.LastLoginDate), nameof(UserDto.LastLoginDate));
DefineMap<User, UserDto>(nameof(User.LastPasswordChangeDate), nameof(UserDto.LastPasswordChangeDate));
DefineMap<User, UserDto>(nameof(User.SecurityStamp), nameof(UserDto.SecurityStampToken));
}
}
}

Some files were not shown because too many files have changed in this diff Show More