1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 00:22:50 -05:00

[AC-1117] Add manage permission (#3126)

* Update sql files to add Manage permission

* Add migration script

* Rename collection manage migration file to remove duplicate migration date

* Migrations

* Add manage to models

* Add manage to repository

* Add constraint to Manage columns

* Migration lint fixes

* Add manage to OrganizationUserUserDetails_ReadWithCollectionsById

* Add missing manage fields

* Add 'Manage' to UserCollectionDetails

* Use CREATE OR ALTER where possible
This commit is contained in:
Robyn MacCallum
2023-08-11 14:50:34 -04:00
committed by GitHub
parent 5275f22f12
commit 4f08039756
44 changed files with 7787 additions and 52 deletions

View File

@ -9,6 +9,7 @@ public class SelectionReadOnlyRequestModel
public string Id { get; set; } public string Id { get; set; }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
public CollectionAccessSelection ToSelectionReadOnly() public CollectionAccessSelection ToSelectionReadOnly()
{ {
@ -17,6 +18,7 @@ public class SelectionReadOnlyRequestModel
Id = new Guid(Id), Id = new Guid(Id),
ReadOnly = ReadOnly, ReadOnly = ReadOnly,
HidePasswords = HidePasswords, HidePasswords = HidePasswords,
Manage = Manage,
}; };
} }
} }

View File

@ -33,10 +33,12 @@ public class CollectionDetailsResponseModel : CollectionResponseModel
{ {
ReadOnly = collectionDetails.ReadOnly; ReadOnly = collectionDetails.ReadOnly;
HidePasswords = collectionDetails.HidePasswords; HidePasswords = collectionDetails.HidePasswords;
Manage = collectionDetails.Manage;
} }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }
public class CollectionAccessDetailsResponseModel : CollectionResponseModel public class CollectionAccessDetailsResponseModel : CollectionResponseModel

View File

@ -14,9 +14,11 @@ public class SelectionReadOnlyResponseModel
Id = selection.Id; Id = selection.Id;
ReadOnly = selection.ReadOnly; ReadOnly = selection.ReadOnly;
HidePasswords = selection.HidePasswords; HidePasswords = selection.HidePasswords;
Manage = selection.Manage;
} }
public Guid Id { get; set; } public Guid Id { get; set; }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }

View File

@ -6,4 +6,5 @@ public class CollectionGroup
public Guid GroupId { get; set; } public Guid GroupId { get; set; }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }

View File

@ -6,4 +6,5 @@ public class CollectionUser
public Guid OrganizationUserId { get; set; } public Guid OrganizationUserId { get; set; }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }

View File

@ -5,4 +5,5 @@ public class CollectionAccessSelection
public Guid Id { get; set; } public Guid Id { get; set; }
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }

View File

@ -6,4 +6,5 @@ public class CollectionDetails : Collection
{ {
public bool ReadOnly { get; set; } public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; } public bool HidePasswords { get; set; }
public bool Manage { get; set; }
} }

View File

@ -40,6 +40,8 @@ public static class DapperHelpers
table.Columns.Add(readOnlyColumn); table.Columns.Add(readOnlyColumn);
var hidePasswordsColumn = new DataColumn("HidePasswords", typeof(bool)); var hidePasswordsColumn = new DataColumn("HidePasswords", typeof(bool));
table.Columns.Add(hidePasswordsColumn); table.Columns.Add(hidePasswordsColumn);
var manageColumn = new DataColumn("Manage", typeof(bool));
table.Columns.Add(manageColumn);
if (values != null) if (values != null)
{ {
@ -49,6 +51,7 @@ public static class DapperHelpers
row[idColumn] = value.Id; row[idColumn] = value.Id;
row[readOnlyColumn] = value.ReadOnly; row[readOnlyColumn] = value.ReadOnly;
row[hidePasswordsColumn] = value.HidePasswords; row[hidePasswordsColumn] = value.HidePasswords;
row[manageColumn] = value.Manage;
table.Rows.Add(row); table.Rows.Add(row);
} }
} }

View File

@ -121,7 +121,8 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
{ {
Id = g.GroupId, Id = g.GroupId,
HidePasswords = g.HidePasswords, HidePasswords = g.HidePasswords,
ReadOnly = g.ReadOnly ReadOnly = g.ReadOnly,
Manage = g.Manage
}).ToList() ?? new List<CollectionAccessSelection>(), }).ToList() ?? new List<CollectionAccessSelection>(),
Users = users Users = users
.FirstOrDefault(u => u.Key == collection.Id)? .FirstOrDefault(u => u.Key == collection.Id)?
@ -129,7 +130,8 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
{ {
Id = c.OrganizationUserId, Id = c.OrganizationUserId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
}).ToList() ?? new List<CollectionAccessSelection>() }).ToList() ?? new List<CollectionAccessSelection>()
} }
) )
@ -163,7 +165,8 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
{ {
Id = g.GroupId, Id = g.GroupId,
HidePasswords = g.HidePasswords, HidePasswords = g.HidePasswords,
ReadOnly = g.ReadOnly ReadOnly = g.ReadOnly,
Manage = g.Manage
}).ToList() ?? new List<CollectionAccessSelection>(), }).ToList() ?? new List<CollectionAccessSelection>(),
Users = users Users = users
.FirstOrDefault(u => u.Key == collection.Id)? .FirstOrDefault(u => u.Key == collection.Id)?
@ -171,7 +174,8 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
{ {
Id = c.OrganizationUserId, Id = c.OrganizationUserId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
}).ToList() ?? new List<CollectionAccessSelection>() }).ToList() ?? new List<CollectionAccessSelection>()
} }
) )

View File

@ -70,7 +70,8 @@ public class GroupRepository : Repository<Group, Guid>, IGroupRepository
{ {
Id = c.CollectionId, Id = c.CollectionId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
} }
).ToList() ?? new List<CollectionAccessSelection>()) ).ToList() ?? new List<CollectionAccessSelection>())
).ToList(); ).ToList();

View File

@ -266,7 +266,8 @@ public class OrganizationUserRepository : Repository<OrganizationUser, Guid>, IO
{ {
Id = uc.CollectionId, Id = uc.CollectionId,
ReadOnly = uc.ReadOnly, ReadOnly = uc.ReadOnly,
HidePasswords = uc.HidePasswords HidePasswords = uc.HidePasswords,
Manage = uc.Manage
}).ToList() ?? new List<CollectionAccessSelection>(); }).ToList() ?? new List<CollectionAccessSelection>();
} }
} }

View File

@ -68,6 +68,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
GroupId = g.Id, GroupId = g.Id,
ReadOnly = g.ReadOnly, ReadOnly = g.ReadOnly,
HidePasswords = g.HidePasswords, HidePasswords = g.HidePasswords,
Manage = g.Manage
}); });
await dbContext.AddRangeAsync(collectionGroups); await dbContext.AddRangeAsync(collectionGroups);
} }
@ -85,6 +86,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
OrganizationUserId = u.Id, OrganizationUserId = u.Id,
ReadOnly = u.ReadOnly, ReadOnly = u.ReadOnly,
HidePasswords = u.HidePasswords, HidePasswords = u.HidePasswords,
Manage = u.Manage
}); });
await dbContext.AddRangeAsync(collectionUsers); await dbContext.AddRangeAsync(collectionUsers);
} }
@ -130,6 +132,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
Id = cg.GroupId, Id = cg.GroupId,
ReadOnly = cg.ReadOnly, ReadOnly = cg.ReadOnly,
HidePasswords = cg.HidePasswords, HidePasswords = cg.HidePasswords,
Manage = cg.Manage
}; };
var groups = await groupQuery.ToArrayAsync(); var groups = await groupQuery.ToArrayAsync();
@ -140,6 +143,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
Id = cg.OrganizationUserId, Id = cg.OrganizationUserId,
ReadOnly = cg.ReadOnly, ReadOnly = cg.ReadOnly,
HidePasswords = cg.HidePasswords, HidePasswords = cg.HidePasswords,
Manage = cg.Manage
}; };
var users = await userQuery.ToArrayAsync(); var users = await userQuery.ToArrayAsync();
var access = new CollectionAccessDetails { Users = users, Groups = groups }; var access = new CollectionAccessDetails { Users = users, Groups = groups };
@ -161,6 +165,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
Id = cg.GroupId, Id = cg.GroupId,
ReadOnly = cg.ReadOnly, ReadOnly = cg.ReadOnly,
HidePasswords = cg.HidePasswords, HidePasswords = cg.HidePasswords,
Manage = cg.Manage
}; };
var groups = await groupQuery.ToArrayAsync(); var groups = await groupQuery.ToArrayAsync();
@ -171,6 +176,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
Id = cg.OrganizationUserId, Id = cg.OrganizationUserId,
ReadOnly = cg.ReadOnly, ReadOnly = cg.ReadOnly,
HidePasswords = cg.HidePasswords, HidePasswords = cg.HidePasswords,
Manage = cg.Manage,
}; };
var users = await userQuery.ToArrayAsync(); var users = await userQuery.ToArrayAsync();
var access = new CollectionAccessDetails { Users = users, Groups = groups }; var access = new CollectionAccessDetails { Users = users, Groups = groups };
@ -207,7 +213,8 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
{ {
Id = g.GroupId, Id = g.GroupId,
HidePasswords = g.HidePasswords, HidePasswords = g.HidePasswords,
ReadOnly = g.ReadOnly ReadOnly = g.ReadOnly,
Manage = g.Manage
}).ToList() ?? new List<CollectionAccessSelection>(), }).ToList() ?? new List<CollectionAccessSelection>(),
Users = users Users = users
.FirstOrDefault(u => u.Key == collection.Id)? .FirstOrDefault(u => u.Key == collection.Id)?
@ -215,7 +222,8 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
{ {
Id = c.OrganizationUserId, Id = c.OrganizationUserId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
}).ToList() ?? new List<CollectionAccessSelection>() }).ToList() ?? new List<CollectionAccessSelection>()
} }
) )
@ -251,7 +259,8 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
{ {
Id = g.GroupId, Id = g.GroupId,
HidePasswords = g.HidePasswords, HidePasswords = g.HidePasswords,
ReadOnly = g.ReadOnly ReadOnly = g.ReadOnly,
Manage = g.Manage
}).ToList() ?? new List<CollectionAccessSelection>(), }).ToList() ?? new List<CollectionAccessSelection>(),
Users = users Users = users
.FirstOrDefault(u => u.Key == collection.Id)? .FirstOrDefault(u => u.Key == collection.Id)?
@ -259,7 +268,8 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
{ {
Id = c.OrganizationUserId, Id = c.OrganizationUserId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
}).ToList() ?? new List<CollectionAccessSelection>() }).ToList() ?? new List<CollectionAccessSelection>()
} }
) )
@ -329,6 +339,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
ExternalId = collectionGroup.Key.ExternalId, ExternalId = collectionGroup.Key.ExternalId,
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))), ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
HidePasswords = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))), HidePasswords = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
Manage = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.Manage))),
}) })
.ToList(); .ToList();
} }
@ -353,6 +364,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
ExternalId = collectionGroup.Key.ExternalId, ExternalId = collectionGroup.Key.ExternalId,
ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))), ReadOnly = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.ReadOnly))),
HidePasswords = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))), HidePasswords = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.HidePasswords))),
Manage = Convert.ToBoolean(collectionGroup.Min(c => Convert.ToInt32(c.Manage))),
}).ToListAsync(); }).ToListAsync();
} }
} }
@ -371,6 +383,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
Id = cu.OrganizationUserId, Id = cu.OrganizationUserId,
ReadOnly = cu.ReadOnly, ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords, HidePasswords = cu.HidePasswords,
Manage = cu.Manage
}).ToArray(); }).ToArray();
} }
} }
@ -415,6 +428,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
OrganizationUserId = requestedUser.Id, OrganizationUserId = requestedUser.Id,
HidePasswords = requestedUser.HidePasswords, HidePasswords = requestedUser.HidePasswords,
ReadOnly = requestedUser.ReadOnly, ReadOnly = requestedUser.ReadOnly,
Manage = requestedUser.Manage
}); });
continue; continue;
} }
@ -422,6 +436,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
// It already exists, update it // It already exists, update it
existingCollectionUser.HidePasswords = requestedUser.HidePasswords; existingCollectionUser.HidePasswords = requestedUser.HidePasswords;
existingCollectionUser.ReadOnly = requestedUser.ReadOnly; existingCollectionUser.ReadOnly = requestedUser.ReadOnly;
existingCollectionUser.Manage = requestedUser.Manage;
dbContext.CollectionUsers.Update(existingCollectionUser); dbContext.CollectionUsers.Update(existingCollectionUser);
} }
@ -487,13 +502,15 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
GroupId = x.g.Id, GroupId = x.g.Id,
ReadOnly = groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly, ReadOnly = groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly,
HidePasswords = groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords, HidePasswords = groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords,
Manage = groups.FirstOrDefault(g => g.Id == x.g.Id).Manage
}).ToList(); }).ToList();
var update = union var update = union
.Where( .Where(
x => x.g != null && x => x.g != null &&
x.cg != null && x.cg != null &&
(x.cg.ReadOnly != groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly || (x.cg.ReadOnly != groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly ||
x.cg.HidePasswords != groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords) x.cg.HidePasswords != groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords ||
x.cg.Manage != groups.FirstOrDefault(g => g.Id == x.g.Id).Manage)
) )
.Select(x => new CollectionGroup .Select(x => new CollectionGroup
{ {
@ -501,6 +518,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
GroupId = x.g.Id, GroupId = x.g.Id,
ReadOnly = groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly, ReadOnly = groups.FirstOrDefault(g => g.Id == x.g.Id).ReadOnly,
HidePasswords = groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords, HidePasswords = groups.FirstOrDefault(g => g.Id == x.g.Id).HidePasswords,
Manage = groups.FirstOrDefault(g => g.Id == x.g.Id).Manage,
}); });
var delete = union var delete = union
.Where( .Where(
@ -549,13 +567,15 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
OrganizationUserId = x.u.Id, OrganizationUserId = x.u.Id,
ReadOnly = users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly, ReadOnly = users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly,
HidePasswords = users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords, HidePasswords = users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords,
Manage = users.FirstOrDefault(u => u.Id == x.u.Id).Manage,
}).ToList(); }).ToList();
var update = union var update = union
.Where( .Where(
x => x.u != null && x => x.u != null &&
x.cu != null && x.cu != null &&
(x.cu.ReadOnly != users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly || (x.cu.ReadOnly != users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly ||
x.cu.HidePasswords != users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords) x.cu.HidePasswords != users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords ||
x.cu.Manage != users.FirstOrDefault(u => u.Id == x.u.Id).Manage)
) )
.Select(x => new CollectionUser .Select(x => new CollectionUser
{ {
@ -563,6 +583,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
OrganizationUserId = x.u.Id, OrganizationUserId = x.u.Id,
ReadOnly = users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly, ReadOnly = users.FirstOrDefault(u => u.Id == x.u.Id).ReadOnly,
HidePasswords = users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords, HidePasswords = users.FirstOrDefault(u => u.Id == x.u.Id).HidePasswords,
Manage = users.FirstOrDefault(u => u.Id == x.u.Id).Manage,
}); });
var delete = union var delete = union
.Where( .Where(

View File

@ -30,6 +30,7 @@ public class GroupRepository : Repository<Core.Entities.Group, Group, Guid>, IGr
GroupId = grp.Id, GroupId = grp.Id,
ReadOnly = y.ReadOnly, ReadOnly = y.ReadOnly,
HidePasswords = y.HidePasswords, HidePasswords = y.HidePasswords,
Manage = y.Manage,
}); });
await dbContext.CollectionGroups.AddRangeAsync(collectionGroups); await dbContext.CollectionGroups.AddRangeAsync(collectionGroups);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
@ -66,6 +67,7 @@ public class GroupRepository : Repository<Core.Entities.Group, Group, Guid>, IGr
Id = c.CollectionId, Id = c.CollectionId,
ReadOnly = c.ReadOnly, ReadOnly = c.ReadOnly,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
Manage = c.Manage,
}).ToList(); }).ToList();
return new Tuple<Core.Entities.Group, ICollection<CollectionAccessSelection>>( return new Tuple<Core.Entities.Group, ICollection<CollectionAccessSelection>>(
grp, collections); grp, collections);
@ -108,7 +110,8 @@ public class GroupRepository : Repository<Core.Entities.Group, Group, Guid>, IGr
{ {
Id = c.CollectionId, Id = c.CollectionId,
HidePasswords = c.HidePasswords, HidePasswords = c.HidePasswords,
ReadOnly = c.ReadOnly ReadOnly = c.ReadOnly,
Manage = c.Manage
} }
).ToList() ?? new List<CollectionAccessSelection>()) ).ToList() ?? new List<CollectionAccessSelection>())
).ToList(); ).ToList();
@ -202,12 +205,14 @@ public class GroupRepository : Repository<Core.Entities.Group, Group, Guid>, IGr
GroupId = group.Id, GroupId = group.Id,
ReadOnly = requestedCollection.ReadOnly, ReadOnly = requestedCollection.ReadOnly,
HidePasswords = requestedCollection.HidePasswords, HidePasswords = requestedCollection.HidePasswords,
Manage = requestedCollection.Manage
}); });
continue; continue;
} }
existingCollectionGroup.ReadOnly = requestedCollection.ReadOnly; existingCollectionGroup.ReadOnly = requestedCollection.ReadOnly;
existingCollectionGroup.HidePasswords = requestedCollection.HidePasswords; existingCollectionGroup.HidePasswords = requestedCollection.HidePasswords;
existingCollectionGroup.Manage = requestedCollection.Manage;
} }
var requestedCollectionIds = requestedCollections.Select(c => c.Id); var requestedCollectionIds = requestedCollections.Select(c => c.Id);

View File

@ -33,6 +33,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
OrganizationUserId = organizationUser.Id, OrganizationUserId = organizationUser.Id,
ReadOnly = y.ReadOnly, ReadOnly = y.ReadOnly,
HidePasswords = y.HidePasswords, HidePasswords = y.HidePasswords,
Manage = y.Manage
}); });
await dbContext.CollectionUsers.AddRangeAsync(collectionUsers); await dbContext.CollectionUsers.AddRangeAsync(collectionUsers);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
@ -141,6 +142,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
Id = cu.CollectionId, Id = cu.CollectionId,
ReadOnly = cu.ReadOnly, ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords, HidePasswords = cu.HidePasswords,
Manage = cu.Manage,
}); });
return new Tuple<Core.Entities.OrganizationUser, ICollection<CollectionAccessSelection>>( return new Tuple<Core.Entities.OrganizationUser, ICollection<CollectionAccessSelection>>(
organizationUser, collections.ToList()); organizationUser, collections.ToList());
@ -235,6 +237,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
Id = cu.CollectionId, Id = cu.CollectionId,
ReadOnly = cu.ReadOnly, ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords, HidePasswords = cu.HidePasswords,
Manage = cu.Manage
}).ToListAsync(); }).ToListAsync();
return new Tuple<OrganizationUserUserDetails, ICollection<CollectionAccessSelection>>(organizationUserUserDetails, collections); return new Tuple<OrganizationUserUserDetails, ICollection<CollectionAccessSelection>>(organizationUserUserDetails, collections);
} }
@ -360,7 +363,8 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
{ {
Id = cu.CollectionId, Id = cu.CollectionId,
ReadOnly = cu.ReadOnly, ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords HidePasswords = cu.HidePasswords,
Manage = cu.Manage,
}).ToList() ?? new List<CollectionAccessSelection>(); }).ToList() ?? new List<CollectionAccessSelection>();
} }
} }
@ -440,6 +444,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
OrganizationUserId = obj.Id, OrganizationUserId = obj.Id,
HidePasswords = requestedCollection.HidePasswords, HidePasswords = requestedCollection.HidePasswords,
ReadOnly = requestedCollection.ReadOnly, ReadOnly = requestedCollection.ReadOnly,
Manage = requestedCollection.Manage
}); });
continue; continue;
} }
@ -447,6 +452,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
// It already exists, update it // It already exists, update it
existingCollectionUser.HidePasswords = requestedCollection.HidePasswords; existingCollectionUser.HidePasswords = requestedCollection.HidePasswords;
existingCollectionUser.ReadOnly = requestedCollection.ReadOnly; existingCollectionUser.ReadOnly = requestedCollection.ReadOnly;
existingCollectionUser.Manage = requestedCollection.Manage;
dbContext.CollectionUsers.Update(existingCollectionUser); dbContext.CollectionUsers.Update(existingCollectionUser);
} }

View File

@ -58,6 +58,8 @@ public class UserCollectionDetailsQuery : IQuery<CollectionDetails>
!((bool?)x.cu.ReadOnly ?? (bool?)x.cg.ReadOnly ?? false) ? false : true, !((bool?)x.cu.ReadOnly ?? (bool?)x.cg.ReadOnly ?? false) ? false : true,
HidePasswords = x.ou.AccessAll || x.g.AccessAll || HidePasswords = x.ou.AccessAll || x.g.AccessAll ||
!((bool?)x.cu.HidePasswords ?? (bool?)x.cg.HidePasswords ?? false) ? false : true, !((bool?)x.cu.HidePasswords ?? (bool?)x.cg.HidePasswords ?? false) ? false : true,
Manage = x.ou.AccessAll || x.g.AccessAll ||
!((bool?)x.cu.Manage ?? (bool?)x.cg.Manage ?? false) ? false : true,
}); });
} }
} }

View File

@ -18,7 +18,15 @@ SELECT
OR COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0 OR COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0
THEN 0 THEN 0
ELSE 1 ELSE 1
END [HidePasswords] END [HidePasswords],
CASE
WHEN
OU.[AccessAll] = 1
OR G.[AccessAll] = 1
OR COALESCE(CU.[Manage], CG.[Manage], 0) = 0
THEN 0
ELSE 1
END [Manage]
FROM FROM
[dbo].[CollectionView] C [dbo].[CollectionView] C
INNER JOIN INNER JOIN

View File

@ -7,9 +7,10 @@ BEGIN
SELECT SELECT
[GroupId] [Id], [GroupId] [Id],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
[dbo].[CollectionGroup] [dbo].[CollectionGroup]
WHERE WHERE
[CollectionId] = @CollectionId [CollectionId] = @CollectionId
END END

View File

@ -7,9 +7,10 @@ BEGIN
SELECT SELECT
[OrganizationUserId] [Id], [OrganizationUserId] [Id],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
[dbo].[CollectionUser] [dbo].[CollectionUser]
WHERE WHERE
[CollectionId] = @CollectionId [CollectionId] = @CollectionId
END END

View File

@ -19,7 +19,8 @@ BEGIN
[Target] [Target]
SET SET
[Target].[ReadOnly] = [Source].[ReadOnly], [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords] [Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
FROM FROM
[dbo].[CollectionUser] [Target] [dbo].[CollectionUser] [Target]
INNER JOIN INNER JOIN
@ -29,6 +30,7 @@ BEGIN
AND ( AND (
[Target].[ReadOnly] != [Source].[ReadOnly] [Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords] OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) )
-- Insert -- Insert
@ -38,7 +40,8 @@ BEGIN
@CollectionId, @CollectionId,
[Source].[Id], [Source].[Id],
[Source].[ReadOnly], [Source].[ReadOnly],
[Source].[HidePasswords] [Source].[HidePasswords],
[Source].[Manage]
FROM FROM
@Users [Source] @Users [Source]
INNER JOIN INNER JOIN
@ -71,4 +74,4 @@ BEGIN
) )
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @CollectionId, @OrgId EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @CollectionId, @OrgId
END END

View File

@ -27,13 +27,15 @@ BEGIN
[CollectionId], [CollectionId],
[GroupId], [GroupId],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
) )
SELECT SELECT
@Id, @Id,
[Id], [Id],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
@Groups @Groups
WHERE WHERE
@ -53,17 +55,19 @@ BEGIN
[CollectionId], [CollectionId],
[OrganizationUserId], [OrganizationUserId],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
) )
SELECT SELECT
@Id, @Id,
[Id], [Id],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
@Users @Users
WHERE WHERE
[Id] IN (SELECT [Id] FROM [AvailableUsersCTE]) [Id] IN (SELECT [Id] FROM [AvailableUsersCTE])
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END END

View File

@ -12,7 +12,8 @@ BEGIN
RevisionDate, RevisionDate,
ExternalId, ExternalId,
MIN([ReadOnly]) AS [ReadOnly], MIN([ReadOnly]) AS [ReadOnly],
MIN([HidePasswords]) AS [HidePasswords] MIN([HidePasswords]) AS [HidePasswords],
MIN([Manage]) AS [Manage]
FROM FROM
[dbo].[UserCollectionDetails](@UserId) [dbo].[UserCollectionDetails](@UserId)
WHERE WHERE

View File

@ -12,7 +12,8 @@ BEGIN
RevisionDate, RevisionDate,
ExternalId, ExternalId,
MIN([ReadOnly]) AS [ReadOnly], MIN([ReadOnly]) AS [ReadOnly],
MIN([HidePasswords]) AS [HidePasswords] MIN([HidePasswords]) AS [HidePasswords],
MIN([Manage]) AS [Manage]
FROM FROM
[dbo].[UserCollectionDetails](@UserId) [dbo].[UserCollectionDetails](@UserId)
GROUP BY GROUP BY

View File

@ -12,7 +12,8 @@ BEGIN
RevisionDate DATETIME2(7), RevisionDate DATETIME2(7),
ExternalId NVARCHAR(300), ExternalId NVARCHAR(300),
ReadOnly BIT, ReadOnly BIT,
HidePasswords BIT) HidePasswords BIT,
Manage BIT)
INSERT INTO @TempUserCollections EXEC [dbo].[Collection_ReadByUserId] @UserId INSERT INTO @TempUserCollections EXEC [dbo].[Collection_ReadByUserId] @UserId
@ -35,4 +36,4 @@ BEGIN
INNER JOIN INNER JOIN
@TempUserCollections C ON C.[Id] = CU.[CollectionId] @TempUserCollections C ON C.[Id] = CU.[CollectionId]
END END

View File

@ -36,14 +36,17 @@ BEGIN
@Id, @Id,
[Source].[Id], [Source].[Id],
[Source].[ReadOnly], [Source].[ReadOnly],
[Source].[HidePasswords] [Source].[HidePasswords],
[Source].[Manage]
) )
WHEN MATCHED AND ( WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly] [Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords] OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN ) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly], UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords] [Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN AND [Target].[CollectionId] = @Id THEN
DELETE DELETE
@ -72,18 +75,21 @@ BEGIN
@Id, @Id,
[Source].[Id], [Source].[Id],
[Source].[ReadOnly], [Source].[ReadOnly],
[Source].[HidePasswords] [Source].[HidePasswords],
[Source].[Manage]
) )
WHEN MATCHED AND ( WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly] [Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords] OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN ) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly], UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords] [Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN AND [Target].[CollectionId] = @Id THEN
DELETE DELETE
; ;
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
END END

View File

@ -26,17 +26,19 @@ BEGIN
[CollectionId], [CollectionId],
[GroupId], [GroupId],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
) )
SELECT SELECT
[Id], [Id],
@Id, @Id,
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
@Collections @Collections
WHERE WHERE
[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE]) [Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE])
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END END

View File

@ -9,9 +9,10 @@ BEGIN
SELECT SELECT
[CollectionId] [Id], [CollectionId] [Id],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
[dbo].[CollectionGroup] [dbo].[CollectionGroup]
WHERE WHERE
[GroupId] = @Id [GroupId] = @Id
END END

View File

@ -35,18 +35,21 @@ BEGIN
[Source].[Id], [Source].[Id],
@Id, @Id,
[Source].[ReadOnly], [Source].[ReadOnly],
[Source].[HidePasswords] [Source].[HidePasswords],
[Source].[Manage]
) )
WHEN MATCHED AND ( WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly] [Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords] OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN ) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly], UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords] [Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE WHEN NOT MATCHED BY SOURCE
AND [Target].[GroupId] = @Id THEN AND [Target].[GroupId] = @Id THEN
DELETE DELETE
; ;
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END END

View File

@ -9,11 +9,12 @@ BEGIN
SELECT SELECT
CU.[CollectionId] Id, CU.[CollectionId] Id,
CU.[ReadOnly], CU.[ReadOnly],
CU.[HidePasswords] CU.[HidePasswords],
CU.[Manage]
FROM FROM
[dbo].[OrganizationUser] OU [dbo].[OrganizationUser] OU
INNER JOIN INNER JOIN
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = [OU].[Id] [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = [OU].[Id]
WHERE WHERE
[OrganizationUserId] = @Id [OrganizationUserId] = @Id
END END

View File

@ -33,13 +33,15 @@ BEGIN
[CollectionId], [CollectionId],
[OrganizationUserId], [OrganizationUserId],
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
) )
SELECT SELECT
[Id], [Id],
@Id, @Id,
[ReadOnly], [ReadOnly],
[HidePasswords] [HidePasswords],
[Manage]
FROM FROM
@Collections @Collections
WHERE WHERE

View File

@ -24,7 +24,8 @@ BEGIN
[Target] [Target]
SET SET
[Target].[ReadOnly] = [Source].[ReadOnly], [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords] [Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
FROM FROM
[dbo].[CollectionUser] AS [Target] [dbo].[CollectionUser] AS [Target]
INNER JOIN INNER JOIN
@ -34,6 +35,7 @@ BEGIN
AND ( AND (
[Target].[ReadOnly] != [Source].[ReadOnly] [Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords] OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) )
-- Insert -- Insert
@ -43,7 +45,8 @@ BEGIN
[Source].[Id], [Source].[Id],
@Id, @Id,
[Source].[ReadOnly], [Source].[ReadOnly],
[Source].[HidePasswords] [Source].[HidePasswords],
[Source].[Manage]
FROM FROM
@Collections AS [Source] @Collections AS [Source]
INNER JOIN INNER JOIN
@ -58,7 +61,7 @@ BEGIN
[CollectionId] = [Source].[Id] [CollectionId] = [Source].[Id]
AND [OrganizationUserId] = @Id AND [OrganizationUserId] = @Id
) )
-- Delete -- Delete
DELETE DELETE
CU CU

View File

@ -3,6 +3,7 @@
[GroupId] UNIQUEIDENTIFIER NOT NULL, [GroupId] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] BIT NOT NULL, [ReadOnly] BIT NOT NULL,
[HidePasswords] BIT NOT NULL, [HidePasswords] BIT NOT NULL,
[Manage] BIT NOT NULL CONSTRAINT D_CollectionGroup_Manage DEFAULT (0),
CONSTRAINT [PK_CollectionGroup] PRIMARY KEY CLUSTERED ([CollectionId] ASC, [GroupId] ASC), CONSTRAINT [PK_CollectionGroup] PRIMARY KEY CLUSTERED ([CollectionId] ASC, [GroupId] ASC),
CONSTRAINT [FK_CollectionGroup_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]), CONSTRAINT [FK_CollectionGroup_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]),
CONSTRAINT [FK_CollectionGroup_Group] FOREIGN KEY ([GroupId]) REFERENCES [dbo].[Group] ([Id]) ON DELETE CASCADE CONSTRAINT [FK_CollectionGroup_Group] FOREIGN KEY ([GroupId]) REFERENCES [dbo].[Group] ([Id]) ON DELETE CASCADE

View File

@ -3,6 +3,7 @@
[OrganizationUserId] UNIQUEIDENTIFIER NOT NULL, [OrganizationUserId] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] BIT NOT NULL, [ReadOnly] BIT NOT NULL,
[HidePasswords] BIT NOT NULL, [HidePasswords] BIT NOT NULL,
[Manage] BIT NOT NULL CONSTRAINT D_CollectionUser_Manage DEFAULT (0),
CONSTRAINT [PK_CollectionUser] PRIMARY KEY CLUSTERED ([CollectionId] ASC, [OrganizationUserId] ASC), CONSTRAINT [PK_CollectionUser] PRIMARY KEY CLUSTERED ([CollectionId] ASC, [OrganizationUserId] ASC),
CONSTRAINT [FK_CollectionUser_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]) ON DELETE CASCADE, CONSTRAINT [FK_CollectionUser_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_CollectionUser_OrganizationUser] FOREIGN KEY ([OrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id]) CONSTRAINT [FK_CollectionUser_OrganizationUser] FOREIGN KEY ([OrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id])

View File

@ -1,5 +1,6 @@
CREATE TYPE [dbo].[SelectionReadOnlyArray] AS TABLE ( CREATE TYPE [dbo].[SelectionReadOnlyArray] AS TABLE (
[Id] UNIQUEIDENTIFIER NOT NULL, [Id] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] BIT NOT NULL, [ReadOnly] BIT NOT NULL,
[HidePasswords] BIT NOT NULL); [HidePasswords] BIT NOT NULL,
[Manage] BIT NOT NULL);

View File

@ -97,6 +97,7 @@ public class CipherRepositoryTests
Id = orgUser.Id, Id = orgUser.Id,
HidePasswords = true, HidePasswords = true,
ReadOnly = true, ReadOnly = true,
Manage = true
}, },
}); });

View File

@ -0,0 +1,794 @@
/*
* Add Manage permission to collections
*/
-- Drop procedures that use the SelectionReadOnlyArray type
IF OBJECT_ID('[dbo].[Group_CreateWithCollections]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Group_CreateWithCollections]
END
GO
IF OBJECT_ID('[dbo].[CollectionUser_UpdateUsers]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[CollectionUser_UpdateUsers]
END
GO
IF OBJECT_ID('[dbo].[Group_UpdateWithCollections]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Group_UpdateWithCollections]
END
GO
IF OBJECT_ID('[dbo].[Collection_UpdateWithGroupsAndUsers]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Collection_UpdateWithGroupsAndUsers]
END
GO
IF OBJECT_ID('[dbo].[OrganizationUser_CreateWithCollections]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[OrganizationUser_CreateWithCollections]
END
GO
IF OBJECT_ID('[dbo].[OrganizationUser_UpdateWithCollections]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[OrganizationUser_UpdateWithCollections]
END
GO
IF OBJECT_ID('[dbo].[Collection_CreateWithGroupsAndUsers]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Collection_CreateWithGroupsAndUsers]
END
GO
IF TYPE_ID('[dbo].[SelectionReadOnlyArray]') IS NOT NULL
BEGIN
DROP TYPE [dbo].[SelectionReadOnlyArray]
END
GO
CREATE TYPE [dbo].[SelectionReadOnlyArray] AS TABLE (
[Id] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] BIT NOT NULL,
[HidePasswords] BIT NOT NULL,
[Manage] BIT NOT NULL);
GO
--Add Manage Column
IF COL_LENGTH('[dbo].[CollectionUser]', 'Manage') IS NULL
BEGIN
ALTER TABLE [dbo].[CollectionUser] ADD [Manage] BIT NOT NULL CONSTRAINT D_CollectionUser_Manage DEFAULT (0);
END
GO
--Add Manage Column
IF COL_LENGTH('[dbo].[CollectionGroup]', 'Manage') IS NULL
BEGIN
ALTER TABLE [dbo].[CollectionGroup] ADD [Manage] BIT NOT NULL CONSTRAINT D_CollectionGroup_Manage DEFAULT (0);
END
GO
CREATE OR ALTER PROCEDURE [dbo].[CollectionUser_ReadByCollectionId]
@CollectionId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[OrganizationUserId] [Id],
[ReadOnly],
[HidePasswords],
[Manage]
FROM
[dbo].[CollectionUser]
WHERE
[CollectionId] = @CollectionId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[CollectionGroup_ReadByCollectionId]
@CollectionId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[GroupId] [Id],
[ReadOnly],
[HidePasswords],
[Manage]
FROM
[dbo].[CollectionGroup]
WHERE
[CollectionId] = @CollectionId
END
GO
CREATE PROCEDURE [dbo].[Group_CreateWithCollections]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name NVARCHAR(100),
@AccessAll BIT,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Collections AS [dbo].[SelectionReadOnlyArray] READONLY
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Group_Create] @Id, @OrganizationId, @Name, @AccessAll, @ExternalId, @CreationDate, @RevisionDate
;WITH [AvailableCollectionsCTE] AS(
SELECT
[Id]
FROM
[dbo].[Collection]
WHERE
[OrganizationId] = @OrganizationId
)
INSERT INTO [dbo].[CollectionGroup]
(
[CollectionId],
[GroupId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
[Id],
@Id,
[ReadOnly],
[HidePasswords],
[Manage]
FROM
@Collections
WHERE
[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE])
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END
GO
CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers]
@CollectionId UNIQUEIDENTIFIER,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS
BEGIN
SET NOCOUNT ON
DECLARE @OrgId UNIQUEIDENTIFIER = (
SELECT TOP 1
[OrganizationId]
FROM
[dbo].[Collection]
WHERE
[Id] = @CollectionId
)
-- Update
UPDATE
[Target]
SET
[Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
FROM
[dbo].[CollectionUser] [Target]
INNER JOIN
@Users [Source] ON [Source].[Id] = [Target].[OrganizationUserId]
WHERE
[Target].[CollectionId] = @CollectionId
AND (
[Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
)
-- Insert
INSERT INTO
[dbo].[CollectionUser]
SELECT
@CollectionId,
[Source].[Id],
[Source].[ReadOnly],
[Source].[HidePasswords],
[Source].[Manage]
FROM
@Users [Source]
INNER JOIN
[dbo].[OrganizationUser] OU ON [Source].[Id] = OU.[Id] AND OU.[OrganizationId] = @OrgId
WHERE
NOT EXISTS (
SELECT
1
FROM
[dbo].[CollectionUser]
WHERE
[CollectionId] = @CollectionId
AND [OrganizationUserId] = [Source].[Id]
)
-- Delete
DELETE
CU
FROM
[dbo].[CollectionUser] CU
WHERE
CU.[CollectionId] = @CollectionId
AND NOT EXISTS (
SELECT
1
FROM
@Users
WHERE
[Id] = CU.[OrganizationUserId]
)
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @CollectionId, @OrgId
END
GO
CREATE PROCEDURE [dbo].[Group_UpdateWithCollections]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name NVARCHAR(100),
@AccessAll BIT,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Collections AS [dbo].[SelectionReadOnlyArray] READONLY
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Group_Update] @Id, @OrganizationId, @Name, @AccessAll, @ExternalId, @CreationDate, @RevisionDate
;WITH [AvailableCollectionsCTE] AS(
SELECT
Id
FROM
[dbo].[Collection]
WHERE
OrganizationId = @OrganizationId
)
MERGE
[dbo].[CollectionGroup] AS [Target]
USING
@Collections AS [Source]
ON
[Target].[CollectionId] = [Source].[Id]
AND [Target].[GroupId] = @Id
WHEN NOT MATCHED BY TARGET
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE]) THEN
INSERT VALUES
(
[Source].[Id],
@Id,
[Source].[ReadOnly],
[Source].[HidePasswords],
[Source].[Manage]
)
WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE
AND [Target].[GroupId] = @Id THEN
DELETE
;
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END
GO
CREATE PROCEDURE [dbo].[Collection_UpdateWithGroupsAndUsers]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Groups AS [dbo].[SelectionReadOnlyArray] READONLY,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate
-- Groups
;WITH [AvailableGroupsCTE] AS(
SELECT
Id
FROM
[dbo].[Group]
WHERE
OrganizationId = @OrganizationId
)
MERGE
[dbo].[CollectionGroup] AS [Target]
USING
@Groups AS [Source]
ON
[Target].[CollectionId] = @Id
AND [Target].[GroupId] = [Source].[Id]
WHEN NOT MATCHED BY TARGET
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE]) THEN
INSERT VALUES
(
@Id,
[Source].[Id],
[Source].[ReadOnly],
[Source].[HidePasswords],
[Source].[Manage]
)
WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN
DELETE
;
-- Users
;WITH [AvailableGroupsCTE] AS(
SELECT
Id
FROM
[dbo].[OrganizationUser]
WHERE
OrganizationId = @OrganizationId
)
MERGE
[dbo].[CollectionUser] AS [Target]
USING
@Users AS [Source]
ON
[Target].[CollectionId] = @Id
AND [Target].[OrganizationUserId] = [Source].[Id]
WHEN NOT MATCHED BY TARGET
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE]) THEN
INSERT VALUES
(
@Id,
[Source].[Id],
[Source].[ReadOnly],
[Source].[HidePasswords],
[Source].[Manage]
)
WHEN MATCHED AND (
[Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
) THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN
DELETE
;
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
END
GO
CREATE PROCEDURE [dbo].[OrganizationUser_CreateWithCollections]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@Email NVARCHAR(256),
@Key VARCHAR(MAX),
@Status SMALLINT,
@Type TINYINT,
@AccessAll BIT,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Permissions NVARCHAR(MAX),
@ResetPasswordKey VARCHAR(MAX),
@Collections AS [dbo].[SelectionReadOnlyArray] READONLY,
@AccessSecretsManager BIT = 0
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[OrganizationUser_Create] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager
;WITH [AvailableCollectionsCTE] AS(
SELECT
[Id]
FROM
[dbo].[Collection]
WHERE
[OrganizationId] = @OrganizationId
)
INSERT INTO [dbo].[CollectionUser]
(
[CollectionId],
[OrganizationUserId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
[Id],
@Id,
[ReadOnly],
[HidePasswords],
[Manage]
FROM
@Collections
WHERE
[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE])
END
GO
CREATE PROCEDURE [dbo].[OrganizationUser_UpdateWithCollections]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@Email NVARCHAR(256),
@Key VARCHAR(MAX),
@Status SMALLINT,
@Type TINYINT,
@AccessAll BIT,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Permissions NVARCHAR(MAX),
@ResetPasswordKey VARCHAR(MAX),
@Collections AS [dbo].[SelectionReadOnlyArray] READONLY,
@AccessSecretsManager BIT = 0
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[OrganizationUser_Update] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager
-- Update
UPDATE
[Target]
SET
[Target].[ReadOnly] = [Source].[ReadOnly],
[Target].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
FROM
[dbo].[CollectionUser] AS [Target]
INNER JOIN
@Collections AS [Source] ON [Source].[Id] = [Target].[CollectionId]
WHERE
[Target].[OrganizationUserId] = @Id
AND (
[Target].[ReadOnly] != [Source].[ReadOnly]
OR [Target].[HidePasswords] != [Source].[HidePasswords]
OR [Target].[Manage] != [Source].[Manage]
)
-- Insert
INSERT INTO
[dbo].[CollectionUser]
SELECT
[Source].[Id],
@Id,
[Source].[ReadOnly],
[Source].[HidePasswords],
[Source].[Manage]
FROM
@Collections AS [Source]
INNER JOIN
[dbo].[Collection] C ON C.[Id] = [Source].[Id] AND C.[OrganizationId] = @OrganizationId
WHERE
NOT EXISTS (
SELECT
1
FROM
[dbo].[CollectionUser]
WHERE
[CollectionId] = [Source].[Id]
AND [OrganizationUserId] = @Id
)
-- Delete
DELETE
CU
FROM
[dbo].[CollectionUser] CU
WHERE
CU.[OrganizationUserId] = @Id
AND NOT EXISTS (
SELECT
1
FROM
@Collections
WHERE
[Id] = CU.[CollectionId]
)
END
GO
CREATE PROCEDURE [dbo].[Collection_CreateWithGroupsAndUsers]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Groups AS [dbo].[SelectionReadOnlyArray] READONLY,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate
-- Groups
;WITH [AvailableGroupsCTE] AS(
SELECT
[Id]
FROM
[dbo].[Group]
WHERE
[OrganizationId] = @OrganizationId
)
INSERT INTO [dbo].[CollectionGroup]
(
[CollectionId],
[GroupId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
@Id,
[Id],
[ReadOnly],
[HidePasswords],
[Manage]
FROM
@Groups
WHERE
[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE])
-- Users
;WITH [AvailableUsersCTE] AS(
SELECT
[Id]
FROM
[dbo].[OrganizationUser]
WHERE
[OrganizationId] = @OrganizationId
)
INSERT INTO [dbo].[CollectionUser]
(
[CollectionId],
[OrganizationUserId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
@Id,
[Id],
[ReadOnly],
[HidePasswords],
[Manage]
FROM
@Users
WHERE
[Id] IN (SELECT [Id] FROM [AvailableUsersCTE])
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[OrganizationUserUserDetails_ReadWithCollectionsById]
@Id UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
EXEC [OrganizationUserUserDetails_ReadById] @Id
SELECT
CU.[CollectionId] Id,
CU.[ReadOnly],
CU.[HidePasswords],
CU.[Manage]
FROM
[dbo].[OrganizationUser] OU
INNER JOIN
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = [OU].[Id]
WHERE
[OrganizationUserId] = @Id
END
GO
CREATE OR ALTER FUNCTION [dbo].[UserCollectionDetails](@UserId UNIQUEIDENTIFIER)
RETURNS TABLE
AS RETURN
SELECT
C.*,
CASE
WHEN
OU.[AccessAll] = 1
OR G.[AccessAll] = 1
OR COALESCE(CU.[ReadOnly], CG.[ReadOnly], 0) = 0
THEN 0
ELSE 1
END [ReadOnly],
CASE
WHEN
OU.[AccessAll] = 1
OR G.[AccessAll] = 1
OR COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0
THEN 0
ELSE 1
END [HidePasswords],
CASE
WHEN
OU.[AccessAll] = 1
OR G.[AccessAll] = 1
OR COALESCE(CU.[Manage], CG.[Manage], 0) = 0
THEN 0
ELSE 1
END [Manage]
FROM
[dbo].[CollectionView] C
INNER JOIN
[dbo].[OrganizationUser] OU ON C.[OrganizationId] = OU.[OrganizationId]
INNER JOIN
[dbo].[Organization] O ON O.[Id] = C.[OrganizationId]
LEFT JOIN
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = [OU].[Id]
LEFT JOIN
[dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id]
LEFT JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
LEFT JOIN
[dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId]
WHERE
OU.[UserId] = @UserId
AND OU.[Status] = 2 -- 2 = Confirmed
AND O.[Enabled] = 1
AND (
OU.[AccessAll] = 1
OR CU.[CollectionId] IS NOT NULL
OR G.[AccessAll] = 1
OR CG.[CollectionId] IS NOT NULL
)
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_ReadByIdUserId]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
Id,
OrganizationId,
[Name],
CreationDate,
RevisionDate,
ExternalId,
MIN([ReadOnly]) AS [ReadOnly],
MIN([HidePasswords]) AS [HidePasswords],
MIN([Manage]) AS [Manage]
FROM
[dbo].[UserCollectionDetails](@UserId)
WHERE
[Id] = @Id
GROUP BY
Id,
OrganizationId,
[Name],
CreationDate,
RevisionDate,
ExternalId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
Id,
OrganizationId,
[Name],
CreationDate,
RevisionDate,
ExternalId,
MIN([ReadOnly]) AS [ReadOnly],
MIN([HidePasswords]) AS [HidePasswords],
MIN([Manage]) AS [Manage]
FROM
[dbo].[UserCollectionDetails](@UserId)
GROUP BY
Id,
OrganizationId,
[Name],
CreationDate,
RevisionDate,
ExternalId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_ReadWithGroupsAndUsersByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DECLARE @TempUserCollections TABLE(
Id UNIQUEIDENTIFIER,
OrganizationId UNIQUEIDENTIFIER,
Name VARCHAR(MAX),
CreationDate DATETIME2(7),
RevisionDate DATETIME2(7),
ExternalId NVARCHAR(300),
ReadOnly BIT,
HidePasswords BIT,
Manage BIT)
INSERT INTO @TempUserCollections EXEC [dbo].[Collection_ReadByUserId] @UserId
SELECT
*
FROM
@TempUserCollections C
SELECT
CG.*
FROM
[dbo].[CollectionGroup] CG
INNER JOIN
@TempUserCollections C ON C.[Id] = CG.[CollectionId]
SELECT
CU.*
FROM
[dbo].[CollectionUser] CU
INNER JOIN
@TempUserCollections C ON C.[Id] = CU.[CollectionId]
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Group_ReadWithCollectionsById]
@Id UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Group_ReadById] @Id
SELECT
[CollectionId] [Id],
[ReadOnly],
[HidePasswords],
[Manage]
FROM
[dbo].[CollectionGroup]
WHERE
[GroupId] = @Id
END
GO

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class _20230711_00_CollectionManagePermissionsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionUsers",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionGroups",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionUsers");
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionGroups");
}
}

View File

@ -284,6 +284,9 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("tinyint(1)"); .HasColumnType("tinyint(1)");
b.Property<bool>("Manage")
.HasColumnType("tinyint(1)");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("tinyint(1)"); .HasColumnType("tinyint(1)");
@ -305,6 +308,9 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("tinyint(1)"); .HasColumnType("tinyint(1)");
b.Property<bool>("Manage")
.HasColumnType("tinyint(1)");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("tinyint(1)"); .HasColumnType("tinyint(1)");

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class _20230711_00_CollectionManagePermissionsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionUsers",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionGroups",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionUsers");
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionGroups");
}
}

View File

@ -293,6 +293,9 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<bool>("Manage")
.HasColumnType("boolean");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("boolean"); .HasColumnType("boolean");
@ -314,6 +317,9 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<bool>("Manage")
.HasColumnType("boolean");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("boolean"); .HasColumnType("boolean");

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class _20230711_00_CollectionManagePermissionsql : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionUsers",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Manage",
table: "CollectionGroups",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionUsers");
migrationBuilder.DropColumn(
name: "Manage",
table: "CollectionGroups");
}
}

View File

@ -282,6 +282,9 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<bool>("Manage")
.HasColumnType("INTEGER");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -303,6 +306,9 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<bool>("HidePasswords") b.Property<bool>("HidePasswords")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<bool>("Manage")
.HasColumnType("INTEGER");
b.Property<bool>("ReadOnly") b.Property<bool>("ReadOnly")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");