Merge branch 'v8/dev' into v8/bugfix/5129-ui-app-header-focus

This commit is contained in:
Warren Buckley
2019-04-12 09:40:02 +01:00
218 changed files with 9578 additions and 10260 deletions
-1
View File
@@ -22,7 +22,6 @@
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="AutoMapper" version="[8.0.0,8.999999)" />
<dependency id="LightInject" version="[5.4.0,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Web" version="[2.0.0,2.999999)" />
+9 -4
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;
}
}
}
@@ -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);
@@ -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;
}
}
@@ -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;
}
+4
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())));
@@ -9,6 +9,10 @@ namespace Umbraco.Core.Composing
/// <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>
@@ -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);
}
}
@@ -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)
{ }
}
}
@@ -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;
}
}
+130
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
}
}
+424
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
}
}
@@ -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),
@@ -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");
}
}
}
+3 -12
View File
@@ -210,9 +210,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 +228,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets all property types, across all property groups.
/// </summary>
/// <inheritdoc />
[IgnoreDataMember]
[DoNotClone]
public IEnumerable<PropertyType> PropertyTypes
@@ -243,12 +239,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
{
@@ -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
{
-1
View File
@@ -25,7 +25,6 @@ namespace Umbraco.Core.Models
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));
if (defaultCulture == null) throw new ArgumentNullException(nameof(defaultCulture));
var cultureForInvariantErrors = savingCultures.Any(x => x.InvariantEquals(defaultCulture))
//the default culture is being flagged for saving so use it
@@ -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
{
}
+3 -3
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; }
@@ -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();
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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";
@@ -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; }
}
}
@@ -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; }
}
}
@@ -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]
@@ -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; }
}
}
@@ -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; }
}
}
@@ -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)
@@ -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;
}
}
}
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
// TODO
// this should be IContentTypeRepository, and what is IContentTypeRepository at the moment should
// become IDocumentTypeRepository - but since these interfaces are public, that would be breaking
/// <summary>
/// Represents the content types common repository, dealing with document, media and member types.
/// </summary>
public interface IContentTypeCommonRepository
{
/// <summary>
/// Gets and cache all types.
/// </summary>
IEnumerable<IContentTypeComposition> GetAllTypes();
/// <summary>
/// Clears the cache.
/// </summary>
void ClearCache();
}
}
@@ -1,16 +1,8 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IMediaTypeRepository : IContentTypeRepositoryBase<IMediaType>
{
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
/// </summary>
/// <param name="query"></param>
/// <returns>An enumerable list of <see cref="IContentType"/> objects</returns>
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
}
{ }
}
@@ -0,0 +1,285 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
/// <summary>
/// Implements <see cref="IContentTypeCommonRepository"/>.
/// </summary>
internal class ContentTypeCommonRepository : IContentTypeCommonRepository
{
private const string CacheKey = "Umbraco.Core.Persistence.Repositories.Implement.ContentTypeCommonRepository::AllTypes";
private readonly AppCaches _appCaches;
private readonly IScopeAccessor _scopeAccessor;
private readonly ITemplateRepository _templateRepository;
/// <summary>
/// Initializes a new instance of the <see cref="IContentTypeCommonRepository"/> class.
/// </summary>
public ContentTypeCommonRepository(IScopeAccessor scopeAccessor, ITemplateRepository templateRepository, AppCaches appCaches)
{
_scopeAccessor = scopeAccessor;
_templateRepository = templateRepository;
_appCaches = appCaches;
}
private IScope AmbientScope => _scopeAccessor.AmbientScope;
private IUmbracoDatabase Database => AmbientScope.Database;
private ISqlContext SqlContext => AmbientScope.SqlContext;
private Sql<ISqlContext> Sql() => SqlContext.Sql();
//private Sql<ISqlContext> Sql(string sql, params object[] args) => SqlContext.Sql(sql, args);
//private ISqlSyntaxProvider SqlSyntax => SqlContext.SqlSyntax;
//private IQuery<T> Query<T>() => SqlContext.Query<T>();
/// <inheritdoc />
public IEnumerable<IContentTypeComposition> GetAllTypes()
{
// use a 5 minutes sliding cache - same as FullDataSet cache policy
return _appCaches.RuntimeCache.GetCacheItem(CacheKey, GetAllTypesInternal, TimeSpan.FromMinutes(5), true);
}
/// <inheritdoc />
public void ClearCache()
{
_appCaches.RuntimeCache.Clear(CacheKey);
}
private IEnumerable<IContentTypeComposition> GetAllTypesInternal()
{
var contentTypes = new Dictionary<int, IContentTypeComposition>();
// get content types
var sql1 = Sql()
.Select<ContentTypeDto>(r => r.Select(x => x.NodeDto))
.From<ContentTypeDto>()
.InnerJoin<NodeDto>().On<ContentTypeDto, NodeDto>((ct, n) => ct.NodeId == n.NodeId)
.OrderBy<ContentTypeDto>(x => x.NodeId);
var contentTypeDtos = Database.Fetch<ContentTypeDto>(sql1);
// get allowed content types
var sql2 = Sql()
.Select<ContentTypeAllowedContentTypeDto>()
.From<ContentTypeAllowedContentTypeDto>()
.OrderBy<ContentTypeAllowedContentTypeDto>(x => x.Id);
var allowedDtos = Database.Fetch<ContentTypeAllowedContentTypeDto>(sql2);
// prepare
// note: same alias could be used for media, content... but always different ids = ok
var aliases = contentTypeDtos.ToDictionary(x => x.NodeId, x => x.Alias);
// create
var allowedDtoIx = 0;
foreach (var contentTypeDto in contentTypeDtos)
{
// create content type
IContentTypeComposition contentType;
if (contentTypeDto.NodeDto.NodeObjectType == Constants.ObjectTypes.MediaType)
contentType = ContentTypeFactory.BuildMediaTypeEntity(contentTypeDto);
else if (contentTypeDto.NodeDto.NodeObjectType == Constants.ObjectTypes.DocumentType)
contentType = ContentTypeFactory.BuildContentTypeEntity(contentTypeDto);
else if (contentTypeDto.NodeDto.NodeObjectType == Constants.ObjectTypes.MemberType)
contentType = ContentTypeFactory.BuildMemberTypeEntity(contentTypeDto);
else throw new Exception("panic");
contentTypes.Add(contentType.Id, contentType);
// map allowed content types
var allowedContentTypes = new List<ContentTypeSort>();
while (allowedDtoIx < allowedDtos.Count && allowedDtos[allowedDtoIx].Id == contentTypeDto.NodeId)
{
var allowedDto = allowedDtos[allowedDtoIx];
if (!aliases.TryGetValue(allowedDto.AllowedId, out var alias)) continue;
allowedContentTypes.Add(new ContentTypeSort(new Lazy<int>(() => allowedDto.AllowedId), allowedDto.SortOrder, alias));
allowedDtoIx++;
}
contentType.AllowedContentTypes = allowedContentTypes;
}
MapTemplates(contentTypes);
MapComposition(contentTypes);
MapGroupsAndProperties(contentTypes);
// finalize
foreach (var contentType in contentTypes.Values)
{
contentType.ResetDirtyProperties(false);
}
return contentTypes.Values;
}
private void MapTemplates(Dictionary<int, IContentTypeComposition> contentTypes)
{
// get templates
var sql1 = Sql()
.Select<ContentTypeTemplateDto>()
.From<ContentTypeTemplateDto>()
.OrderBy<ContentTypeTemplateDto>(x => x.ContentTypeNodeId);
var templateDtos = Database.Fetch<ContentTypeTemplateDto>(sql1);
//var templates = templateRepository.GetMany(templateDtos.Select(x => x.TemplateNodeId).ToArray()).ToDictionary(x => x.Id, x => x);
var templates = _templateRepository.GetMany().ToDictionary(x => x.Id, x => x);
var templateDtoIx = 0;
foreach (var c in contentTypes.Values)
{
if (!(c is ContentType contentType)) continue;
// map allowed templates
var allowedTemplates = new List<ITemplate>();
var defaultTemplateId = 0;
while (templateDtoIx < templateDtos.Count && templateDtos[templateDtoIx].ContentTypeNodeId == contentType.Id)
{
var allowedDto = templateDtos[templateDtoIx];
if (!templates.TryGetValue(allowedDto.TemplateNodeId, out var template)) continue;
allowedTemplates.Add(template);
templateDtoIx++;
if (allowedDto.IsDefault)
defaultTemplateId = template.Id;
}
contentType.AllowedTemplates = allowedTemplates;
contentType.DefaultTemplateId = defaultTemplateId;
}
}
private void MapComposition(IDictionary<int, IContentTypeComposition> contentTypes)
{
// get parent/child
var sql1 = Sql()
.Select<ContentType2ContentTypeDto>()
.From<ContentType2ContentTypeDto>()
.OrderBy<ContentType2ContentTypeDto>(x => x.ChildId);
var compositionDtos = Database.Fetch<ContentType2ContentTypeDto>(sql1);
// map
var compositionIx = 0;
foreach (var contentType in contentTypes.Values)
{
while (compositionIx < compositionDtos.Count && compositionDtos[compositionIx].ChildId == contentType.Id)
{
var parentDto = compositionDtos[compositionIx];
if (!contentTypes.TryGetValue(parentDto.ParentId, out var parentContentType)) continue;
contentType.AddContentType(parentContentType);
compositionIx++;
}
}
}
private void MapGroupsAndProperties(IDictionary<int, IContentTypeComposition> contentTypes)
{
var sql1 = Sql()
.Select<PropertyTypeGroupDto>()
.From<PropertyTypeGroupDto>()
.InnerJoin<ContentTypeDto>().On<PropertyTypeGroupDto, ContentTypeDto>((ptg, ct) => ptg.ContentTypeNodeId == ct.NodeId)
.OrderBy<ContentTypeDto>(x => x.NodeId)
.AndBy<PropertyTypeGroupDto>(x => x.SortOrder, x => x.Id);
var groupDtos = Database.Fetch<PropertyTypeGroupDto>(sql1);
var sql2 = Sql()
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto))
.AndSelect<MemberPropertyTypeDto>()
.From<PropertyTypeDto>()
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((pt, dt) => pt.DataTypeId == dt.NodeId)
.InnerJoin<ContentTypeDto>().On<PropertyTypeDto, ContentTypeDto>((pt, ct) => pt.ContentTypeId == ct.NodeId)
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeDto, PropertyTypeGroupDto>((pt, ptg) => pt.PropertyTypeGroupId == ptg.Id)
.LeftJoin<MemberPropertyTypeDto>().On<PropertyTypeDto, MemberPropertyTypeDto>((pt, mpt) => pt.Id == mpt.PropertyTypeId)
.OrderBy<ContentTypeDto>(x => x.NodeId)
.AndBy<PropertyTypeGroupDto>(x => x.SortOrder, x => x.Id) // NULLs will come first or last, never mind, we deal with it below
.AndBy<PropertyTypeDto>(x => x.SortOrder, x => x.Id);
var propertyDtos = Database.Fetch<PropertyTypeCommonDto>(sql2);
var builtinProperties = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var groupIx = 0;
var propertyIx = 0;
foreach (var contentType in contentTypes.Values)
{
// only IContentType is publishing
var isPublishing = contentType is IContentType;
// get group-less properties (in case NULL is ordered first)
var noGroupPropertyTypes = new PropertyTypeCollection(isPublishing);
while (propertyIx < propertyDtos.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == null)
{
noGroupPropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties));
propertyIx++;
}
// get groups and their properties
var groupCollection = new PropertyGroupCollection();
while (groupIx < groupDtos.Count && groupDtos[groupIx].ContentTypeNodeId == contentType.Id)
{
var group = MapPropertyGroup(groupDtos[groupIx], isPublishing);
groupCollection.Add(group);
groupIx++;
while (propertyIx < propertyDtos.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == group.Id)
{
group.PropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties));
propertyIx++;
}
}
contentType.PropertyGroups = groupCollection;
// get group-less properties (in case NULL is ordered last)
while (propertyIx < propertyDtos.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == null)
{
noGroupPropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties));
propertyIx++;
}
contentType.NoGroupPropertyTypes = noGroupPropertyTypes;
}
}
private PropertyGroup MapPropertyGroup(PropertyTypeGroupDto dto, bool isPublishing)
{
return new PropertyGroup(new PropertyTypeCollection(isPublishing))
{
Id = dto.Id,
Name = dto.Text,
SortOrder = dto.SortOrder,
Key = dto.UniqueId
};
}
private PropertyType MapPropertyType(IContentTypeComposition contentType, PropertyTypeCommonDto dto, IDictionary<string, PropertyType> builtinProperties)
{
var groupId = dto.PropertyTypeGroupId;
var readonlyStorageType = builtinProperties.TryGetValue(dto.Alias, out var propertyType);
var storageType = readonlyStorageType ? propertyType.ValueStorageType : Enum<ValueStorageType>.Parse(dto.DataTypeDto.DbType);
if (contentType is MemberType memberType)
{
var access = new MemberTypePropertyProfileAccess(dto.ViewOnProfile, dto.CanEdit, dto.IsSensitive);
memberType.MemberTypePropertyTypes.Add(dto.Alias, access);
}
return new PropertyType(dto.DataTypeDto.EditorAlias, storageType, readonlyStorageType, dto.Alias)
{
Description = dto.Description,
DataTypeId = dto.DataTypeId,
Id = dto.Id,
Key = dto.UniqueId,
Mandatory = dto.Mandatory,
Name = dto.Name,
PropertyGroupId = groupId.HasValue ? new Lazy<int>(() => groupId.Value) : null,
SortOrder = dto.SortOrder,
ValidationRegExp = dto.ValidationRegExp,
Variations = (ContentVariation)dto.Variations
};
}
}
}
@@ -17,13 +17,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class ContentTypeRepository : ContentTypeRepositoryBase<IContentType>, IContentTypeRepository
{
private readonly ITemplateRepository _templateRepository;
public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, ITemplateRepository templateRepository)
: base(scopeAccessor, cache, logger)
{
_templateRepository = templateRepository;
}
public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
{ }
protected override bool SupportsPublishing => ContentType.SupportsPublishingConst;
@@ -32,75 +28,81 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return new FullDataSetRepositoryCachePolicy<IContentType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
// every GetExists method goes cachePolicy.GetSomething which in turns goes PerformGetAll,
// since this is a FullDataSet policy - and everything is cached
// so here,
// every PerformGet/Exists just GetMany() and then filters
// except PerformGetAll which is the one really doing the job
// TODO: the filtering is highly inefficient as we deep-clone everything
// there should be a way to GetMany(predicate) right from the cache policy!
// and ah, well, this all caching should be refactored + the cache refreshers
// should to repository.Clear() not deal with magic caches by themselves
protected override IContentType PerformGet(int id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Id == id);
}
=> GetMany().FirstOrDefault(x => x.Id == id);
protected override IContentType PerformGet(Guid id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Key == id);
}
=> GetMany().FirstOrDefault(x => x.Key == id);
protected override IContentType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
=> GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
protected override bool PerformExists(Guid id)
{
return GetMany().FirstOrDefault(x => x.Key == id) != null;
}
=> GetMany().FirstOrDefault(x => x.Key == id) != null;
protected override IEnumerable<IContentType> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, SupportsPublishing, this, _templateRepository)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, SupportsPublishing, this, _templateRepository);
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
return CommonRepository.GetAllTypes().OfType<IContentType>();
}
protected override IEnumerable<IContentType> PerformGetAll(params Guid[] ids)
{
// use the underlying GetAll which will force cache all content types
return ids.Any() ? GetMany().Where(x => ids.Contains(x.Key)) : GetMany();
var all = GetMany();
return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all;
}
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContentType>(sqlClause, query);
var baseQuery = GetBaseQuery(false);
var translator = new SqlTranslator<IContentType>(baseQuery, query);
var sql = translator.Translate();
var ids = Database.Fetch<int>(sql).Distinct().ToArray();
var dtos = Database.Fetch<ContentTypeTemplateDto>(sql);
return
//This returns a lookup from the GetAll cached lookup
(dtos.Any()
? GetMany(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
: Enumerable.Empty<IContentType>())
//order the result by name
.OrderBy(x => x.Name);
return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty<IContentType>();
}
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
/// </summary>
/// <param name="query"></param>
/// <returns>An enumerable list of <see cref="IContentType"/> objects</returns>
/// <inheritdoc />
public IEnumerable<IContentType> GetByQuery(IQuery<PropertyType> query)
{
var ints = PerformGetByQuery(query).ToArray();
return ints.Any()
? GetMany(ints)
: Enumerable.Empty<IContentType>();
return ints.Length > 0 ? GetMany(ints) : Enumerable.Empty<IContentType>();
}
protected IEnumerable<int> PerformGetByQuery(IQuery<PropertyType> query)
{
// used by DataTypeService to remove properties
// from content types if they have a deleted data type - see
// notes in DataTypeService.Delete as it's a bit weird
var sqlClause = Sql()
.SelectAll()
.From<PropertyTypeGroupDto>()
.RightJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.NodeId);
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
var sql = translator.Translate()
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
return Database
.FetchOneToMany<PropertyTypeGroupDto>(x => x.PropertyTypeDtos, sql)
.Select(x => x.ContentTypeNodeId).Distinct();
}
/// <summary>
@@ -141,7 +143,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (aliases.Length == 0) return Enumerable.Empty<int>();
var sql = Sql()
.Select("cmsContentType.nodeId")
.Select<ContentTypeDto>(x => x.NodeId)
.From<ContentTypeDto>()
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
@@ -156,14 +158,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
sql = isCount
? sql.SelectCount()
: sql.Select<ContentTypeTemplateDto>(r => r.Select(x => x.ContentTypeDto, r1 => r1.Select(x => x.NodeDto)));
: sql.Select<ContentTypeDto>(x => x.NodeId);
sql
.From<ContentTypeDto>()
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.LeftJoin<ContentTypeTemplateDto>()
.On<ContentTypeTemplateDto, ContentTypeDto>(left => left.ContentTypeNodeId, right => right.NodeId)
.InnerJoin<NodeDto>().On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.LeftJoin<ContentTypeTemplateDto>().On<ContentTypeTemplateDto, ContentTypeDto>(left => left.ContentTypeNodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
@@ -10,11 +10,9 @@ using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
@@ -28,9 +26,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
internal abstract class ContentTypeRepositoryBase<TEntity> : NPocoRepositoryBase<int, TEntity>, IReadRepository<Guid, TEntity>
where TEntity : class, IContentTypeComposition
{
protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger)
protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger)
{ }
{
CommonRepository = commonRepository;
}
protected IContentTypeCommonRepository CommonRepository { get; }
protected abstract bool SupportsPublishing { get; }
@@ -82,38 +84,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return moveInfo;
}
/// <summary>
/// Returns the content type ids that match the query
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
protected IEnumerable<int> PerformGetByQuery(IQuery<PropertyType> query)
protected virtual PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType storageType, string propertyTypeAlias)
{
// used by DataTypeDefinitionRepository to remove properties
// from content types if they have a deleted data type - see
// notes in DataTypeDefinitionRepository.Delete as it's a bit
// weird
var sqlClause = Sql()
.SelectAll()
.From<PropertyTypeGroupDto>()
.RightJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.NodeId);
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
var sql = translator.Translate()
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
return Database
.FetchOneToMany<PropertyTypeGroupDto>(x => x.PropertyTypeDtos, sql)
.Select(x => x.ContentTypeNodeId).Distinct();
return new PropertyType(propertyEditorAlias, storageType, propertyTypeAlias);
}
protected virtual PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType dbType, string propertyTypeAlias)
protected override void PersistDeletedItem(TEntity entity)
{
return new PropertyType(propertyEditorAlias, dbType, propertyTypeAlias);
base.PersistDeletedItem(entity);
CommonRepository.ClearCache(); // always
}
protected void PersistNewBaseContentType(IContentTypeComposition entity)
@@ -228,6 +208,8 @@ AND umbracoNode.nodeObjectType = @objectType",
propertyType.PropertyEditorAlias = dataTypeDto.EditorAlias;
propertyType.ValueStorageType = dataTypeDto.DbType.EnumParse<ValueStorageType>(true);
}
CommonRepository.ClearCache(); // always
}
protected void PersistUpdatedBaseContentType(IContentTypeComposition entity)
@@ -532,6 +514,8 @@ AND umbracoNode.id <> @id",
if (orphanPropertyTypeIds != null)
foreach (var id in orphanPropertyTypeIds)
DeletePropertyType(entity.Id, id);
CommonRepository.ClearCache(); // always
}
private IEnumerable<IContentTypeComposition> GetImpactedContentTypes(IContentTypeComposition contentType, IEnumerable<IContentTypeComposition> all)
@@ -992,74 +976,6 @@ AND umbracoNode.id <> @id",
new { Id = contentTypeId, PropertyTypeId = propertyTypeId });
}
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
{
var sql = Sql()
.SelectAll()
.From<ContentTypeAllowedContentTypeDto>()
.LeftJoin<ContentTypeDto>()
.On<ContentTypeAllowedContentTypeDto, ContentTypeDto>(left => left.AllowedId, right => right.NodeId)
.Where<ContentTypeAllowedContentTypeDto>(x => x.Id == id);
var allowedContentTypeDtos = Database.Fetch<ContentTypeAllowedContentTypeDto>(sql);
return allowedContentTypeDtos.Select(x => new ContentTypeSort(new Lazy<int>(() => x.AllowedId), x.SortOrder, x.ContentTypeDto.Alias)).ToList();
}
protected PropertyGroupCollection GetPropertyGroupCollection(int id, DateTime createDate, DateTime updateDate)
{
var sql = Sql()
.SelectAll()
.From<PropertyTypeGroupDto>()
.LeftJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.LeftJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.NodeId)
.Where<PropertyTypeGroupDto>(x => x.ContentTypeNodeId == id)
.OrderBy<PropertyTypeGroupDto>(x => x.Id);
var dtos = Database
.Fetch<PropertyTypeGroupDto>(sql);
var propertyGroups = PropertyGroupFactory.BuildEntity(dtos, SupportsPublishing, id, createDate, updateDate,CreatePropertyType);
return new PropertyGroupCollection(propertyGroups);
}
protected PropertyTypeCollection GetPropertyTypeCollection(int id, DateTime createDate, DateTime updateDate)
{
var sql = Sql()
.SelectAll()
.From<PropertyTypeDto>()
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.NodeId)
.Where<PropertyTypeDto>(x => x.ContentTypeId == id);
var dtos = Database.Fetch<PropertyTypeDto>(sql);
// TODO: Move this to a PropertyTypeFactory
var list = new List<PropertyType>();
foreach (var dto in dtos.Where(x => x.PropertyTypeGroupId <= 0))
{
var propType = CreatePropertyType(dto.DataTypeDto.EditorAlias, dto.DataTypeDto.DbType.EnumParse<ValueStorageType>(true), dto.Alias);
propType.DataTypeId = dto.DataTypeId;
propType.Description = dto.Description;
propType.Id = dto.Id;
propType.Key = dto.UniqueId;
propType.Name = dto.Name;
propType.Mandatory = dto.Mandatory;
propType.SortOrder = dto.SortOrder;
propType.ValidationRegExp = dto.ValidationRegExp;
propType.CreateDate = createDate;
propType.UpdateDate = updateDate;
list.Add(propType);
}
//Reset dirty properties
Parallel.ForEach(list, currentFile => currentFile.ResetDirtyProperties(false));
return new PropertyTypeCollection(SupportsPublishing, list);
}
protected void ValidateAlias(PropertyType pt)
{
if (string.IsNullOrWhiteSpace(pt.Alias))
@@ -1114,589 +1030,6 @@ AND umbracoNode.id <> @id",
}
}
internal static class ContentTypeQueryMapper
{
public class AssociatedTemplate
{
public AssociatedTemplate(int templateId, string alias, string templateName)
{
TemplateId = templateId;
Alias = alias;
TemplateName = templateName;
}
public int TemplateId { get; set; }
public string Alias { get; set; }
public string TemplateName { get; set; }
protected bool Equals(AssociatedTemplate other)
{
return TemplateId == other.TemplateId;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((AssociatedTemplate)obj);
}
public override int GetHashCode()
{
return TemplateId;
}
}
public static IEnumerable<IMediaType> GetMediaTypes<TRepo>(
IDatabase db, ISqlSyntaxProvider sqlSyntax, bool isPublishing,
TRepo contentTypeRepository)
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<int, List<int>> allParentMediaTypeIds;
var mediaTypes = MapMediaTypes(db, sqlSyntax, out allParentMediaTypeIds)
.ToArray();
MapContentTypeChildren(mediaTypes, db, sqlSyntax, isPublishing, contentTypeRepository, allParentMediaTypeIds);
return mediaTypes;
}
public static IEnumerable<IContentType> GetContentTypes<TRepo>(
IDatabase db, ISqlSyntaxProvider sqlSyntax, bool isPublishing,
TRepo contentTypeRepository,
ITemplateRepository templateRepository)
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<int, List<AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, List<int>> allParentContentTypeIds;
var contentTypes = MapContentTypes(db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
.ToArray();
if (contentTypes.Any())
{
MapContentTypeTemplates(
contentTypes, db, contentTypeRepository, templateRepository, allAssociatedTemplates);
MapContentTypeChildren(contentTypes, db, sqlSyntax, isPublishing, contentTypeRepository, allParentContentTypeIds);
}
return contentTypes;
}
internal static void MapContentTypeChildren<TRepo>(IContentTypeComposition[] contentTypes,
IDatabase db, ISqlSyntaxProvider sqlSyntax, bool isPublishing,
TRepo contentTypeRepository,
IDictionary<int, List<int>> allParentContentTypeIds)
where TRepo : IReadRepository<int, TEntity>
{
//NOTE: SQL call #2
var ids = contentTypes.Select(x => x.Id).ToArray();
IDictionary<int, PropertyGroupCollection> allPropGroups;
IDictionary<int, PropertyTypeCollection> allPropTypes;
MapGroupsAndProperties(ids, db, sqlSyntax, isPublishing, out allPropTypes, out allPropGroups);
foreach (var contentType in contentTypes)
{
contentType.PropertyGroups = allPropGroups[contentType.Id];
contentType.NoGroupPropertyTypes = allPropTypes[contentType.Id];
}
//NOTE: SQL call #3++
if (allParentContentTypeIds != null)
{
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
if (allParentIdsAsArray.Any())
{
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
foreach (var contentType in contentTypes)
{
var entityId = contentType.Id;
var parentContentTypes = allParentContentTypes.Where(x =>
{
var parentEntityId = x.Id;
return allParentContentTypeIds[entityId].Contains(parentEntityId);
});
foreach (var parentContentType in parentContentTypes)
{
var result = contentType.AddContentType(parentContentType);
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
}
// reset dirty initial properties (U4-1946)
((EntityBase)contentType).ResetDirtyProperties(false);
}
}
}
}
internal static void MapContentTypeTemplates<TRepo>(IContentType[] contentTypes,
IDatabase db,
TRepo contentTypeRepository,
ITemplateRepository templateRepository,
IDictionary<int, List<AssociatedTemplate>> associatedTemplates)
where TRepo : IReadRepository<int, TEntity>
{
if (associatedTemplates == null || associatedTemplates.Any() == false) return;
//NOTE: SQL call #3++
//SEE: http://issues.umbraco.org/issue/U4-5174 to fix this
var templateIds = associatedTemplates.SelectMany(x => x.Value).Select(x => x.TemplateId)
.Distinct()
.ToArray();
var templates = (templateIds.Any()
? templateRepository.GetMany(templateIds)
: Enumerable.Empty<ITemplate>()).ToArray();
foreach (var contentType in contentTypes)
{
var entityId = contentType.Id;
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
.Distinct()
.ToArray();
contentType.AllowedTemplates = (associatedTemplateIds.Any()
? templates.Where(x => associatedTemplateIds.Contains(x.Id))
: Enumerable.Empty<ITemplate>()).ToArray();
}
}
internal static IEnumerable<IMediaType> MapMediaTypes(IDatabase db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<int>> parentMediaTypeIds)
{
if (db == null) throw new ArgumentNullException(nameof(db));
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
umbracoNode.uniqueID as nUniqueId
FROM cmsContentType
INNER JOIN umbracoNode
ON cmsContentType.nodeId = umbracoNode.id
LEFT JOIN (
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
FROM cmsContentTypeAllowedContentType
INNER JOIN cmsContentType
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
) AllowedTypes
ON AllowedTypes.Id = cmsContentType.nodeId
LEFT JOIN (
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
FROM cmsContentType2ContentType
INNER JOIN umbracoNode
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = Constants.ObjectTypes.MediaType });
if (result.Any() == false)
{
parentMediaTypeIds = null;
return Enumerable.Empty<IMediaType>();
}
parentMediaTypeIds = new Dictionary<int, List<int>>();
var mappedMediaTypes = new List<IMediaType>();
//loop through each result and fill in our required values, each row will contain different required data than the rest.
// it is much quicker to iterate each result and populate instead of looking up the values over and over in the result like
// we used to do.
var queue = new Queue<dynamic>(result);
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
var ct = queue.Dequeue();
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
currAllowedContentTypes.Add(ctSort);
}
}
//always ensure there's a list for this content type
if (parentMediaTypeIds.ContainsKey(ct.ctId) == false)
parentMediaTypeIds[ct.ctId] = new List<int>();
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
var associatedParentIds = parentMediaTypeIds[ct.ctId];
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var mediaType = CreateForMapping(ct, currAllowedContentTypes);
mappedMediaTypes.Add(mediaType);
//Here we need to reset the current variables, we're now collecting data for a different content type
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedMediaTypes;
}
private static IMediaType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes)
{
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
var contentTypeDto = new ContentTypeDto
{
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
IsElement = currCt.ctIsElement,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
Variations = (byte) currCt.ctVariations,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
};
//now create the content type object;
var mediaType = ContentTypeFactory.BuildMediaTypeEntity(contentTypeDto);
//map the allowed content types
mediaType.AllowedContentTypes = currAllowedContentTypes;
return mediaType;
}
internal static IEnumerable<IContentType> MapContentTypes(IDatabase db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
out IDictionary<int, List<int>> parentContentTypeIds)
{
if (db == null) throw new ArgumentNullException(nameof(db));
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
umbracoNode.uniqueID as nUniqueId,
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
FROM cmsContentType
INNER JOIN umbracoNode
ON cmsContentType.nodeId = umbracoNode.id
LEFT JOIN cmsDocumentType
ON cmsDocumentType.contentTypeNodeId = cmsContentType.nodeId
LEFT JOIN (
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
FROM cmsContentTypeAllowedContentType
INNER JOIN cmsContentType
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
) AllowedTypes
ON AllowedTypes.Id = cmsContentType.nodeId
LEFT JOIN (
SELECT * FROM cmsTemplate
INNER JOIN umbracoNode
ON cmsTemplate.nodeId = umbracoNode.id
) as Template
ON Template.nodeId = cmsDocumentType.templateNodeId
LEFT JOIN (
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
FROM cmsContentType2ContentType
INNER JOIN umbracoNode
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = Constants.ObjectTypes.DocumentType });
if (result.Any() == false)
{
parentContentTypeIds = null;
associatedTemplates = null;
return Enumerable.Empty<IContentType>();
}
parentContentTypeIds = new Dictionary<int, List<int>>();
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
var mappedContentTypes = new List<IContentType>();
var queue = new Queue<dynamic>(result);
var currDefaultTemplate = -1;
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
var ct = queue.Dequeue();
//check for default templates
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
int? templateId = ct.dtTemplateId;
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && isDefaultTemplate.Value && templateId.HasValue)
{
currDefaultTemplate = templateId.Value;
}
//always ensure there's a list for this content type
if (associatedTemplates.ContainsKey(ct.ctId) == false)
associatedTemplates[ct.ctId] = new List<AssociatedTemplate>();
//check for associated templates and assign to the outgoing collection
if (ct.tId != null)
{
var associatedTemplate = new AssociatedTemplate(ct.tId, ct.tAlias, ct.tText);
var associatedList = associatedTemplates[ct.ctId];
if (associatedList.Contains(associatedTemplate) == false)
associatedList.Add(associatedTemplate);
}
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
currAllowedContentTypes.Add(ctSort);
}
}
//always ensure there's a list for this content type
if (parentContentTypeIds.ContainsKey(ct.ctId) == false)
parentContentTypeIds[ct.ctId] = new List<int>();
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
var associatedParentIds = parentContentTypeIds[ct.ctId];
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var contentType = CreateForMapping(ct, currAllowedContentTypes, currDefaultTemplate);
mappedContentTypes.Add(contentType);
//Here we need to reset the current variables, we're now collecting data for a different content type
currDefaultTemplate = -1;
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedContentTypes;
}
private static IContentType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes, int currDefaultTemplate)
{
// * set the default template to the first one if a default isn't found
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
var dtDto = new ContentTypeTemplateDto
{
//create the content type dto
ContentTypeDto = new ContentTypeDto
{
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
IsElement = currCt.ctIsElement,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
Variations = (byte) currCt.ctVariations,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
},
ContentTypeNodeId = currCt.ctId,
IsDefault = currDefaultTemplate != -1,
TemplateNodeId = currDefaultTemplate != -1 ? currDefaultTemplate : 0,
};
//now create the content type object
var contentType = ContentTypeFactory.BuildContentTypeEntity(dtDto.ContentTypeDto);
// NOTE
// that was done by the factory but makes little sense, moved here, so
// now we have to reset dirty props again (as the factory does it) and yet,
// we are not managing allowed templates... the whole thing is weird.
((ContentType)contentType).DefaultTemplateId = dtDto.TemplateNodeId;
contentType.ResetDirtyProperties(false);
//map the allowed content types
contentType.AllowedContentTypes = currAllowedContentTypes;
return contentType;
}
internal static void MapGroupsAndProperties(int[] contentTypeIds, IDatabase db, ISqlSyntaxProvider sqlSyntax, bool isPublishing,
out IDictionary<int, PropertyTypeCollection> allPropertyTypeCollection,
out IDictionary<int, PropertyGroupCollection> allPropertyGroupCollection)
{
allPropertyGroupCollection = new Dictionary<int, PropertyGroupCollection>();
allPropertyTypeCollection = new Dictionary<int, PropertyTypeCollection>();
// query below is not safe + pointless if array is empty
if (contentTypeIds.Length == 0) return;
var sqlGroups = @"SELECT
pg.contenttypeNodeId AS contentTypeId,
pg.id AS id, pg.uniqueID AS " + sqlSyntax.GetQuotedColumnName("key") + @",
pg.sortOrder AS sortOrder, pg." + sqlSyntax.GetQuotedColumnName("text") + @" AS text
FROM cmsPropertyTypeGroup pg
WHERE pg.contenttypeNodeId IN (@ids)
ORDER BY contentTypeId, id";
var sqlProps = @"SELECT
pt.contentTypeId AS contentTypeId,
pt.id AS id, pt.uniqueID AS " + sqlSyntax.GetQuotedColumnName("key") + @",
pt.propertyTypeGroupId AS groupId,
pt.Alias AS alias, pt." + sqlSyntax.GetQuotedColumnName("Description") + @" AS " + sqlSyntax.GetQuotedColumnName("desc") + $@", pt.mandatory AS mandatory,
pt.Name AS name, pt.sortOrder AS sortOrder, pt.validationRegExp AS regexp, pt.variations as variations,
dt.nodeId as dataTypeId, dt.dbType as dbType, dt.propertyEditorAlias as editorAlias
FROM cmsPropertyType pt
INNER JOIN {Constants.DatabaseSchema.Tables.DataType} as dt ON pt.dataTypeId = dt.nodeId
WHERE pt.contentTypeId IN (@ids)
ORDER BY contentTypeId, groupId, id";
if (contentTypeIds.Length > 2000)
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
var groups = db.Fetch<dynamic>(sqlGroups, new { ids = contentTypeIds });
var groupsEnumerator = groups.GetEnumerator();
var group = groupsEnumerator.MoveNext() ? groupsEnumerator.Current : null;
var props = db.Fetch<dynamic>(sqlProps, new { ids = contentTypeIds });
var propsEnumerator = props.GetEnumerator();
var prop = propsEnumerator.MoveNext() ? propsEnumerator.Current : null;
// groups are ordered by content type, group id
// props are ordered by content type, group id, prop id
foreach (var contentTypeId in contentTypeIds)
{
var propertyTypeCollection = allPropertyTypeCollection[contentTypeId] = new PropertyTypeCollection(isPublishing);
var propertyGroupCollection = allPropertyGroupCollection[contentTypeId] = new PropertyGroupCollection();
while (prop != null && prop.contentTypeId == contentTypeId && prop.groupId == null)
{
AddPropertyType(propertyTypeCollection, prop);
prop = propsEnumerator.MoveNext() ? propsEnumerator.Current : null;
}
while (group != null && group.contentTypeId == contentTypeId)
{
var propertyGroup = new PropertyGroup(new PropertyTypeCollection(isPublishing))
{
Id = group.id,
Name = group.text,
SortOrder = group.sortOrder,
Key = group.key
};
propertyGroupCollection.Add(propertyGroup);
while (prop != null && prop.groupId == group.id)
{
AddPropertyType(propertyGroup.PropertyTypes, prop, propertyGroup);
prop = propsEnumerator.MoveNext() ? propsEnumerator.Current : null;
}
group = groupsEnumerator.MoveNext() ? groupsEnumerator.Current : null;
}
}
propsEnumerator.Dispose();
groupsEnumerator.Dispose();
}
private static void AddPropertyType(PropertyTypeCollection propertyTypes, dynamic prop, PropertyGroup propertyGroup = null)
{
var propertyType = new PropertyType(prop.editorAlias, Enum<ValueStorageType>.Parse(prop.dbType), prop.alias)
{
Description = prop.desc,
DataTypeId = prop.dataTypeId,
Id = prop.id,
Key = prop.key,
Mandatory = Convert.ToBoolean(prop.mandatory),
Name = prop.name,
PropertyGroupId = propertyGroup == null ? null : new Lazy<int>(() => propertyGroup.Id),
SortOrder = prop.sortOrder,
ValidationRegExp = prop.regexp,
Variations = (ContentVariation) prop.variations
};
propertyTypes.Add(propertyType);
}
}
protected abstract TEntity PerformGet(Guid id);
protected abstract TEntity PerformGet(string alias);
protected abstract IEnumerable<TEntity> PerformGetAll(params Guid[] ids);
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class MediaTypeRepository : ContentTypeRepositoryBase<IMediaType>, IMediaTypeRepository
{
public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger)
: base(scopeAccessor, cache, logger)
public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
{ }
protected override bool SupportsPublishing => MediaType.SupportsPublishingConst;
@@ -27,83 +27,46 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return new FullDataSetRepositoryCachePolicy<IMediaType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
// every GetExists method goes cachePolicy.GetSomething which in turns goes PerformGetAll,
// since this is a FullDataSet policy - and everything is cached
// so here,
// every PerformGet/Exists just GetMany() and then filters
// except PerformGetAll which is the one really doing the job
protected override IMediaType PerformGet(int id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Id == id);
}
=> GetMany().FirstOrDefault(x => x.Id == id);
protected override IMediaType PerformGet(Guid id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Key == id);
}
=> GetMany().FirstOrDefault(x => x.Key == id);
protected override bool PerformExists(Guid id)
{
return GetMany().FirstOrDefault(x => x.Key == id) != null;
}
=> GetMany().FirstOrDefault(x => x.Key == id) != null;
protected override IMediaType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
=> GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, SupportsPublishing, this)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, SupportsPublishing, this);
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
return CommonRepository.GetAllTypes().OfType<IMediaType>();
}
protected override IEnumerable<IMediaType> PerformGetAll(params Guid[] ids)
{
//use the underlying GetAll which will force cache all content types
if (ids.Any())
{
return GetMany().Where(x => ids.Contains(x.Key));
}
else
{
return GetMany();
}
var all = GetMany();
return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all;
}
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
var baseQuery = GetBaseQuery(false);
var translator = new SqlTranslator<IMediaType>(baseQuery, query);
var sql = translator.Translate();
var ids = Database.Fetch<int>(sql).Distinct().ToArray();
var dtos = Database.Fetch<ContentTypeDto>(sql);
return
//This returns a lookup from the GetAll cached lookup
(dtos.Any()
? GetMany(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
: Enumerable.Empty<IMediaType>())
//order the result by name
.OrderBy(x => x.Name);
}
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
/// </summary>
/// <param name="query"></param>
/// <returns>An enumerable list of <see cref="IMediaType"/> objects</returns>
public IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query)
{
var ints = PerformGetByQuery(query).ToArray();
return ints.Any()
? GetMany(ints)
: Enumerable.Empty<IMediaType>();
return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty<IMediaType>();
}
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
@@ -112,12 +75,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
sql = isCount
? sql.SelectCount()
: sql.Select<ContentTypeDto>(r => r.Select(x => x.NodeDto));
: sql.Select<ContentTypeDto>(x => x.NodeId);
sql
.From<ContentTypeDto>()
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>( left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>().On<ContentTypeDto, NodeDto>( left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class MemberTypeRepository : ContentTypeRepositoryBase<IMemberType>, IMemberTypeRepository
{
public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger)
: base(scopeAccessor, cache, logger)
public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
{ }
protected override bool SupportsPublishing => MemberType.SupportsPublishingConst;
@@ -28,108 +28,49 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return new FullDataSetRepositoryCachePolicy<IMemberType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
// every GetExists method goes cachePolicy.GetSomething which in turns goes PerformGetAll,
// since this is a FullDataSet policy - and everything is cached
// so here,
// every PerformGet/Exists just GetMany() and then filters
// except PerformGetAll which is the one really doing the job
protected override IMemberType PerformGet(int id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Id == id);
}
=> GetMany().FirstOrDefault(x => x.Id == id);
protected override IMemberType PerformGet(Guid id)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Key == id);
}
=> GetMany().FirstOrDefault(x => x.Key == id);
protected override IEnumerable<IMemberType> PerformGetAll(params Guid[] ids)
{
//use the underlying GetAll which will force cache all content types
if (ids.Any())
{
return GetMany().Where(x => ids.Contains(x.Key));
}
else
{
return GetMany();
}
var all = GetMany();
return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all;
}
protected override bool PerformExists(Guid id)
{
return GetMany().FirstOrDefault(x => x.Key == id) != null;
}
=> GetMany().FirstOrDefault(x => x.Key == id) != null;
protected override IMemberType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
=> GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
{
var sql = GetBaseQuery(false);
if (ids.Any())
{
//NOTE: This logic should never be executed according to our cache policy
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
sql.Where(statement);
}
sql.OrderByDescending<NodeDto>(x => x.NodeId);
var dtos = Database
.Fetch<MemberTypeReadOnlyDto>(sql) // cannot use FetchOneToMany because we have 2 collections!
.Transform(MapOneToManies)
.ToList();
return BuildFromDtos(dtos);
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
return CommonRepository.GetAllTypes().OfType<IMemberType>();
}
protected override IEnumerable<IMemberType> PerformGetByQuery(IQuery<IMemberType> query)
{
var sqlSubquery = GetSubquery();
var translator = new SqlTranslator<IMemberType>(sqlSubquery, query);
var subquery = translator.Translate();
var subQuery = GetSubquery();
var translator = new SqlTranslator<IMemberType>(subQuery, query);
var subSql = translator.Translate();
var sql = GetBaseQuery(false)
.Append("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments)
.WhereIn<NodeDto>(x => x.NodeId, subSql)
.OrderBy<NodeDto>(x => x.SortOrder);
var ids = Database.Fetch<int>(sql).Distinct().ToArray();
var dtos = Database
.Fetch<MemberTypeReadOnlyDto>(sql) // cannot use FetchOneToMany because we have 2 collections!
.Transform(MapOneToManies)
.ToList();
return BuildFromDtos(dtos);
}
private IEnumerable<MemberTypeReadOnlyDto> MapOneToManies(IEnumerable<MemberTypeReadOnlyDto> dtos)
{
MemberTypeReadOnlyDto acc = null;
foreach (var dto in dtos)
{
if (acc == null)
{
acc = dto;
}
else if (acc.UniqueId == dto.UniqueId)
{
var prop = dto.PropertyTypes.SingleOrDefault();
var group = dto.PropertyTypeGroups.SingleOrDefault();
if (prop != null && prop.Id.HasValue && acc.PropertyTypes.Any(x => x.Id == prop.Id.Value) == false)
acc.PropertyTypes.Add(prop);
if (group != null && group.Id.HasValue && acc.PropertyTypeGroups.Any(x => x.Id == group.Id.Value) == false)
acc.PropertyTypeGroups.Add(group);
}
else
{
yield return acc;
acc = dto;
}
}
if (acc != null)
yield return acc;
return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty<IMemberType>();
}
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
@@ -144,18 +85,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
var sql = Sql()
.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias",
"cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.mandatory", "cmsPropertyType.UniqueID",
"cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId",
"cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsMemberType.isSensitive",
$"{Constants.DatabaseSchema.Tables.DataType}.propertyEditorAlias", $"{Constants.DatabaseSchema.Tables.DataType}.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID",
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
.Select<NodeDto>(x => x.NodeId)
.From<NodeDto>()
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.LeftJoin<PropertyTypeDto>().On<PropertyTypeDto, NodeDto>(left => left.ContentTypeId, right => right.NodeId)
.LeftJoin<MemberTypeDto>().On<MemberTypeDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.LeftJoin<MemberPropertyTypeDto>().On<MemberPropertyTypeDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.LeftJoin<DataTypeDto>().On<DataTypeDto, PropertyTypeDto>(left => left.NodeId, right => right.DataTypeId)
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeGroupDto, NodeDto>(left => left.ContentTypeNodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
@@ -170,7 +104,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.From<NodeDto>()
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.LeftJoin<PropertyTypeDto>().On<PropertyTypeDto, NodeDto>(left => left.ContentTypeId, right => right.NodeId)
.LeftJoin<MemberTypeDto>().On<MemberTypeDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.LeftJoin<MemberPropertyTypeDto>().On<MemberPropertyTypeDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.LeftJoin<DataTypeDto>().On<DataTypeDto, PropertyTypeDto>(left => left.NodeId, right => right.DataTypeId)
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeGroupDto, NodeDto>(left => left.ContentTypeNodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
@@ -212,12 +146,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
entity.AddPropertyType(standardPropertyType.Value, Constants.Conventions.Member.StandardPropertiesGroupName);
}
EnsureExplicitDataTypeForBuiltInProperties(entity);
PersistNewBaseContentType(entity);
//Handles the MemberTypeDto (cmsMemberType table)
var memberTypeDtos = ContentTypeFactory.BuildMemberTypeDtos(entity);
var memberTypeDtos = ContentTypeFactory.BuildMemberPropertyTypeDtos(entity);
foreach (var memberTypeDto in memberTypeDtos)
{
Database.Insert(memberTypeDto);
@@ -245,13 +179,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
entity.SortOrder = maxSortOrder + 1;
}
EnsureExplicitDataTypeForBuiltInProperties(entity);
PersistUpdatedBaseContentType(entity);
// remove and insert - handle cmsMemberType table
Database.Delete<MemberTypeDto>("WHERE NodeId = @Id", new { Id = entity.Id });
var memberTypeDtos = ContentTypeFactory.BuildMemberTypeDtos(entity);
Database.Delete<MemberPropertyTypeDto>("WHERE NodeId = @Id", new { Id = entity.Id });
var memberTypeDtos = ContentTypeFactory.BuildMemberPropertyTypeDtos(entity);
foreach (var memberTypeDto in memberTypeDtos)
{
Database.Insert(memberTypeDto);
@@ -264,19 +198,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// Override so we can specify explicit db type's on any property types that are built-in.
/// </summary>
/// <param name="propertyEditorAlias"></param>
/// <param name="dbType"></param>
/// <param name="storageType"></param>
/// <param name="propertyTypeAlias"></param>
/// <returns></returns>
protected override PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType dbType, string propertyTypeAlias)
protected override PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType storageType, string propertyTypeAlias)
{
//custom property type constructor logic to set explicit dbtype's for built in properties
var stdProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var propDbType = GetDbTypeForBuiltInProperty(propertyTypeAlias, dbType, stdProps);
return new PropertyType(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,
propertyTypeAlias);
var builtinProperties = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var readonlyStorageType = builtinProperties.TryGetValue(propertyTypeAlias, out var propertyType);
storageType = readonlyStorageType ? propertyType.ValueStorageType : storageType;
return new PropertyType(propertyEditorAlias, storageType, readonlyStorageType, propertyTypeAlias);
}
/// <summary>
@@ -286,62 +217,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <param name="memberType"></param>
private static void EnsureExplicitDataTypeForBuiltInProperties(IContentTypeBase memberType)
{
var stdProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var builtinProperties = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
foreach (var propertyType in memberType.PropertyTypes)
{
var dbTypeAttempt = GetDbTypeForBuiltInProperty(propertyType.Alias, propertyType.ValueStorageType, stdProps);
if (dbTypeAttempt)
if (builtinProperties.ContainsKey(propertyType.Alias))
{
//this reset's it's current data type reference which will be re-assigned based on the property editor assigned on the next line
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
propertyType.DataTypeId = 0;
}
}
}
/// <summary>
/// Builds a collection of entities from a collection of Dtos
/// </summary>
/// <param name="dtos"></param>
/// <returns></returns>
private IEnumerable<IMemberType> BuildFromDtos(List<MemberTypeReadOnlyDto> dtos)
{
if (dtos == null || dtos.Any() == false)
return Enumerable.Empty<IMemberType>();
return dtos.Select(x =>
{
bool needsSaving;
var memberType = MemberTypeReadOnlyFactory.BuildEntity(x, out needsSaving);
if (needsSaving) PersistUpdatedItem(memberType);
return memberType;
}).ToList();
}
/// <summary>
/// If this is one of our internal properties - we will manually assign the data type since they must
/// always correspond to the correct db type no matter what the backing data type is assigned.
/// </summary>
/// <param name="propAlias"></param>
/// <param name="dbType"></param>
/// <param name="standardProps"></param>
/// <returns>
/// Successful attempt if it was a built in property
/// </returns>
internal static Attempt<ValueStorageType> GetDbTypeForBuiltInProperty(
string propAlias,
ValueStorageType dbType,
Dictionary<string, PropertyType> standardProps)
{
var aliases = standardProps.Select(x => x.Key).ToArray();
//check if it is built in
if (aliases.Contains(propAlias))
{
//return the pre-determined db type for this property
return Attempt<ValueStorageType>.Succeed(standardProps.Single(x => x.Key == propAlias).Value.ValueStorageType);
}
return Attempt<ValueStorageType>.Fail(dbType);
}
}
}
@@ -78,51 +78,24 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
}
// TODO: but now that we have 1 unique repository?
// this is a *bad* idea because PerformCount captures the current repository and its UOW
//
//private static RepositoryCachePolicyOptions _defaultOptions;
//protected virtual RepositoryCachePolicyOptions DefaultOptions
//{
// get
// {
// return _defaultOptions ?? (_defaultOptions
// = new RepositoryCachePolicyOptions(() =>
// {
// // get count of all entities of current type (TEntity) to ensure cached result is correct
// // create query once if it is needed (no need for locking here) - query is static!
// var query = _hasIdQuery ?? (_hasIdQuery = Query<TEntity>.Builder.Where(x => x.Id != 0));
// return PerformCount(query);
// }));
// }
//}
// ReSharper disable once StaticMemberInGenericType
private static RepositoryCachePolicyOptions _defaultOptions;
// ReSharper disable once InconsistentNaming
protected virtual RepositoryCachePolicyOptions DefaultOptions
{
get
{
return new RepositoryCachePolicyOptions(() =>
{
// get count of all entities of current type (TEntity) to ensure cached result is correct
// create query once if it is needed (no need for locking here) - query is static!
var query = _hasIdQuery ?? (_hasIdQuery = AmbientScope.SqlContext.Query<TEntity>().Where(x => x.Id != 0));
return PerformCount(query);
});
return _defaultOptions ?? (_defaultOptions
= new RepositoryCachePolicyOptions(() =>
{
// get count of all entities of current type (TEntity) to ensure cached result is correct
// create query once if it is needed (no need for locking here) - query is static!
var query = _hasIdQuery ?? (_hasIdQuery = AmbientScope.SqlContext.Query<TEntity>().Where(x => x.Id != 0));
return PerformCount(query);
}));
}
}
// this would be better for perfs BUT it breaks the tests - l8tr
//
//private static IRepositoryCachePolicy<TEntity, TId> _defaultCachePolicy;
//protected virtual IRepositoryCachePolicy<TEntity, TId> DefaultCachePolicy
//{
// get
// {
// return _defaultCachePolicy ?? (_defaultCachePolicy
// = new DefaultRepositoryCachePolicy<TEntity, TId>(IsolatedCache, DefaultOptions));
// }
//}
protected IRepositoryCachePolicy<TEntity, TId> CachePolicy
{
get
@@ -1,28 +1,12 @@
using System.Collections.Generic;
using AutoMapper;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
namespace Umbraco.Core.Runtime
{
public class CoreInitialComponent : IComponent
{
private readonly IEnumerable<Profile> _mapperProfiles;
public CoreInitialComponent(IEnumerable<Profile> mapperProfiles)
{
_mapperProfiles = mapperProfiles;
}
public void Initialize()
{
// mapper profiles have been registered & are created by the container
Mapper.Initialize(configuration =>
{
foreach (var profile in _mapperProfiles)
configuration.AddProfile(profile);
});
// ensure we have some essential directories
// every other component can then initialize safely
IOHelper.EnsurePathExists("~/App_Data");
+7 -21
View File
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
@@ -12,10 +10,8 @@ using Umbraco.Core.Exceptions;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Logging.Serilog;
using Umbraco.Core.Migrations.Upgrade;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Services.Implement;
using Umbraco.Core.Sync;
namespace Umbraco.Core.Runtime
@@ -70,15 +66,19 @@ namespace Umbraco.Core.Runtime
// objects.
using (var timer = profilingLogger.TraceDuration<CoreRuntime>(
$"Booting Umbraco {UmbracoVersion.SemanticVersion.ToSemanticString()} on {NetworkHelper.MachineName}.",
$"Booting Umbraco {UmbracoVersion.SemanticVersion.ToSemanticString()}.",
"Booted.",
"Boot failed."))
{
logger.Info<CoreRuntime>("Booting site '{HostingSiteName}', app '{HostingApplicationID}', path '{HostingPhysicalPath}', server '{MachineName}'.",
HostingEnvironment.SiteName,
HostingEnvironment.ApplicationID,
HostingEnvironment.ApplicationPhysicalPath,
NetworkHelper.MachineName);
logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
// application environment
ConfigureUnhandledException();
ConfigureAssemblyResolve();
ConfigureApplicationRootPath();
Boot(register, timer);
@@ -211,20 +211,6 @@ namespace Umbraco.Core.Runtime
};
}
protected virtual void ConfigureAssemblyResolve()
{
// When an assembly can't be resolved. In here we can do magic with the assembly name and try loading another.
// This is used for loading a signed assembly of AutoMapper (v. 3.1+) without having to recompile old code.
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
// 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 -> stack overflow
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
return null;
};
}
protected virtual void ConfigureApplicationRootPath()
{
var path = GetApplicationRootPath();
+1 -1
View File
@@ -252,7 +252,7 @@ namespace Umbraco.Core
FinalMigrationState = upgrader.Plan.FinalState;
}
logger.Debug<RuntimeState>("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", CurrentMigrationState, FinalMigrationState ?? "<null>");
logger.Debug<RuntimeState>("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? "<null>");
return CurrentMigrationState == FinalMigrationState;
}
@@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Security;
using AutoMapper;
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Umbraco.Core.Configuration;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
@@ -19,7 +17,7 @@ using Task = System.Threading.Tasks.Task;
namespace Umbraco.Core.Security
{
public class BackOfficeUserStore : DisposableObjectSlim,
public class BackOfficeUserStore : DisposableObjectSlim,
IUserStore<BackOfficeIdentityUser, int>,
IUserPasswordStore<BackOfficeIdentityUser, int>,
IUserEmailStore<BackOfficeIdentityUser, int>,
@@ -40,9 +38,10 @@ namespace Umbraco.Core.Security
private readonly IEntityService _entityService;
private readonly IExternalLoginService _externalLoginService;
private readonly IGlobalSettings _globalSettings;
private readonly UmbracoMapper _mapper;
private bool _disposed = false;
public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider)
public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider, UmbracoMapper mapper)
{
_userService = userService;
_memberTypeService = memberTypeService;
@@ -52,6 +51,7 @@ namespace Umbraco.Core.Security
if (userService == null) throw new ArgumentNullException("userService");
if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider");
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
_mapper = mapper;
_userService = userService;
_externalLoginService = externalLoginService;
@@ -185,7 +185,8 @@ namespace Umbraco.Core.Security
{
return null;
}
return await Task.FromResult(AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user)));
return await Task.FromResult(AssignLoginsCallback(_mapper.Map<BackOfficeIdentityUser>(user)));
}
/// <summary>
@@ -202,7 +203,7 @@ namespace Umbraco.Core.Security
return null;
}
var result = AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user));
var result = AssignLoginsCallback(_mapper.Map<BackOfficeIdentityUser>(user));
return await Task.FromResult(result);
}
@@ -314,7 +315,7 @@ namespace Umbraco.Core.Security
var user = _userService.GetByEmail(email);
var result = user == null
? null
: Mapper.Map<BackOfficeIdentityUser>(user);
: _mapper.Map<BackOfficeIdentityUser>(user);
return Task.FromResult(AssignLoginsCallback(result));
}
@@ -391,7 +392,7 @@ namespace Umbraco.Core.Security
var user = _userService.GetUserById(l.UserId);
if (user != null)
{
output = Mapper.Map<BackOfficeIdentityUser>(user);
output = _mapper.Map<BackOfficeIdentityUser>(user);
break;
}
}
@@ -424,7 +424,6 @@ namespace Umbraco.Core.Services.Implement
return;
}
// find ContentTypes using this IDataTypeDefinition on a PropertyType, and delete
// TODO: media and members?!
// TODO: non-group properties?!
+15 -5
View File
@@ -55,7 +55,11 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="AutoMapper" Version="8.0.0" />
<PackageReference Include="Umbraco.Code">
<Version>1.0.5</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="LightInject" Version="5.4.0" />
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="LightInject.Web" Version="2.0.0" />
@@ -208,10 +212,18 @@
<Compile Include="Composing\TypeHelper.cs" />
<Compile Include="Composing\TypeLoader.cs" />
<Compile Include="IO\MediaPathSchemes\UniqueMediaPathScheme.cs" />
<Compile Include="Mapping\MapperContext.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_1\ChangeNuCacheJsonFormat.cs" />
<Compile Include="Mapping\MapDefinitionCollection.cs" />
<Compile Include="Mapping\MapDefinitionCollectionBuilder.cs" />
<Compile Include="Mapping\IMapDefinition.cs" />
<Compile Include="Mapping\UmbracoMapper.cs" />
<Compile Include="Models\CultureImpact.cs" />
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
<Compile Include="Persistence\Repositories\Implement\ContentTypeCommonRepository.cs" />
<Compile Include="Persistence\Repositories\IContentTypeCommonRepository.cs" />
<Compile Include="Persistence\Repositories\Implement\LanguageRepositoryExtensions.cs" />
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
@@ -441,7 +453,7 @@
<Compile Include="Models\IAuditItem.cs" />
<Compile Include="Models\IConsent.cs" />
<Compile Include="Models\ISimpleContentType.cs" />
<Compile Include="Models\Identity\IdentityMapperProfile.cs" />
<Compile Include="Models\Identity\IdentityMapDefinition.cs" />
<Compile Include="Models\Membership\MemberExportModel.cs" />
<Compile Include="Models\Membership\MemberExportProperty.cs" />
<Compile Include="Models\NotificationEmailBodyParams.cs" />
@@ -855,8 +867,7 @@
<Compile Include="Persistence\Dtos\MacroPropertyDto.cs" />
<Compile Include="Persistence\Dtos\Member2MemberGroupDto.cs" />
<Compile Include="Persistence\Dtos\MemberDto.cs" />
<Compile Include="Persistence\Dtos\MemberTypeDto.cs" />
<Compile Include="Persistence\Dtos\MemberTypeReadOnlyDto.cs" />
<Compile Include="Persistence\Dtos\MemberPropertyTypeDto.cs" />
<Compile Include="Persistence\Dtos\NodeDto.cs" />
<Compile Include="Persistence\Dtos\PropertyDataDto.cs" />
<Compile Include="Persistence\Dtos\PropertyTypeDto.cs" />
@@ -951,7 +962,6 @@
<Compile Include="Persistence\Factories\MacroFactory.cs" />
<Compile Include="Persistence\Factories\ContentBaseFactory.cs" />
<Compile Include="Persistence\Factories\MemberGroupFactory.cs" />
<Compile Include="Persistence\Factories\MemberTypeReadOnlyFactory.cs" />
<Compile Include="Persistence\Factories\PropertyFactory.cs" />
<Compile Include="Persistence\Factories\PropertyGroupFactory.cs" />
<Compile Include="Persistence\Factories\PublicAccessEntryFactory.cs" />
+40 -56
View File
@@ -54,62 +54,46 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed"/>
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
+148
View File
@@ -0,0 +1,148 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Tests.Mapping
{
[TestFixture]
public class MappingTests
{
[Test]
public void SimpleMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var thing1 = new Thing1 { Value = "value" };
var thing2 = mapper.Map<Thing1, Thing2>(thing1);
Assert.IsNotNull(thing2);
Assert.AreEqual("value", thing2.Value);
thing2 = mapper.Map<Thing2>(thing1);
Assert.IsNotNull(thing2);
Assert.AreEqual("value", thing2.Value);
thing2 = new Thing2();
mapper.Map(thing1, thing2);
Assert.AreEqual("value", thing2.Value);
}
[Test]
public void EnumerableMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var thing1A = new Thing1 { Value = "valueA" };
var thing1B = new Thing1 { Value = "valueB" };
var thing1 = new[] { thing1A, thing1B };
var thing2 = mapper.Map<IEnumerable<Thing1>, IEnumerable<Thing2>>(thing1).ToList();
Assert.IsNotNull(thing2);
Assert.AreEqual(2, thing2.Count);
Assert.AreEqual("valueA", thing2[0].Value);
Assert.AreEqual("valueB", thing2[1].Value);
thing2 = mapper.Map<IEnumerable<Thing2>>(thing1).ToList();
Assert.IsNotNull(thing2);
Assert.AreEqual(2, thing2.Count);
Assert.AreEqual("valueA", thing2[0].Value);
Assert.AreEqual("valueB", thing2[1].Value);
thing2 = mapper.MapEnumerable<Thing1, Thing2>(thing1).ToList();
Assert.IsNotNull(thing2);
Assert.AreEqual(2, thing2.Count);
Assert.AreEqual("valueA", thing2[0].Value);
Assert.AreEqual("valueB", thing2[1].Value);
}
[Test]
public void InheritedMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(definitions);
var thing3 = new Thing3 { Value = "value" };
var thing2 = mapper.Map<Thing3, Thing2>(thing3);
Assert.IsNotNull(thing2);
Assert.AreEqual("value", thing2.Value);
thing2 = mapper.Map<Thing2>(thing3);
Assert.IsNotNull(thing2);
Assert.AreEqual("value", thing2.Value);
thing2 = new Thing2();
mapper.Map(thing3, thing2);
Assert.AreEqual("value", thing2.Value);
}
[Test]
public void CollectionsMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition2(),
});
var mapper = new UmbracoMapper(definitions);
// can map a PropertyCollection
var source = new PropertyCollection();
var target = mapper.Map<IEnumerable<ContentPropertyDto>>(source);
}
private class Thing1
{
public string Value { get; set; }
}
private class Thing3 : Thing1
{ }
private class Thing2
{
public string Value { get; set; }
}
private class MapperDefinition1 : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
mapper.Define<Thing1, Thing2>((source, context) => new Thing2(), Map);
}
private void Map(Thing1 source, Thing2 target, MapperContext context)
{
target.Value = source.Value;
}
}
private class MapperDefinition2 : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
mapper.Define<Property, ContentPropertyDto>((source, context) => new ContentPropertyDto(), Map);
}
private static void Map(Property source, ContentPropertyDto target, MapperContext context)
{ }
}
}
}
@@ -1,198 +0,0 @@
using System;
using AutoMapper;
using NUnit.Framework;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
public class AutoMapper6Tests
{
[Test]
public void Test1()
{
ThingProfile.CtorCount = 0;
Assert.AreEqual(0, ThingProfile.CtorCount);
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile1>();
});
Assert.AreEqual(1, ThingProfile.CtorCount);
Assert.AreEqual(0, MemberValueResolver.CtorCount);
var mapper = config.CreateMapper();
Assert.AreEqual(1, ThingProfile.CtorCount);
Assert.AreEqual(0, MemberValueResolver.CtorCount);
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(1, ThingProfile.CtorCount); // one single profile
Assert.AreEqual(4, MemberValueResolver.CtorCount); // many resolvers
}
[Test]
public void Test2()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile2>();
});
var mapper = config.CreateMapper();
Assert.AreEqual(0, ValueResolver.CtorCount);
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(4, ValueResolver.CtorCount); // many resolvers
}
[Test]
public void Test3()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile3>();
});
var mapper = config.CreateMapper();
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
}
// Resolve destination member using a custom value resolver
// void ResolveUsing<TValueResolver>()
// where TValueResolver : IValueResolver<TSource, TDestination, TDestMember>;
// Resolve destination member using a custom value resolver from a source member
// void ResolveUsing<TValueResolver, TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
// void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
// Resolve destination member using a custom value resolver instance
// void ResolveUsing(IValueResolver<TSource, TDestination, TMember> valueResolver);
// void ResolveUsing<TSourceMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember> valueResolver, Expression<Func<TSource, TSourceMember>> sourceMember);
// Resolve destination member using a custom value resolver callback
// void ResolveUsing<TResult>(Func<TSource, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver);
// read https://stackoverflow.com/questions/14875075/automapper-what-is-the-difference-between-mapfrom-and-resolveusing
// about the diff between MapFrom and ResolveUsing... keeping ResolveUsing in our code
public class ThingProfile : Profile
{
public static int CtorCount { get; set; }
public ThingProfile(int ver)
{
CtorCount++;
var map = CreateMap<ThingA, ThingB>()
.ForMember(dest => dest.ValueInt, opt => opt.MapFrom(src => src.ValueInt));
switch (ver)
{
case 0:
break;
case 1:
map
.ForMember(dest => dest.ValueString, opt => opt.MapFrom<MemberValueResolver, string>(src => src.ValueString));
break;
case 2:
map
.ForMember(dest => dest.ValueString, opt => opt.MapFrom<ValueResolver>());
break;
case 3:
// in most cases that should be perfectly enough?
map
.ForMember(dest => dest.ValueString, opt => opt.MapFrom(source => "!!" + source.ValueString + "!!"));
break;
default:
throw new ArgumentOutOfRangeException(nameof(ver));
}
}
}
public class ThingProfile1 : ThingProfile
{
public ThingProfile1() : base(1) { }
}
public class ThingProfile2 : ThingProfile
{
public ThingProfile2() : base(2) { }
}
public class ThingProfile3 : ThingProfile
{
public ThingProfile3() : base(3) { }
}
public class ValueResolver : IValueResolver<ThingA, ThingB, string>
{
public static int CtorCount { get; set; }
public ValueResolver()
{
CtorCount++;
}
public string Resolve(ThingA source, ThingB destination, string destMember, ResolutionContext context)
{
return "!!" + source.ValueString + "!!";
}
}
public class MemberValueResolver : IMemberValueResolver<ThingA, ThingB, string, string>
{
public static int CtorCount { get; set; }
public MemberValueResolver()
{
CtorCount++;
}
public string Resolve(ThingA source, ThingB destination, string sourceMember, string destMember, ResolutionContext context)
{
return "!!" + sourceMember + "!!";
}
}
public class ThingA
{
public int ValueInt { get; set; }
public string ValueString { get; set; }
}
public class ThingB
{
public int ValueInt { get; set; }
public string ValueString { get; set; }
}
}
}
@@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using NUnit.Framework;
using Umbraco.Core.Cache;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
[UmbracoTest(WithApplication = true)]
public class AutoMapperTests : UmbracoTestBase
{
protected override void Compose()
{
base.Compose();
var manifestBuilder = new ManifestParser(
AppCaches.Disabled,
new ManifestValueValidatorCollection(Enumerable.Empty<IManifestValueValidator>()),
Composition.Logger)
{
Path = TestHelper.CurrentAssemblyDirectory
};
Composition.RegisterUnique(_ => manifestBuilder);
Func<IEnumerable<Type>> typeListProducerList = Enumerable.Empty<Type>;
Composition.WithCollectionBuilder<DataEditorCollectionBuilder>()
.Clear()
.Add(typeListProducerList);
}
[Test]
public void AssertConfigurationIsValid()
{
var profiles = Factory.GetAllInstances<Profile>().ToArray();
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
cfg.AddProfile(profile);
});
// validate each profile (better granularity for error reports)
Console.WriteLine("Validate each profile:");
foreach (var profile in profiles)
{
try
{
config.AssertConfigurationIsValid(profile.GetType().FullName);
//Console.WriteLine("OK " + profile.GetType().FullName);
}
catch (Exception e)
{
Console.WriteLine("KO " + profile.GetType().FullName);
Console.WriteLine(e);
}
}
Console.WriteLine();
Console.WriteLine("Validate each profile and throw:");
foreach (var profile in profiles)
{
try
{
config.AssertConfigurationIsValid(profile.GetType().FullName);
}
catch
{
Console.WriteLine("KO " + profile.GetType().FullName);
throw;
}
}
// validate the global config
Console.WriteLine();
Console.WriteLine("Validate global config:");
config.AssertConfigurationIsValid();
}
}
}
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using AutoMapper;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -11,7 +10,6 @@ using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Tests.Testing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Models.Mapping
@@ -28,22 +26,6 @@ namespace Umbraco.Tests.Models.Mapping
private readonly Mock<IFileService> _fileService = new Mock<IFileService>();
private Mock<PropertyEditorCollection> _editorsMock;
public override void SetUp()
{
base.SetUp();
// FIXME: are we initializing mappers that... have already been?
Mapper.Reset();
Mapper.Initialize(configuration =>
{
//initialize our content type mapper
var profile1 = new ContentTypeMapperProfile(_editorsMock.Object, _dataTypeService.Object, _fileService.Object, _contentTypeService.Object, Mock.Of<IMediaTypeService>(), Mock.Of<ILogger>());
configuration.AddProfile(profile1);
var profile2 = new EntityMapperProfile();
configuration.AddProfile(profile2);
});
}
protected override void Compose()
{
base.Compose();
@@ -1,6 +1,5 @@
using System.Globalization;
using System.Linq;
using AutoMapper;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -22,7 +21,7 @@ using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
public class ContentWebModelMappingTests : TestWithDatabaseBase
{
private IContentTypeService _contentTypeService;
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using AutoMapper;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
@@ -10,7 +9,7 @@ using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
public class UserModelMapperTests : TestWithDatabaseBase
{
[Test]
@@ -1,200 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NPoco;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
// fixme - does it make any sense to keep these tests here?
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using NPoco;
//using NUnit.Framework;
//using Umbraco.Core;
//using Umbraco.Core.Models;
//using Umbraco.Core.Persistence.Dtos;
//using Umbraco.Core.Persistence.Repositories;
//using Umbraco.Core.Persistence.Repositories.Implement;
//using Umbraco.Tests.TestHelpers;
//using Umbraco.Tests.Testing;
namespace Umbraco.Tests.Persistence.Querying
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class ContentTypeSqlMappingTests : TestWithDatabaseBase
{
[Test]
public void Can_Map_Content_Type_Templates_And_Allowed_Types()
{
IDictionary<int, List<ContentTypeRepository.ContentTypeQueryMapper.AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, List<int>> allParentContentTypeIds;
IContentType[] contentTypes;
//namespace Umbraco.Tests.Persistence.Querying
//{
// [TestFixture]
// [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
// public class ContentTypeSqlMappingTests : TestWithDatabaseBase
// {
// [Test]
// public void Can_Map_Content_Type_Templates_And_Allowed_Types()
// {
// IDictionary<int, List<ContentTypeQueryMapper<IContentType>.AssociatedTemplate>> allAssociatedTemplates;
// IDictionary<int, List<int>> allParentContentTypeIds;
// IContentType[] contentTypes;
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55554, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55554", SortOrder = 1, UniqueId = new Guid("87D1EAB6-AB27-4852-B3DF-DE8DBA4A1AA0"), Text = "Template 1", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Template 2", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Content Type 1", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// using (var scope = ScopeProvider.CreateScope())
// {
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55554, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55554", SortOrder = 1, UniqueId = new Guid("87D1EAB6-AB27-4852-B3DF-DE8DBA4A1AA0"), Text = "Template 1", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Template 2", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Content Type 1", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsTemplate"))));
scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55554, Alias = "testTemplate1", PrimaryKey = 22221});
scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55555, Alias = "testTemplate2", PrimaryKey = 22222 });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsTemplate"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsTemplate"))));
// scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55554, Alias = "testTemplate1", PrimaryKey = 22221});
// scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55555, Alias = "testTemplate2", PrimaryKey = 22222 });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsTemplate"))));
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = true, TemplateNodeId = 55555 });
scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = false, TemplateNodeId = 55554 });
// scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = true, TemplateNodeId = 55555 });
// scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = false, TemplateNodeId = 55554 });
scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 });
scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2});
// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 });
// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2});
scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997});
scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 });
// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997});
// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 });
contentTypes = ContentTypeRepository.ContentTypeQueryMapper.MapContentTypes(
scope.Database, SqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
.Where(x => new[] { 99997, 99998 }.Contains(x.Id))
.ToArray();
// contentTypes = ContentTypeQueryMapper.GetContentTypes(
// scope.Database, out allAssociatedTemplates, out allParentContentTypeIds)
// .Where(x => new[] { 99997, 99998 }.Contains(x.Id))
// .ToArray();
scope.Complete();
}
// scope.Complete();
// }
var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);
Assert.IsNotNull(contentType1);
// var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);
// Assert.IsNotNull(contentType1);
var associatedTemplates1 = allAssociatedTemplates[contentType1.Id];
var parentContentTypes1 = allParentContentTypeIds[contentType1.Id];
// var associatedTemplates1 = allAssociatedTemplates[contentType1.Id];
// var parentContentTypes1 = allParentContentTypeIds[contentType1.Id];
Assert.AreEqual(2, contentType1.AllowedContentTypes.Count());
Assert.AreEqual(2, associatedTemplates1.Count());
Assert.AreEqual(0, parentContentTypes1.Count());
// Assert.AreEqual(2, contentType1.AllowedContentTypes.Count());
// Assert.AreEqual(2, associatedTemplates1.Count());
// Assert.AreEqual(0, parentContentTypes1.Count());
var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998);
Assert.IsNotNull(contentType2);
// var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998);
// Assert.IsNotNull(contentType2);
var associatedTemplates2 = allAssociatedTemplates[contentType2.Id];
var parentContentTypes2 = allParentContentTypeIds[contentType2.Id];
// var associatedTemplates2 = allAssociatedTemplates[contentType2.Id];
// var parentContentTypes2 = allParentContentTypeIds[contentType2.Id];
Assert.AreEqual(0, contentType2.AllowedContentTypes.Count());
Assert.AreEqual(0, associatedTemplates2.Count());
Assert.AreEqual(1, parentContentTypes2.Count());
}
// Assert.AreEqual(0, contentType2.AllowedContentTypes.Count());
// Assert.AreEqual(0, associatedTemplates2.Count());
// Assert.AreEqual(1, parentContentTypes2.Count());
// }
[Test]
public void Can_Map_Media_Type_And_Allowed_Types()
{
IDictionary<int, List<int>> allParentContentTypeIds;
IMediaType[] contentTypes;
// [Test]
// public void Can_Map_Media_Type_And_Allowed_Types()
// {
// IDictionary<int, List<int>> allParentContentTypeIds;
// IMediaType[] contentTypes;
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Media Type 1", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// using (var scope = ScopeProvider.CreateScope())
// {
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Media Type 1", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 });
scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2 });
// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 });
// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2 });
scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997 });
scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 });
// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997 });
// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 });
contentTypes = ContentTypeRepository.ContentTypeQueryMapper.MapMediaTypes(
scope.Database, SqlSyntax, out allParentContentTypeIds)
.Where(x => (new[] { 99997, 99998 }).Contains(x.Id))
.ToArray();
// contentTypes = ContentTypeQueryMapper<IContentType>.MapMediaTypes(
// scope.Database, SqlSyntax, out allParentContentTypeIds)
// .Where(x => (new[] { 99997, 99998 }).Contains(x.Id))
// .ToArray();
scope.Complete();
}
// scope.Complete();
// }
var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);
Assert.IsNotNull(contentType1);
// var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997);
// Assert.IsNotNull(contentType1);
var parentContentTypes1 = allParentContentTypeIds[contentType1.Id];
// var parentContentTypes1 = allParentContentTypeIds[contentType1.Id];
Assert.AreEqual(2, contentType1.AllowedContentTypes.Count());
Assert.AreEqual(0, parentContentTypes1.Count());
// Assert.AreEqual(2, contentType1.AllowedContentTypes.Count());
// Assert.AreEqual(0, parentContentTypes1.Count());
var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998);
Assert.IsNotNull(contentType2);
// var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998);
// Assert.IsNotNull(contentType2);
var parentContentTypes2 = allParentContentTypeIds[contentType2.Id];
// var parentContentTypes2 = allParentContentTypeIds[contentType2.Id];
Assert.AreEqual(0, contentType2.AllowedContentTypes.Count());
Assert.AreEqual(1, parentContentTypes2.Count());
// Assert.AreEqual(0, contentType2.AllowedContentTypes.Count());
// Assert.AreEqual(1, parentContentTypes2.Count());
}
// }
[Test]
public void Can_Map_All_Property_Groups_And_Types()
{
IDictionary<int, PropertyTypeCollection> allPropTypeCollection;
IDictionary<int, PropertyGroupCollection> allPropGroupCollection;
// [Test]
// public void Can_Map_All_Property_Groups_And_Types()
// {
// IDictionary<int, PropertyTypeCollection> allPropTypeCollection;
// IDictionary<int, PropertyGroupCollection> allPropGroupCollection;
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Test Data Type", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("129241F0-D24E-4FC3-92D1-BC2D48B7C431"), Text = "Test Content Type", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// using (var scope = ScopeProvider.CreateScope())
// {
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Test Data Type", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("129241F0-D24E-4FC3-92D1-BC2D48B7C431"), Text = "Test Content Type", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode"))));
scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 55555, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
// scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 55555, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99999, Alias = "TestContentType", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99999, Alias = "TestContentType", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType"))));
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup"))));
scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77776, UniqueId = 77776.ToGuid(), ContentTypeNodeId = 99999, Text = "Group1", SortOrder = 1 });
scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77777, UniqueId = 77777.ToGuid(), ContentTypeNodeId = 99999, Text = "Group2", SortOrder = 2 });
scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77778, UniqueId = 77778.ToGuid(), ContentTypeNodeId = 99999, Text = "Group3", SortOrder = 3 });
scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77779, UniqueId = 77779.ToGuid(), ContentTypeNodeId = 99999, Text = "Group4", SortOrder = 4 });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup"))));
// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77776, UniqueId = 77776.ToGuid(), ContentTypeNodeId = 99999, Text = "Group1", SortOrder = 1 });
// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77777, UniqueId = 77777.ToGuid(), ContentTypeNodeId = 99999, Text = "Group2", SortOrder = 2 });
// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77778, UniqueId = 77778.ToGuid(), ContentTypeNodeId = 99999, Text = "Group3", SortOrder = 3 });
// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77779, UniqueId = 77779.ToGuid(), ContentTypeNodeId = 99999, Text = "Group4", SortOrder = 4 });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup"))));
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyType"))));
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66662, UniqueId = 66662.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property1", Name = "Property 1", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66663, UniqueId = 66663.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property2", Name = "Property 2", SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66664, UniqueId = 66664.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property3", Name = "Property 3", SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66665, UniqueId = 66665.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property4", Name = "Property 4", SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66666, UniqueId = 66666.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = null, Alias = "property5", Name = "Property 5", SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66667, UniqueId = 66667.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property6", Name = "Property 6", SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66668, UniqueId = 66668.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property7", Name = "Property 7", SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null });
scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyType"))));
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyType"))));
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66662, UniqueId = 66662.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property1", Name = "Property 1", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66663, UniqueId = 66663.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property2", Name = "Property 2", SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66664, UniqueId = 66664.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property3", Name = "Property 3", SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66665, UniqueId = 66665.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property4", Name = "Property 4", SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66666, UniqueId = 66666.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = null, Alias = "property5", Name = "Property 5", SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66667, UniqueId = 66667.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property6", Name = "Property 6", SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66668, UniqueId = 66668.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property7", Name = "Property 7", SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null });
// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyType"))));
ContentTypeRepository.ContentTypeQueryMapper.MapGroupsAndProperties(new[] { 99999 }, scope.Database, SqlSyntax, true, out allPropTypeCollection, out allPropGroupCollection);
// ContentTypeQueryMapper<IContentType>.MapGroupsAndProperties_(new[] { 99999 }, scope.Database, SqlSyntax, true, out allPropTypeCollection, out allPropGroupCollection);
scope.Complete();
}
// scope.Complete();
// }
var propGroupCollection = allPropGroupCollection[99999];
var propTypeCollection = allPropTypeCollection[99999];
// var propGroupCollection = allPropGroupCollection[99999];
// var propTypeCollection = allPropTypeCollection[99999];
Assert.AreEqual(4, propGroupCollection.Count);
Assert.AreEqual(2, propGroupCollection["Group1"].PropertyTypes.Count);
Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property1"));
Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property2"));
Assert.AreEqual(2, propGroupCollection["Group2"].PropertyTypes.Count);
Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property3"));
Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property4"));
Assert.AreEqual(2, propGroupCollection["Group3"].PropertyTypes.Count);
Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property6"));
Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property7"));
Assert.AreEqual(0, propGroupCollection["Group4"].PropertyTypes.Count);
// Assert.AreEqual(4, propGroupCollection.Count);
// Assert.AreEqual(2, propGroupCollection["Group1"].PropertyTypes.Count);
// Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property1"));
// Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property2"));
// Assert.AreEqual(2, propGroupCollection["Group2"].PropertyTypes.Count);
// Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property3"));
// Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property4"));
// Assert.AreEqual(2, propGroupCollection["Group3"].PropertyTypes.Count);
// Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property6"));
// Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property7"));
// Assert.AreEqual(0, propGroupCollection["Group4"].PropertyTypes.Count);
Assert.AreEqual(1, propTypeCollection.Count);
Assert.IsTrue(propTypeCollection.Contains("property5"));
}
}
}
// Assert.AreEqual(1, propTypeCollection.Count);
// Assert.IsTrue(propTypeCollection.Contains("property5"));
// }
// }
//}
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
@@ -20,7 +17,7 @@ using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Tests.Persistence.Repositories
{
[TestFixture]
[UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class ContentTypeRepositoryTest : TestWithDatabaseBase
{
public override void SetUp()
@@ -32,25 +29,28 @@ namespace Umbraco.Tests.Persistence.Repositories
private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository)
{
var cacheHelper = AppCaches.Disabled;
var templateRepository = new TemplateRepository(scopeAccessor, cacheHelper, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(scopeAccessor, cacheHelper, Logger);
contentTypeRepository = new ContentTypeRepository(scopeAccessor, cacheHelper, Logger, templateRepository);
var languageRepository = new LanguageRepository(scopeAccessor, cacheHelper, Logger);
var repository = new DocumentRepository(scopeAccessor, cacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, Logger);
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled);
contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger);
var repository = new DocumentRepository(scopeAccessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
}
private ContentTypeRepository CreateRepository(IScopeAccessor scopeAccessor)
{
var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled);
var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository);
return contentTypeRepository;
}
private MediaTypeRepository CreateMediaTypeRepository(IScopeAccessor scopeAccessor)
{
var contentTypeRepository = new MediaTypeRepository(scopeAccessor, AppCaches.Disabled, Logger);
var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled);
var contentTypeRepository = new MediaTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository);
return contentTypeRepository;
}
@@ -60,7 +60,7 @@ namespace Umbraco.Tests.Persistence.Repositories
}
// TODO: Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id).
[Test]
public void Maps_Templates_Correctly()
{
@@ -80,13 +80,13 @@ namespace Umbraco.Tests.Persistence.Repositories
{
templateRepo.Save(template);
}
var contentType = MockedContentTypes.CreateSimpleContentType();
contentType.AllowedTemplates = new[] { templates[0], templates[1] };
contentType.SetDefaultTemplate(templates[0]);
repository.Save(contentType);
//re-get
var result = repository.Get(contentType.Id);
@@ -107,16 +107,16 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateRepository((IScopeAccessor) provider);
var container1 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah1" };
containerRepository.Save(container1);
var container2 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah2", ParentId = container1.Id };
containerRepository.Save(container2);
var contentType = (IContentType)MockedContentTypes.CreateBasicContentType("asdfasdf");
contentType.ParentId = container2.Id;
repository.Save(contentType);
//create a
var contentType2 = (IContentType)new ContentType(contentType, "hello")
@@ -125,10 +125,10 @@ namespace Umbraco.Tests.Persistence.Repositories
};
contentType.ParentId = contentType.Id;
repository.Save(contentType2);
var result = repository.Move(contentType, container1).ToArray();
Assert.AreEqual(2, result.Count());
@@ -152,7 +152,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer);
var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" };
containerRepository.Save(container);
Assert.That(container.Id, Is.GreaterThan(0));
var found = containerRepository.Get(container.Id);
@@ -176,7 +176,7 @@ namespace Umbraco.Tests.Persistence.Repositories
containerRepository.Save(container2);
container3 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container3" };
containerRepository.Save(container3);
Assert.That(container1.Id, Is.GreaterThan(0));
Assert.That(container2.Id, Is.GreaterThan(0));
Assert.That(container3.Id, Is.GreaterThan(0));
@@ -201,11 +201,11 @@ namespace Umbraco.Tests.Persistence.Repositories
var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer);
var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" };
containerRepository.Save(container);
// Act
containerRepository.Delete(container);
var found = containerRepository.Get(container.Id);
Assert.IsNull(found);
@@ -222,12 +222,12 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateRepository((IScopeAccessor) provider);
var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" };
containerRepository.Save(container);
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup");
contentType.ParentId = container.Id;
repository.Save(contentType);
Assert.AreEqual(container.Id, contentType.ParentId);
}
@@ -243,16 +243,16 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = CreateMediaTypeRepository((IScopeAccessor) provider);
var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" };
containerRepository.Save(container);
IMediaType contentType = MockedContentTypes.CreateSimpleMediaType("test", "Test", propertyGroupName: "testGroup");
contentType.ParentId = container.Id;
repository.Save(contentType);
// Act
containerRepository.Delete(container);
var found = containerRepository.Get(container.Id);
Assert.IsNull(found);
@@ -274,7 +274,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup");
repository.Save(contentType);
var fetched = repository.Get(contentType.Id);
@@ -294,7 +294,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreNotEqual(propertyType.Key, Guid.Empty);
}
TestHelper.AssertPropertyValuesAreEqual(contentType, fetched, "yyyy-MM-dd HH:mm:ss", ignoreProperties: new [] { "DefaultTemplate", "AllowedTemplates", "UpdateDate" });
TestHelper.AssertPropertyValuesAreEqual(fetched, contentType, "yyyy-MM-dd HH:mm:ss", ignoreProperties: new [] { "DefaultTemplate", "AllowedTemplates", "UpdateDate" });
}
}
@@ -323,7 +323,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual(4, mapped.PropertyTypes.Count());
repository.Save(mapped);
Assert.AreEqual(4, mapped.PropertyTypes.Count());
@@ -371,7 +371,7 @@ namespace Umbraco.Tests.Persistence.Repositories
DataTypeId = -88
});
repository.Save(contentType);
var dirty = contentType.IsDirty();
@@ -469,7 +469,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.IsTrue(mapped.PropertyTypes.Any(x => x.Alias == "subtitle"));
repository.Save(mapped);
var dirty = mapped.IsDirty();
@@ -500,11 +500,11 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var contentType = MockedContentTypes.CreateSimpleContentType();
repository.Save(contentType);
var contentType2 = repository.Get(contentType.Id);
repository.Delete(contentType2);
var exists = repository.Exists(contentType.Id);
@@ -528,13 +528,13 @@ namespace Umbraco.Tests.Persistence.Repositories
repository.Save(ctMain);
repository.Save(ctChild1);
repository.Save(ctChild2);
// Act
var resolvedParent = repository.Get(ctMain.Id);
repository.Delete(resolvedParent);
// Assert
Assert.That(repository.Exists(ctMain.Id), Is.False);
@@ -546,19 +546,27 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Can_Perform_Query_On_ContentTypeRepository_Sort_By_Name()
{
IContentType contentType;
// Arrange
var provider = TestObjects.GetScopeProvider(Logger);
using (var scope = provider.CreateScope())
{
var repository = CreateRepository((IScopeAccessor) provider);
var contentType = repository.Get(NodeDto.NodeIdSeed + 1);
contentType = repository.Get(NodeDto.NodeIdSeed + 1);
var child1 = MockedContentTypes.CreateSimpleContentType("abc", "abc", contentType, randomizeAliases: true);
repository.Save(child1);
var child3 = MockedContentTypes.CreateSimpleContentType("zyx", "zyx", contentType, randomizeAliases: true);
repository.Save(child3);
var child2 = MockedContentTypes.CreateSimpleContentType("a123", "a123", contentType, randomizeAliases: true);
repository.Save(child2);
scope.Complete();
}
using (var scope = provider.CreateScope())
{
var repository = CreateRepository((IScopeAccessor)provider);
// Act
var contentTypes = repository.Get(scope.SqlContext.Query<IContentType>().Where(x => x.ParentId == contentType.Id));
@@ -601,7 +609,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var contentType = repository.Get(NodeDto.NodeIdSeed + 1);
var childContentType = MockedContentTypes.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases:true);
repository.Save(childContentType);
// Act
var result = repository.Get(childContentType.Key);
@@ -703,7 +711,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
contentType.PropertyGroups["Meta"].PropertyTypes.Remove("description");
repository.Save(contentType);
var result = repository.Get(NodeDto.NodeIdSeed + 1);
@@ -779,7 +787,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5));
repository.Save(contentType);
// Assert
var updated = repository.Get(NodeDto.NodeIdSeed + 1);
@@ -804,7 +812,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var simpleSubpageContentType = MockedContentTypes.CreateSimpleContentType("umbSimpleSubpage", "Simple Subpage");
repository.Save(subpageContentType);
repository.Save(simpleSubpageContentType);
// Act
var contentType = repository.Get(NodeDto.NodeIdSeed);
@@ -814,7 +822,7 @@ namespace Umbraco.Tests.Persistence.Repositories
new ContentTypeSort(new Lazy<int>(() => simpleSubpageContentType.Id), 1, simpleSubpageContentType.Alias)
};
repository.Save(contentType);
//Assert
var updated = repository.Get(NodeDto.NodeIdSeed);
@@ -838,12 +846,12 @@ namespace Umbraco.Tests.Persistence.Repositories
var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
contentRepository.Save(subpage);
// Act
contentType.RemovePropertyType("keywords");
repository.Save(contentType);
// Assert
Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(3));
@@ -865,13 +873,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
contentRepository.Save(subpage);
// Act
var propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
propertyGroup.PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
repository.Save(contentType);
// Assert
Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5));
@@ -893,18 +901,18 @@ namespace Umbraco.Tests.Persistence.Repositories
var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
contentRepository.Save(subpage);
var propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
propertyGroup.PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
repository.Save(contentType);
// Act
var content = contentRepository.Get(subpage.Id);
content.SetValue("metaAuthor", "John Doe");
contentRepository.Save(content);
//Assert
var updated = contentRepository.Get(subpage.Id);
@@ -927,7 +935,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
contentRepository.Save(subpage);
//Remove PropertyType
contentType.RemovePropertyType("keywords");
@@ -935,13 +943,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
propertyGroup.PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
repository.Save(contentType);
// Act
var content = contentRepository.Get(subpage.Id);
content.SetValue("metaAuthor", "John Doe");
contentRepository.Save(content);
//Assert
var updated = contentRepository.Get(subpage.Id);
@@ -66,7 +66,8 @@ namespace Umbraco.Tests.Persistence.Repositories
templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger);
contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches);
contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, commonRepository);
var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger);
var repository = new DocumentRepository(scopeAccessor, appCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
@@ -22,7 +22,8 @@ namespace Umbraco.Tests.Persistence.Repositories
var accessor = (IScopeAccessor) provider;
var templateRepository = new TemplateRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, commonRepository);
languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
var domainRepository = new DomainRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
@@ -4,6 +4,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence;
@@ -35,7 +36,9 @@ namespace Umbraco.Tests.Persistence.Repositories
appCaches = appCaches ?? AppCaches;
var scopeAccessor = (IScopeAccessor) provider;
mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger);
var templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock());
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches);
mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger, commonRepository);
var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger);
var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
return repository;
@@ -6,7 +6,6 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Scoping;
using Umbraco.Tests.TestHelpers;
@@ -21,7 +20,10 @@ namespace Umbraco.Tests.Persistence.Repositories
{
private MediaTypeRepository CreateRepository(IScopeProvider provider)
{
return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var cacheHelper = AppCaches.Disabled;
var templateRepository = new TemplateRepository((IScopeAccessor)provider, cacheHelper, Logger, TestObjects.GetFileSystemsMock());
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches);
return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository);
}
private EntityContainerRepository CreateContainerRepository(IScopeProvider provider)
@@ -29,7 +29,9 @@ namespace Umbraco.Tests.Persistence.Repositories
private MemberRepository CreateRepository(IScopeProvider provider, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository)
{
var accessor = (IScopeAccessor) provider;
memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, Logger);
var templateRepository = Mock.Of<ITemplateRepository>();
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository);
memberGroupRepository = new MemberGroupRepository(accessor, AppCaches.Disabled, Logger);
var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger);
var repository = new MemberRepository(accessor, AppCaches.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of<ILanguageRepository>());
@@ -196,17 +198,17 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType = MockedContentTypes.CreateSimpleMemberType();
memberTypeRepository.Save(memberType);
var member = MockedMember.CreateSimpleMember(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty");
repository.Save(member);
sut = repository.Get(member.Id);
//when the password is null it will not overwrite what is already there.
sut.RawPasswordValue = null;
repository.Save(sut);
sut = repository.Get(member.Id);
Assert.That(sut.RawPasswordValue, Is.EqualTo("123"));
@@ -226,17 +228,17 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType = MockedContentTypes.CreateSimpleMemberType();
memberTypeRepository.Save(memberType);
var member = MockedMember.CreateSimpleMember(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty");
repository.Save(member);
sut = repository.Get(member.Id);
sut.Username = "This is new";
sut.Email = "thisisnew@hello.com";
repository.Save(sut);
sut = repository.Get(member.Id);
Assert.That(sut.Email, Is.EqualTo("thisisnew@hello.com"));
@@ -278,7 +280,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
memberType = MockedContentTypes.CreateSimpleMemberType();
memberTypeRepository.Save(memberType);
}
var member = MockedMember.CreateSimpleMember(memberType, name ?? "Johnny Hefty", email ?? "johnny@example.com", password ?? "123", username ?? "hefty", key);
@@ -22,7 +22,9 @@ namespace Umbraco.Tests.Persistence.Repositories
{
private MemberTypeRepository CreateRepository(IScopeProvider provider)
{
return new MemberTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>());
var templateRepository = Mock.Of<ITemplateRepository>();
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches);
return new MemberTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), commonRepository);
}
[Test]
@@ -35,7 +37,6 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType = (IMemberType) MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
var sut = repository.Get(memberType.Id);
@@ -88,7 +89,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType = MockedContentTypes.CreateSimpleMemberType();
memberType.Alias = null;
Assert.Throws<InvalidOperationException>(() => repository.Save(memberType));
}
@@ -104,13 +105,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType1 = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType1);
var memberType2 = MockedContentTypes.CreateSimpleMemberType();
memberType2.Name = "AnotherType";
memberType2.Alias = "anotherType";
repository.Save(memberType2);
var result = repository.GetMany();
@@ -129,13 +130,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType1 = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType1);
var memberType2 = MockedContentTypes.CreateSimpleMemberType();
memberType2.Name = "AnotherType";
memberType2.Alias = "anotherType";
repository.Save(memberType2);
var result = ((IReadRepository<Guid, IMemberType>)repository).GetMany(memberType1.Key, memberType2.Key);
@@ -154,13 +155,13 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType1 = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType1);
var memberType2 = MockedContentTypes.CreateSimpleMemberType();
memberType2.Name = "AnotherType";
memberType2.Alias = "anotherType";
repository.Save(memberType2);
var result = repository.Get(memberType1.Key);
@@ -183,14 +184,14 @@ namespace Umbraco.Tests.Persistence.Repositories
var memberType1 = MockedContentTypes.CreateSimpleMemberType();
memberType1.PropertyTypeCollection.Clear();
repository.Save(memberType1);
var memberType2 = MockedContentTypes.CreateSimpleMemberType();
memberType2.PropertyTypeCollection.Clear();
memberType2.Name = "AnotherType";
memberType2.Alias = "anotherType";
repository.Save(memberType2);
var result = repository.GetMany();
@@ -210,7 +211,7 @@ namespace Umbraco.Tests.Persistence.Repositories
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
memberType = repository.Get(memberType.Id);
Assert.That(memberType, Is.Not.Null);
}
@@ -226,7 +227,7 @@ namespace Umbraco.Tests.Persistence.Repositories
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
memberType = repository.Get(memberType.Key);
Assert.That(memberType, Is.Not.Null);
}
@@ -242,7 +243,7 @@ namespace Umbraco.Tests.Persistence.Repositories
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
memberType = repository.Get(memberType.Id);
@@ -265,7 +266,7 @@ namespace Umbraco.Tests.Persistence.Repositories
IMemberType memberType2 = MockedContentTypes.CreateSimpleMemberType("test2");
repository.Save(memberType1);
repository.Save(memberType2);
var m1Ids = memberType1.PropertyTypes.Select(x => x.Id).ToArray();
var m2Ids = memberType2.PropertyTypes.Select(x => x.Id).ToArray();
@@ -286,11 +287,11 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
var contentType2 = repository.Get(memberType.Id);
repository.Delete(contentType2);
var exists = repository.Exists(memberType.Id);
@@ -307,7 +307,8 @@ namespace Umbraco.Tests.Persistence.Repositories
var accessor = (IScopeAccessor) provider;
var templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, AppCaches, Logger);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository);
var languageRepository = new LanguageRepository(accessor, AppCaches, Logger);
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
@@ -955,7 +955,8 @@ namespace Umbraco.Tests.Persistence.Repositories
var accessor = (IScopeAccessor) provider;
var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
@@ -964,8 +965,10 @@ namespace Umbraco.Tests.Persistence.Repositories
private MediaRepository CreateMediaRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository)
{
var accessor = (IScopeAccessor) provider;
var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger);
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled);
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository);
var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
return repository;
}
@@ -238,7 +238,8 @@ namespace Umbraco.Tests.Persistence.Repositories
var templateRepository = CreateRepository(ScopeProvider);
var tagRepository = new TagRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger);
var contentTypeRepository = new ContentTypeRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(ScopeProvider, templateRepository, AppCaches);
var contentTypeRepository = new ContentTypeRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger);
var contentRepo = new DocumentRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
@@ -3,8 +3,6 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Mappers;
@@ -26,7 +24,9 @@ namespace Umbraco.Tests.Persistence.Repositories
private MediaRepository CreateMediaRepository(IScopeProvider provider, out IMediaTypeRepository mediaTypeRepository)
{
var accessor = (IScopeAccessor) provider;
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches, Mock.Of<ILogger>());
var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches, Mock.Of<ILogger>(), commonRepository);
var tagRepository = new TagRepository(accessor, AppCaches, Mock.Of<ILogger>());
var repository = new MediaRepository(accessor, AppCaches, Mock.Of<ILogger>(), mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
return repository;
@@ -43,7 +43,8 @@ namespace Umbraco.Tests.Persistence.Repositories
var accessor = (IScopeAccessor) provider;
templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, AppCaches, Logger);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository);
var languageRepository = new LanguageRepository(accessor, AppCaches, Logger);
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
@@ -316,7 +316,7 @@ namespace Umbraco.Tests.Persistence
helper.CreateTable<NodeDto>();
helper.CreateTable<ContentTypeDto>();
helper.CreateTable<MemberTypeDto>();
helper.CreateTable<MemberPropertyTypeDto>();
scope.Complete();
}
@@ -165,7 +165,8 @@ namespace Umbraco.Tests.Services
{
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository);
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
@@ -198,7 +199,8 @@ namespace Umbraco.Tests.Services
{
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository);
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
@@ -229,7 +231,8 @@ namespace Umbraco.Tests.Services
{
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository);
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor) provider, tRepository, AppCaches);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
@@ -263,7 +266,8 @@ namespace Umbraco.Tests.Services
{
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, tRepository);
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
@@ -757,7 +757,7 @@ namespace Umbraco.Tests.Services
content = ServiceContext.ContentService.GetById(content.Id);
Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode));
Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode));
}
@@ -784,7 +784,7 @@ namespace Umbraco.Tests.Services
IContent content = new Content("content", Constants.System.Root, contentType);
content.SetCultureName("content-en", langGB.IsoCode);
content.SetCultureName("content-fr", langFr.IsoCode);
Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content, new []{ langGB.IsoCode , langFr.IsoCode }).Success);
//re-get
@@ -1597,7 +1597,7 @@ namespace Umbraco.Tests.Services
var contentType = MockedContentTypes.CreateAllTypesContentType("test", "test");
ServiceContext.ContentTypeService.Save(contentType, Constants.Security.SuperUserId);
object obj =
new
{
@@ -3007,7 +3007,8 @@ namespace Umbraco.Tests.Services
var accessor = (IScopeAccessor) provider;
var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock());
var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, templateRepository);
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository);
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
return repository;
@@ -1654,17 +1654,31 @@ namespace Umbraco.Tests.Services
// create 'page' content type with a 'Content_' group
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, false, "Content_");
Assert.IsTrue(page.PropertyGroups.Contains("Content_"));
Assert.AreEqual(1, page.PropertyGroups.Count);
Assert.AreEqual("Content_", page.PropertyGroups.First().Name);
Assert.AreEqual(3, page.PropertyTypes.Count());
Assert.AreEqual("Title", page.PropertyTypes.First().Name);
Assert.AreEqual("Body Text", page.PropertyTypes.Skip(1).First().Name);
Assert.AreEqual("Author", page.PropertyTypes.Skip(2).First().Name);
service.Save(page);
// create 'contentPage' content type as a child of 'page'
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true);
Assert.AreEqual(1, page.PropertyGroups.Count);
Assert.AreEqual("Content_", page.PropertyGroups.First().Name);
Assert.AreEqual(3, contentPage.PropertyTypes.Count());
Assert.AreEqual("Title", contentPage.PropertyTypes.First().Name);
Assert.AreEqual("Body Text", contentPage.PropertyTypes.Skip(1).First().Name);
Assert.AreEqual("Author", contentPage.PropertyTypes.Skip(2).First().Name);
service.Save(contentPage);
// add 'Content' group to 'meta' content type
var meta = MockedContentTypes.CreateMetaContentType();
Assert.AreEqual(1, meta.PropertyGroups.Count);
Assert.AreEqual("Meta", meta.PropertyGroups.First().Name);
Assert.AreEqual(2, meta.PropertyTypes.Count());
Assert.AreEqual("Meta Keywords", meta.PropertyTypes.First().Name);
Assert.AreEqual("Meta Description", meta.PropertyTypes.Skip(1).First().Name);
meta.AddPropertyGroup("Content");
Assert.AreEqual(2, meta.PropertyTypes.Count());
service.Save(meta);
@@ -12,17 +12,17 @@ namespace Umbraco.Tests.Testing
/// <remarks>
/// <para>Default is false.</para>
/// <para>This is for tests that inherited from TestWithApplicationBase.</para>
/// <para>Implies AutoMapper = true (, ResetPluginManager = false).</para>
/// <para>Implies Mapper = true (, ResetPluginManager = false).</para>
/// </remarks>
public bool WithApplication { get => _withApplication.ValueOrDefault(false); set => _withApplication.Set(value); }
private readonly Settable<bool> _withApplication = new Settable<bool>();
/// <summary>
/// Gets or sets a value indicating whether to compose and initialize AutoMapper.
/// Gets or sets a value indicating whether to compose and initialize the mapper.
/// </summary>
/// <remarks>Default is false unless WithApplication is true, in which case default is true.</remarks>
public bool AutoMapper { get => _autoMapper.ValueOrDefault(WithApplication); set => _autoMapper.Set(value); }
private readonly Settable<bool> _autoMapper = new Settable<bool>();
public bool Mapper { get => _mapper.ValueOrDefault(WithApplication); set => _mapper.Set(value); }
private readonly Settable<bool> _mapper = new Settable<bool>();
// FIXME: to be completed
/// <summary>
@@ -59,7 +59,7 @@ namespace Umbraco.Tests.Testing
base.Merge(other);
_autoMapper.Set(attr._autoMapper);
_mapper.Set(attr._mapper);
_publishedRepositoryEvents.Set(attr._publishedRepositoryEvents);
_logger.Set(attr._logger);
_database.Set(attr._database);
+5 -18
View File
@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Reflection;
using AutoMapper;
using Examine;
using Moq;
using NUnit.Framework;
@@ -37,6 +36,7 @@ using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Trees;
using Umbraco.Core.Composing.CompositionExtensions;
using Umbraco.Core.Mapping;
using Umbraco.Web.Composing.CompositionExtensions;
using Umbraco.Web.Sections;
using Current = Umbraco.Core.Composing.Current;
@@ -108,6 +108,8 @@ namespace Umbraco.Tests.Testing
protected IMapperCollection Mappers => Factory.GetInstance<IMapperCollection>();
protected UmbracoMapper Mapper => Factory.GetInstance<UmbracoMapper>();
#endregion
#region Setup
@@ -148,7 +150,7 @@ namespace Umbraco.Tests.Testing
protected virtual void Compose()
{
ComposeAutoMapper(Options.AutoMapper);
ComposeMapper(Options.Mapper);
ComposeDatabase(Options.Database);
ComposeApplication(Options.WithApplication);
@@ -165,7 +167,6 @@ namespace Umbraco.Tests.Testing
protected virtual void Initialize()
{
InitializeAutoMapper(Options.AutoMapper);
InitializeApplication(Options.WithApplication);
}
@@ -249,7 +250,7 @@ namespace Umbraco.Tests.Testing
Composition.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
}
protected virtual void ComposeAutoMapper(bool configure)
protected virtual void ComposeMapper(bool configure)
{
if (configure == false) return;
@@ -371,18 +372,6 @@ namespace Umbraco.Tests.Testing
#region Initialize
protected virtual void InitializeAutoMapper(bool configure)
{
if (configure == false) return;
Mapper.Initialize(configuration =>
{
var profiles = Factory.GetAllInstances<Profile>();
foreach (var profile in profiles)
configuration.AddProfile(profile);
});
}
protected virtual void InitializeApplication(bool withApplication)
{
if (withApplication == false) return;
@@ -430,8 +419,6 @@ namespace Umbraco.Tests.Testing
UriUtility.ResetAppDomainAppVirtualPath();
SettingsForTests.Reset(); // FIXME: should it be optional?
Mapper.Reset();
// clear static events
DocumentRepository.ClearScopeEvents();
MediaRepository.ClearScopeEvents();
+1 -3
View File
@@ -78,7 +78,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="8.0.0" />
<PackageReference Include="Castle.Core" Version="4.3.1" />
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="HtmlAgilityPack">
@@ -131,6 +130,7 @@
<Compile Include="LegacyXmlPublishedCache\PreviewXmlDto.cs" />
<Compile Include="Logging\LogviewerTests.cs" />
<Compile Include="Manifest\ManifestContentAppTests.cs" />
<Compile Include="Mapping\MappingTests.cs" />
<Compile Include="Migrations\MigrationPlanTests.cs" />
<Compile Include="Migrations\MigrationTests.cs" />
<Compile Include="Models\ContentScheduleTests.cs" />
@@ -166,7 +166,6 @@
<Compile Include="Issues\U9560.cs" />
<Compile Include="Integration\ContentEventsTests.cs" />
<Compile Include="Migrations\AdvancedMigrationTests.cs" />
<Compile Include="Models\Mapping\AutoMapper6Tests.cs" />
<Compile Include="Models\Mapping\UserModelMapperTests.cs" />
<Compile Include="Packaging\PackageExtractionTests.cs" />
<Compile Include="Persistence\NPocoTests\NPocoFetchTests.cs" />
@@ -275,7 +274,6 @@
<Compile Include="Migrations\Stubs\SixZeroMigration2.cs" />
<Compile Include="Testing\TestingTests\MockTests.cs" />
<Compile Include="Models\MacroTests.cs" />
<Compile Include="Models\Mapping\AutoMapperTests.cs" />
<Compile Include="Models\Collections\Item.cs" />
<Compile Include="Models\Collections\OrderItem.cs" />
<Compile Include="Models\Collections\SimpleOrder.cs" />
@@ -291,84 +291,3 @@ function appState(eventsService) {
};
}
angular.module('umbraco.services').factory('appState', appState);
/**
* @ngdoc service
* @name umbraco.services.editorState
* @function
*
* @description
* Tracks the parent object for complex editors by exposing it as
* an object reference via editorState.current.entity
*
* it is possible to modify this object, so should be used with care
*/
angular.module('umbraco.services').factory("editorState", function() {
var current = null;
var state = {
/**
* @ngdoc function
* @name umbraco.services.angularHelper#set
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Sets the current entity object for the currently active editor
* This is only used when implementing an editor with a complex model
* like the content editor, where the model is modified by several
* child controllers.
*/
set: function (entity) {
current = entity;
},
/**
* @ngdoc function
* @name umbraco.services.angularHelper#reset
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Since the editorstate entity is read-only, you cannot set it to null
* only through the reset() method
*/
reset: function() {
current = null;
},
/**
* @ngdoc function
* @name umbraco.services.angularHelper#getCurrent
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Returns an object reference to the current editor entity.
* the entity is the root object of the editor.
* EditorState is used by property/parameter editors that need
* access to the entire entity being edited, not just the property/parameter
*
* editorState.current can not be overwritten, you should only read values from it
* since modifying individual properties should be handled by the property editors
*/
getCurrent: function() {
return current;
}
};
// TODO: This shouldn't be removed! use getCurrent() method instead of a hacked readonly property which is confusing.
//create a get/set property but don't allow setting
Object.defineProperty(state, "current", {
get: function () {
return current;
},
set: function (value) {
throw "Use editorState.set to set the value of the current entity";
}
});
return state;
});
@@ -0,0 +1,80 @@
/**
* @ngdoc service
* @name umbraco.services.editorState
* @function
*
* @description
* Tracks the parent object for complex editors by exposing it as
* an object reference via editorState.current.entity
*
* it is possible to modify this object, so should be used with care
*/
angular.module('umbraco.services').factory("editorState", function() {
var current = null;
var state = {
/**
* @ngdoc function
* @name umbraco.services.angularHelper#set
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Sets the current entity object for the currently active editor
* This is only used when implementing an editor with a complex model
* like the content editor, where the model is modified by several
* child controllers.
*/
set: function (entity) {
current = entity;
},
/**
* @ngdoc function
* @name umbraco.services.angularHelper#reset
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Since the editorstate entity is read-only, you cannot set it to null
* only through the reset() method
*/
reset: function() {
current = null;
},
/**
* @ngdoc function
* @name umbraco.services.angularHelper#getCurrent
* @methodOf umbraco.services.editorState
* @function
*
* @description
* Returns an object reference to the current editor entity.
* the entity is the root object of the editor.
* EditorState is used by property/parameter editors that need
* access to the entire entity being edited, not just the property/parameter
*
* editorState.current can not be overwritten, you should only read values from it
* since modifying individual properties should be handled by the property editors
*/
getCurrent: function() {
return current;
}
};
// TODO: This shouldn't be removed! use getCurrent() method instead of a hacked readonly property which is confusing.
//create a get/set property but don't allow setting
Object.defineProperty(state, "current", {
get: function () {
return current;
},
set: function (value) {
throw "Use editorState.set to set the value of the current entity";
}
});
return state;
});
@@ -397,6 +397,54 @@
}
}
/**
* @ngdoc method
* @name umbraco.services.listViewHelper#selectAllItemsToggle
* @methodOf umbraco.services.listViewHelper
*
* @description
* Helper method for toggling the select state on all items.
*
* @param {Array} items Items to toggle selection on, should be $scope.items
* @param {Array} selection Listview selection, available as $scope.selection
*/
function selectAllItemsToggle(items, selection) {
if (!angular.isArray(items)) {
return;
}
if (isSelectedAll(items, selection)) {
// unselect all items
angular.forEach(items, function (item) {
item.selected = false;
});
// reset selection without loosing reference.
selection.length = 0;
} else {
// reset selection without loosing reference.
selection.length = 0;
// select all items
angular.forEach(items, function (item) {
var obj = {
id: item.id
};
if (item.key) {
obj.key = item.key;
}
item.selected = true;
selection.push(obj);
});
}
}
/**
* @ngdoc method
@@ -527,6 +575,7 @@
deselectItem: deselectItem,
clearSelection: clearSelection,
selectAllItems: selectAllItems,
selectAllItemsToggle: selectAllItemsToggle,
isSelectedAll: isSelectedAll,
setSortingDirection: setSortingDirection,
setSorting: setSorting,
@@ -10,47 +10,111 @@
}
}
.umb-toggle:focus .umb-toggle__toggle{
box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%);
}
.umb-toggle__handler {
position: absolute;
top: 0;
left: 0;
display: block;
width: 24px;
height: 24px;
background-color: @white;
border-radius: 50px;
transform: rotate(-45deg);
}
.umb-toggle__toggle {
cursor: pointer;
align-items: center;
display: flex;
width: 48px;
height: 24px;
background: @gray-8;
border-radius: 90px;
width: 38px;
height: 18px;
border-radius: 10px;
border: 1px solid @inputBorder;
background-color: @inputBorder;
position: relative;
transition: box-shadow .3s;
transition: background-color 120ms;
.umb-toggle:hover &,
.umb-toggle:focus & {
border-color: @inputBorderFocus;
}
.umb-toggle.umb-toggle--checked & {
border-color: @ui-btn;
background-color: @ui-btn;
&:hover {
background-color: @ui-btn-hover;
}
}
.umb-toggle.umb-toggle--checked:focus & {
border-color: black;
}
}
.umb-toggle--checked .umb-toggle__toggle {
background-color: @green;
.umb-toggle__handler {
position: absolute;
top: 1px;
left: 1px;
display: block;
width: 16px;
height: 16px;
background-color: @white;
border-radius: 8px;
transition: transform 120ms ease-in-out, background-color 120ms;
.umb-toggle.umb-toggle--checked & {
transform: translateX(20px);
background-color: white;
}
}
.umb-toggle--disabled .umb-toggle__toggle {
cursor: not-allowed;
opacity: 0.8;
/* Icons */
.umb-toggle__icon {
position: absolute;
font-size: 12px;
line-height: 1em;
text-decoration: none;
transition: all 0.2s ease;
}
.umb-toggle--checked .umb-toggle__handler {
transform: translate3d(24px, 0, 0) rotate(0);
.umb-toggle__icon--left {
left: 5px;
color: white;
transition: opacity 120ms;
opacity: 0;
// .umb-toggle:hover & {
// color: @ui-btn-hover;
// }
.umb-toggle--checked & {
opacity: 1;
}
.umb-toggle.umb-toggle--checked:hover & {
color: white;
}
}
.umb-toggle__icon--right {
right: 5px;
color: @ui-btn;
transition: opacity 120ms;
.umb-toggle--checked & {
opacity: 0;
}
.umb-toggle:hover & {
color: @ui-btn-hover;
}
}
.umb-toggle.umb-toggle--disabled {
.umb-toggle__toggle {
cursor: not-allowed;
border-color: @gray-5;
}
.umb-toggle__handler {
background-color: @gray-5;
}
}
/* Labels */
.umb-toggle__label {
@@ -64,22 +128,3 @@
.umb-toggle__label--right {
margin-left: 8px;
}
/* Icons */
.umb-toggle__icon {
position: absolute;
line-height: 1em;
text-decoration: none;
transition: all 0.2s ease;
}
.umb-toggle__icon--left {
left: 7px;
color: @white;
}
.umb-toggle__icon--right {
right: 7px;
color: @gray-5;
}
@@ -90,6 +90,9 @@
.umb-editor-header__name-and-description {
margin-right: 20px;
.umb-panel-header-description {
padding: 0 10px;
}
}
.-split-view-active .umb-editor-header__name-and-description {
@@ -75,7 +75,7 @@
display: flex;
align-items: center;
border-bottom: 1px solid @gray-9;
padding: 10px 15px;
padding: 10px 15px 10px 10px;
}
.umb-group-builder__group-title {
@@ -112,7 +112,7 @@ input.umb-group-builder__group-title-input {
}
input.umb-group-builder__group-title-input:disabled:hover {
border: none;
border-color: transparent;
}
.umb-group-builder__group-title-input:hover {
@@ -135,12 +135,35 @@ input.umb-group-builder__group-title-input:disabled:hover {
margin-left: auto;
}
.umb-group-builder__group-add-property {
min-height: 46px;
margin-right: 30px;
margin-left: 270px;
border-radius: 3px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
border: 1px dashed @gray-7;
background-color: transparent;
color: @ui-action-type;
font-weight: bold;
position: relative;
&:hover {
color:@ui-action-type-hover;
text-decoration: none;
border-color: @ui-active-type-hover;
}
}
/* ---------- PROPERTIES ---------- */
.umb-group-builder__properties {
list-style: none;
margin: 0;
padding: 15px;
padding-right: 5px;
min-height: 35px; // the height of a sortable property
}
@@ -228,6 +251,9 @@ input.umb-group-builder__group-title-input:disabled:hover {
overflow: hidden;
border-color: transparent;
background: transparent;
&:focus {
border-color: @inputBorderFocus;
}
}
.umb-group-builder__property-meta-label textarea.ng-invalid {
@@ -247,6 +273,9 @@ input.umb-group-builder__group-title-input:disabled:hover {
overflow: hidden;
border-color: transparent;
background: transparent;
&:focus {
border-color: @inputBorderFocus;
}
}
.umb-group-builder__property-preview {
@@ -265,21 +294,17 @@ input.umb-group-builder__group-title-input:disabled:hover {
bottom: 0;
left: 0;
right: 0;
background: rgba(0,0,0,0.1);
background: rgba(225,225,225,.5);
transition: opacity 120ms;
}
}
.umb-group-builder__property-preview:hover {
.umb-group-builder__property-preview:not(.-not-clickable):hover {
&::after {
opacity: .8;
opacity: .66;
}
}
.umb-group-builder__property-preview:focus {
outline: none;
}
.umb-group-builder__property-preview.-not-clickable {
cursor: auto;
}
@@ -301,23 +326,54 @@ input.umb-group-builder__group-title-input:disabled:hover {
opacity: 0.8
}
.umb-group-builder__open-settings {
position: absolute;
z-index:1;
top: 0;
bottom:0;
left: 0;
width: 100%;
background-color: transparent;
border: none;
&:focus {
outline:0;
border: 1px solid @inputBorderFocus;
}
}
.umb-group-builder__property-actions {
flex: 0 0 40px;
text-align: center;
margin: 15px 0 0 15px;
flex: 0 0 44px;
text-align: right;
margin-top: 7px;
}
.umb-group-builder__property-action {
margin: 0 0 10px 0;
display: block;
font-size: 18px;
position: relative;
cursor: pointer;
color: @ui-icon;
}
.umb-group-builder__property-action:hover {
color: @ui-icon-hover;
position: relative;
margin: 5px 0;
> button {
border: none;
font-size: 18px;
position: relative;
cursor: pointer;
color: @ui-icon;
margin: 0;
padding: 5px 10px;
width: auto;
overflow: visible;
background: transparent;
line-height: normal;
outline: 0;
-webkit-appearance: none;
&:hover, &:focus {
color: @ui-icon-hover;
}
}
}
.umb-group-builder__property-tags {
@@ -439,7 +495,7 @@ input.umb-group-builder__group-sort-value {
font-size: 14px;
color: @ui-action-type;
&:hover {
&:hover{
text-decoration: none;
color:@ui-action-type-hover;
border-color:@ui-action-border-hover;
@@ -533,6 +533,10 @@ div.help {
}
table.domains .help-inline {
color:@red;
}
// INPUT GROUPS
// ------------
@@ -11,7 +11,7 @@
hide-description="true">
</umb-editor-header>
<umb-editor-container>
<umb-editor-container class="form-horizontal">
<umb-load-indicator
ng-if="vm.loadingDataType">
@@ -6,9 +6,9 @@
</span>
<div class="umb-toggle__toggle">
<i ng-show="checked && hideIcons !== 'true'" class="umb-toggle__icon umb-toggle__icon--left icon-check"></i>
<div class="umb-toggle__handler shadow-depth-1"></div>
<i ng-show="!checked && hideIcons !== 'true'" class="umb-toggle__icon umb-toggle__icon--right icon-wrong"></i>
<i ng-show="hideIcons !== 'true'" class="umb-toggle__icon umb-toggle__icon--left icon-check"></i>
<i ng-show="hideIcons !== 'true'" class="umb-toggle__icon umb-toggle__icon--right icon-wrong"></i>
<div class="umb-toggle__handler"></div>
</div>
<span ng-if="labelPosition === 'right' && showLabels === 'true'">
@@ -116,7 +116,7 @@
<!-- Add new property -->
<a href=""
data-element="property-add"
class="btn btn-info"
class="umb-group-builder__group-add-property"
ng-if="property.propertyState=='init' && !sortingMode"
hotkey="alt+shift+p"
hotkey-when="{{tab.tabState === 'active' && property.propertyState=='init'}}"
@@ -183,7 +183,7 @@
</div>
<div tabindex="-1" class="umb-group-builder__property-preview" ng-click="editPropertyTypeSettings(property, tab)" ng-if="!sortingMode" ng-class="{'-not-clickable': !sortingMode && (property.inherited || property.locked)}">
<div tabindex="-1" class="umb-group-builder__property-preview" ng-if="!sortingMode" ng-class="{'-not-clickable': !sortingMode && (property.inherited || property.locked)}">
<div class="umb-group-builder__property-tags">
@@ -234,29 +234,31 @@
</div>
<ng-form name="propertyEditorPreviewForm" umb-disable-form-validation>
<umb-property-editor
ng-if="property.view !== undefined"
model="property"
preview="true">
</umb-property-editor>
<ng-form inert class="umb-group-builder__property-preview-form" name="propertyEditorPreviewForm" umb-disable-form-validation ng-click="editPropertyTypeSettings(property, tab)">
<umb-property-editor
ng-if="property.view !== undefined"
model="property"
preview="true">
</umb-property-editor>
</ng-form>
<button class="umb-group-builder__open-settings" ng-if="!property.inherited && !property.locked" ng-click="editPropertyTypeSettings(property, tab)"></button>
</div>
<!-- row tools -->
<div class="umb-group-builder__property-actions" ng-if="!sortingMode">
<div class="umb-group-builder__property-actions">
<div ng-if="!property.inherited">
<!-- settings for property -->
<div class="umb-group-builder__property-action" ng-click="editPropertyTypeSettings(property, tab)">
<i class="icon icon-settings"></i>
<div class="umb-group-builder__property-action">
<button class="icon icon-settings" ng-click="editPropertyTypeSettings(property, tab)"></button>
</div>
<!-- delete property -->
<div ng-if="!property.locked" class="umb-group-builder__property-action">
<i class="icon-trash" ng-click="togglePrompt(property)"></i>
<button class="icon-trash" ng-click="togglePrompt(property)"></button>
<umb-confirm-action
ng-if="property.deletePrompt"
direction="left"
@@ -4,15 +4,15 @@
<div class="umb-table-head">
<div class="umb-table-row">
<div class="umb-table-cell">
<input class="umb-table__input" type="checkbox"
ng-show="vm.allowSelectAll"
ng-click="vm.selectAll($event)"
ng-checked="vm.isSelectedAll()">
<a href="" style="text-decoration: none;" ng-show="vm.allowSelectAll" ng-click="vm.selectAll()">
<umb-checkmark checked="vm.isSelectedAll()" size="xs"></umb-checkmark>
</a>
</div>
<div class="umb-table-cell umb-table__name">
<localize key="general_name">Name</localize>
<i class="umb-table-head__icon icon" ng-class="{'icon-navigation-up': vm.isSortDirection('Name', 'asc'), 'icon-navigation-down': vm.isSortDirection('Name', 'desc')}"></i>
</a>
<localize key="general_name">Name</localize>
<i class="umb-table-head__icon icon" ng-class="{'icon-navigation-up': vm.isSortDirection('Name', 'asc'), 'icon-navigation-down': vm.isSortDirection('Name', 'desc')}"></i>
</div>
<div class="umb-table-cell" ng-show="vm.items[0].state">
<localize key="general_status">Status</localize>
@@ -250,7 +250,7 @@
<umb-box>
<umb-box-content>
<div class="umb-package-details__section-title"><localize key="packager_packageCompatibility">Compatibility</localize></div>
<div class="umb-package-details__section-description"><localize key="packager_packageCompatibilityDescription">This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100%</localize></div>
<div class="umb-package-details__section-description"><localize key="packager_packageCompatibilityDescription">This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be guaranteed for versions reported below 100%</localize></div>
<div class="umb-package-details__compatability" ng-repeat="compatibility in vm.package.compatibility | filter:percentage > 0">
<div class="umb-package-details__compatability-label">
<span class="umb-package-details__information-item-label">{{compatibility.version}}</span>
@@ -1,75 +1,84 @@
angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListController",
function ($scope) {
var vm = this;
vm.configItems = [];
vm.viewItems = [];
vm.changed = changed;
function init() {
//we can't really do anything if the config isn't an object
// currently the property editor will onyl work if our input is an object.
if (angular.isObject($scope.model.config.items)) {
//now we need to format the items in the dictionary because we always want to have an array
var configItems = [];
// formatting the items in the dictionary into an array
var sortedItems = [];
var vals = _.values($scope.model.config.items);
var keys = _.keys($scope.model.config.items);
for (var i = 0; i < vals.length; i++) {
configItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: vals[i].value });
sortedItems.push({ key: keys[i], sortOrder: vals[i].sortOrder, value: vals[i].value});
}
//ensure the items are sorted by the provided sort order
configItems.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
sortedItems.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
vm.configItems = sortedItems;
if ($scope.model.value === null || $scope.model.value === undefined) {
$scope.model.value = [];
}
updateViewModel(configItems);
// update view model.
generateViewModel($scope.model.value);
//watch the model.value in case it changes so that we can keep our view model in sync
$scope.$watchCollection("model.value",
function (newVal) {
updateViewModel(configItems);
});
$scope.$watchCollection("model.value", updateViewModel);
}
}
function updateViewModel(configItems) {
function updateViewModel(newVal) {
//get the checked vals from the view model
var selectedVals = _.map(
_.filter($scope.selectedItems,
function(f) {
return f.checked;
}
),
function(m) {
return m.value;
var i = vm.configItems.length;
while(i--) {
var item = vm.configItems[i];
// are this item the same in the model
if (item.checked !== (newVal.indexOf(item.value) !== -1)) {
// if not lets update the full model.
generateViewModel(newVal);
return;
}
);
//if the length is zero, then we are in sync, just exit.
if (_.difference($scope.model.value, selectedVals).length === 0) {
return;
}
$scope.selectedItems = [];
}
function generateViewModel(newVal) {
vm.viewItems = [];
var iConfigItem;
for (var i = 0; i < configItems.length; i++) {
iConfigItem = configItems[i];
var isChecked = _.contains($scope.model.value, iConfigItem.value);
$scope.selectedItems.push({
for (var i = 0; i < vm.configItems.length; i++) {
iConfigItem = vm.configItems[i];
var isChecked = _.contains(newVal, iConfigItem.value);
vm.viewItems.push({
checked: isChecked,
key: iConfigItem.id,
val: iConfigItem.value
key: iConfigItem.key,
value: iConfigItem.value
});
}
}
function changed(model, value) {
var index = $scope.model.value.indexOf(value);
if (model) {
if (model === true) {
//if it doesn't exist in the model, then add it
if (index < 0) {
$scope.model.value.push(value);
@@ -80,11 +89,9 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
$scope.model.value.splice(index, 1);
}
}
}
$scope.selectedItems = [];
$scope.changed = changed;
init();
});
@@ -1,7 +1,7 @@
<div class="umb-property-editor umb-checkboxlist" ng-controller="Umbraco.PropertyEditors.CheckboxListController">
<div class="umb-property-editor umb-checkboxlist" ng-controller="Umbraco.PropertyEditors.CheckboxListController as vm">
<ul class="unstyled">
<li ng-repeat="item in selectedItems track by item.key">
<umb-checkbox name="{{model.alias}}" value="{{item.val}}" model="item.checked" text="{{item.val}}" on-change="changed(model, value)" required="model.validation.mandatory && !model.value.length"></umb-checkbox>
<li ng-repeat="item in vm.viewItems track by item.key">
<umb-checkbox name="{{::model.alias}}" value="{{::item.value}}" model="item.checked" text="{{::item.value}}" on-change="vm.changed(model, value)" required="vm.model.validation.mandatory && !vm.model.value.length"></umb-checkbox>
</li>
</ul>
</div>
@@ -40,8 +40,8 @@
}
}
function selectAll($event) {
listViewHelper.selectAllItems($scope.items, $scope.selection, $event);
function selectAll() {
listViewHelper.selectAllItemsToggle($scope.items, $scope.selection);
}
function isSelectedAll() {
-1
View File
@@ -83,7 +83,6 @@
<Folder Include="Views\MacroPartials\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="8.0.0" />
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
<PackageReference Include="ClientDependency" Version="1.9.7" />
<PackageReference Include="ClientDependency-Mvc5" Version="1.8.0.0" />
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,8 @@ using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Changes;
using Umbraco.Web.PublishedCache;
@@ -14,14 +16,16 @@ namespace Umbraco.Web.Cache
{
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
private readonly IdkMap _idkMap;
public ContentTypeCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IdkMap idkMap)
public ContentTypeCacheRefresher(AppCaches appCaches, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IdkMap idkMap, IContentTypeCommonRepository contentTypeCommonRepository)
: base(appCaches)
{
_publishedSnapshotService = publishedSnapshotService;
_publishedModelFactory = publishedModelFactory;
_idkMap = idkMap;
_contentTypeCommonRepository = contentTypeCommonRepository;
}
#region Define
@@ -44,6 +48,8 @@ namespace Umbraco.Web.Cache
// we should NOT directly clear caches here, but instead ask whatever class
// is managing the cache to please clear that cache properly
_contentTypeCommonRepository.ClearCache(); // always
if (payloads.Any(x => x.ItemType == typeof(IContentType).Name))
{
ClearAllIsolatedCacheByEntityType<IContent>();
@@ -1,10 +1,7 @@
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Core.Mapping;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Composing.CompositionExtensions
{
@@ -12,37 +9,28 @@ namespace Umbraco.Web.Composing.CompositionExtensions
{
public static Composition ComposeWebMappingProfiles(this Composition composition)
{
//register the profiles
composition.Register<Profile, AuditMapperProfile>();
composition.Register<Profile, CodeFileMapperProfile>();
composition.Register<Profile, ContentMapperProfile>();
composition.Register<Profile, ContentPropertyMapperProfile>();
composition.Register<Profile, ContentTypeMapperProfile>();
composition.Register<Profile, DataTypeMapperProfile>();
composition.Register<Profile, EntityMapperProfile>();
composition.Register<Profile, DictionaryMapperProfile>();
composition.Register<Profile, MacroMapperProfile>();
composition.Register<Profile, MediaMapperProfile>();
composition.Register<Profile, MemberMapperProfile>();
composition.Register<Profile, RedirectUrlMapperProfile>();
composition.Register<Profile, RelationMapperProfile>();
composition.Register<Profile, SectionMapperProfile>();
composition.Register<Profile, TagMapperProfile>();
composition.Register<Profile, TemplateMapperProfile>();
composition.Register<Profile, UserMapperProfile>();
composition.Register<Profile, LanguageMapperProfile>();
composition.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<AuditMapDefinition>()
.Add<CodeFileMapDefinition>()
.Add<ContentMapDefinition>()
.Add<ContentPropertyMapDefinition>()
.Add<ContentTypeMapDefinition>()
.Add<DataTypeMapDefinition>()
.Add<EntityMapDefinition>()
.Add<DictionaryMapDefinition>()
.Add<MacroMapDefinition>()
.Add<MediaMapDefinition>()
.Add<MemberMapDefinition>()
.Add<RedirectUrlMapDefinition>()
.Add<RelationMapDefinition>()
.Add<SectionMapDefinition>()
.Add<TagMapDefinition>()
.Add<TemplateMapDefinition>()
.Add<UserMapDefinition>()
.Add<LanguageMapDefinition>();
//register any resolvers, etc.. that the profiles use
composition.Register<ContentUrlResolver>();
composition.Register<ContentTreeNodeUrlResolver<IContent, ContentTreeController>>();
composition.Register<TabsAndPropertiesResolver<IContent, ContentVariantDisplay>>();
composition.Register<TabsAndPropertiesResolver<IMedia, MediaItemDisplay>>();
composition.Register<ContentTreeNodeUrlResolver<IMedia, MediaTreeController>>();
composition.Register<MemberTabsAndPropertiesResolver>();
composition.Register<MemberTreeNodeUrlResolver>();
composition.Register<MemberBasicPropertiesResolver>();
composition.Register<MediaAppResolver>();
composition.Register<ContentAppResolver>();
composition.Register<CommonMapper>();
composition.Register<MemberTabsAndPropertiesMapper>();
return composition;
}
+3
View File
@@ -11,6 +11,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Mapping;
using Umbraco.Core.PackageActions;
using Umbraco.Core.Packaging;
using Umbraco.Core.PropertyEditors;
@@ -164,6 +165,8 @@ namespace Umbraco.Web.Composing
// proxy Core for convenience
public static UmbracoMapper Mapper => CoreCurrent.Mapper;
public static IRuntimeState RuntimeState => CoreCurrent.RuntimeState;
public static TypeLoader TypeLoader => CoreCurrent.TypeLoader;
@@ -8,14 +8,12 @@ using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using AutoMapper;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
@@ -2,7 +2,6 @@
using System.Linq;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -53,14 +52,14 @@ namespace Umbraco.Web.Editors.Binders
if (variant.Culture.IsNullOrWhiteSpace())
{
//map the property dto collection (no culture is passed to the mapping context so it will be invariant)
variant.PropertyCollectionDto = Mapper.Map<ContentPropertyCollectionDto>(model.PersistedContent);
variant.PropertyCollectionDto = Current.Mapper.Map<ContentPropertyCollectionDto>(model.PersistedContent);
}
else
{
//map the property dto collection with the culture of the current variant
variant.PropertyCollectionDto = Mapper.Map<ContentPropertyCollectionDto>(
variant.PropertyCollectionDto = Current.Mapper.Map<ContentPropertyCollectionDto>(
model.PersistedContent,
options => options.SetCulture(variant.Culture));
context => context.SetCulture(variant.Culture));
}
//now map all of the saved values to the dto
@@ -1,14 +1,10 @@
using System;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.WebApi;
namespace Umbraco.Web.Editors.Binders
{
@@ -46,7 +42,7 @@ namespace Umbraco.Web.Editors.Binders
//create the dto from the persisted model
if (model.PersistedContent != null)
{
model.PropertyCollectionDto = Mapper.Map<IMedia, ContentPropertyCollectionDto>(model.PersistedContent);
model.PropertyCollectionDto = Current.Mapper.Map<IMedia, ContentPropertyCollectionDto>(model.PersistedContent);
//now map all of the saved values to the dto
_modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
}
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Security;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
@@ -50,7 +49,7 @@ namespace Umbraco.Web.Editors.Binders
//create the dto from the persisted model
if (model.PersistedContent != null)
{
model.PropertyCollectionDto = Mapper.Map<IMember, ContentPropertyCollectionDto>(model.PersistedContent);
model.PropertyCollectionDto = Current.Mapper.Map<IMember, ContentPropertyCollectionDto>(model.PersistedContent);
//now map all of the saved values to the dto
_modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
}
@@ -106,7 +105,7 @@ namespace Umbraco.Web.Editors.Binders
//}
//member.Key = convertResult.Result;
var member = Mapper.Map<MembershipUser, IMember>(membershipUser);
var member = Current.Mapper.Map<MembershipUser, IMember>(membershipUser);
return member;
}
@@ -1,5 +1,4 @@
using System;
using AutoMapper;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+5 -6
View File
@@ -9,7 +9,6 @@ using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Security;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
@@ -191,7 +190,7 @@ namespace Umbraco.Web.Editors
//get all user groups and map their default permissions to the AssignedUserGroupPermissions model.
//we do this because not all groups will have true assigned permissions for this node so if they don't have assigned permissions, we need to show the defaults.
var defaultPermissionsByGroup = Mapper.Map<IEnumerable<AssignedUserGroupPermissions>>(allUserGroups).ToArray();
var defaultPermissionsByGroup = Mapper.MapEnumerable<IUserGroup, AssignedUserGroupPermissions>(allUserGroups);
var defaultPermissionsAsDictionary = defaultPermissionsByGroup
.ToDictionary(x => Convert.ToInt32(x.Id), x => x);
@@ -505,14 +504,14 @@ namespace Umbraco.Web.Editors
var pagedResult = new PagedResult<ContentItemBasic<ContentPropertyBasic>>(totalChildren, pageNumber, pageSize);
pagedResult.Items = children.Select(content =>
Mapper.Map<IContent, ContentItemBasic<ContentPropertyBasic>>(content,
opts =>
context =>
{
opts.SetCulture(cultureName);
context.SetCulture(cultureName);
// if there's a list of property aliases to map - we will make sure to store this in the mapping context.
if (!includeProperties.IsNullOrWhiteSpace())
opts.SetIncludedProperties(includeProperties.Split(new[] { ", ", "," }, StringSplitOptions.RemoveEmptyEntries));
context.SetIncludedProperties(includeProperties.Split(new[] { ", ", "," }, StringSplitOptions.RemoveEmptyEntries));
}))
.ToList(); // evaluate now
@@ -666,7 +665,7 @@ namespace Umbraco.Web.Editors
//The default validation language will be either: The default languauge, else if the content is brand new and the default culture is
// not marked to be saved, it will be the first culture in the list marked for saving.
var defaultCulture = _allLangs.Value.First(x => x.Value.IsDefault).Key;
var defaultCulture = _allLangs.Value.Values.FirstOrDefault(x => x.IsDefault)?.CultureName;
var cultureForInvariantErrors = CultureImpact.GetCultureForInvariantErrors(
contentItem.PersistedContent,
contentItem.Variants.Where(x => x.Save).Select(x => x.Culture).ToArray(),
@@ -1,5 +1,4 @@
using AutoMapper;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -5,7 +5,6 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
@@ -15,7 +14,6 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -502,13 +500,13 @@ namespace Umbraco.Web.Editors
where TPropertyType : PropertyTypeBasic
{
InvalidCompositionException invalidCompositionException = null;
if (ex is AutoMapperMappingException && ex.InnerException is InvalidCompositionException)
if (ex is InvalidCompositionException)
{
invalidCompositionException = (InvalidCompositionException)ex.InnerException;
invalidCompositionException = (InvalidCompositionException)ex;
}
else if (ex.InnerException is InvalidCompositionException)
{
invalidCompositionException = (InvalidCompositionException)ex;
invalidCompositionException = (InvalidCompositionException)ex.InnerException;
}
if (invalidCompositionException != null)
{
@@ -1,12 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using AutoMapper;
using Umbraco.Core.Composing;
using Umbraco.Core.Services;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
@@ -15,7 +12,6 @@ using Umbraco.Web.WebApi;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Web.Security;
using Umbraco.Web.WebApi.Filters;

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