diff --git a/src/Api/Controllers/CiphersController.cs b/src/Api/Controllers/CiphersController.cs index 35411fca4..3ec2cbb89 100644 --- a/src/Api/Controllers/CiphersController.cs +++ b/src/Api/Controllers/CiphersController.cs @@ -12,7 +12,6 @@ using Bit.Api.Utilities; using Bit.Core.Utilities; using Core.Models.Data; using System.Collections.Generic; -using Microsoft.AspNetCore.Identity; using Bit.Core.Models.Table; namespace Bit.Api.Controllers @@ -87,22 +86,13 @@ namespace Bit.Api.Controllers } [HttpGet("")] - public async Task> Get([FromQuery]Core.Enums.CipherType? type = null) + public async Task> Get() { var userId = _userService.GetProperUserId(User).Value; - - IEnumerable ciphers; - if(type.HasValue) - { - ciphers = await _cipherRepository.GetManyByTypeAndUserIdAsync(type.Value, userId); - } - else - { - ciphers = await _cipherRepository.GetManyByUserIdAsync(userId); - } - + var hasOrgs = _currentContext.Organizations.Any(); + var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId, hasOrgs); Dictionary> collectionCiphersGroupDict = null; - if(_currentContext.Organizations.Any()) + if(hasOrgs) { var collectionCiphers = await _collectionCipherRepository.GetManyByUserIdAsync(userId); collectionCiphersGroupDict = collectionCiphers.GroupBy(c => c.CipherId).ToDictionary(s => s.Key); @@ -184,24 +174,6 @@ namespace Bit.Api.Controllers return response; } - [Obsolete] - [HttpGet("details")] - public async Task> GetCollections() - { - var userId = _userService.GetProperUserId(User).Value; - var ciphers = await _cipherRepository.GetManyByUserIdHasCollectionsAsync(userId); - - Dictionary> collectionCiphersGroupDict = null; - if(_currentContext.Organizations.Any()) - { - var collectionCiphers = await _collectionCipherRepository.GetManyByUserIdAsync(userId); - collectionCiphersGroupDict = collectionCiphers.GroupBy(c => c.CipherId).ToDictionary(s => s.Key); - } - - var responses = ciphers.Select(c => new CipherDetailsResponseModel(c, _globalSettings, collectionCiphersGroupDict)); - return new ListResponseModel(responses); - } - [HttpGet("organization-details")] public async Task> GetOrganizationCollections(string organizationId) { diff --git a/src/Api/Controllers/SyncController.cs b/src/Api/Controllers/SyncController.cs index 0adec41a4..b043d5e55 100644 --- a/src/Api/Controllers/SyncController.cs +++ b/src/Api/Controllers/SyncController.cs @@ -55,12 +55,13 @@ namespace Bit.Api.Controllers var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id, OrganizationUserStatusType.Confirmed); + var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled); var folders = await _folderRepository.GetManyByUserIdAsync(user.Id); - var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id); + var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, hasEnabledOrgs); IEnumerable collections = null; IDictionary> collectionCiphersGroupDict = null; - if(organizationUserDetails.Any(o => o.Enabled)) + if(hasEnabledOrgs) { collections = await _collectionRepository.GetManyByUserIdAsync(user.Id, false); var collectionCiphers = await _collectionCipherRepository.GetManyByUserIdAsync(user.Id); diff --git a/src/Core/Repositories/ICipherRepository.cs b/src/Core/Repositories/ICipherRepository.cs index 4b204f072..c6843e92b 100644 --- a/src/Core/Repositories/ICipherRepository.cs +++ b/src/Core/Repositories/ICipherRepository.cs @@ -12,10 +12,8 @@ namespace Bit.Core.Repositories Task GetByIdAsync(Guid id, Guid userId); Task GetDetailsByIdAsync(Guid id); Task GetCanEditByIdAsync(Guid userId, Guid cipherId); - Task> GetManyByUserIdAsync(Guid userId); - Task> GetManyByUserIdHasCollectionsAsync(Guid userId); + Task> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true); Task> GetManyByOrganizationIdAsync(Guid organizationId); - Task> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId); Task CreateAsync(CipherDetails cipher); Task ReplaceAsync(CipherDetails cipher); Task UpsertAsync(CipherDetails cipher); diff --git a/src/Core/Repositories/SqlServer/CipherRepository.cs b/src/Core/Repositories/SqlServer/CipherRepository.cs index c7afacfa5..dcf207250 100644 --- a/src/Core/Repositories/SqlServer/CipherRepository.cs +++ b/src/Core/Repositories/SqlServer/CipherRepository.cs @@ -62,33 +62,27 @@ namespace Bit.Core.Repositories.SqlServer } } - public async Task> GetManyByUserIdAsync(Guid userId) + public async Task> GetManyByUserIdAsync(Guid userId, bool withOrganizations = true) { - using(var connection = new SqlConnection(ConnectionString)) + string sprocName = null; + // Always "with organizations" for now. Future TODO is to possibly move to another, simpler sproc when no + // orgs are expected. + if(true || withOrganizations) { - var results = await connection.QueryAsync( - $"[{Schema}].[CipherDetails_ReadByUserId]", - new { UserId = userId }, - commandType: CommandType.StoredProcedure); - - // Return distinct Id results. If at least one of the grouped results allows edit, that we return it. - return results - .GroupBy(c => c.Id) - .Select(g => g.OrderByDescending(og => og.Edit).First()) - .ToList(); + sprocName = $"[{Schema}].[CipherDetails_ReadByUserId]"; + } + else + { + sprocName = $"[{Schema}].[CipherDetails_ReadWithoutOrganizationsByUserId]"; } - } - public async Task> GetManyByUserIdHasCollectionsAsync(Guid userId) - { using(var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( - $"[{Schema}].[CipherDetails_ReadByUserIdHasCollection]", + sprocName, new { UserId = userId }, commandType: CommandType.StoredProcedure); - // Return distinct Id results. If at least one of the grouped results allows edit, that we return it. return results .GroupBy(c => c.Id) .Select(g => g.OrderByDescending(og => og.Edit).First()) @@ -109,27 +103,6 @@ namespace Bit.Core.Repositories.SqlServer } } - public async Task> GetManyByTypeAndUserIdAsync(Enums.CipherType type, Guid userId) - { - using(var connection = new SqlConnection(ConnectionString)) - { - var results = await connection.QueryAsync( - $"[{Schema}].[CipherDetails_ReadByTypeUserId]", - new - { - Type = type, - UserId = userId - }, - commandType: CommandType.StoredProcedure); - - // Return distinct Id results. If at least one of the grouped results allows edit, that we return it. - return results - .GroupBy(c => c.Id) - .Select(g => g.OrderByDescending(og => og.Edit).First()) - .ToList(); - } - } - public async Task CreateAsync(CipherDetails cipher) { cipher.SetNewId(); diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 2ebb81a63..c30cd482b 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -181,9 +181,7 @@ - - @@ -226,5 +224,6 @@ + \ No newline at end of file diff --git a/src/Sql/dbo/Functions/CipherDetails.sql b/src/Sql/dbo/Functions/CipherDetails.sql index af819c5ea..f8e14282e 100644 --- a/src/Sql/dbo/Functions/CipherDetails.sql +++ b/src/Sql/dbo/Functions/CipherDetails.sql @@ -10,18 +10,20 @@ SELECT C.[Attachments], C.[CreationDate], C.[RevisionDate], - CASE WHEN - @UserId IS NULL - OR C.[Favorites] IS NULL - OR JSON_VALUE(C.[Favorites], CONCAT('$."', @UserId, '"')) IS NULL - THEN 0 - ELSE 1 + CASE + WHEN + @UserId IS NULL + OR C.[Favorites] IS NULL + OR JSON_VALUE(C.[Favorites], CONCAT('$."', @UserId, '"')) IS NULL + THEN 0 + ELSE 1 END [Favorite], - CASE WHEN - @UserId IS NULL - OR C.[Folders] IS NULL - THEN NULL - ELSE TRY_CONVERT(UNIQUEIDENTIFIER, JSON_VALUE(C.[Folders], CONCAT('$."', @UserId, '"'))) + CASE + WHEN + @UserId IS NULL + OR C.[Folders] IS NULL + THEN NULL + ELSE TRY_CONVERT(UNIQUEIDENTIFIER, JSON_VALUE(C.[Folders], CONCAT('$."', @UserId, '"'))) END [FolderId] FROM [dbo].[Cipher] C \ No newline at end of file diff --git a/src/Sql/dbo/Functions/UserCipherDetails.sql b/src/Sql/dbo/Functions/UserCipherDetails.sql index 1cf038e15..69ff05310 100644 --- a/src/Sql/dbo/Functions/UserCipherDetails.sql +++ b/src/Sql/dbo/Functions/UserCipherDetails.sql @@ -1,42 +1,62 @@ CREATE FUNCTION [dbo].[UserCipherDetails](@UserId UNIQUEIDENTIFIER) RETURNS TABLE AS RETURN +WITH [CTE] AS ( + SELECT + [Id], + [OrganizationId], + [AccessAll] + FROM + [OrganizationUser] + WHERE + [UserId] = @UserId + AND [Status] = 2 -- Confirmed +) SELECT C.*, - CASE - WHEN C.[UserId] IS NOT NULL OR OU.[AccessAll] = 1 OR CU.[ReadOnly] = 0 OR G.[AccessAll] = 1 OR CG.[ReadOnly] = 0 THEN 1 + CASE + WHEN + OU.[AccessAll] = 1 + OR CU.[ReadOnly] = 0 + OR G.[AccessAll] = 1 + OR CG.[ReadOnly] = 0 + THEN 1 ELSE 0 END [Edit], - CASE - WHEN C.[UserId] IS NULL AND O.[UseTotp] = 1 THEN 1 + CASE + WHEN O.[UseTotp] = 1 + THEN 1 ELSE 0 END [OrganizationUseTotp] FROM [dbo].[CipherDetails](@UserId) C +INNER JOIN + [CTE] OU ON C.[UserId] IS NULL AND C.[OrganizationId] IN (SELECT [OrganizationId] FROM [CTE]) +INNER JOIN + [dbo].[Organization] O ON O.[Id] = OU.OrganizationId AND O.[Id] = C.[OrganizationId] AND O.[Enabled] = 1 LEFT JOIN - [dbo].[Organization] O ON C.[UserId] IS NULL AND O.[Id] = C.[OrganizationId] -LEFT JOIN - [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId -LEFT JOIN - [dbo].[CollectionCipher] CC ON C.[UserId] IS NULL AND OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] + [dbo].[CollectionCipher] CC ON OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] LEFT JOIN [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] LEFT JOIN - [dbo].[GroupUser] GU ON C.[UserId] IS NULL AND CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] + [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] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] WHERE - C.[UserId] = @UserId - OR ( - C.[UserId] IS NULL - 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 - ) - ) \ No newline at end of file + OU.[AccessAll] = 1 + OR CU.[CollectionId] IS NOT NULL + OR G.[AccessAll] = 1 + OR CG.[CollectionId] IS NOT NULL + +UNION ALL + +SELECT + *, + 1 [Edit], + 0 [OrganizationUseTotp] +FROM + [dbo].[CipherDetails](@UserId) +WHERE + [UserId] = @UserId diff --git a/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByTypeUserId.sql b/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByTypeUserId.sql deleted file mode 100644 index 7c0dff1e7..000000000 --- a/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByTypeUserId.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE PROCEDURE [dbo].[CipherDetails_ReadByTypeUserId] - @Type TINYINT, - @UserId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - * - FROM - [dbo].[UserCipherDetails](@UserId) - WHERE - [Type] = @Type -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByUserIdHasCollection.sql b/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByUserIdHasCollection.sql deleted file mode 100644 index 2a4b67d88..000000000 --- a/src/Sql/dbo/Stored Procedures/CipherDetails_ReadByUserIdHasCollection.sql +++ /dev/null @@ -1,42 +0,0 @@ -CREATE PROCEDURE [dbo].[CipherDetails_ReadByUserIdHasCollection] - @UserId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - C.*, - CASE - WHEN C.[UserId] IS NOT NULL OR OU.[AccessAll] = 1 OR CU.[ReadOnly] = 0 OR G.[AccessAll] = 1 OR CG.[ReadOnly] = 0 THEN 1 - ELSE 0 - END [Edit], - CASE - WHEN C.[UserId] IS NULL AND O.[UseTotp] = 1 THEN 1 - ELSE 0 - END [OrganizationUseTotp] - FROM - [dbo].[CipherDetails](@UserId) C - INNER JOIN - [dbo].[Organization] O ON C.[UserId] IS NULL AND O.[Id] = C.[OrganizationId] - INNER JOIN - [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId - LEFT JOIN - [dbo].[CollectionCipher] CC ON C.[UserId] IS NULL AND OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] - LEFT JOIN - [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] - LEFT JOIN - [dbo].[GroupUser] GU ON C.[UserId] IS NULL AND 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] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] - WHERE - 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 - ) -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CipherDetails_ReadWithoutOrganizationsByUserId.sql b/src/Sql/dbo/Stored Procedures/CipherDetails_ReadWithoutOrganizationsByUserId.sql new file mode 100644 index 000000000..95fc04ba7 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/CipherDetails_ReadWithoutOrganizationsByUserId.sql @@ -0,0 +1,14 @@ +CREATE PROCEDURE [dbo].[CipherDetails_ReadWithoutOrganizationsByUserId] + @UserId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + 1 [Edit], + 0 [OrganizationUseTotp] + FROM + [dbo].[CipherDetails](@UserId) + WHERE + [UserId] = @UserId +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Cipher_ReadByOrganizationId.sql b/src/Sql/dbo/Stored Procedures/Cipher_ReadByOrganizationId.sql index ee05ffc2f..9049e91e7 100644 --- a/src/Sql/dbo/Stored Procedures/Cipher_ReadByOrganizationId.sql +++ b/src/Sql/dbo/Stored Procedures/Cipher_ReadByOrganizationId.sql @@ -9,5 +9,6 @@ BEGIN FROM [dbo].[CipherView] WHERE - [OrganizationId] = @OrganizationId + [UserId] IS NULL + AND [OrganizationId] = @OrganizationId END \ No newline at end of file diff --git a/src/Sql/dbo/Tables/Cipher.sql b/src/Sql/dbo/Tables/Cipher.sql index c260c1b4c..f08f54269 100644 --- a/src/Sql/dbo/Tables/Cipher.sql +++ b/src/Sql/dbo/Tables/Cipher.sql @@ -16,12 +16,7 @@ GO -CREATE NONCLUSTERED INDEX [IX_Cipher_OrganizationId_Type] - ON [dbo].[Cipher]([OrganizationId] ASC, [Type] ASC) WHERE ([OrganizationId] IS NOT NULL); - - -GO -CREATE NONCLUSTERED INDEX [IX_Cipher_UserId_Type_IncludeAll] - ON [dbo].[Cipher]([UserId] ASC, [Type] ASC) - INCLUDE ([OrganizationId], [Data], [Favorites], [Folders], [Attachments], [CreationDate], [RevisionDate]); +CREATE NONCLUSTERED INDEX [IX_Cipher_UserId_OrganizationId_IncludeAll] + ON [dbo].[Cipher]([UserId] ASC, [OrganizationId] ASC) + INCLUDE ([Type], [Data], [Favorites], [Folders], [Attachments], [CreationDate], [RevisionDate]); diff --git a/src/Sql/dbo/Tables/GroupUser.sql b/src/Sql/dbo/Tables/GroupUser.sql index 801d5c32c..f194c40c1 100644 --- a/src/Sql/dbo/Tables/GroupUser.sql +++ b/src/Sql/dbo/Tables/GroupUser.sql @@ -6,3 +6,10 @@ CONSTRAINT [FK_GroupUser_OrganizationUser] FOREIGN KEY ([OrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id]) ); + +GO +CREATE NONCLUSTERED INDEX [IX_GroupUser_OrganizationUserId] + ON [dbo].[GroupUser]([OrganizationUserId] ASC); + + + diff --git a/src/Sql/dbo/Tables/Organization.sql b/src/Sql/dbo/Tables/Organization.sql index 5f2dffcea..6601fe683 100644 --- a/src/Sql/dbo/Tables/Organization.sql +++ b/src/Sql/dbo/Tables/Organization.sql @@ -33,3 +33,9 @@ CONSTRAINT [PK_Organization] PRIMARY KEY CLUSTERED ([Id] ASC) ); + +GO +CREATE NONCLUSTERED INDEX [IX_Organization_Enabled] + ON [dbo].[Organization]([Id] ASC, [Enabled] ASC) + INCLUDE ([UseTotp]); + diff --git a/util/Setup/DbScripts/2018-04-24_00_CipherQueryTuning.sql b/util/Setup/DbScripts/2018-04-24_00_CipherQueryTuning.sql new file mode 100644 index 000000000..4c725f08d --- /dev/null +++ b/util/Setup/DbScripts/2018-04-24_00_CipherQueryTuning.sql @@ -0,0 +1,212 @@ +IF OBJECT_ID('[dbo].[CipherDetails]') IS NOT NULL +BEGIN + DROP FUNCTION [dbo].[CipherDetails] +END +GO + +CREATE FUNCTION [dbo].[CipherDetails](@UserId UNIQUEIDENTIFIER) +RETURNS TABLE +AS RETURN +SELECT + C.[Id], + C.[UserId], + C.[OrganizationId], + C.[Type], + C.[Data], + C.[Attachments], + C.[CreationDate], + C.[RevisionDate], + CASE + WHEN + @UserId IS NULL + OR C.[Favorites] IS NULL + OR JSON_VALUE(C.[Favorites], CONCAT('$."', @UserId, '"')) IS NULL + THEN 0 + ELSE 1 + END [Favorite], + CASE + WHEN + @UserId IS NULL + OR C.[Folders] IS NULL + THEN NULL + ELSE TRY_CONVERT(UNIQUEIDENTIFIER, JSON_VALUE(C.[Folders], CONCAT('$."', @UserId, '"'))) + END [FolderId] +FROM + [dbo].[Cipher] C +GO + +IF OBJECT_ID('[dbo].[UserCipherDetails]') IS NOT NULL +BEGIN + DROP FUNCTION [dbo].[UserCipherDetails] +END +GO + +CREATE FUNCTION [dbo].[UserCipherDetails](@UserId UNIQUEIDENTIFIER) +RETURNS TABLE +AS RETURN +WITH [CTE] AS ( + SELECT + [Id], + [OrganizationId], + [AccessAll] + FROM + [OrganizationUser] + WHERE + [UserId] = @UserId + AND [Status] = 2 -- Confirmed +) +SELECT + C.*, + CASE + WHEN + OU.[AccessAll] = 1 + OR CU.[ReadOnly] = 0 + OR G.[AccessAll] = 1 + OR CG.[ReadOnly] = 0 + THEN 1 + ELSE 0 + END [Edit], + CASE + WHEN O.[UseTotp] = 1 + THEN 1 + ELSE 0 + END [OrganizationUseTotp] +FROM + [dbo].[CipherDetails](@UserId) C +INNER JOIN + [CTE] OU ON C.[UserId] IS NULL AND C.[OrganizationId] IN (SELECT [OrganizationId] FROM [CTE]) +INNER JOIN + [dbo].[Organization] O ON O.[Id] = OU.OrganizationId AND O.[Id] = C.[OrganizationId] AND O.[Enabled] = 1 +LEFT JOIN + [dbo].[CollectionCipher] CC ON OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] +LEFT JOIN + [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] 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] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] +WHERE + OU.[AccessAll] = 1 + OR CU.[CollectionId] IS NOT NULL + OR G.[AccessAll] = 1 + OR CG.[CollectionId] IS NOT NULL + +UNION ALL + +SELECT + *, + 1 [Edit], + 0 [OrganizationUseTotp] +FROM + [dbo].[CipherDetails](@UserId) +WHERE + [UserId] = @UserId +GO + +IF EXISTS ( + SELECT * FROM sys.indexes WHERE [Name]='IX_Cipher_OrganizationId_Type' + AND object_id = OBJECT_ID('[dbo].[Cipher]') +) +BEGIN + DROP INDEX [IX_Cipher_OrganizationId_Type] ON [dbo].[Cipher] +END +GO + +IF EXISTS ( + SELECT * FROM sys.indexes WHERE [Name]='IX_Cipher_UserId_Type_IncludeAll' + AND object_id = OBJECT_ID('[dbo].[Cipher]') +) +BEGIN + DROP INDEX [IX_Cipher_UserId_Type_IncludeAll] ON [dbo].[Cipher] +END +GO + +IF NOT EXISTS ( + SELECT * FROM sys.indexes WHERE [Name]='IX_Cipher_UserId_OrganizationId_IncludeAll' + AND object_id = OBJECT_ID('[dbo].[Cipher]') +) +BEGIN + CREATE NONCLUSTERED INDEX [IX_Cipher_UserId_OrganizationId_IncludeAll] + ON [dbo].[Cipher]([UserId] ASC, [OrganizationId] ASC) + INCLUDE ([Type], [Data], [Favorites], [Folders], [Attachments], [CreationDate], [RevisionDate]) +END +GO + +IF NOT EXISTS ( + SELECT * FROM sys.indexes WHERE [Name]='IX_GroupUser_OrganizationUserId' + AND object_id = OBJECT_ID('[dbo].[GroupUser]') +) +BEGIN + CREATE NONCLUSTERED INDEX [IX_GroupUser_OrganizationUserId] + ON [dbo].[GroupUser]([OrganizationUserId] ASC) +END +GO + +IF NOT EXISTS ( + SELECT * FROM sys.indexes WHERE [Name]='IX_Organization_Enabled' + AND object_id = OBJECT_ID('[dbo].[Organization]') +) +BEGIN + CREATE NONCLUSTERED INDEX [IX_Organization_Enabled] + ON [dbo].[Organization]([Id] ASC, [Enabled] ASC) + INCLUDE ([UseTotp]) +END +GO + +IF OBJECT_ID('[dbo].[CipherDetails_ReadByTypeUserId]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[CipherDetails_ReadByTypeUserId] +END +GO + +IF OBJECT_ID('[dbo].[CipherDetails_ReadByUserIdHasCollection]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[CipherDetails_ReadByUserIdHasCollection] +END +GO + +IF OBJECT_ID('[dbo].[CipherDetails_ReadWithoutOrganizationsByUserId]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[CipherDetails_ReadWithoutOrganizationsByUserId] +END +GO + +CREATE PROCEDURE [dbo].[CipherDetails_ReadWithoutOrganizationsByUserId] + @UserId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + 1 [Edit], + 0 [OrganizationUseTotp] + FROM + [dbo].[CipherDetails](@UserId) + WHERE + [UserId] = @UserId +END +GO + +IF OBJECT_ID('[dbo].[Cipher_ReadByOrganizationId]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[Cipher_ReadByOrganizationId] +END +GO + +CREATE PROCEDURE [dbo].[Cipher_ReadByOrganizationId] + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + * + FROM + [dbo].[CipherView] + WHERE + [UserId] IS NULL + AND [OrganizationId] = @OrganizationId +END +GO diff --git a/util/Setup/Setup.csproj b/util/Setup/Setup.csproj index 83fdaf665..03e3d3380 100644 --- a/util/Setup/Setup.csproj +++ b/util/Setup/Setup.csproj @@ -9,9 +9,11 @@ + +