diff --git a/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs b/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs index e990c03..091b639 100644 --- a/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs +++ b/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs @@ -44,9 +44,133 @@ namespace Robware.Api.Auth.Tests.Controllers { }; apiKeyRepository.Create("test").Returns(expectedKey); - + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); (await controller.Create("test")).Value.Should().BeEquivalentTo(expectedKey); } + + [Fact] + public async Task List_ReturnsAllApiKeys() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + var apiKeys = new[] { + new ApiKey {Name = "test1", Key = "test1", IssueTimestamp = DateTime.Now, Enabled = true}, + new ApiKey {Name = "test2", Key = "test2", IssueTimestamp = DateTime.Now, Enabled = false}, + new ApiKey {Name = "test3", Key = "test3", IssueTimestamp = DateTime.Now, Enabled = true} + }; + + apiKeyRepository.GetAll().Returns(apiKeys); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.List()).Value.Should().BeEquivalentTo(apiKeys); + } + + [Fact] + public async Task Delete_WithSuccessfulDeletion_ReturnsNoContent() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + apiKeyRepository.Delete("test").Returns(true); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Delete("test")).Should().BeOfType(); + } + + [Fact] + public async Task Delete_WithUnsuccessfulDeletion_ReturnsBadRequest() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + apiKeyRepository.Delete("test").Returns(false); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Delete("test")).Should().BeOfType(); + } + + [Fact] + public async Task Disable_WithSuccessfulDisablement_ReturnsNoContent() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + var apiKey = new ApiKey { + Name = "test", + Key = "test", + IssueTimestamp = DateTime.Now, + Enabled = true + }; + + apiKeyRepository.Get("test").Returns(apiKey); + apiKeyRepository.Update(apiKey).Returns(true); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Disable("test")).Should().BeOfType(); + apiKey.Enabled.Should().BeFalse(); + } + + [Fact] + public async Task Disable_WithUnsuccessfulDisablement_ReturnsBadRequest() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + var apiKey = new ApiKey { + Name = "test", + Key = "test", + IssueTimestamp = DateTime.Now, + Enabled = true + }; + + apiKeyRepository.Get("test").Returns(apiKey); + apiKeyRepository.Update(apiKey).Returns(false); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Disable("test")).Should().BeOfType(); + } + + [Fact] + public async Task Enable_WithSuccessfulEnablement_ReturnsNoContent() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + var apiKey = new ApiKey { + Name = "test", + Key = "test", + IssueTimestamp = DateTime.Now, + Enabled = false + }; + + apiKeyRepository.Get("test").Returns(apiKey); + apiKeyRepository.Update(apiKey).Returns(true); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Enable("test")).Should().BeOfType(); + apiKey.Enabled.Should().BeTrue(); + } + + [Fact] + public async Task Enable_WithUnsuccessfulEnablement_ReturnsBadRequest() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + var apiKeyRepository = Substitute.For(); + + var apiKey = new ApiKey { + Name = "test", + Key = "test", + IssueTimestamp = DateTime.Now, + Enabled = false + }; + + apiKeyRepository.Get("test").Returns(apiKey); + apiKeyRepository.Update(apiKey).Returns(false); + + var controller = new ApiController(logger, apiKeyValidator, apiKeyRepository); + (await controller.Enable("test")).Should().BeOfType(); + } } } \ No newline at end of file diff --git a/src/Robware.Api.Auth/Controllers/ApiController.cs b/src/Robware.Api.Auth/Controllers/ApiController.cs index 3258ee5..7352290 100644 --- a/src/Robware.Api.Auth/Controllers/ApiController.cs +++ b/src/Robware.Api.Auth/Controllers/ApiController.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Robware.Auth.API; +using System.Linq; namespace Robware.Api.Auth.Controllers { [ApiController] @@ -24,5 +25,34 @@ namespace Robware.Api.Auth.Controllers { [HttpPost(nameof(Create))] [Authorize] public async Task> Create(string name) => await _apiKeyRepository.Create(name); + + [HttpGet(nameof(List))] + [Authorize] + public async Task> List() => (await _apiKeyRepository.GetAll()).ToArray(); + + [HttpDelete(nameof(Delete))] + [Authorize] + public async Task Delete(string key) => await _apiKeyRepository.Delete(key) ? (ActionResult) NoContent() : BadRequest(); + + private async Task SetEnabled(string key, bool enabled) { + try { + var apiKey = await _apiKeyRepository.Get(key); + + apiKey.Enabled = enabled; + + return await _apiKeyRepository.Update(apiKey) ? (ActionResult)NoContent() : BadRequest(); + } + catch (ApiKeyNotFoundException) { + return NotFound(); + } + } + + [HttpPatch(nameof(Disable))] + [Authorize] + public async Task Disable(string key) => await SetEnabled(key, false); + + [HttpPatch(nameof(Enable))] + [Authorize] + public async Task Enable(string key) => await SetEnabled(key, true); } } diff --git a/src/Robware.Auth/API/IApiKeys.cs b/src/Robware.Auth/API/IApiKeys.cs index 45ab091..25edd85 100644 --- a/src/Robware.Auth/API/IApiKeys.cs +++ b/src/Robware.Auth/API/IApiKeys.cs @@ -1,8 +1,12 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; namespace Robware.Auth.API { public interface IApiKeys { Task Get(string apiKey); Task Create(string name); + Task> GetAll(); + Task Delete(string key); + Task Update(ApiKey apiKey); } } \ No newline at end of file diff --git a/src/Robware.Data/ApiKeyRepository.cs b/src/Robware.Data/ApiKeyRepository.cs index eba493b..1a88aa3 100644 --- a/src/Robware.Data/ApiKeyRepository.cs +++ b/src/Robware.Data/ApiKeyRepository.cs @@ -3,6 +3,8 @@ using Robware.Auth.API; using Robware.Data.ApiKeys; using Robware.Data.ApiKeys.State; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace Robware.Data { @@ -34,5 +36,17 @@ namespace Robware.Data { return apiKey; } + + public async Task> GetAll() => (await _collection.FindAsync(_ => true)).ToEnumerable().Select(state => new DatabaseApiKey(state)); + + public async Task Delete(string key) { + var deleteResult = await _collection.DeleteOneAsync(state => state.Key == key); + return deleteResult.IsAcknowledged && deleteResult.DeletedCount == 1; + } + + public async Task Update(ApiKey apiKey) { + var result = await _collection.ReplaceOneAsync(state => state.Key == apiKey.Key, new ApiKeyState(apiKey)); + return result.IsAcknowledged && result.ModifiedCount == 1; + } } } \ No newline at end of file