Merge remote-tracking branch 'origin/7.1.5' into 7.2.0

Conflicts:
	src/Umbraco.Web.UI.Client/gruntFile.js
	src/Umbraco.Web.UI.Client/lib/lazyload/lazyload.min.js
	src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js
	src/Umbraco.Web/Umbraco.Web.csproj
	src/Umbraco.Web/packages.config
This commit is contained in:
Sebastiaan Janssen
2014-08-04 13:32:44 +02:00
195 changed files with 6163 additions and 2412 deletions

View File

@@ -590,6 +590,12 @@ namespace Umbraco.Core.Models
{
throw new IndexOutOfRangeException("No property exists with name " + propertyTypeAlias);
}
property.SetTags(storageType, propertyTypeAlias, tags, replaceTags, tagGroup);
}
internal static void SetTags(this Property property, TagCacheStorageType storageType, string propertyTypeAlias, IEnumerable<string> tags, bool replaceTags, string tagGroup = "default")
{
if (property == null) throw new ArgumentNullException("property");
var trimmedTags = tags.Select(x => x.Trim()).ToArray();

View File

@@ -1,4 +1,6 @@
namespace Umbraco.Core.Models.Membership
using System.Collections;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a user -> entity permission

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity -> user & permission key value pair collection
/// </summary>
public class EntityPermissionSet
{
/// <summary>
/// The entity id with permissions assigned
/// </summary>
public int EntityId { get; private set; }
/// <summary>
/// The key/value pairs of user id & single permission
/// </summary>
public IEnumerable<UserPermission> UserPermissionsSet { get; private set; }
public EntityPermissionSet(int entityId, IEnumerable<UserPermission> userPermissionsSet)
{
EntityId = entityId;
UserPermissionsSet = userPermissionsSet;
}
public class UserPermission
{
public UserPermission(int userId, string permission)
{
UserId = userId;
Permission = permission;
}
public int UserId { get; private set; }
public string Permission { get; private set; }
protected bool Equals(UserPermission other)
{
return UserId == other.UserId && string.Equals(Permission, other.Permission);
}
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((UserPermission) obj);
}
public override int GetHashCode()
{
unchecked
{
return (UserId*397) ^ Permission.GetHashCode();
}
}
}
}
}

View File

@@ -1,27 +1,55 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents the Type for a Backoffice User
/// </summary>
/// <remarks>
/// Should be internal until a proper user/membership implementation
/// is part of the roadmap.
/// </remarks>
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class UserType : Entity, IUserType
{
[DataMember]
public string Alias { get; set; }
private string _alias;
private string _name;
private IEnumerable<string> _permissions;
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
private static readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
[DataMember]
public string Name { get; set; }
public string Alias
{
get { return _alias; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
return _alias;
}, _alias, AliasSelector);
}
}
[DataMember]
public string Name
{
get { return _name; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_name = value;
return _name;
}, _name, NameSelector);
}
}
/// <summary>
/// The set of default permissions for the user type
@@ -30,6 +58,17 @@ namespace Umbraco.Core.Models.Membership
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions { get; set; }
public IEnumerable<string> Permissions
{
get { return _permissions; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_permissions = value;
return _permissions;
}, _permissions, PermissionsSelector);
}
}
}
}

View File

@@ -43,6 +43,11 @@ namespace Umbraco.Core.Models.PublishedContent
internal static IPublishedContentExtended Extend(IPublishedContent content, IEnumerable<IPublishedContent> contentSet)
{
// first unwrap content down to the lowest possible level, ie either the deepest inner
// IPublishedContent or the first extended that has added properties. this is to avoid
// nesting extended objects as much as possible, so we try to re-extend that lowest
// object.
var wrapped = content as PublishedContentExtended;
while (wrapped != null && ((IPublishedContentExtended)wrapped).HasAddedProperties == false)
wrapped = (content = wrapped.Unwrap()) as PublishedContentExtended;
@@ -51,14 +56,38 @@ namespace Umbraco.Core.Models.PublishedContent
// a model, and then that model has to inherit from PublishedContentExtended,
// => implements the internal IPublishedContentExtended.
// here we assume that either the factory just created a model that implements
// IPublishedContentExtended and therefore does not need to be extended again,
// because it can carry the extra property - or that it did *not* create a
// model and therefore returned the original content unchanged.
var model = content.CreateModel();
var extended = model == content // == means the factory did not create a model
? new PublishedContentExtended(content) // so we have to extend
: model; // else we can use what the factory returned
// so extended should always implement IPublishedContentExtended, however if
// by mistake the factory returned a different object that does not implement
// IPublishedContentExtended (which would be an error), throw.
//
// see also PublishedContentExtensionsForModels.CreateModel
// NOTE
// could we lift that constraint and accept that models just be IPublishedContent?
// would then mean that we cannot assume a model is IPublishedContentExtended, so
// either it is, or we need to wrap it. so instead of having
// (Model:IPublishedContentExtended (IPublishedContent))
// we'd have
// (PublishedContentExtended (Model (IPublishedContent)))
// and it is that bad? any other consequences?
//
// would also allow the factory to cache the model (though that should really
// be done by the content cache, not by the factory).
var extended2 = extended as IPublishedContentExtended;
if (extended2 != null) // always true, but keeps Resharper happy
extended2.SetContentSet(contentSet);
if (extended2 == null)
throw new Exception("Extended does not implement IPublishedContentExtended.");
extended2.SetContentSet(contentSet);
return extended2;
}

View File

@@ -1,4 +1,6 @@
namespace Umbraco.Core.Models.PublishedContent
using System;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides strongly typed published content models services.
@@ -12,9 +14,32 @@
/// <returns>The strongly typed published content model.</returns>
public static IPublishedContent CreateModel(this IPublishedContent content)
{
return PublishedContentModelFactoryResolver.Current.HasValue
? PublishedContentModelFactoryResolver.Current.Factory.CreateModel(content)
: content;
if (content == null)
return null;
if (PublishedContentModelFactoryResolver.Current.HasValue == false)
return content;
// get model
// if factory returns nothing, throw
// if factory just returns what it got, return
var model = PublishedContentModelFactoryResolver.Current.Factory.CreateModel(content);
if (model == null)
throw new Exception("IPublishedContentFactory returned null.");
if (ReferenceEquals(model, content))
return content;
// at the moment, other parts of our code assume that all models will
// somehow implement IPublishedContentExtended and not just be IPublishedContent,
// so we'd better check this here to fail as soon as we can.
//
// see also PublishedContentExtended.Extend
var extended = model as IPublishedContentExtended;
if (extended == null)
throw new Exception("IPublishedContentFactory created an object that does not implement IPublishedContentModelExtended.");
return model;
}
}
}

View File

@@ -31,7 +31,7 @@ namespace Umbraco.Core.Models.PublishedContent
public PublishedContentModelFactory(IEnumerable<Type> types)
{
var ctorArgTypes = new[] { typeof(IPublishedContent) };
var constructors = new Dictionary<string, Func<IPublishedContent, IPublishedContent>>();
var constructors = new Dictionary<string, Func<IPublishedContent, IPublishedContent>>(StringComparer.InvariantCultureIgnoreCase);
foreach (var type in types)
{
@@ -40,7 +40,6 @@ namespace Umbraco.Core.Models.PublishedContent
throw new InvalidOperationException(string.Format("Type {0} is missing a public constructor with one argument of type IPublishedContent.", type.FullName));
var attribute = type.GetCustomAttribute<PublishedContentModelAttribute>(false);
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
typeName = typeName.ToLowerInvariant();
if (constructors.ContainsKey(typeName))
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
@@ -70,7 +69,7 @@ namespace Umbraco.Core.Models.PublishedContent
return content;
// be case-insensitive
var contentTypeAlias = content.DocumentTypeAlias.ToLowerInvariant();
var contentTypeAlias = content.DocumentTypeAlias;
//ConstructorInfo constructor;
//return _constructors.TryGetValue(contentTypeAlias, out constructor)

View File

@@ -78,5 +78,23 @@ namespace Umbraco.Core.Models.Rdbms
return string.Empty;
}
}
protected bool Equals(PropertyDataDto other)
{
return Id == other.Id;
}
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((PropertyDataDto) obj);
}
public override int GetHashCode()
{
return Id;
}
}
}

View File

@@ -1,38 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
public class TaggedEntity
{
public TaggedEntity(int entityId, IEnumerable<TaggedProperty> taggedProperties)
{
EntityId = entityId;
TaggedProperties = taggedProperties;
}
public int EntityId { get; private set; }
public IEnumerable<TaggedProperty> TaggedProperties { get; private set; }
}
public class TaggedProperty
{
public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable<Tag> tags)
{
PropertyTypeId = propertyTypeId;
PropertyTypeAlias = propertyTypeAlias;
Tags = tags;
}
public int PropertyTypeId { get; private set; }
public string PropertyTypeAlias { get; private set; }
public IEnumerable<Tag> Tags { get; private set; }
}
[Serializable]
[DataContract(IsReference = true)]
public class Tag : Entity, ITag

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models
{
public class TaggedEntity
{
public TaggedEntity(int entityId, IEnumerable<TaggedProperty> taggedProperties)
{
EntityId = entityId;
TaggedProperties = taggedProperties;
}
public int EntityId { get; private set; }
public IEnumerable<TaggedProperty> TaggedProperties { get; private set; }
}
}

View File

@@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models
{
public class TaggedProperty
{
public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable<ITag> tags)
{
PropertyTypeId = propertyTypeId;
PropertyTypeAlias = propertyTypeAlias;
Tags = tags;
}
public int PropertyTypeId { get; private set; }
public string PropertyTypeAlias { get; private set; }
public IEnumerable<ITag> Tags { get; private set; }
}
}