diff --git a/Retroactiune.Core/Entities/Token.cs b/Retroactiune.Core/Entities/Token.cs
index 702d182..314be63 100644
--- a/Retroactiune.Core/Entities/Token.cs
+++ b/Retroactiune.Core/Entities/Token.cs
@@ -33,6 +33,16 @@ namespace Retroactiune.Core.Entities
[JsonPropertyName("expiry_time")] public DateTime? ExpiryTime { get; set; }
+ public static bool operator ==(Token left, Token right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(Token left, Token right)
+ {
+ return !Equals(left, right);
+ }
+
public override bool Equals(object obj)
{
if (!(obj is Token convertedObj))
@@ -50,13 +60,18 @@ namespace Retroactiune.Core.Entities
return RuntimeHelpers.GetHashCode(this);
}
+ public bool IsValid()
+ {
+ var hasExpired = ExpiryTime != null && ExpiryTime <= DateTime.UtcNow;
+ var isUsed = TimeUsed != null;
+ return !(hasExpired || isUsed);
+ }
+
public bool IsValid(FeedbackReceiver feedbackReceiver)
{
Guard.Against.Null(feedbackReceiver, nameof(feedbackReceiver));
- var hasExpired = ExpiryTime != null && ExpiryTime <= DateTime.UtcNow;
var differentFeedbackReceiver = !FeedbackReceiverId.Equals(feedbackReceiver.Id);
- var isUsed = TimeUsed != null;
- return !(hasExpired || differentFeedbackReceiver || isUsed);
+ return !differentFeedbackReceiver && IsValid();
}
}
}
\ No newline at end of file
diff --git a/Retroactiune.Core/Services/FeedbacksListFilters.cs b/Retroactiune.Core/Services/FeedbacksListFilters.cs
index a0c4cde..3a46a9d 100644
--- a/Retroactiune.Core/Services/FeedbacksListFilters.cs
+++ b/Retroactiune.Core/Services/FeedbacksListFilters.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
namespace Retroactiune.Core.Services
{
@@ -7,12 +8,11 @@ namespace Retroactiune.Core.Services
///
public class FeedbacksListFilters
{
-
///
/// FeedbackReceiverId the ID of the FeedbackReceiver.
///
public string FeedbackReceiverId { get; set; }
-
+
///
/// CreatedAfter filters items that have been created after the given date.
///
@@ -27,5 +27,23 @@ namespace Retroactiune.Core.Services
/// Rating filters for the rating.
///
public uint Rating { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ return obj != null && Equals((FeedbacksListFilters) obj);
+ }
+
+ private bool Equals(FeedbacksListFilters other)
+ {
+ return FeedbackReceiverId == other.FeedbackReceiverId &&
+ Nullable.Equals(CreatedAfter, other.CreatedAfter) &&
+ Nullable.Equals(CreatedBefore, other.CreatedBefore) && Rating == other.Rating;
+ }
+
+ [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(FeedbackReceiverId, CreatedAfter, CreatedBefore, Rating);
+ }
}
}
\ 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 0dc176f..e3fc00c 100644
--- a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs
+++ b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs
@@ -202,9 +202,6 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
mockService.Verify(s => s.FindAsync(filterArr, offset, limit), Times.Once);
}
- // Invalid token
- // happy
-
[Theory, AutoData]
public async Task AddFeedback_No_FeedbackReceiver(FeedbackInDto requestBody)
{
@@ -272,7 +269,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
TimeUsed = DateTime.UtcNow
}
});
-
+
// Test
var controller = new FeedbackReceiversController(feedbackReceiversService.Object, tokensService.Object,
feedbacksService.Object, mapper, null,
@@ -282,8 +279,8 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Assert
Assert.IsType(result);
}
-
-
+
+
[Theory, AutoData]
public async Task AddFeedback_Happy(FeedbackInDto requestBody)
{
@@ -295,11 +292,15 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
var logger = new Mock>();
feedbackReceiversService
- .Setup(i => i.FindAsync(It.IsAny>(), It.IsAny(), It.IsAny()))
- .ReturnsAsync(new[] {new FeedbackReceiver
+ .Setup(i => i.FindAsync(It.IsAny>(),
+ It.IsAny(), It.IsAny()))
+ .ReturnsAsync(new[]
{
- Id = "batman"
- }});
+ new FeedbackReceiver
+ {
+ Id = "batman"
+ }
+ });
tokensService.Setup(i => i.FindAsync(It.IsAny()))
.ReturnsAsync(new[]
@@ -310,7 +311,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
TimeUsed = null
}
});
-
+
// Test
var controller = new FeedbackReceiversController(feedbackReceiversService.Object, tokensService.Object,
feedbacksService.Object, mapper, null, logger.Object);
@@ -318,6 +319,32 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
// Assert
Assert.IsType(result);
+ feedbacksService.Verify(i => i.AddFeedbackAsync(It.IsAny(),
+ It.IsAny()));
+ tokensService.Verify(i => i.MarkTokenAsUsedAsync(It.IsAny()));
+ }
+
+ [Theory, AutoData]
+ public async Task GetFeedbacks_Happy(string guid, ListFeedbacksFiltersDto filters)
+ {
+ // Arrange
+ var mapper = TestUtils.GetMapper();
+ var feedbackReceiversService = new Mock();
+ var tokensService = new Mock();
+ var feedbacksService = new Mock();
+ var logger = new Mock>();
+
+ // Test
+ var controller = new FeedbackReceiversController(feedbackReceiversService.Object, tokensService.Object,
+ feedbacksService.Object, mapper, null, logger.Object);
+ var result = await controller.GetFeedbacks(guid, filters);
+
+ // Assert
+ Assert.IsType(result);
+
+ var listFilters = mapper.Map(filters);
+ listFilters.FeedbackReceiverId = guid;
+ feedbacksService.Verify(i => i.GetFeedbacksAsync(listFilters));
}
}
}
\ No newline at end of file
diff --git a/Retroactiune.WebAPI/Controllers/FeedbackReceivers.FeedbacksController.cs b/Retroactiune.WebAPI/Controllers/FeedbackReceivers.FeedbacksController.cs
index 8281010..e9fd1c7 100644
--- a/Retroactiune.WebAPI/Controllers/FeedbackReceivers.FeedbacksController.cs
+++ b/Retroactiune.WebAPI/Controllers/FeedbackReceivers.FeedbacksController.cs
@@ -82,7 +82,7 @@ namespace Retroactiune.Controllers
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
public async Task GetFeedbacks(string guid, [FromQuery] ListFeedbacksFiltersDto filters)
{
- // TODO: Unit & Integration test.
+ // TODO: Integration test.
var feedbacksListFilters = _mapper.Map(filters);
feedbacksListFilters.FeedbackReceiverId = guid;
var response = await _feedbacksService.GetFeedbacksAsync(feedbacksListFilters);
diff --git a/Retroactiune.WebAPI/Controllers/TokensController.cs b/Retroactiune.WebAPI/Controllers/TokensController.cs
index a50a5e7..23c4c72 100644
--- a/Retroactiune.WebAPI/Controllers/TokensController.cs
+++ b/Retroactiune.WebAPI/Controllers/TokensController.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
@@ -145,5 +146,41 @@ namespace Retroactiune.Controllers
});
}
}
+
+ ///
+ /// Checks if a token is valid or not.
+ ///
+ /// The the result of the check.
+ /// The request is invalid.
+ [HttpGet("{guid}/check")]
+ [ProducesResponseType(typeof(CheckTokenDto), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task CheckToken(
+ [StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
+ string guid
+ )
+ {
+ // TODO: Unit test.
+ var response = await _tokensService.FindAsync(new TokenListFilters
+ {
+ Ids = new[] {guid}
+ });
+ try
+ {
+ var token = response.ElementAt(0);
+ return Ok(new CheckTokenDto
+ {
+ IsValid = token.IsValid()
+ });
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ _logger.LogWarning("Invalid token {Guid}", guid);
+ return Ok(new CheckTokenDto
+ {
+ IsValid = true
+ });
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Retroactiune.WebAPI/DataTransferObjects/CheckTokenDto.cs b/Retroactiune.WebAPI/DataTransferObjects/CheckTokenDto.cs
new file mode 100644
index 0000000..384b826
--- /dev/null
+++ b/Retroactiune.WebAPI/DataTransferObjects/CheckTokenDto.cs
@@ -0,0 +1,7 @@
+namespace Retroactiune.DataTransferObjects
+{
+ public class CheckTokenDto
+ {
+ public bool IsValid { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Retroactiune.WebAPI/Startup.cs b/Retroactiune.WebAPI/Startup.cs
index 2a47f32..3adbfdf 100644
--- a/Retroactiune.WebAPI/Startup.cs
+++ b/Retroactiune.WebAPI/Startup.cs
@@ -21,6 +21,7 @@ namespace Retroactiune
public class Startup
{
// TODO: External auth provider.
+ // TODO: Improve coverage.
// TODO: UI?
public Startup(IConfiguration configuration)
{