Compare commits

...

29 Commits

Author SHA1 Message Date
Sebastiaan Janssen a8d7a1d01d Makes the test green: don't add the passed in composition as a dependency to itself.. also added another invariant check 2014-12-15 19:52:28 +01:00
Sebastiaan Janssen e62597521e Remove the renaming to 'title' which would cause a duplicate and make the next test fail 2014-12-15 19:51:37 +01:00
Sebastiaan Janssen fa91321299 Adds test for adding properties to a composition that has been saved and now doesn't allow a new property to be added 2014-12-15 18:56:58 +01:00
Morten Christensen 2d81691407 Adding new test case for renaming PropertyType aliases on indirect references 2014-12-15 16:34:41 +01:00
Morten Christensen 21f08ca491 Refactoring validation and adding new test case for renaming PropertyTypes 2014-12-15 15:33:05 +01:00
Morten Christensen e202f21934 Adds new test, fix, refactoring for adding duplicate PropertyType aliases 2014-12-15 14:29:48 +01:00
Shannon 2936ff0bf9 Makes provider user key type for new membership provider configurable, by default it is int 2014-12-15 20:44:00 +11:00
Sebastiaan Janssen 8e4e575276 Makes sure messages are shown in the user's configured language 2014-12-15 09:30:04 +01:00
Sebastiaan Janssen 84752babc8 Moved both new sections to the bottom so it's easier for upgraders to merge them 2014-12-15 09:04:25 +01:00
Shannon 60a1116acd Fixes: U4-6009 Distributed calls not working in 7.2 2014-12-15 11:45:55 +11:00
Sebastiaan Janssen a480d7bbe6 U4-5959 Getting YSOD when wanting to create partial view in a subfolder in the backoffie
#U4-5959 Fixed Due in version 7.2.1
2014-12-14 17:22:10 +01:00
Sebastiaan Janssen 7316c5462a U4-5928 Umbraco 7.2 RC GetCurrentMemberProfileModel Null Ref
#U4-5928 Fixed Due in version 7.2.1
2014-12-14 16:50:11 +01:00
Morten Christensen 2a9960afb3 Adding UI feedback for invalid compositions 2014-12-12 17:04:53 +01:00
Morten Christensen ed899ec73d Adding additional test coverage for Compositions and updating PropertyTypes and PropertyGroups 2014-12-12 17:04:11 +01:00
Morten Christensen 8f26f9385d Refactoring the logic around saving updates to PropertyTypes and PropertyGroups 2014-12-12 17:02:03 +01:00
Morten Christensen a446cc224d Refactoring the logic in the validation method for when ContentTypes are saved 2014-12-11 17:14:01 +01:00
Morten Christensen 07f9a9700d Ensures that inherited PropertyType aliases are also checked for indirect references 2014-12-11 12:22:49 +01:00
Sebastiaan Janssen 7e7acd0049 Correcting my mistakes to the unit test, using the wrong alias 2014-12-11 11:02:51 +01:00
Morten Christensen 57985c26a2 Updating the name of PropertyGroups in DB to ensure renaming is done properly 2014-12-11 10:55:33 +01:00
Morten Christensen 504c1f7254 Updating tests related to #U4-5986
Conflicts:
	src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
2014-12-11 10:55:21 +01:00
Shannon 52ad36a6c2 removes commented out code form PR 2014-12-11 10:49:41 +01:00
Peter Gregory 01670e0832 Fixes issue U4-5925 GetMedia returning nothing
Removed the use of FromXElement that was only used by GetMedia.  The change introduced in commit f3f6504398 caused GetMedia to return nothing due to the introduction of the FromXElement method.
2014-12-11 10:49:30 +01:00
Stephan 99c96bce86 U4-5986 - reject ppty alias used by ancestor 2014-12-10 13:01:51 +01:00
Sebastiaan Janssen da2bc6764b Version also updates in the csproj 2014-12-10 12:59:08 +01:00
Shannon d11a377f0f bump version 2014-12-10 12:28:06 +01:00
Stephan d445f7cb0d U4-5986 - reject ppty alias used by descendant 2014-12-10 12:27:55 +01:00
Sebastiaan Janssen 899d325ca1 Updates unit tests to use the newer new ContentType method and obsoletes the old one 2014-12-10 11:52:03 +01:00
Sebastiaan Janssen f1107b7a91 Fixes U4-5986 Compositions: Possible to get stuck in document type ysod's
#U4-5986 Fixed Due in version 7.2.1
2014-12-10 11:51:53 +01:00
Stephan a3f171e7b3 U4-5931 - fix DocType inheritance issue 2014-12-10 11:51:42 +01:00
24 changed files with 1181 additions and 198 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.2.0
7.2.1
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.2.0");
private static readonly Version Version = new Version("7.2.1");
/// <summary>
/// Gets the current version of Umbraco.
+9 -8
View File
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
{
private int _defaultTemplate;
private IEnumerable<ITemplate> _allowedTemplates;
/// <summary>
/// Constuctor for creating a ContentType with the parent's id.
/// </summary>
@@ -31,9 +31,10 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
public ContentType(IContentType parent) : this(parent, null)
{
}
[Obsolete("This method is obsolete, use ContentType(IContentType parent, string alias) instead.", false)]
public ContentType(IContentType parent) : this(parent, null)
{
}
/// <summary>
/// Constuctor for creating a ContentType with the parent as an inherited type.
@@ -49,7 +50,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.DefaultTemplateId);
private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ITemplate>>(x => x.AllowedTemplates);
/// <summary>
/// Gets or sets the alias of the default Template.
/// </summary>
@@ -106,7 +107,7 @@ namespace Umbraco.Core.Models
}
DefaultTemplateId = template.Id;
if(_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
if (_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
{
var templates = AllowedTemplates.ToList();
templates.Add(template);
@@ -140,7 +141,7 @@ namespace Umbraco.Core.Models
{
base.AddingEntity();
if(Key == Guid.Empty)
if (Key == Guid.Empty)
Key = Guid.NewGuid();
}
@@ -151,7 +152,7 @@ namespace Umbraco.Core.Models
/// <returns></returns>
[Obsolete("Use DeepCloneWithResetIdentities instead")]
public IContentType Clone(string alias)
{
{
return DeepCloneWithResetIdentities(alias);
}
+3 -1
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -15,6 +16,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public abstract class ContentTypeBase : Entity, IContentTypeBase
{
private Lazy<int> _parentId;
@@ -497,7 +499,6 @@ namespace Umbraco.Core.Models
/// <param name="propertyTypeAlias">Alias of the <see cref="PropertyType"/> to remove</param>
public void RemovePropertyType(string propertyTypeAlias)
{
//check if the property exist in one of our collections
if (PropertyGroups.Any(group => group.PropertyTypes.Any(pt => pt.Alias == propertyTypeAlias))
|| _propertyTypes.Any(x => x.Alias == propertyTypeAlias))
@@ -524,6 +525,7 @@ namespace Umbraco.Core.Models
public void RemovePropertyGroup(string propertyGroupName)
{
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(PropertyGroupCollectionSelector);
}
/// <summary>
+1 -34
View File
@@ -20,7 +20,6 @@ namespace Umbraco.Core.Models
private string _email;
private string _rawPasswordValue;
private object _providerUserKey;
private Type _userTypeKey;
/// <summary>
/// Constructor for creating an empty Member object
@@ -114,7 +113,6 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Email);
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.RawPasswordValue);
private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo<Member, object>(x => x.ProviderUserKey);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<Member, Type>(x => x.ProviderUserKeyType);
/// <summary>
/// Gets or sets the Username
@@ -502,38 +500,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Models.Membership
{
internal static class MembershipUserExtensions
{
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName)
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
var membershipMember = new UmbracoMembershipMember(member, providerName);
var membershipMember = new UmbracoMembershipMember(member, providerName, providerKeyAsGuid);
return membershipMember;
}
@@ -1,5 +1,6 @@
using System;
using System.Web.Security;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Models.Membership
{
@@ -25,7 +26,7 @@ namespace Umbraco.Core.Models.Membership
//NOTE: We are not calling the base constructor which will validate that a provider with the specified name exists which causes issues with unit tests. The ctor
// validation for that doesn't need to be there anyways (have checked the source).
public UmbracoMembershipMember(IMembershipUser member, string providerName)
public UmbracoMembershipMember(IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
_member = member;
//NOTE: We are copying the values here so that everything is consistent with how the underlying built-in ASP.Net membership user
@@ -37,7 +38,7 @@ namespace Umbraco.Core.Models.Membership
if (member.PasswordQuestion != null)
_passwordQuestion = member.PasswordQuestion.Trim();
_providerName = providerName;
_providerUserKey = member.ProviderUserKey;
_providerUserKey = providerKeyAsGuid ? member.ProviderUserKey : member.Id;
_comment = member.Comments;
_isApproved = member.IsApproved;
_isLockedOut = member.IsLockedOut;
@@ -58,7 +58,6 @@ namespace Umbraco.Core.Models.Membership
private IUserType _userType;
private string _name;
private Type _userTypeKey;
private List<string> _addedSections;
private List<string> _removedSections;
private ObservableCollection<string> _sectionCollection;
@@ -80,7 +79,6 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<User, Type>(x => x.ProviderUserKeyType);
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Email);
@@ -101,37 +99,6 @@ namespace Umbraco.Core.Models.Membership
set { throw new NotSupportedException("Cannot set the provider user key for a user"); }
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
[DataMember]
public string Username
@@ -71,16 +71,34 @@ namespace Umbraco.Core.Models
{
using (new WriteLock(_addLocker))
{
var key = GetKeyForItem(item);
if (key != null)
//Note this is done to ensure existig groups can be renamed
if (item.HasIdentity && item.Id > 0)
{
var exists = this.Contains(key);
var exists = this.Contains(item.Id);
if (exists)
{
SetItem(IndexOfKey(key), item);
var keyExists = this.Contains(item.Name);
if(keyExists)
throw new Exception(string.Format("Naming conflict: Changing the name of PropertyGroup '{0}' would result in duplicates", item.Name));
SetItem(IndexOfKey(item.Id), item);
return;
}
}
else
{
var key = GetKeyForItem(item);
if (key != null)
{
var exists = this.Contains(key);
if (exists)
{
SetItem(IndexOfKey(key), item);
return;
}
}
}
base.Add(item);
OnAdd.IfNotNull(x => x.Invoke());//Could this not be replaced by a Mandate/Contract for ensuring item is not null
@@ -99,6 +117,11 @@ namespace Umbraco.Core.Models
return this.Any(x => x.Name == groupName);
}
public bool Contains(int id)
{
return this.Any(x => x.Id == id);
}
public void RemoveItem(string propertyGroupName)
{
var key = IndexOfKey(propertyGroupName);
@@ -119,6 +142,18 @@ namespace Umbraco.Core.Models
return -1;
}
public int IndexOfKey(int id)
{
for (var i = 0; i < this.Count; i++)
{
if (this[i].Id == id)
{
return i;
}
}
return -1;
}
protected override string GetKeyForItem(PropertyGroup item)
{
return item.Name;
+2 -1
View File
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public class PropertyType : Entity, IEquatable<PropertyType>
{
private readonly bool _isExplicitDbType;
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
@@ -297,9 +298,38 @@ AND umbracoNode.id <> @id",
//Delete Tabs/Groups by excepting entries from db with entries from collections
var dbPropertyGroups =
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new {Id = entity.Id})
.Select(x => new Tuple<int, string>(x.Id, x.Text));
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name));
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
.Select(x => new Tuple<int, string>(x.Id, x.Text))
.ToList();
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name)).ToList();
var tabsToDelete = dbPropertyGroups.Select(x => x.Item1).Except(entityPropertyGroups.Select(x => x.Item1));
var tabs = dbPropertyGroups.Where(x => tabsToDelete.Any(y => y == x.Item1));
//Update Tab name downstream to ensure renaming is done properly
foreach (var propertyGroup in entityPropertyGroups)
{
Database.Update<PropertyTypeGroupDto>("SET Text = @TabName WHERE parentGroupId = @TabId",
new { TabName = propertyGroup.Item2, TabId = propertyGroup.Item1 });
var childGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE parentGroupId = @TabId", new { TabId = propertyGroup.Item1 });
foreach (var childGroup in childGroups)
{
var sibling = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name",
new { Id = childGroup.ContentTypeNodeId, Name = propertyGroup.Item2 })
.FirstOrDefault(x => x.ParentGroupId.HasValue == false || x.ParentGroupId.Value.Equals(propertyGroup.Item1) == false);
//If the child group doesn't have a sibling there is no chance of duplicates and we continue
if (sibling == null || (sibling.ParentGroupId.HasValue && sibling.ParentGroupId.Value.Equals(propertyGroup.Item1))) continue;
//Since the child group has a sibling with the same name we need to point any PropertyTypes to the sibling
//as this child group is about to leave the party.
Database.Update<PropertyTypeDto>(
"SET propertyTypeGroupId = @PropertyTypeGroupId WHERE propertyTypeGroupId = @PropertyGroupId AND ContentTypeId = @ContentTypeId",
new { PropertyTypeGroupId = sibling.Id, PropertyGroupId = childGroup.Id, ContentTypeId = childGroup.ContentTypeNodeId });
//Since the parent group has been renamed and we have duplicates we remove this group
//and leave our sibling in charge of the part.
Database.Delete(childGroup);
}
}
//Do Tab updates
foreach (var tab in tabs)
{
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId = @PropertyGroupId",
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
@@ -8,11 +9,13 @@ using System.Threading;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -273,6 +276,74 @@ namespace Umbraco.Core.Services
}
public void Validate(IContentTypeComposition compo)
{
using (new WriteLock(Locker))
{
ValidateLocked(compo);
}
}
private void ValidateLocked(IContentTypeComposition compositionContentType)
{
// performs business-level validation of the composition
// should ensure that it is absolutely safe to save the composition
// eg maybe a property has been added, with an alias that's OK (no conflict with ancestors)
// but that cannot be used (conflict with descendants)
var contentType = compositionContentType as IContentType;
var mediaType = compositionContentType as IMediaType;
IContentTypeComposition[] allContentTypes;
if (contentType != null)
allContentTypes = GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
else if (mediaType != null)
allContentTypes = GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray();
else
throw new Exception("Composition is neither IContentType nor IMediaType?");
var compositionAliases = compositionContentType.CompositionAliases();
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
var propertyTypeAliases = compositionContentType.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).ToArray();
var indirectReferences = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == compositionContentType.Id));
var comparer = new DelegateEqualityComparer<IContentTypeComposition>((x, y) => x.Id == y.Id, x => x.Id);
var dependencies = new HashSet<IContentTypeComposition>(compositions, comparer);
var stack = new Stack<IContentTypeComposition>();
indirectReferences.ForEach(stack.Push);//Push indirect references to a stack, so we can add recursively
while (stack.Count > 0)
{
var indirectReference = stack.Pop();
dependencies.Add(indirectReference);
//Get all compositions for the current indirect reference
var directReferences = indirectReference.ContentTypeComposition;
foreach (var directReference in directReferences)
{
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
dependencies.Add(directReference);
//A direct reference has compositions of its own - these also need to be taken into account
var directReferenceGraph = directReference.CompositionAliases();
allContentTypes.Where(x => directReferenceGraph.Any(y => x.Alias.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ForEach(c => dependencies.Add(c));
}
//Recursive lookup of indirect references
allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == indirectReference.Id)).ForEach(stack.Push);
}
foreach (var dependency in dependencies)
{
if (dependency.Id == compositionContentType.Id) continue;
var contentTypeDependency = allContentTypes.FirstOrDefault(x => x.Alias.Equals(dependency.Alias, StringComparison.InvariantCultureIgnoreCase));
if (contentTypeDependency == null) continue;
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
if (intersect.Length == 0) continue;
var message = string.Format("The following PropertyType aliases from the current ContentType conflict with existing PropertyType aliases: {0}.",
string.Join(", ", intersect));
throw new Exception(message);
}
}
/// <summary>
/// Saves a single <see cref="IContentType"/> object
/// </summary>
@@ -288,6 +359,7 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
ValidateLocked(contentType); // throws if invalid
contentType.CreatorId = userId;
repository.AddOrUpdate(contentType);
@@ -317,6 +389,11 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
// all-or-nothing, validate them all first
foreach (var contentType in asArray)
{
ValidateLocked(contentType); // throws if invalid
}
foreach (var contentType in asArray)
{
contentType.CreatorId = userId;
@@ -487,6 +564,7 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
ValidateLocked(mediaType); // throws if invalid
mediaType.CreatorId = userId;
repository.AddOrUpdate(mediaType);
uow.Commit();
@@ -517,7 +595,11 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
// all-or-nothing, validate them all first
foreach (var mediaType in asArray)
{
ValidateLocked(mediaType); // throws if invalid
}
foreach (var mediaType in asArray)
{
mediaType.CreatorId = userId;
@@ -74,7 +74,8 @@ namespace Umbraco.Tests.PublishedContent
{
var contentTypeService = ctx.Application.Services.ContentTypeService;
var baseType = new ContentType(-1) {Alias = "base", Name = "Base"};
var inheritedType = new ContentType(baseType) {Alias = "inherited", Name = "Inherited"};
const string contentTypeAlias = "inherited";
var inheritedType = new ContentType(baseType, contentTypeAlias) {Alias = contentTypeAlias, Name = "Inherited"};
contentTypeService.Save(baseType);
contentTypeService.Save(inheritedType);
createContentTypes = false;
@@ -1,3 +1,4 @@
using System.Runtime.Remoting;
using NUnit.Framework;
using System;
using System.Collections.Generic;
@@ -5,6 +6,8 @@ using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Tests.CodeFirst.TestModels.Composition;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -178,10 +181,11 @@ namespace Umbraco.Tests.Services
/*,"Navigation"*/);
cts.Save(ctBase);
var ctHomePage = new ContentType(ctBase)
const string contentTypeAlias = "HomePage";
var ctHomePage = new ContentType(ctBase, contentTypeAlias)
{
Name = "Home Page",
Alias = "HomePage",
Alias = contentTypeAlias,
Icon = "settingDomain.gif",
Thumbnail = "folder.png",
AllowedAsRoot = true
@@ -191,7 +195,7 @@ namespace Umbraco.Tests.Services
cts.Save(ctHomePage);
// Act
var homeDoc = cs.CreateContent("Home Page", -1, "HomePage");
var homeDoc = cs.CreateContent("Home Page", -1, contentTypeAlias);
cs.SaveAndPublishWithStatus(homeDoc);
// Assert
@@ -243,13 +247,13 @@ namespace Umbraco.Tests.Services
var global = MockedContentTypes.CreateSimpleContentType("global", "Global");
service.Save(global);
var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global);
var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global, true);
service.Save(components);
var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components);
var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components, true);
service.Save(component);
var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global);
var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global, true);
service.Save(category);
var success = category.AddContentType(component);
@@ -464,6 +468,766 @@ namespace Umbraco.Tests.Services
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.StartsWith("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.StartsWith("Content")).Id);
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_To_Referenced_Composition()
{
//Related the second issue in screencast from this post http://issues.umbraco.org/issue/U4-5986
// Arrange
var service = ServiceContext.ContentTypeService;
var parent = MockedContentTypes.CreateSimpleContentType();
service.Save(parent);
var child = MockedContentTypes.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, true);
service.Save(child);
var composition = MockedContentTypes.CreateMetaContentType();
service.Save(composition);
//Adding Meta-composition to child doc type
child.AddContentType(composition);
service.Save(child);
// Act
var duplicatePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var added = composition.AddPropertyType(duplicatePropertyType, "Meta");
// Assert
Assert.That(added, Is.True);
Assert.Throws<Exception>(() => service.Save(composition));
Assert.DoesNotThrow(() => service.GetContentType("simpleChildPage"));
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_In_Composition_Graph()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true);
service.Save(basePage);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true);
service.Save(advancedPage);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaAdded = contentPage.AddContentType(metaComposition);
service.Save(contentPage);
var seoAdded = advancedPage.AddContentType(seoComposition);
service.Save(advancedPage);
// Act
var duplicatePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var addedToBasePage = basePage.AddPropertyType(duplicatePropertyType, "Content");
var addedToAdvancedPage = advancedPage.AddPropertyType(duplicatePropertyType, "Content");
var addedToMeta = metaComposition.AddPropertyType(duplicatePropertyType, "Meta");
var addedToSeo = seoComposition.AddPropertyType(duplicatePropertyType, "Seo");
// Assert
Assert.That(metaAdded, Is.True);
Assert.That(seoAdded, Is.True);
Assert.That(addedToBasePage, Is.True);
Assert.That(addedToAdvancedPage, Is.False);
Assert.That(addedToMeta, Is.True);
Assert.That(addedToSeo, Is.True);
Assert.Throws<Exception>(() => service.Save(basePage));
Assert.Throws<Exception>(() => service.Save(metaComposition));
Assert.Throws<Exception>(() => service.Save(seoComposition));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("meta"));
Assert.DoesNotThrow(() => service.GetContentType("seo"));
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_At_Root_Which_Conflicts_With_Third_Levels_Composition()
{
/*
* BasePage, gets 'Title' added but should not be allowed
* -- Content Page
* ---- Advanced Page -> Content Meta
* Content Meta :: Composition, has 'Title'
*
* Content Meta has 'Title' PropertyType
* Adding 'Title' to BasePage should fail
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = advancedPage.AddContentType(contentMetaComposition);
service.Save(advancedPage);
//NOTE: It should not be possible to Save 'BasePage' with the Title PropertyType added
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = basePage.AddPropertyType(titlePropertyType, "Content");
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(basePage));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Cannot_Rename_PropertyType_Alias_On_Composition_Which_Would_Cause_Conflict_In_Other_Composition()
{
/*
* Meta renames alias to 'title'
* Seo has 'Title'
* BasePage
* -- ContentPage
* ---- AdvancedPage -> Seo
* ------ MoreAdvanedPage -> Meta
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage);
service.Save(moreAdvancedPage);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content");
service.Save(advancedPage);
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content");
service.Save(seoComposition);
var seoCompositionAdded = advancedPage.AddContentType(seoComposition);
var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition);
service.Save(advancedPage);
service.Save(moreAdvancedPage);
var keywordsPropertyType = metaComposition.PropertyTypes.First(x => x.Alias.Equals("metakeywords"));
keywordsPropertyType.Alias = "title";
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(seoCompositionAdded, Is.True);
Assert.That(metaCompositionAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(metaComposition));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("moreAdvancedPage"));
}
[Test]
public void Can_Add_Additional_Properties_On_Composition_Once_Composition_Has_Been_Saved()
{
/*
* Meta renames alias to 'title'
* Seo has 'Title'
* BasePage
* -- ContentPage
* ---- AdvancedPage -> Seo
* ------ MoreAdvancedPage -> Meta
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage);
service.Save(moreAdvancedPage);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content");
service.Save(advancedPage);
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content");
service.Save(seoComposition);
var seoCompositionAdded = advancedPage.AddContentType(seoComposition);
var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition);
service.Save(advancedPage);
service.Save(moreAdvancedPage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(seoCompositionAdded, Is.True);
Assert.That(metaCompositionAdded, Is.True);
var testPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "test", Name = "Test", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var testAdded = seoComposition.AddPropertyType(testPropertyType, "Content");
service.Save(seoComposition);
Assert.That(testAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("moreAdvancedPage"));
}
[Test]
public void Cannot_Rename_PropertyGroup_On_Child_Avoiding_Conflict_With_Parent_PropertyGroup()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content_");
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Details");
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = contentPage.PropertyGroups["Content_"];
Assert.Throws<Exception>(() => contentPage.PropertyGroups.Add(new PropertyGroup
{
Id = propertyGroup.Id,
Name = "Content",
SortOrder = 0
}));
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Cannot_Rename_PropertyType_Alias_Causing_Conflicts_With_Parents()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
// Act
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = basePage.AddPropertyType(titlePropertyType, "Content");
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = contentPage.AddPropertyType(bodyTextPropertyType, "Content");
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content");
service.Save(basePage);
service.Save(contentPage);
service.Save(advancedPage);
//Rename the PropertyType to something that already exists in the Composition - NOTE this should not be allowed and Saving should throw an exception
var authorPropertyTypeToRename = advancedPage.PropertyTypes.First(x => x.Alias.Equals("author"));
authorPropertyTypeToRename.Alias = "title";
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(advancedPage));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Can_Add_PropertyType_Alias_Which_Exists_In_Composition_Outside_Graph()
{
/*
* Meta (Composition)
* Content Meta (Composition) has 'Title' -> Meta
* BasePage
* -- ContentPage gets 'Title' added -> Meta
* ---- Advanced Page
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true);
service.Save(basePage);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage, true);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true);
service.Save(advancedPage);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
var metaAdded = contentPage.AddContentType(metaComposition);
service.Save(contentPage);
var metaAddedToComposition = contentMetaComposition.AddContentType(metaComposition);
service.Save(contentMetaComposition);
// Act
var propertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var addedToContentPage = contentPage.AddPropertyType(propertyType, "Content");
// Assert
Assert.That(metaAdded, Is.True);
Assert.That(metaAddedToComposition, Is.True);
Assert.That(addedToContentPage, Is.True);
Assert.DoesNotThrow(() => service.Save(contentPage));
}
[Test]
public void Can_Rename_PropertyGroup_With_Inherited_PropertyGroups()
{
//Related the first issue in screencast from this post http://issues.umbraco.org/issue/U4-5986
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, false, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true);
service.Save(contentPage);
var composition = MockedContentTypes.CreateMetaContentType();
composition.AddPropertyGroup("Content");
service.Save(composition);
//Adding Meta-composition to child doc type
contentPage.AddContentType(composition);
service.Save(contentPage);
// Act
var propertyTypeOne = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "testTextbox", Name = "Test Textbox", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var firstOneAdded = contentPage.AddPropertyType(propertyTypeOne, "Content_");
var propertyTypeTwo = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "anotherTextbox", Name = "Another Test Textbox", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var secondOneAdded = contentPage.AddPropertyType(propertyTypeTwo, "Content");
service.Save(contentPage);
Assert.That(page.PropertyGroups.Contains("Content_"), Is.True);
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup{ Id = propertyGroup.Id, Name = "ContentTab", SortOrder = 0});
service.Save(page);
// Assert
Assert.That(firstOneAdded, Is.True);
Assert.That(secondOneAdded, Is.True);
var contentType = service.GetContentType("contentPage");
Assert.That(contentType, Is.Not.Null);
var compositionPropertyGroups = contentType.CompositionPropertyGroups;
Assert.That(compositionPropertyGroups.Count(x => x.Name.Equals("Content_")), Is.EqualTo(0));
var propertyTypeCount = contentType.PropertyTypes.Count();
var compPropertyTypeCount = contentType.CompositionPropertyTypes.Count();
Assert.That(propertyTypeCount, Is.EqualTo(5));
Assert.That(compPropertyTypeCount, Is.EqualTo(10));
}
[Test]
public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Contentx");
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Contenty");
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = contentPage.AddPropertyType(bodyTextPropertyType, "Content_");//Will be added to the parent tab
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");//Will be added to the "Content Meta" composition
service.Save(contentPage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var descriptionPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "description", Name = "Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var keywordsPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "keywords", Name = "Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content_");//Will be added to an ancestor tab
var descriptionAdded = advancedPage.AddPropertyType(descriptionPropertyType, "Contentx");//Will be added to a parent tab
var keywordsAdded = advancedPage.AddPropertyType(keywordsPropertyType, "Content");//Will be added to the "Content Meta" composition
service.Save(advancedPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 });
service.Save(page);
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(descriptionAdded, Is.True);
Assert.That(keywordsAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var advancedPageReloaded = service.GetContentType("advancedPage");
var contentUnderscoreTabExists = advancedPageReloaded.CompositionPropertyGroups.Any(x => x.Name.Equals("Content_"));
Assert.That(contentUnderscoreTabExists, Is.False);
var numberOfContentTabs = advancedPageReloaded.CompositionPropertyGroups.Count(x => x.Name.Equals("Content"));
Assert.That(numberOfContentTabs, Is.EqualTo(4));
}
[Test]
public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups_v2()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content");
service.Save(contentPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = page.AddPropertyType(bodyTextPropertyType, "Content_");
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content_");
service.Save(page);
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 });
service.Save(page);
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
}
[Test]
public void Can_Remove_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
basePage.RemovePropertyGroup("Content");
service.Save(basePage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var contentType = service.GetContentType("contentPage");
var propertyGroup = contentType.PropertyGroups["Content"];
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
}
[Test]
public void Can_Add_PropertyGroup_With_Same_Name_On_Parent_and_Child()
{
/*
* BasePage
* - Content Page
* -- Advanced Page
* Content Meta :: Composition
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var contentType = service.GetContentType("contentPage");
var propertyGroup = contentType.PropertyGroups["Content"];
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
var numberOfContentTabs = contentType.CompositionPropertyGroups.Count(x => x.Name.Equals("Content"));
Assert.That(numberOfContentTabs, Is.EqualTo(3));
//Ensure that adding a new PropertyType to the "Content"-tab also adds it to the right group
var descriptionPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "description", Name = "Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 1,DataTypeDefinitionId = -88
};
var descriptionAdded = contentType.AddPropertyType(descriptionPropertyType, "Content");
service.Save(contentType);
Assert.That(descriptionAdded, Is.True);
var contentPageReloaded = service.GetContentType("contentPage");
var propertyGroupReloaded = contentPageReloaded.PropertyGroups["Content"];
var hasDescriptionPropertyType = propertyGroupReloaded.PropertyTypes.Contains("description");
Assert.That(hasDescriptionPropertyType, Is.True);
Assert.That(propertyGroupReloaded.ParentId.HasValue, Is.False);
var descriptionPropertyTypeReloaded = propertyGroupReloaded.PropertyTypes["description"];
Assert.That(descriptionPropertyTypeReloaded.PropertyGroupId.IsValueCreated, Is.False);
}
private ContentType CreateComponent()
{
var component = new ContentType(-1)
@@ -487,9 +1251,10 @@ namespace Umbraco.Tests.Services
private ContentType CreateBannerComponent(ContentType parent)
{
var banner = new ContentType(parent)
const string contentTypeAlias = "banner";
var banner = new ContentType(parent, contentTypeAlias)
{
Alias = "banner",
Alias = contentTypeAlias,
Name = "Banner Component",
Description = "ContentType used for Banner Component",
Icon = ".sprTreeDoc3",
@@ -535,9 +1300,10 @@ namespace Umbraco.Tests.Services
private ContentType CreateHomepage(ContentType parent)
{
var contentType = new ContentType(parent)
const string contentTypeAlias = "homepage";
var contentType = new ContentType(parent, contentTypeAlias)
{
Alias = "homepage",
Alias = contentTypeAlias,
Name = "Homepage",
Description = "ContentType used for the Homepage",
Icon = ".sprTreeDoc3",
@@ -6,7 +6,25 @@ namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedContentTypes
{
public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page",
ContentType parent = null)
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
contentType.Description = "ContentType used for basic pages";
contentType.Icon = ".sprTreeDoc3";
contentType.Thumbnail = "doc2.png";
contentType.SortOrder = 1;
contentType.CreatorId = 0;
contentType.Trashed = false;
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateTextpageContentType(string alias = "textPage", string name = "Text Page")
{
@@ -65,6 +83,57 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateContentMetaContentType()
{
var contentType = new ContentType(-1)
{
Alias = "contentMeta",
Name = "Content Meta",
Description = "ContentType used for Content Meta",
Icon = ".sprTreeDoc3",
Thumbnail = "doc.png",
SortOrder = 1,
CreatorId = 0,
Trashed = false
};
var metaCollection = new PropertyTypeCollection();
metaCollection.Add(new PropertyType("test", DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Content", SortOrder = 2 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSeoContentType()
{
var contentType = new ContentType(-1)
{
Alias = "seo",
Name = "Seo",
Description = "ContentType used for Seo",
Icon = ".sprTreeDoc3",
Thumbnail = "doc.png",
SortOrder = 1,
CreatorId = 0,
Trashed = false
};
var metaCollection = new PropertyTypeCollection();
metaCollection.Add(new PropertyType("seotest", DataTypeDatabaseType.Ntext) { Alias = "seokeywords", Name = "Seo Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
metaCollection.Add(new PropertyType("seotest", DataTypeDatabaseType.Ntext) { Alias = "seodescription", Name = "Seo Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -89 });
contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Seo", SortOrder = 5 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSimpleContentType()
{
var contentType = new ContentType(-1)
@@ -92,9 +161,9 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false)
public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content")
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent);
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
@@ -110,7 +179,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TinyMCEAlias, DataTypeDatabaseType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -87 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext) { Alias = RandomAlias("author", randomizeAliases) , Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeDefinitionId = -88 });
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = propertyGroupName, SortOrder = 1 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
@@ -167,6 +236,27 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection collection, string propertyGroupName, IContentType parent = null)
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
contentType.Description = "ContentType used for simple text pages";
contentType.Icon = ".sprTreeDoc3";
contentType.Thumbnail = "doc2.png";
contentType.SortOrder = 1;
contentType.CreatorId = 0;
contentType.Trashed = false;
contentType.PropertyGroups.Add(new PropertyGroup(collection) { Name = propertyGroupName, SortOrder = 1 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection groupedCollection, PropertyTypeCollection nonGroupedCollection)
{
var contentType = CreateSimpleContentType(alias, name, groupedCollection);
+2 -2
View File
@@ -2542,9 +2542,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7200</DevelopmentServerPort>
<DevelopmentServerPort>7210</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7200</IISUrl>
<IISUrl>http://localhost:7210</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -130,7 +130,7 @@
<create assembly="umbraco" type="MediaTypeTasks" />
<delete assembly="umbraco" type="MediaTypeTasks" />
</tasks>
</nodeType>
</nodeType>
<nodeType alias="initmember">
<header>member</header>
<usercontrol>/create/member.ascx</usercontrol>
@@ -324,7 +324,7 @@
</nodeType>
<nodeType alias="partialViews">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
@@ -338,4 +338,20 @@
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacrosFolder">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewMacroTasks" />
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
</createUI>
@@ -330,14 +330,6 @@
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacros">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
@@ -346,6 +338,14 @@
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacrosFolder">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
+1 -1
View File
@@ -415,7 +415,7 @@ namespace Umbraco.Web.Security
if (member != null)
{
var propValue = member.Properties[prop.Alias];
if (propValue != null)
if (propValue != null && propValue.Value != null)
{
value = propValue.Value.ToString();
}
@@ -42,6 +42,7 @@ namespace Umbraco.Web.Security.Providers
private string _defaultMemberTypeAlias = "Member";
private volatile bool _hasDefaultMember = false;
private static readonly object Locker = new object();
private bool _providerKeyAsGuid = false;
public override string ProviderName
{
@@ -58,7 +59,7 @@ namespace Umbraco.Web.Security.Providers
protected override MembershipUser ConvertToMembershipUser(IMember entity)
{
return entity.AsConcreteMembershipUser(Name);
return entity.AsConcreteMembershipUser(Name, _providerKeyAsGuid);
}
public string LockPropertyTypeAlias { get; private set; }
@@ -85,6 +86,15 @@ namespace Umbraco.Web.Security.Providers
}
_hasDefaultMember = true;
}
//devs can configure the provider user key to be a guid if they want, by default it is int
if (config["providerKeyType"] != null)
{
if (config["providerKeyType"] == "guid")
{
_providerKeyAsGuid = true;
}
}
}
public override string DefaultMemberTypeAlias
@@ -47,7 +47,7 @@ namespace Umbraco.Web.Security.Providers
protected override MembershipUser ConvertToMembershipUser(IUser entity)
{
//the provider user key is always the int id
return entity.AsConcreteMembershipUser(Name);
return entity.AsConcreteMembershipUser(Name, true);
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
@@ -500,15 +500,18 @@ namespace umbraco
() => GetMediaDo(MediaId, Deep));
if (xml != null)
{
return FromXElement(xml, xml.Attribute("nodeTypeAlias").Value);
{
//returning the root element of the Media item fixes the problem
return xml.CreateNavigator().Select("/");
}
}
else
{
var xml = GetMediaDo(MediaId, Deep);
return FromXElement(xml, xml.Attribute("nodeTypeAlias").Value);
//returning the root element of the Media item fixes the problem
return xml.CreateNavigator().Select("/");
}
}
catch(Exception ex)
@@ -536,15 +539,6 @@ namespace umbraco
return serialized;
}
private static XPathNodeIterator FromXElement(XNode xml, string mediaContentType)
{
var xp = xml.CreateNavigator();
var xpath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
? "/node"
: String.Format("/{0}", Casing.SafeAliasWithForcingCheck(mediaContentType));
return xp.Select(xpath);
}
/// <summary>
/// Get a member as an xml object
/// </summary>
@@ -16,6 +16,7 @@ using System.Web.UI.WebControls;
using ClientDependency.Core;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Strings;
@@ -308,7 +309,7 @@ namespace umbraco.controls
Trace.Write("ContentTypeControlNew", "executing task");
//we need to re-set the UmbracoContext since it will be nulled and our cache handlers need it
//global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext;
global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext;
_contentType.ContentTypeItem.Name = txtName.Text;
_contentType.ContentTypeItem.Alias = txtAlias.Text; // raw, contentType.Alias takes care of it
@@ -322,56 +323,71 @@ namespace umbraco.controls
var ids = SaveAllowedChildTypes();
_contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort {Id = new Lazy<int>(() => x), SortOrder = i++});
//Saving ContentType Compositions
var compositionIds = SaveCompositionContentTypes();
var existingCompsitionIds = _contentType.ContentTypeItem.CompositionIds().ToList();
if (compositionIds.Any())
// figure out whether compositions are locked
var allContentTypes = Request.Path.ToLowerInvariant().Contains("editmediatype.aspx")
? ApplicationContext.Services.ContentTypeService.GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray()
: ApplicationContext.Services.ContentTypeService.GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
var isUsing = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == _contentType.Id)).ToArray();
// if compositions are locked, do nothing (leave them as they are)
// else process the checkbox list and add/remove compositions accordingly
if (isUsing.Length == 0)
{
//Iterate ContentType Ids from the save-collection
foreach (var compositionId in compositionIds)
//Saving ContentType Compositions
var compositionIds = SaveCompositionContentTypes();
var existingCompsitionIds = _contentType.ContentTypeItem.CompositionIds().ToList();
if (compositionIds.Any())
{
//If the compositionId is the Id of the current ContentType we skip it
if(_contentType.Id.Equals(compositionId)) continue;
// if some compositions were checked in the list, iterate over them
foreach (var compositionId in compositionIds)
{
// ignore if it is the current content type
if (_contentType.Id.Equals(compositionId)) continue;
//If the Id already exists we'll just skip it
if (existingCompsitionIds.Any(x => x.Equals(compositionId))) continue;
// ignore if it is already a composition of the content type
if (existingCompsitionIds.Any(x => x.Equals(compositionId))) continue;
//New Ids will get added to the collection
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(compositionId)
.SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(compositionId)
.SafeCast<IContentTypeComposition>();
var added = _contentType.ContentTypeItem.AddContentType(compositionType);
//TODO if added=false then return error message
// add to the content type compositions
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(compositionId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(compositionId).SafeCast<IContentTypeComposition>();
try
{
//TODO if added=false then return error message
var added = _contentType.ContentTypeItem.AddContentType(compositionType);
}
catch (InvalidCompositionException ex)
{
state.SaveArgs.IconType = BasePage.speechBubbleIcon.error;
state.SaveArgs.Message = ex.Message;
}
}
// then iterate over removed = existing except checked
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
{
// and remove from the content type composition
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId).SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
//Iterate the set except of existing and new Ids
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
else if (existingCompsitionIds.Any())
{
//Remove ContentTypes that was deselected in the list
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId)
.SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId)
.SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
else if (existingCompsitionIds.Any())
{
//Iterate the set except of existing and new Ids
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
{
//Remove ContentTypes that was deselected in the list
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId)
.SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId)
.SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
// else none were checked - if the content type had compositions,
// iterate over them all and remove them
var removeIds = existingCompsitionIds.Except(compositionIds); // except here makes no sense?
foreach (var removeId in removeIds)
{
// remove existing
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId).SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
}
@@ -419,6 +435,11 @@ namespace umbraco.controls
state.SaveArgs.Message = ex.Message;
return;
}
catch (Exception ex)
{
state.SaveArgs.IconType = BasePage.speechBubbleIcon.error;
state.SaveArgs.Message = ex.Message;
}
Trace.Write("ContentTypeControlNew", "task completing");
};
@@ -710,7 +731,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
DualContentTypeCompositions.Value = "";
PlaceHolderContentTypeCompositions.Controls.Add(new Literal { Text = "<em>This content type is used as a parent and/or in "
+ "a composition, and therefore cannot be composed itself.<br /><br />"
+ "a composition, and therefore cannot be composed itself.<br /><br />Used by: "
+ string.Join(", ", isUsing.Select(x => x.Name))
+ "</em>" });
}
@@ -795,16 +816,10 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
private int[] SaveCompositionContentTypes()
{
var tmp = new ArrayList();
foreach (ListItem li in lstContentTypeCompositions.Items)
{
if (li.Selected)
tmp.Add(int.Parse(li.Value));
}
var ids = new int[tmp.Count];
for (int i = 0; i < tmp.Count; i++) ids[i] = (int)tmp[i];
return ids;
return lstContentTypeCompositions.Items.Cast<ListItem>()
.Where(x => x.Selected)
.Select(x => int.Parse(x.Value))
.ToArray();
}
#endregion
@@ -1067,7 +1082,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
private string GetHtmlForNoPropertiesMessageListItem()
{
return @"<li class=""no-properties-on-tab"">" + ui.Text("settings", "noPropertiesDefinedOnTab") + "</li></ul>";
return @"<li class=""no-properties-on-tab"">" + ui.Text("settings", "noPropertiesDefinedOnTab", Security.CurrentUser) + "</li></ul>";
}
private void SavePropertyType(SaveClickEventArgs e, IContentTypeComposition contentTypeItem)
@@ -1121,7 +1136,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
}
else
{
e.Message = ui.Text("contentTypeDublicatePropertyType");
e.Message = ui.Text("contentTypeDublicatePropertyType", Security.CurrentUser);
e.IconType = BasePage.speechBubbleIcon.warning;
}
}
@@ -1424,7 +1439,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
LoadContentType();
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated"));
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated", Security.CurrentUser));
ea.IconType = BasePage.speechBubbleIcon.success;
RaiseBubbleEvent(new object(), ea);
@@ -1463,7 +1478,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
LoadContentType();
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted"));
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted", Security.CurrentUser));
ea.IconType = BasePage.speechBubbleIcon.success;
RaiseBubbleEvent(new object(), ea);
@@ -24,13 +24,18 @@ namespace umbraco
//NOTE: TypeID is the parent id!
//NOTE: ParentID is aparently a flag to determine if we are to create a template! Hack much ?! :P
var parentId = TypeID != 0 ? TypeID : -1;
var contentType = parentId == -1
? new ContentType(-1)
: new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId));
contentType.CreatorId = User.Id;
// when creating a content type, enforce PascalCase
// preserve separator because contentType.Alias will re-alias it
contentType.Alias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' ');
var cleanAlias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' ');
var contentType = parentId == -1
? new ContentType(-1)
: new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId), cleanAlias);
contentType.CreatorId = User.Id;
contentType.Alias = cleanAlias;
contentType.Name = Alias.Replace("'", "''");
contentType.Icon = ".sprTreeFolder";