Updates user permissions lookup to do one query instead of one query per user group

This commit is contained in:
Shannon
2017-07-13 10:43:42 +10:00
parent df18cdc7f7
commit 76f9e2c22a
4 changed files with 63 additions and 49 deletions

View File

@@ -28,17 +28,17 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Gets explicilty defined permissions for the group for specified entities
/// </summary>
/// <param name="groupId">Id of group</param>
/// <param name="groupIds"></param>
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
EntityPermissionCollection GetPermissionsForEntities(int groupId, params int[] entityIds);
EntityPermissionCollection GetPermissions(int[] groupIds, params int[] entityIds);
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="group">The group</param>
/// <param name="groups"></param>
/// <param name="fallbackToDefaultPermissions">If true will include the group's default permissions if no permissions are explicitly assigned</param>
/// <param name="nodeIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
EntityPermissionCollection GetPermissionsForEntities(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds);
EntityPermissionCollection GetPermissions(IReadOnlyUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds);
/// <summary>
/// Replaces the same permission set for a single group to any number of entities

View File

@@ -39,43 +39,53 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Returns explicitly defined permissions for a user group for any number of nodes
/// </summary>
/// <param name="groupId"></param>
/// <param name="groupIds">
/// The group ids to lookup permissions for
/// </param>
/// <param name="entityIds"></param>
/// <returns></returns>
public EntityPermissionCollection GetPermissionsForEntities(int groupId, params int[] entityIds)
/// <remarks>
/// This method will not support passing in more than 2000 group Ids
/// </remarks>
public EntityPermissionCollection GetPermissionsForEntities(int[] groupIds, params int[] entityIds)
{
var result = new EntityPermissionCollection();
if (entityIds.Length == 0)
foreach (var groupOfGroupIds in groupIds.InGroupsOf(2000))
{
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => dto.UserGroupId == groupId, SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
foreach (var permission in ConvertToPermissionList(permissions))
{
result.Add(permission);
}
}
else
{
//iterate in groups of 2000 since we don't want to exceed the max SQL param count
foreach (var groupOfIds in entityIds.InGroupsOf(2000))
{
var ids = groupOfIds;
//copy local
var localIds = groupOfGroupIds.ToArray();
var sql = new Sql();
if (entityIds.Length == 0)
{
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => dto.UserGroupId == groupId && ids.Contains(dto.NodeId), SqlSyntax);
.Where<UserGroup2NodePermissionDto>(dto => localIds.Contains(dto.UserGroupId), SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
foreach (var permission in ConvertToPermissionList(permissions))
{
result.Add(permission);
}
}
else
{
//iterate in groups of 2000 since we don't want to exceed the max SQL param count
foreach (var groupOfEntityIds in entityIds.InGroupsOf(2000))
{
var ids = groupOfEntityIds;
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => localIds.Contains(dto.UserGroupId) && ids.Contains(dto.NodeId), SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
foreach (var permission in ConvertToPermissionList(permissions))
{
result.Add(permission);
}
}
}
}
}
return result;
}

View File

@@ -91,42 +91,46 @@ namespace Umbraco.Core.Persistence.Repositories
_userGroupWithUsersRepository.AddOrUpdate(new UserGroupWithUsers(userGroup, userIds));
}
/// <summary>
/// Gets explicilty defined permissions for the group for specified entities
/// </summary>
/// <param name="groupId">Id of group</param>
/// <param name="groupIds"></param>
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
public EntityPermissionCollection GetPermissionsForEntities(int groupId, params int[] entityIds)
public EntityPermissionCollection GetPermissions(int[] groupIds, params int[] entityIds)
{
return _permissionRepository.GetPermissionsForEntities(groupId, entityIds);
return _permissionRepository.GetPermissionsForEntities(groupIds, entityIds);
}
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="group">The group</param>
/// <param name="groups"></param>
/// <param name="fallbackToDefaultPermissions">If true will include the group's default permissions if no permissions are explicitly assigned</param>
/// <param name="nodeIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
public EntityPermissionCollection GetPermissionsForEntities(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
public EntityPermissionCollection GetPermissions(IReadOnlyUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
if (group == null) throw new ArgumentNullException("group");
if (groups == null) throw new ArgumentNullException("groups");
var explicitPermissions = GetPermissionsForEntities(group.Id, nodeIds);
var groupIds = groups.Select(x => x.Id).ToArray();
var explicitPermissions = GetPermissions(groupIds, nodeIds);
var result = new EntityPermissionCollection(explicitPermissions);
// If requested, and no permissions are assigned to a particular node, then we will fill in those permissions with the group's defaults
if (fallbackToDefaultPermissions)
{
var missingIds = nodeIds.Except(result.Select(x => x.EntityId)).ToArray();
if (missingIds.Length > 0)
foreach (var group in groups)
{
foreach (var permission in missingIds
.Select(i => new EntityPermission(group.Id, i, group.Permissions.ToArray(), isDefaultPermissions: true)))
var missingIds = nodeIds.Except(result.Select(x => x.EntityId)).ToArray();
if (missingIds.Length > 0)
{
result.Add(permission);
foreach (var permission in missingIds
.Select(i => new EntityPermission(group.Id, i, group.Permissions.ToArray(), isDefaultPermissions: true)))
{
result.Add(permission);
}
}
}
}
}
return result;
}

View File

@@ -847,19 +847,19 @@ namespace Umbraco.Core.Services
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public EntityPermissionCollection GetPermissions(IUser user, params int[] nodeIds)
{
//TODO: we don't need to run this query for each group assigned, we can do this in one query
{
var result = new EntityPermissionCollection();
foreach (var group in user.Groups)
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
foreach (var permission in GetPermissions(group, true, nodeIds))
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
foreach (var permission in repository.GetPermissions(user.Groups.ToArray(), true, nodeIds))
{
result.Add(permission);
}
}
}
return result;
}
@@ -879,7 +879,7 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
return repository.GetPermissionsForEntities(group, fallbackToDefaultPermissions, nodeIds);
return repository.GetPermissions(new[] { group }, fallbackToDefaultPermissions, nodeIds);
}
}
@@ -898,7 +898,7 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
return repository.GetPermissionsForEntities(group.ToReadOnlyGroup(), fallbackToDefaultPermissions, nodeIds);
return repository.GetPermissions(new[] { group.ToReadOnlyGroup() }, fallbackToDefaultPermissions, nodeIds);
}
}