mirror of
https://github.com/bitwarden/server
synced 2025-12-25 12:43:14 +00:00
[AC-2084] Include Collection permissions for admin endpoints (#3793)
* [AC-2084] Add documentation to existing collection repository getters * [AC-2084] Add new CollectionAdminDetails model * [AC-2084] Add SQL and migration scripts * [AC-2084] Introduce new repository methods to include permission details for collections * [AC-2084] Add EF repository methods and integration tests * [AC-2084] Update CollectionsController and response models * [AC-2084] Fix failing SqlServer test * [AC-2084] Clean up admin endpoint response models - vNext endpoints should now always return CollectionDetailsResponse models - Update constructors in CollectionDetailsResponseModel to be more explicit and add named static constructors for additional clarity * [AC-2084] Fix failing tests * [AC-2084] Fix potential provider/member bug * [AC-2084] Fix broken collections controller * [AC-2084] Cleanup collection response model types and constructors * [AC-2084] Remove redundant authorization check * [AC-2084] Cleanup ambiguous model name * [AC-2084] Add GroupBy clause to sprocs * [AC-2084] Add GroupBy logic to EF repository * [AC-2084] Update collection repository tests * [AC-2084] Update migration script date * Update migration script date --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: kejaeger <138028972+kejaeger@users.noreply.github.com>
This commit is contained in:
@@ -370,6 +370,210 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<CollectionAdminDetails>> GetManyByOrganizationIdWithPermissionsAsync(
|
||||
Guid organizationId, Guid userId, bool includeAccessRelationships)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = CollectionAdminDetailsQuery.ByOrganizationId(organizationId, userId).Run(dbContext);
|
||||
|
||||
ICollection<CollectionAdminDetails> collections;
|
||||
|
||||
// SQLite does not support the GROUP BY clause
|
||||
if (dbContext.Database.IsSqlite())
|
||||
{
|
||||
collections = (await query.ToListAsync())
|
||||
.GroupBy(c => new
|
||||
{
|
||||
c.Id,
|
||||
c.OrganizationId,
|
||||
c.Name,
|
||||
c.CreationDate,
|
||||
c.RevisionDate,
|
||||
c.ExternalId
|
||||
}).Select(collectionGroup => new CollectionAdminDetails
|
||||
{
|
||||
Id = collectionGroup.Key.Id,
|
||||
OrganizationId = collectionGroup.Key.OrganizationId,
|
||||
Name = collectionGroup.Key.Name,
|
||||
CreationDate = collectionGroup.Key.CreationDate,
|
||||
RevisionDate = collectionGroup.Key.RevisionDate,
|
||||
ExternalId = collectionGroup.Key.ExternalId,
|
||||
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
|
||||
HidePasswords =
|
||||
Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
|
||||
Manage = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Manage))),
|
||||
Assigned = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Assigned)))
|
||||
}).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
collections = await (from c in query
|
||||
group c by new
|
||||
{
|
||||
c.Id,
|
||||
c.OrganizationId,
|
||||
c.Name,
|
||||
c.CreationDate,
|
||||
c.RevisionDate,
|
||||
c.ExternalId
|
||||
}
|
||||
into collectionGroup
|
||||
select new CollectionAdminDetails
|
||||
{
|
||||
Id = collectionGroup.Key.Id,
|
||||
OrganizationId = collectionGroup.Key.OrganizationId,
|
||||
Name = collectionGroup.Key.Name,
|
||||
CreationDate = collectionGroup.Key.CreationDate,
|
||||
RevisionDate = collectionGroup.Key.RevisionDate,
|
||||
ExternalId = collectionGroup.Key.ExternalId,
|
||||
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
|
||||
HidePasswords =
|
||||
Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
|
||||
Manage = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Manage))),
|
||||
Assigned = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Assigned)))
|
||||
}).ToListAsync();
|
||||
}
|
||||
|
||||
if (!includeAccessRelationships)
|
||||
{
|
||||
return collections;
|
||||
}
|
||||
|
||||
var groups = (from c in collections
|
||||
join cg in dbContext.CollectionGroups on c.Id equals cg.CollectionId
|
||||
group cg by cg.CollectionId into g
|
||||
select g).ToList();
|
||||
|
||||
var users = (from c in collections
|
||||
join cu in dbContext.CollectionUsers on c.Id equals cu.CollectionId
|
||||
group cu by cu.CollectionId into u
|
||||
select u).ToList();
|
||||
|
||||
foreach (var collection in collections)
|
||||
{
|
||||
collection.Groups = groups
|
||||
.FirstOrDefault(g => g.Key == collection.Id)?
|
||||
.Select(g => new CollectionAccessSelection
|
||||
{
|
||||
Id = g.GroupId,
|
||||
HidePasswords = g.HidePasswords,
|
||||
ReadOnly = g.ReadOnly,
|
||||
Manage = g.Manage,
|
||||
}).ToList() ?? new List<CollectionAccessSelection>();
|
||||
collection.Users = users
|
||||
.FirstOrDefault(u => u.Key == collection.Id)?
|
||||
.Select(c => new CollectionAccessSelection
|
||||
{
|
||||
Id = c.OrganizationUserId,
|
||||
HidePasswords = c.HidePasswords,
|
||||
ReadOnly = c.ReadOnly,
|
||||
Manage = c.Manage
|
||||
}).ToList() ?? new List<CollectionAccessSelection>();
|
||||
}
|
||||
|
||||
return collections;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CollectionAdminDetails> GetByIdWithPermissionsAsync(Guid collectionId, Guid? userId,
|
||||
bool includeAccessRelationships)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = CollectionAdminDetailsQuery.ByCollectionId(collectionId, userId).Run(dbContext);
|
||||
|
||||
CollectionAdminDetails collectionDetails;
|
||||
|
||||
// SQLite does not support the GROUP BY clause
|
||||
if (dbContext.Database.IsSqlite())
|
||||
{
|
||||
collectionDetails = (await query.ToListAsync())
|
||||
.GroupBy(c => new
|
||||
{
|
||||
c.Id,
|
||||
c.OrganizationId,
|
||||
c.Name,
|
||||
c.CreationDate,
|
||||
c.RevisionDate,
|
||||
c.ExternalId
|
||||
}).Select(collectionGroup => new CollectionAdminDetails
|
||||
{
|
||||
Id = collectionGroup.Key.Id,
|
||||
OrganizationId = collectionGroup.Key.OrganizationId,
|
||||
Name = collectionGroup.Key.Name,
|
||||
CreationDate = collectionGroup.Key.CreationDate,
|
||||
RevisionDate = collectionGroup.Key.RevisionDate,
|
||||
ExternalId = collectionGroup.Key.ExternalId,
|
||||
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
|
||||
HidePasswords =
|
||||
Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
|
||||
Manage = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Manage))),
|
||||
Assigned = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Assigned)))
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
collectionDetails = await (from c in query
|
||||
group c by new
|
||||
{
|
||||
c.Id,
|
||||
c.OrganizationId,
|
||||
c.Name,
|
||||
c.CreationDate,
|
||||
c.RevisionDate,
|
||||
c.ExternalId
|
||||
}
|
||||
into collectionGroup
|
||||
select new CollectionAdminDetails
|
||||
{
|
||||
Id = collectionGroup.Key.Id,
|
||||
OrganizationId = collectionGroup.Key.OrganizationId,
|
||||
Name = collectionGroup.Key.Name,
|
||||
CreationDate = collectionGroup.Key.CreationDate,
|
||||
RevisionDate = collectionGroup.Key.RevisionDate,
|
||||
ExternalId = collectionGroup.Key.ExternalId,
|
||||
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
|
||||
HidePasswords =
|
||||
Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
|
||||
Manage = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Manage))),
|
||||
Assigned = Convert.ToBoolean(collectionGroup.Max(c => Convert.ToInt32(c.Assigned)))
|
||||
}).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
if (!includeAccessRelationships)
|
||||
{
|
||||
return collectionDetails;
|
||||
}
|
||||
|
||||
var groupsQuery = from cg in dbContext.CollectionGroups
|
||||
where cg.CollectionId.Equals(collectionId)
|
||||
select new CollectionAccessSelection
|
||||
{
|
||||
Id = cg.GroupId,
|
||||
ReadOnly = cg.ReadOnly,
|
||||
HidePasswords = cg.HidePasswords,
|
||||
Manage = cg.Manage
|
||||
};
|
||||
collectionDetails.Groups = await groupsQuery.ToListAsync();
|
||||
|
||||
var usersQuery = from cg in dbContext.CollectionUsers
|
||||
where cg.CollectionId.Equals(collectionId)
|
||||
select new CollectionAccessSelection
|
||||
{
|
||||
Id = cg.OrganizationUserId,
|
||||
ReadOnly = cg.ReadOnly,
|
||||
HidePasswords = cg.HidePasswords,
|
||||
Manage = cg.Manage
|
||||
};
|
||||
collectionDetails.Users = await usersQuery.ToListAsync();
|
||||
|
||||
return collectionDetails;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ICollection<CollectionAccessSelection>> GetManyUsersByIdAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
|
||||
Reference in New Issue
Block a user