diff --git a/src/Umbraco.Core/Models/Membership/EntityPermission.cs b/src/Umbraco.Core/Models/Membership/EntityPermission.cs index c417a4985c..175e571fdf 100644 --- a/src/Umbraco.Core/Models/Membership/EntityPermission.cs +++ b/src/Umbraco.Core/Models/Membership/EntityPermission.cs @@ -5,14 +5,14 @@ /// public class EntityPermission { - public EntityPermission(object userId, int entityId, string[] assignedPermissions) + public EntityPermission(int userId, int entityId, string[] assignedPermissions) { UserId = userId; EntityId = entityId; AssignedPermissions = assignedPermissions; } - public object UserId { get; private set; } + public int UserId { get; private set; } public int EntityId { get; private set; } /// diff --git a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs index 555b87f6e4..6c2f7e6727 100644 --- a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs @@ -243,6 +243,10 @@ namespace Umbraco.Core.Persistence.Querying args.RemoveAt(0); } + //TODO: We should probably add the same logic we've done for ModelToSqlExpressionHelper with checking for: + // InvariantStartsWith, InvariantEndsWith, SqlWildcard, etc... + // since we should be able to easily handle that with the Poco objects too. + switch (m.Method.Name) { case "ToUpper": diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index f994e08ed7..9fb35156cc 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -286,7 +286,7 @@ namespace Umbraco.Core.Persistence.Repositories var userPermissions = ( from perm in parentPermissions from p in perm.AssignedPermissions - select new Tuple(perm.UserId, p)).ToList(); + select new Tuple(perm.UserId, p)).ToList(); permissionsRepo.AssignEntityPermissions(entity, userPermissions); //flag the entity's permissions changed flag so we can track those changes. @@ -558,7 +558,7 @@ namespace Umbraco.Core.Persistence.Repositories return GetByVersion(dto.ContentVersionDto.VersionId); } - public void AssignEntityPermissions(IContent entity, char permission, IEnumerable userIds) + public void AssignEntityPermissions(IContent entity, char permission, IEnumerable userIds) { var repo = new PermissionRepository(UnitOfWork, _cacheHelper); repo.AssignEntityPermissions(entity, permission, userIds); diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs index 06beebda9e..a8cb9a88c5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs @@ -23,8 +23,13 @@ namespace Umbraco.Core.Persistence.Repositories /// An enumerable list of IEnumerable GetByPublishedVersion(IQuery query); - void AssignEntityPermissions(IContent entity, char permission, IEnumerable userIds); + void AssignEntityPermissions(IContent entity, char permission, IEnumerable userIds); + /// + /// Gets the list of permissions for the content item + /// + /// + /// IEnumerable GetPermissionsForEntity(int entityId); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 08d22ff3f6..20224ca3fb 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -131,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// /// - internal void AssignEntityPermissions(TEntity entity, char permission, IEnumerable userIds) + internal void AssignEntityPermissions(TEntity entity, char permission, IEnumerable userIds) { var actions = userIds.Select(id => new User2NodePermissionDto { @@ -150,13 +150,13 @@ namespace Umbraco.Core.Persistence.Repositories /// /// A key/value pair list containing a userId and a permission to assign /// - internal void AssignEntityPermissions(TEntity entity, IEnumerable> userPermissions) + internal void AssignEntityPermissions(TEntity entity, IEnumerable> userPermissions) { var actions = userPermissions.Select(p => new User2NodePermissionDto { NodeId = entity.Id, Permission = p.Item2, - UserId = (int)p.Item1 + UserId = p.Item1 }); _unitOfWork.Database.BulkInsertRecords(actions); @@ -168,7 +168,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// /// - internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) + internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) { _unitOfWork.Database.Update( GenerateReplaceEntityPermissionsSql(entity.Id, permissions, userIds.ToArray())); @@ -183,7 +183,7 @@ namespace Umbraco.Core.Persistence.Repositories /// A callback to get the descendant Ids of the current entity /// /// - internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func> getDescendantIds, IEnumerable userIds) + internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func> getDescendantIds, IEnumerable userIds) { _unitOfWork.Database.Update( GenerateReplaceEntityPermissionsSql( @@ -192,12 +192,12 @@ namespace Umbraco.Core.Persistence.Repositories userIds.ToArray())); } - internal static string GenerateReplaceEntityPermissionsSql(int entityId, string permissions, object[] userIds) + internal static string GenerateReplaceEntityPermissionsSql(int entityId, string permissions, int[] userIds) { return GenerateReplaceEntityPermissionsSql(new[] { entityId }, permissions, userIds); } - internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, string permissions, object[] userIds) + internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, string permissions, int[] userIds) { //create the "SET" clause of the update statement var sqlSet = string.Format("SET {0}={1}", diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 097473a891..f14a88ba74 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -157,7 +157,10 @@ namespace Umbraco.Core.Persistence.Repositories } } - var entityCollection = PerformGetAll(ids).ToArray(); + var entityCollection = PerformGetAll(ids) + //ensure we don't include any null refs in the returned collection! + .WhereNotNull() + .ToArray(); foreach (var entity in entityCollection) { @@ -178,7 +181,9 @@ namespace Umbraco.Core.Persistence.Repositories /// public IEnumerable GetByQuery(IQuery query) { - return PerformGetByQuery(query); + return PerformGetByQuery(query) + //ensure we don't include any null refs in the returned collection! + .WhereNotNull(); } protected abstract bool PerformExists(TId id); diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index d3305af031..aad6b31514 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -34,7 +34,7 @@ namespace Umbraco.Core /// it will use the cached resolved plugins that it has already found which means that no assembly scanning is necessary. This leads /// to much faster startup times. /// - internal class PluginManager + public class PluginManager { private readonly ApplicationContext _appContext; private const string CacheKey = "umbraco-plugins.list"; @@ -107,7 +107,7 @@ namespace Umbraco.Core /// /// The setter is generally only used for unit tests /// - internal static PluginManager Current + public static PluginManager Current { get { @@ -783,6 +783,7 @@ namespace Umbraco.Core UpdateCachedPluginsFile(typeList.GetTypes(), resolutionKind); } + #region Public Methods /// /// Generic method to find the specified type and cache the result /// @@ -802,7 +803,7 @@ namespace Umbraco.Core /// /// /// - internal IEnumerable ResolveTypesWithAttribute(bool cacheResult = true) + public IEnumerable ResolveTypesWithAttribute(bool cacheResult = true) where TAttribute : Attribute { return ResolveTypes( @@ -816,14 +817,15 @@ namespace Umbraco.Core /// /// /// - internal IEnumerable ResolveAttributedTypes(bool cacheResult = true) + public IEnumerable ResolveAttributedTypes(bool cacheResult = true) where TAttribute : Attribute { return ResolveTypes( () => TypeFinder.FindClassesWithAttribute(AssembliesToScan), TypeResolutionKind.FindAttributedTypes, cacheResult); - } + } + #endregion /// /// Used for unit tests diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index f4956329ae..60dcaf2b5b 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -59,9 +59,13 @@ namespace Umbraco.Core.Services _repositoryFactory = repositoryFactory; } - //TODO: There are various ways to expose permission setting on this service, we just need to list out the different ways we'll need to - // be able to acheive this for the core, for now this is here so I can run a unit test. - internal void AssignContentPermissions(IContent entity, char permission, IEnumerable userIds) + /// + /// Assigns a single permission to the current content item for the specified user ids + /// + /// + /// + /// + public void AssignContentPermissions(IContent entity, char permission, IEnumerable userIds) { var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) @@ -70,6 +74,20 @@ namespace Umbraco.Core.Services } } + /// + /// Gets the list of permissions for the content item + /// + /// + /// + public IEnumerable GetPermissionsForEntity(IContent content) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + return repository.GetPermissionsForEntity(content.Id); + } + } + /// /// Creates an object using the alias of the /// that this Content should based on. @@ -1220,6 +1238,7 @@ namespace Umbraco.Core.Services } } + /// /// Sends an to Publication, which executes handlers and events for the 'Send to Publication' action. /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 9acdef9bc3..672973a3ca 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -11,6 +11,20 @@ namespace Umbraco.Core.Services /// public interface IContentService : IService { + /// + /// Assigns a single permission to the current content item for the specified user ids + /// + /// + /// + /// + void AssignContentPermissions(IContent entity, char permission, IEnumerable userIds); + + /// + /// Gets the list of permissions for the content item + /// + /// + /// + IEnumerable GetPermissionsForEntity(IContent content); bool SendToPublication(IContent content, int userId = 0); diff --git a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs index eb98548c19..7f96dfade2 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Persistence.Querying public void Generate_Replace_Entity_Permissions_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "A", new object[] {10, 11, 12}); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "A", new int[] {10, 11, 12}); // Assert Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Persistence.Querying public void Generate_Replace_Entity_Permissions_With_Descendants_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] { 123, 456 },"A", new object[] { 10, 11, 12 }); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] { 123, 456 }, "A", new int[] { 10, 11, 12 }); // Assert Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index 813b6b0f98..cb0eb78aa2 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -70,7 +70,7 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Commit(); // Act - repository.AssignEntityPermissions(parentPage, 'A', new object[] { 0 }); + repository.AssignEntityPermissions(parentPage, 'A', new int[] { 0 }); var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); repository.AddOrUpdate(childPage); unitOfWork.Commit(); diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index 1105fef7ee..5a76ffc4bb 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -76,14 +76,14 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(0), ActionBrowse.Instance.Letter, new object[] { user.Id }); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(0), ActionDelete.Instance.Letter, new object[] { user.Id }); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(0), ActionMove.Instance.Letter, new object[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { user.Id }); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(1), ActionBrowse.Instance.Letter, new object[] { user.Id }); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(1), ActionDelete.Instance.Letter, new object[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { user.Id }); - ((ContentService)ServiceContext.ContentService).AssignContentPermissions(content.ElementAt(2), ActionBrowse.Instance.Letter, new object[] { user.Id }); + ServiceContext.ContentService.AssignContentPermissions(content.ElementAt(2), ActionBrowse.Instance.Letter, new int[] { user.Id }); // Act var permissions = userService.GetPermissions(user, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id); @@ -156,6 +156,17 @@ namespace Umbraco.Tests.Services Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); } + [Test] + public void Get_By_Username_With_Backslash() + { + var userType = MockedUserType.CreateUserType(); + ServiceContext.UserService.SaveUserType(userType); + var user = ServiceContext.UserService.CreateMemberWithIdentity("mydomain\\JohnDoe", "john@umbraco.io", "12345", userType); + + Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); + Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); + } + [Test] public void Get_By_Object_Id() { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs index 58b8f9ebc1..16e034b8f5 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs @@ -178,15 +178,8 @@ namespace umbraco.cms.presentation.Trees // tree type contains a comma (meaning it is assembly qualified) if (tree.AssemblyName.IsNullOrWhiteSpace() || tree.Type.Contains(",")) { - var clrType = Type.GetType(tree.Type); - if (clrType == null) - { - LogHelper.Warn("The tree definition: " + tree.Type + " could not be resolved to a .Net object type"); - return false; - } - - return clrType == type; - } + return tree.GetRuntimeType() == type; + } //otherwise match using legacy match rules return (string.Format("{0}.{1}", tree.AssemblyName, tree.Type).InvariantEquals(type.FullName)); diff --git a/src/umbraco.businesslogic/ApplicationTree.cs b/src/umbraco.businesslogic/ApplicationTree.cs index 6458885edd..2c015c9b05 100644 --- a/src/umbraco.businesslogic/ApplicationTree.cs +++ b/src/umbraco.businesslogic/ApplicationTree.cs @@ -84,6 +84,17 @@ namespace umbraco.BusinessLogic /// The type. public string Type { get; set; } + private Type _runtimeType; + + /// + /// Returns the CLR type based on it's assembly name stored in the config + /// + /// + internal Type GetRuntimeType() + { + return _runtimeType ?? (_runtimeType = System.Type.GetType(Type)); + } + /// /// Gets or sets the default tree action. ///