1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 16:12:49 -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 bool ReadOnly { get; set; }
public bool HidePasswords { get; set; }
public bool Manage { get; set; }
public CollectionAccessSelection ToSelectionReadOnly()
{
@ -17,6 +18,7 @@ public class SelectionReadOnlyRequestModel
Id = new Guid(Id),
ReadOnly = ReadOnly,
HidePasswords = HidePasswords,
Manage = Manage,
};
}
}

View File

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

View File

@ -14,9 +14,11 @@ public class SelectionReadOnlyResponseModel
Id = selection.Id;
ReadOnly = selection.ReadOnly;
HidePasswords = selection.HidePasswords;
Manage = selection.Manage;
}
public Guid Id { get; set; }
public bool ReadOnly { 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 bool ReadOnly { 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 bool ReadOnly { 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 bool ReadOnly { 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 HidePasswords { get; set; }
public bool Manage { get; set; }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
OrganizationUserId = organizationUser.Id,
ReadOnly = y.ReadOnly,
HidePasswords = y.HidePasswords,
Manage = y.Manage
});
await dbContext.CollectionUsers.AddRangeAsync(collectionUsers);
await dbContext.SaveChangesAsync();
@ -141,6 +142,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
Id = cu.CollectionId,
ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords,
Manage = cu.Manage,
});
return new Tuple<Core.Entities.OrganizationUser, ICollection<CollectionAccessSelection>>(
organizationUser, collections.ToList());
@ -235,6 +237,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
Id = cu.CollectionId,
ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords,
Manage = cu.Manage
}).ToListAsync();
return new Tuple<OrganizationUserUserDetails, ICollection<CollectionAccessSelection>>(organizationUserUserDetails, collections);
}
@ -360,7 +363,8 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
{
Id = cu.CollectionId,
ReadOnly = cu.ReadOnly,
HidePasswords = cu.HidePasswords
HidePasswords = cu.HidePasswords,
Manage = cu.Manage,
}).ToList() ?? new List<CollectionAccessSelection>();
}
}
@ -440,6 +444,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
OrganizationUserId = obj.Id,
HidePasswords = requestedCollection.HidePasswords,
ReadOnly = requestedCollection.ReadOnly,
Manage = requestedCollection.Manage
});
continue;
}
@ -447,6 +452,7 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
// It already exists, update it
existingCollectionUser.HidePasswords = requestedCollection.HidePasswords;
existingCollectionUser.ReadOnly = requestedCollection.ReadOnly;
existingCollectionUser.Manage = requestedCollection.Manage;
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,
HidePasswords = x.ou.AccessAll || x.g.AccessAll ||
!((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
THEN 0
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
[dbo].[CollectionView] C
INNER JOIN

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,14 +36,17 @@ BEGIN
@Id,
[Source].[Id],
[Source].[ReadOnly],
[Source].[HidePasswords]
[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].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN
DELETE
@ -72,18 +75,21 @@ BEGIN
@Id,
[Source].[Id],
[Source].[ReadOnly],
[Source].[HidePasswords]
[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].[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
END

View File

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

View File

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

View File

@ -35,18 +35,21 @@ BEGIN
[Source].[Id],
@Id,
[Source].[ReadOnly],
[Source].[HidePasswords]
[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].[HidePasswords] = [Source].[HidePasswords],
[Target].[Manage] = [Source].[Manage]
WHEN NOT MATCHED BY SOURCE
AND [Target].[GroupId] = @Id THEN
DELETE
;
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
END
END

View File

@ -9,11 +9,12 @@ BEGIN
SELECT
CU.[CollectionId] Id,
CU.[ReadOnly],
CU.[HidePasswords]
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
END

View File

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

View File

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

View File

@ -3,6 +3,7 @@
[GroupId] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] 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 [FK_CollectionGroup_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]),
CONSTRAINT [FK_CollectionGroup_Group] FOREIGN KEY ([GroupId]) REFERENCES [dbo].[Group] ([Id]) ON DELETE CASCADE

View File

@ -3,6 +3,7 @@
[OrganizationUserId] UNIQUEIDENTIFIER NOT NULL,
[ReadOnly] 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 [FK_CollectionUser_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_CollectionUser_OrganizationUser] FOREIGN KEY ([OrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id])

View File

@ -1,5 +1,6 @@
CREATE TYPE [dbo].[SelectionReadOnlyArray] AS TABLE (
[Id] UNIQUEIDENTIFIER 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,
HidePasswords = 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")
.HasColumnType("tinyint(1)");
b.Property<bool>("Manage")
.HasColumnType("tinyint(1)");
b.Property<bool>("ReadOnly")
.HasColumnType("tinyint(1)");
@ -305,6 +308,9 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<bool>("HidePasswords")
.HasColumnType("tinyint(1)");
b.Property<bool>("Manage")
.HasColumnType("tinyint(1)");
b.Property<bool>("ReadOnly")
.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")
.HasColumnType("boolean");
b.Property<bool>("Manage")
.HasColumnType("boolean");
b.Property<bool>("ReadOnly")
.HasColumnType("boolean");
@ -314,6 +317,9 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<bool>("HidePasswords")
.HasColumnType("boolean");
b.Property<bool>("Manage")
.HasColumnType("boolean");
b.Property<bool>("ReadOnly")
.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")
.HasColumnType("INTEGER");
b.Property<bool>("Manage")
.HasColumnType("INTEGER");
b.Property<bool>("ReadOnly")
.HasColumnType("INTEGER");
@ -303,6 +306,9 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<bool>("HidePasswords")
.HasColumnType("INTEGER");
b.Property<bool>("Manage")
.HasColumnType("INTEGER");
b.Property<bool>("ReadOnly")
.HasColumnType("INTEGER");