diff --git a/Retroactiune.Core/Interfaces/ITokensService.cs b/Retroactiune.Core/Interfaces/ITokensService.cs
index b6cba63..6062263 100644
--- a/Retroactiune.Core/Interfaces/ITokensService.cs
+++ b/Retroactiune.Core/Interfaces/ITokensService.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Retroactiune.Core.Entities;
+using Retroactiune.Core.Services;
namespace Retroactiune.Core.Interfaces
{
@@ -22,5 +24,12 @@ namespace Retroactiune.Core.Interfaces
/// A list of tokens to delete.
/// The result of the delete operation.
public Task DeleteTokens(IEnumerable tokenIds);
+
+ ///
+ /// List and filters tokens.
+ ///
+ /// Filters object for filtering results.
+ /// A list of tokens matching the filters.
+ public Task> ListTokens(TokenListFilters filters);
}
}
\ No newline at end of file
diff --git a/Retroactiune.Core/Services/TokenListFilters.cs b/Retroactiune.Core/Services/TokenListFilters.cs
new file mode 100644
index 0000000..cc2e9a4
--- /dev/null
+++ b/Retroactiune.Core/Services/TokenListFilters.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace Retroactiune.Core.Services
+{
+ ///
+ /// TokenListFilters is a data class representing the filters used to list tokens.
+ ///
+ public class TokenListFilters
+ {
+ ///
+ /// Id filters tokens by their ids.
+ ///
+ public IEnumerable Id { get; set; }
+
+ ///
+ /// FeedbackReceiverId filters tokens by their assigned FeedbackReceiverId.
+ ///
+ public string FeedbackReceiverId { get; set; }
+
+ ///
+ /// CreatedAfter filters token that have been created after the given date.
+ ///
+ public DateTime? CreatedAfter { get; set; }
+
+ ///
+ /// CreatedBefore filters token that have been created before the given date.
+ ///
+ public DateTime? CreatedBefore { get; set; }
+
+ ///
+ /// UsedAfter filters token that have been used after the given date.
+ ///
+ public DateTime? UsedAfter { get; set; }
+
+ ///
+ /// UsedBefore filters token that have been used before the given date.
+ ///
+ public DateTime? UsedBefore { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Retroactiune.Core/Services/TokensService.cs b/Retroactiune.Core/Services/TokensService.cs
index 8f4a9db..95076b0 100644
--- a/Retroactiune.Core/Services/TokensService.cs
+++ b/Retroactiune.Core/Services/TokensService.cs
@@ -52,5 +52,12 @@ namespace Retroactiune.Core.Services
throw new GenericServiceException($"Operation failed: {e.Message} {e.StackTrace}");
}
}
+
+ public async Task> ListTokens(TokenListFilters filters)
+ {
+ // TODO Write unit tests.
+ // TODO: Implement
+ throw new NotImplementedException();
+ }
}
}
\ No newline at end of file
diff --git a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs
index e7a61b6..1ad19ae 100644
--- a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs
+++ b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using AutoFixture.Xunit2;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
using Moq;
using Retroactiune.Controllers;
using Retroactiune.Core.Entities;
@@ -20,9 +21,10 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.Post(new List());
// Assert, null because we don't have the ApiBehaviourOptions set, which would generate the IActionResult for the invalid input.
@@ -36,9 +38,10 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.Post(items);
// Assert
@@ -52,9 +55,10 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.Delete("bad_guid_but_unit_test_works_cause_validation_doesnt");
// Assert
@@ -62,16 +66,17 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
mockService.Verify(s => s.DeleteManyAsync(new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt"}),
Times.Once);
}
-
+
[Fact]
public async Task DeleteMany_Successful()
{
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"};
var result = await controller.DeleteMany(items);
@@ -87,11 +92,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
mockService.Setup(i => i.FindAsync(It.IsAny>(), null, null))
.ReturnsAsync(new[] {new FeedbackReceiver()});
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
// Assert
@@ -107,9 +113,10 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
// Assert
@@ -125,10 +132,11 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Arrange
var mapper = TestUtils.GetMapper();
var mockService = new Mock();
+ var logger = new Mock>();
var filterArr = filter as string[] ?? filter.ToArray();
// Test
- var controller = new FeedbackReceiversController(mockService.Object, mapper, null);
+ var controller = new FeedbackReceiversController(mockService.Object, mapper, null, logger.Object);
var result = await controller.List(filterArr, offset, limit);
Assert.IsType(result);
diff --git a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs
index be51e64..1fcaf2a 100644
--- a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs
+++ b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using AutoFixture.Xunit2;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
using Moq;
using Retroactiune.Controllers;
using Retroactiune.Core.Entities;
@@ -19,10 +20,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
{
// Arrange
var feedbackService = new Mock();
+ var mapper = TestUtils.GetMapper();
var tokens = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.GenerateTokens(new GenerateTokensDto());
// Assert
@@ -33,8 +36,10 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
public async Task Test_GenerateTokens_Success(FeedbackReceiver randFedFeedbackReceiver)
{
// Arrange
+ var mapper = TestUtils.GetMapper();
var feedbackService = new Mock();
var tokens = new Mock();
+ var logger = new Mock>();
feedbackService.Setup(i => i.FindAsync(It.IsAny>(),
It.IsAny(),
@@ -42,7 +47,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
.ReturnsAsync(new[] {randFedFeedbackReceiver});
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.GenerateTokens(new GenerateTokensDto
{
NumberOfTokens = 2,
@@ -58,11 +63,13 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
public async Task Test_Delete_Ok()
{
// Arrange
+ var mapper = TestUtils.GetMapper();
var feedbackService = new Mock();
var tokens = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.DeleteToken("my_guid");
// Assert
@@ -74,13 +81,15 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
public async Task Test_Delete_BadRequest()
{
// Arrange
+ var mapper = TestUtils.GetMapper();
var feedbackService = new Mock();
var tokens = new Mock();
+ var logger = new Mock>();
tokens.Setup(i => i.DeleteTokens(It.IsAny>()))
.Throws(new GenericServiceException("op fail"));
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.DeleteToken("my_guid");
// Assert
@@ -92,11 +101,13 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
public async Task Test_DeleteMany_Ok()
{
// Arrange
+ var mapper = TestUtils.GetMapper();
var feedbackService = new Mock();
var tokens = new Mock();
+ var logger = new Mock>();
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.DeleteTokens(new[] {"my_guid", "b"});
// Assert
@@ -108,13 +119,15 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
public async Task Test_DeleteMany_BadRequest()
{
// Arrange
+ var mapper = TestUtils.GetMapper();
var feedbackService = new Mock();
var tokens = new Mock();
+ var logger = new Mock>();
tokens.Setup(i => i.DeleteTokens(It.IsAny>()))
.Throws(new GenericServiceException("op fail"));
// Test
- var controller = new TokensController(feedbackService.Object, tokens.Object);
+ var controller = new TokensController(feedbackService.Object, tokens.Object, logger.Object, mapper);
var result = await controller.DeleteTokens(new[] {"my_guid", "b"});
// Assert
diff --git a/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs b/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs
index 9def126..16fd295 100644
--- a/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs
+++ b/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Retroactiune.Core.Entities;
using Retroactiune.Core.Interfaces;
@@ -21,13 +22,15 @@ namespace Retroactiune.Controllers
private readonly IOptions _apiBehaviorOptions;
private readonly IFeedbackReceiverService _service;
private readonly IMapper _mapper;
+ private readonly ILogger _logger;
public FeedbackReceiversController(IFeedbackReceiverService service, IMapper mapper,
- IOptions apiBehaviorOptions)
+ IOptions apiBehaviorOptions, ILogger logger)
{
_service = service;
_mapper = mapper;
_apiBehaviorOptions = apiBehaviorOptions;
+ _logger = logger;
}
@@ -80,7 +83,7 @@ namespace Retroactiune.Controllers
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
string guid)
{
- await _service.DeleteManyAsync(new [] {guid});
+ await _service.DeleteManyAsync(new[] {guid});
return NoContent();
}
@@ -133,7 +136,7 @@ namespace Retroactiune.Controllers
{
return Ok(await _service.FindAsync(filter, offset, limit));
}
-
+
///
/// Deletes FeedbackReceiver identified by ids.
///
@@ -143,7 +146,7 @@ namespace Retroactiune.Controllers
///
[HttpDelete]
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
- [ProducesResponseType(typeof(BasicResponse),StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
public async Task DeleteMany([Required] IEnumerable ids)
{
try
@@ -153,6 +156,7 @@ namespace Retroactiune.Controllers
}
catch (GenericServiceException e)
{
+ _logger.LogError("{Message}", e.Message);
return BadRequest(new BasicResponse
{
Message = e.Message
diff --git a/Retroactiune.WebAPI/Controllers/TokensController.cs b/Retroactiune.WebAPI/Controllers/TokensController.cs
index 711c9a2..ab27a91 100644
--- a/Retroactiune.WebAPI/Controllers/TokensController.cs
+++ b/Retroactiune.WebAPI/Controllers/TokensController.cs
@@ -2,8 +2,11 @@
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
+using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using Retroactiune.Core.Entities;
using Retroactiune.Core.Interfaces;
using Retroactiune.Core.Services;
using Retroactiune.DataTransferObjects;
@@ -14,18 +17,46 @@ namespace Retroactiune.Controllers
[Route("api/v1/[controller]")]
public class TokensController : ControllerBase
{
- // TODO: Implement ListTokens.
- // Filters for: FeedbackReceiver IDS
- // for: start < CreatedTime < end
- // for start < TimeUsed end
-
private readonly IFeedbackReceiverService _feedbackReceiverService;
private readonly ITokensService _tokensService;
+ private readonly IMapper _mapper;
+ private readonly ILogger _logger;
- public TokensController(IFeedbackReceiverService feedbackReceiverService, ITokensService tokensService)
+ public TokensController(IFeedbackReceiverService feedbackReceiverService, ITokensService tokensService,
+ ILogger logger, IMapper mapper)
{
_feedbackReceiverService = feedbackReceiverService;
_tokensService = tokensService;
+ _mapper = mapper;
+ _logger = logger;
+ }
+
+ ///
+ /// The list tokens controller retrieves a list of tokens.
+ ///
+ /// Object that holds filters for listing tokens.
+ /// A list of tokens.
+ /// The request is invalid.
+ [HttpGet]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task ListTokens([FromQuery] ListTokensFiltersDto filtersDto)
+ {
+ // TODO: Write unit & integration tests.
+ try
+ {
+ var tokenFilters = _mapper.Map(filtersDto);
+ var response = await _tokensService.ListTokens(tokenFilters);
+ return Ok(response);
+ }
+ catch (GenericServiceException e)
+ {
+ _logger.LogError("{Message}", e.Message);
+ return BadRequest(new BasicResponse()
+ {
+ Message = e.Message
+ });
+ }
}
///
@@ -69,7 +100,7 @@ namespace Retroactiune.Controllers
///
[HttpDelete]
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
- [ProducesResponseType(typeof(BasicResponse),StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
public async Task DeleteTokens([Required] IEnumerable tokenIds)
{
try
@@ -79,13 +110,14 @@ namespace Retroactiune.Controllers
}
catch (GenericServiceException e)
{
+ _logger.LogError("{Message}", e.Message);
return BadRequest(new BasicResponse
{
Message = e.Message
});
}
}
-
+
///
/// Deletes a Token given it's guid.
///
@@ -97,15 +129,17 @@ namespace Retroactiune.Controllers
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task DeleteToken(
- [StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)] string guid)
+ [StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
+ string guid)
{
try
{
- await _tokensService.DeleteTokens(new []{ guid });
+ await _tokensService.DeleteTokens(new[] {guid});
return NoContent();
}
catch (GenericServiceException e)
{
+ _logger.LogError("{Message}", e.Message);
return BadRequest(new BasicResponse
{
Message = e.Message
diff --git a/Retroactiune.WebAPI/DataTransferObjects/ListTokensFiltersDto.cs b/Retroactiune.WebAPI/DataTransferObjects/ListTokensFiltersDto.cs
new file mode 100644
index 0000000..369674f
--- /dev/null
+++ b/Retroactiune.WebAPI/DataTransferObjects/ListTokensFiltersDto.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Retroactiune.Core.Entities;
+
+namespace Retroactiune.DataTransferObjects
+{
+ ///
+ /// DTO with filters for listing tokens.
+ ///
+ public class ListTokensFiltersDto
+ {
+ public IEnumerable Id { get; set; }
+ [StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
+ public string FeedbackReceiverId { get; set; }
+ public DateTime? CreatedAfter { get; set; }
+ public DateTime? CreatedBefore { get; set; }
+ public DateTime? UsedAfter { get; set; }
+ public DateTime? UsedBefore { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Retroactiune.WebAPI/MappingProfile.cs b/Retroactiune.WebAPI/MappingProfile.cs
index 60d38e5..c3e5a07 100644
--- a/Retroactiune.WebAPI/MappingProfile.cs
+++ b/Retroactiune.WebAPI/MappingProfile.cs
@@ -1,5 +1,6 @@
using AutoMapper;
using Retroactiune.Core.Entities;
+using Retroactiune.Core.Services;
using Retroactiune.DataTransferObjects;
namespace Retroactiune
@@ -8,6 +9,7 @@ namespace Retroactiune
{
public MappingProfile()
{
+ CreateMap();
CreateMap().ReverseMap();
CreateMap();
}