1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 16:12:49 -05:00

Merge branch 'main' into auth/pm-20348/extension-auth-approvals-add-auth-request-endpoint

This commit is contained in:
Ike
2025-06-12 18:00:06 -04:00
committed by GitHub
594 changed files with 38113 additions and 5486 deletions

View File

@ -129,7 +129,7 @@ BEGIN
END
-- Check if the attachment exists before trying to remove it
IF JSON_PATH_EXISTS(@CurrentAttachments, @AttachmentIdPath) = 0
IF JSON_QUERY(@CurrentAttachments, @AttachmentIdPath) IS NULL
BEGIN
-- Attachment doesn't exist, nothing to do
RETURN;

View File

@ -0,0 +1,139 @@
-- Add `Emails` field that stores a comma-separated list of email addresses for
-- email/OTP authentication to table and write methods. The read methods
-- don't need to be updated because they all use `*`.
IF NOT EXISTS(
SELECT *
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID(N'[dbo].[Send]')
AND [name] = 'Emails')
BEGIN
ALTER TABLE [dbo].[Send] ADD [Emails] NVARCHAR(1024) NULL;
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Send_Update]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Type TINYINT,
@Data VARCHAR(MAX),
@Key VARCHAR(MAX),
@Password NVARCHAR(300),
@MaxAccessCount INT,
@AccessCount INT,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ExpirationDate DATETIME2(7),
@DeletionDate DATETIME2(7),
@Disabled BIT,
@HideEmail BIT,
@CipherId UNIQUEIDENTIFIER = NULL,
@Emails NVARCHAR(1024) = NULL
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[Send]
SET
[UserId] = @UserId,
[OrganizationId] = @OrganizationId,
[Type] = @Type,
[Data] = @Data,
[Key] = @Key,
[Password] = @Password,
[MaxAccessCount] = @MaxAccessCount,
[AccessCount] = @AccessCount,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[ExpirationDate] = @ExpirationDate,
[DeletionDate] = @DeletionDate,
[Disabled] = @Disabled,
[HideEmail] = @HideEmail,
[CipherId] = @CipherId,
[Emails] = @Emails
WHERE
[Id] = @Id
IF @UserId IS NOT NULL
BEGIN
EXEC [dbo].[User_BumpAccountRevisionDate] @UserId
END
-- TODO: OrganizationId bump?
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Send_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Type TINYINT,
@Data VARCHAR(MAX),
@Key VARCHAR(MAX),
@Password NVARCHAR(300),
@MaxAccessCount INT,
@AccessCount INT,
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@ExpirationDate DATETIME2(7),
@DeletionDate DATETIME2(7),
@Disabled BIT,
@HideEmail BIT,
@CipherId UNIQUEIDENTIFIER = NULL,
@Emails NVARCHAR(1024) = NULL
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Send]
(
[Id],
[UserId],
[OrganizationId],
[Type],
[Data],
[Key],
[Password],
[MaxAccessCount],
[AccessCount],
[CreationDate],
[RevisionDate],
[ExpirationDate],
[DeletionDate],
[Disabled],
[HideEmail],
[CipherId],
[Emails]
)
VALUES
(
@Id,
@UserId,
@OrganizationId,
@Type,
@Data,
@Key,
@Password,
@MaxAccessCount,
@AccessCount,
@CreationDate,
@RevisionDate,
@ExpirationDate,
@DeletionDate,
@Disabled,
@HideEmail,
@CipherId,
@Emails
)
IF @UserId IS NOT NULL
BEGIN
IF @Type = 1 --File
BEGIN
EXEC [dbo].[User_UpdateStorage] @UserId
END
EXEC [dbo].[User_BumpAccountRevisionDate] @UserId
END
-- TODO: OrganizationId bump?
END
GO

View File

@ -0,0 +1,38 @@
CREATE OR ALTER PROCEDURE [dbo].[Organization_ReadOccupiedSeatCountByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
(
-- Count organization users
SELECT COUNT(1)
FROM [dbo].[OrganizationUserView]
WHERE OrganizationId = @OrganizationId
AND Status >= 0 --Invited
) as Users,
(
-- Count admin-initiated sponsorships towards the seat count
-- Introduced in https://bitwarden.atlassian.net/browse/PM-17772
SELECT COUNT(1)
FROM [dbo].[OrganizationSponsorship]
WHERE SponsoringOrganizationId = @OrganizationId
AND IsAdminInitiated = 1
AND (
-- Not marked for deletion - always count
(ToDelete = 0)
OR
-- Marked for deletion but has a valid until date in the future (RevokeWhenExpired status)
(ToDelete = 1 AND ValidUntil IS NOT NULL AND ValidUntil > GETUTCDATE())
)
AND (
-- SENT status: When SponsoredOrganizationId is null
SponsoredOrganizationId IS NULL
OR
-- ACCEPTED status: When SponsoredOrganizationId is not null and ValidUntil is null or in the future
(SponsoredOrganizationId IS NOT NULL AND (ValidUntil IS NULL OR ValidUntil > GETUTCDATE()))
)
) as Sponsored
END
GO

View File

@ -0,0 +1,67 @@
IF EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'SsoUser'
AND COLUMN_NAME = 'ExternalId'
AND DATA_TYPE = 'nvarchar'
AND CHARACTER_MAXIMUM_LENGTH < 300
)
BEGIN
-- Update table ExternalId column size
ALTER TABLE [dbo].[SsoUser]
ALTER COLUMN [ExternalId] NVARCHAR(300) NOT NULL
END
GO
-- Update stored procedures to handle the new ExternalId column size
CREATE OR ALTER PROCEDURE [dbo].[SsoUser_Create]
@Id BIGINT OUTPUT,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[SsoUser]
(
[UserId],
[OrganizationId],
[ExternalId],
[CreationDate]
)
VALUES
(
@UserId,
@OrganizationId,
@ExternalId,
@CreationDate
)
SET @Id = SCOPE_IDENTITY();
END
GO
CREATE OR ALTER PROCEDURE [dbo].[SsoUser_Update]
@Id BIGINT OUTPUT,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7)
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[SsoUser]
SET
[UserId] = @UserId,
[OrganizationId] = @OrganizationId,
[ExternalId] = @ExternalId,
[CreationDate] = @CreationDate
WHERE
[Id] = @Id
END
GO

View File

@ -0,0 +1,78 @@
CREATE OR ALTER PROCEDURE [dbo].[Cipher_DeleteAttachment]
@Id UNIQUEIDENTIFIER,
@AttachmentId VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON
DECLARE @AttachmentIdKey VARCHAR(50) = CONCAT('"', @AttachmentId, '"')
DECLARE @AttachmentIdPath VARCHAR(50) = CONCAT('$.', @AttachmentIdKey)
DECLARE @UserId UNIQUEIDENTIFIER
DECLARE @OrganizationId UNIQUEIDENTIFIER
DECLARE @CurrentAttachments NVARCHAR(MAX)
DECLARE @NewAttachments NVARCHAR(MAX)
-- Get current cipher data
SELECT
@UserId = [UserId],
@OrganizationId = [OrganizationId],
@CurrentAttachments = [Attachments]
FROM
[dbo].[Cipher]
WHERE [Id] = @Id
-- If there are no attachments, nothing to do
IF @CurrentAttachments IS NULL
BEGIN
RETURN;
END
-- Validate the initial JSON
IF ISJSON(@CurrentAttachments) = 0
BEGIN
THROW 50000, 'Current initial attachments data is not valid JSON', 1;
RETURN;
END
-- Check if the attachment exists before trying to remove it
IF JSON_QUERY(@CurrentAttachments, @AttachmentIdPath) IS NULL
BEGIN
-- Attachment doesn't exist, nothing to do
RETURN;
END
-- Create the new attachments JSON with the specified attachment removed
SET @NewAttachments = JSON_MODIFY(@CurrentAttachments, @AttachmentIdPath, NULL)
-- Validate the resulting JSON
IF ISJSON(@NewAttachments) = 0
BEGIN
THROW 50000, 'Failed to create valid JSON when removing attachment', 1;
RETURN;
END
-- Check if we've removed all attachments and have an empty object
IF @NewAttachments = '{}'
BEGIN
-- If we have an empty JSON object, set to NULL instead
SET @NewAttachments = NULL;
END
-- Update with validated JSON
UPDATE [dbo].[Cipher]
SET [Attachments] = @NewAttachments
WHERE [Id] = @Id
IF @OrganizationId IS NOT NULL
BEGIN
EXEC [dbo].[Organization_UpdateStorage] @OrganizationId
EXEC [dbo].[User_BumpAccountRevisionDateByCipherId] @Id, @OrganizationId
END
ELSE IF @UserId IS NOT NULL
BEGIN
EXEC [dbo].[User_UpdateStorage] @UserId
EXEC [dbo].[User_BumpAccountRevisionDate] @UserId
END
END
GO

View File

@ -0,0 +1,55 @@
IF NOT EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Collection'
AND COLUMN_NAME = 'DefaultUserCollectionEmail'
)
BEGIN
ALTER TABLE [dbo].[Collection]
ADD [DefaultUserCollectionEmail] NVARCHAR(256) NULL
END
GO
IF NOT EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Collection'
AND COLUMN_NAME = 'Type'
)
BEGIN
ALTER TABLE [dbo].[Collection]
ADD [Type] TINYINT NOT NULL DEFAULT (0)
END
GO
IF OBJECT_ID('[dbo].[CollectionView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[CollectionView]';
END
GO
IF OBJECT_ID('[dbo].[Collection_ReadById]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[Collection_ReadById]';
END
GO
IF OBJECT_ID('[dbo].[Collection_ReadByIds]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[Collection_ReadByIds]';
END
GO
IF OBJECT_ID('[dbo].[Collection_ReadByOrganizationId]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[Collection_ReadByOrganizationId]';
END
GO
IF OBJECT_ID('[dbo].[UserCollectionDetails]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[UserCollectionDetails]';
END
GO

View File

@ -0,0 +1,456 @@
CREATE OR ALTER PROCEDURE [dbo].[Collection_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@DefaultUserCollectionEmail NVARCHAR(256) = NULL,
@Type TINYINT = 0
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Collection]
(
[Id],
[OrganizationId],
[Name],
[ExternalId],
[CreationDate],
[RevisionDate],
[DefaultUserCollectionEmail],
[Type]
)
VALUES
(
@Id,
@OrganizationId,
@Name,
@ExternalId,
@CreationDate,
@RevisionDate,
@DefaultUserCollectionEmail,
@Type
)
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
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],
MAX([Manage]) AS [Manage],
[DefaultUserCollectionEmail],
[Type]
FROM
[dbo].[UserCollectionDetails](@UserId)
GROUP BY
[Id],
[OrganizationId],
[Name],
[CreationDate],
[RevisionDate],
[ExternalId],
[DefaultUserCollectionEmail],
[Type]
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_Update]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@DefaultUserCollectionEmail NVARCHAR(256) = NULL,
@Type TINYINT = 0
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[Collection]
SET
[OrganizationId] = @OrganizationId,
[Name] = @Name,
[ExternalId] = @ExternalId,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[DefaultUserCollectionEmail] = @DefaultUserCollectionEmail,
[Type] = @Type
WHERE
[Id] = @Id
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_UpdateWithGroupsAndUsers]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Groups AS [dbo].[CollectionAccessSelectionType] READONLY,
@Users AS [dbo].[CollectionAccessSelectionType] READONLY,
@DefaultUserCollectionEmail NVARCHAR(256) = NULL,
@Type TINYINT = 0
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate, @DefaultUserCollectionEmail, @Type
-- Groups
-- Delete groups that are no longer in source
DELETE cg
FROM [dbo].[CollectionGroup] cg
LEFT JOIN @Groups g ON cg.GroupId = g.Id
WHERE cg.CollectionId = @Id
AND g.Id IS NULL;
-- Update existing groups
UPDATE cg
SET cg.ReadOnly = g.ReadOnly,
cg.HidePasswords = g.HidePasswords,
cg.Manage = g.Manage
FROM [dbo].[CollectionGroup] cg
INNER JOIN @Groups g ON cg.GroupId = g.Id
WHERE cg.CollectionId = @Id
AND (cg.ReadOnly != g.ReadOnly
OR cg.HidePasswords != g.HidePasswords
OR cg.Manage != g.Manage);
-- Insert new groups
INSERT INTO [dbo].[CollectionGroup]
(
[CollectionId],
[GroupId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
@Id,
g.Id,
g.ReadOnly,
g.HidePasswords,
g.Manage
FROM @Groups g
INNER JOIN [dbo].[Group] grp ON grp.Id = g.Id
LEFT JOIN [dbo].[CollectionGroup] cg
ON cg.CollectionId = @Id AND cg.GroupId = g.Id
WHERE grp.OrganizationId = @OrganizationId
AND cg.CollectionId IS NULL;
-- Users
-- Delete users that are no longer in source
DELETE cu
FROM [dbo].[CollectionUser] cu
LEFT JOIN @Users u ON cu.OrganizationUserId = u.Id
WHERE cu.CollectionId = @Id
AND u.Id IS NULL;
-- Update existing users
UPDATE cu
SET cu.ReadOnly = u.ReadOnly,
cu.HidePasswords = u.HidePasswords,
cu.Manage = u.Manage
FROM [dbo].[CollectionUser] cu
INNER JOIN @Users u ON cu.OrganizationUserId = u.Id
WHERE cu.CollectionId = @Id
AND (cu.ReadOnly != u.ReadOnly
OR cu.HidePasswords != u.HidePasswords
OR cu.Manage != u.Manage);
-- Insert new users
INSERT INTO [dbo].[CollectionUser]
(
[CollectionId],
[OrganizationUserId],
[ReadOnly],
[HidePasswords],
[Manage]
)
SELECT
@Id,
u.Id,
u.ReadOnly,
u.HidePasswords,
u.Manage
FROM @Users u
INNER JOIN [dbo].[OrganizationUser] ou ON ou.Id = u.Id
LEFT JOIN [dbo].[CollectionUser] cu
ON cu.CollectionId = @Id AND cu.OrganizationUserId = u.Id
WHERE ou.OrganizationId = @OrganizationId
AND cu.CollectionId IS NULL;
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_ReadByOrganizationIdWithPermissions]
@OrganizationId UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@IncludeAccessRelationships BIT
AS
BEGIN
SET NOCOUNT ON
SELECT
C.*,
MIN(CASE
WHEN
COALESCE(CU.[ReadOnly], CG.[ReadOnly], 0) = 0
THEN 0
ELSE 1
END) AS [ReadOnly],
MIN(CASE
WHEN
COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0
THEN 0
ELSE 1
END) AS [HidePasswords],
MAX(CASE
WHEN
COALESCE(CU.[Manage], CG.[Manage], 0) = 0
THEN 0
ELSE 1
END) AS [Manage],
MAX(CASE
WHEN
CU.[CollectionId] IS NULL AND CG.[CollectionId] IS NULL
THEN 0
ELSE 1
END) AS [Assigned],
CASE
WHEN
-- No user or group has manage rights
NOT EXISTS(
SELECT 1
FROM [dbo].[CollectionUser] CU2
JOIN [dbo].[OrganizationUser] OU2 ON CU2.[OrganizationUserId] = OU2.[Id]
WHERE
CU2.[CollectionId] = C.[Id] AND
CU2.[Manage] = 1
)
AND NOT EXISTS (
SELECT 1
FROM [dbo].[CollectionGroup] CG2
WHERE
CG2.[CollectionId] = C.[Id] AND
CG2.[Manage] = 1
)
THEN 1
ELSE 0
END AS [Unmanaged]
FROM
[dbo].[CollectionView] C
LEFT JOIN
[dbo].[OrganizationUser] OU ON C.[OrganizationId] = OU.[OrganizationId] AND OU.[UserId] = @UserId
LEFT JOIN
[dbo].[CollectionUser] CU ON CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = [OU].[Id]
LEFT JOIN
[dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id]
LEFT JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
LEFT JOIN
[dbo].[CollectionGroup] CG ON CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId]
WHERE
C.[OrganizationId] = @OrganizationId
GROUP BY
C.[Id],
C.[OrganizationId],
C.[Name],
C.[CreationDate],
C.[RevisionDate],
C.[ExternalId],
C.[DefaultUserCollectionEmail],
C.[Type]
IF (@IncludeAccessRelationships = 1)
BEGIN
EXEC [dbo].[CollectionGroup_ReadByOrganizationId] @OrganizationId
EXEC [dbo].[CollectionUser_ReadByOrganizationId] @OrganizationId
END
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Collection_CreateWithGroupsAndUsers]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Name VARCHAR(MAX),
@ExternalId NVARCHAR(300),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@Groups AS [dbo].[CollectionAccessSelectionType] READONLY,
@Users AS [dbo].[CollectionAccessSelectionType] READONLY,
@DefaultUserCollectionEmail NVARCHAR(256) = NULL,
@Type TINYINT = 0
AS
BEGIN
SET NOCOUNT ON
EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate, @DefaultUserCollectionEmail, @Type
-- 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].[Collection_ReadByIdWithPermissions]
@CollectionId UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@IncludeAccessRelationships BIT
AS
BEGIN
SET NOCOUNT ON
SELECT
C.*,
MIN(CASE
WHEN
COALESCE(CU.[ReadOnly], CG.[ReadOnly], 0) = 0
THEN 0
ELSE 1
END) AS [ReadOnly],
MIN (CASE
WHEN
COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0
THEN 0
ELSE 1
END) AS [HidePasswords],
MAX(CASE
WHEN
COALESCE(CU.[Manage], CG.[Manage], 0) = 0
THEN 0
ELSE 1
END) AS [Manage],
MAX(CASE
WHEN
CU.[CollectionId] IS NULL AND CG.[CollectionId] IS NULL
THEN 0
ELSE 1
END) AS [Assigned],
CASE
WHEN
-- No user or group has manage rights
NOT EXISTS(
SELECT 1
FROM [dbo].[CollectionUser] CU2
JOIN [dbo].[OrganizationUser] OU2 ON CU2.[OrganizationUserId] = OU2.[Id]
WHERE
CU2.[CollectionId] = C.[Id] AND
CU2.[Manage] = 1
)
AND NOT EXISTS (
SELECT 1
FROM [dbo].[CollectionGroup] CG2
WHERE
CG2.[CollectionId] = C.[Id] AND
CG2.[Manage] = 1
)
THEN 1
ELSE 0
END AS [Unmanaged]
FROM
[dbo].[CollectionView] C
LEFT JOIN
[dbo].[OrganizationUser] OU ON C.[OrganizationId] = OU.[OrganizationId] AND OU.[UserId] = @UserId
LEFT JOIN
[dbo].[CollectionUser] CU ON CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = [OU].[Id]
LEFT JOIN
[dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id]
LEFT JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
LEFT JOIN
[dbo].[CollectionGroup] CG ON CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId]
WHERE
C.[Id] = @CollectionId
GROUP BY
C.[Id],
C.[OrganizationId],
C.[Name],
C.[CreationDate],
C.[RevisionDate],
C.[ExternalId],
C.[DefaultUserCollectionEmail],
C.[Type]
IF (@IncludeAccessRelationships = 1)
BEGIN
EXEC [dbo].[CollectionGroup_ReadByCollectionId] @CollectionId
EXEC [dbo].[CollectionUser_ReadByCollectionId] @CollectionId
END
END