diff --git a/src/Api/Controllers/CiphersController.cs b/src/Api/Controllers/CiphersController.cs index e7702834c..624b71e12 100644 --- a/src/Api/Controllers/CiphersController.cs +++ b/src/Api/Controllers/CiphersController.cs @@ -44,6 +44,21 @@ namespace Bit.Api.Controllers return new CipherResponseModel(cipher); } + [HttpGet("{id}/full-details")] + public async Task GetDetails(string id) + { + var userId = _userService.GetProperUserId(User).Value; + var cipherId = new Guid(id); + var cipher = await _cipherRepository.GetFullDetailsByIdAsync(cipherId, userId); + if(cipher == null) + { + throw new NotFoundException(); + } + + var subvaultCiphers = await _subvaultCipherRepository.GetManyByUserIdCipherIdAsync(userId, cipherId); + return new CipherFullDetailsResponseModel(cipher, subvaultCiphers); + } + [HttpGet("")] public async Task> Get() { @@ -53,7 +68,7 @@ namespace Bit.Api.Controllers return new ListResponseModel(responses); } - [HttpGet("subvaults")] + [HttpGet("details")] public async Task> GetSubvaults() { var userId = _userService.GetProperUserId(User).Value; diff --git a/src/Core/Models/Api/Response/CipherResponseModel.cs b/src/Core/Models/Api/Response/CipherResponseModel.cs index eb27da1f5..716c31a17 100644 --- a/src/Core/Models/Api/Response/CipherResponseModel.cs +++ b/src/Core/Models/Api/Response/CipherResponseModel.cs @@ -45,8 +45,8 @@ namespace Bit.Core.Models.Api public class CipherDetailsResponseModel : CipherResponseModel { public CipherDetailsResponseModel(CipherDetails cipher, - IDictionary> subvaultCiphers) - : base(cipher, "cipherDetails") + IDictionary> subvaultCiphers, string obj = "cipherDetails") + : base(cipher, obj) { if(subvaultCiphers.ContainsKey(cipher.Id)) { @@ -58,6 +58,24 @@ namespace Bit.Core.Models.Api } } + public CipherDetailsResponseModel(CipherDetails cipher, IEnumerable subvaultCiphers, + string obj = "cipherDetails") + : base(cipher, obj) + { + SubvaultIds = subvaultCiphers.Select(s => s.SubvaultId); + } + public IEnumerable SubvaultIds { get; set; } } + + public class CipherFullDetailsResponseModel : CipherDetailsResponseModel + { + public CipherFullDetailsResponseModel(CipherFullDetails cipher, IEnumerable subvaultCiphers) + : base(cipher, subvaultCiphers, "cipherFullDetails") + { + Edit = cipher.Edit; + } + + public bool Edit { get; set; } + } } diff --git a/src/Core/Repositories/ISubvaultCipherRepository.cs b/src/Core/Repositories/ISubvaultCipherRepository.cs index ef44859f2..4b6efefb1 100644 --- a/src/Core/Repositories/ISubvaultCipherRepository.cs +++ b/src/Core/Repositories/ISubvaultCipherRepository.cs @@ -8,5 +8,6 @@ namespace Bit.Core.Repositories public interface ISubvaultCipherRepository { Task> GetManyByUserIdAsync(Guid userId); + Task> GetManyByUserIdCipherIdAsync(Guid userId, Guid cipherId); } } diff --git a/src/Core/Repositories/SqlServer/SubvaultCipherRepository.cs b/src/Core/Repositories/SqlServer/SubvaultCipherRepository.cs index b7ae455d4..542167c9f 100644 --- a/src/Core/Repositories/SqlServer/SubvaultCipherRepository.cs +++ b/src/Core/Repositories/SqlServer/SubvaultCipherRepository.cs @@ -31,5 +31,18 @@ namespace Bit.Core.Repositories.SqlServer return results.ToList(); } } + + public async Task> GetManyByUserIdCipherIdAsync(Guid userId, Guid cipherId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[dbo].[SubvaultCipher_ReadByUserIdCipherId]", + new { UserId = userId, CipherId = cipherId }, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } } } diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index bd0592ea9..fbc5b588d 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -182,5 +182,6 @@ + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/SubvaultCipher_ReadByCipherId.sql b/src/Sql/dbo/Stored Procedures/SubvaultCipher_ReadByCipherId.sql new file mode 100644 index 000000000..b0969e46b --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/SubvaultCipher_ReadByCipherId.sql @@ -0,0 +1,20 @@ +CREATE PROCEDURE [dbo].[SubvaultCipher_ReadByUserIdCipherId] + @UserId UNIQUEIDENTIFIER, + @CipherId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + SC.* + FROM + [dbo].[SubvaultCipher] SC + INNER JOIN + [dbo].[SubvaultUser] SU ON SU.[SubvaultId] = SC.[SubvaultId] + INNER JOIN + [dbo].[OrganizationUser] OU ON OU.[Id] = SU.[OrganizationUserId] + WHERE + SC.[CipherId] = @CipherId + AND OU.[UserId] = @UserId + AND OU.[Status] = 2 -- Confirmed +END \ No newline at end of file