Implement CheckToken API operation.
This commit is contained in:
parent
127652002b
commit
bf431cb3e4
7 changed files with 123 additions and 18 deletions
|
@ -33,6 +33,16 @@ namespace Retroactiune.Core.Entities
|
||||||
|
|
||||||
[JsonPropertyName("expiry_time")] public DateTime? ExpiryTime { get; set; }
|
[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)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (!(obj is Token convertedObj))
|
if (!(obj is Token convertedObj))
|
||||||
|
@ -50,13 +60,18 @@ namespace Retroactiune.Core.Entities
|
||||||
return RuntimeHelpers.GetHashCode(this);
|
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)
|
public bool IsValid(FeedbackReceiver feedbackReceiver)
|
||||||
{
|
{
|
||||||
Guard.Against.Null(feedbackReceiver, nameof(feedbackReceiver));
|
Guard.Against.Null(feedbackReceiver, nameof(feedbackReceiver));
|
||||||
var hasExpired = ExpiryTime != null && ExpiryTime <= DateTime.UtcNow;
|
|
||||||
var differentFeedbackReceiver = !FeedbackReceiverId.Equals(feedbackReceiver.Id);
|
var differentFeedbackReceiver = !FeedbackReceiverId.Equals(feedbackReceiver.Id);
|
||||||
var isUsed = TimeUsed != null;
|
return !differentFeedbackReceiver && IsValid();
|
||||||
return !(hasExpired || differentFeedbackReceiver || isUsed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Retroactiune.Core.Services
|
namespace Retroactiune.Core.Services
|
||||||
{
|
{
|
||||||
|
@ -7,7 +8,6 @@ namespace Retroactiune.Core.Services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FeedbacksListFilters
|
public class FeedbacksListFilters
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// FeedbackReceiverId the ID of the FeedbackReceiver.
|
/// FeedbackReceiverId the ID of the FeedbackReceiver.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -27,5 +27,23 @@ namespace Retroactiune.Core.Services
|
||||||
/// Rating filters for the rating.
|
/// Rating filters for the rating.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint Rating { get; set; }
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -202,9 +202,6 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
mockService.Verify(s => s.FindAsync(filterArr, offset, limit), Times.Once);
|
mockService.Verify(s => s.FindAsync(filterArr, offset, limit), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid token
|
|
||||||
// happy
|
|
||||||
|
|
||||||
[Theory, AutoData]
|
[Theory, AutoData]
|
||||||
public async Task AddFeedback_No_FeedbackReceiver(FeedbackInDto requestBody)
|
public async Task AddFeedback_No_FeedbackReceiver(FeedbackInDto requestBody)
|
||||||
{
|
{
|
||||||
|
@ -295,11 +292,15 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
feedbackReceiversService
|
feedbackReceiversService
|
||||||
.Setup(i => i.FindAsync(It.IsAny<IEnumerable<string>>(), It.IsAny<int?>(), It.IsAny<int?>()))
|
.Setup(i => i.FindAsync(It.IsAny<IEnumerable<string>>(),
|
||||||
.ReturnsAsync(new[] {new FeedbackReceiver
|
It.IsAny<int?>(), It.IsAny<int?>()))
|
||||||
|
.ReturnsAsync(new[]
|
||||||
{
|
{
|
||||||
Id = "batman"
|
new FeedbackReceiver
|
||||||
}});
|
{
|
||||||
|
Id = "batman"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
tokensService.Setup(i => i.FindAsync(It.IsAny<TokenListFilters>()))
|
tokensService.Setup(i => i.FindAsync(It.IsAny<TokenListFilters>()))
|
||||||
.ReturnsAsync(new[]
|
.ReturnsAsync(new[]
|
||||||
|
@ -318,6 +319,32 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<OkResult>(result);
|
Assert.IsType<OkResult>(result);
|
||||||
|
feedbacksService.Verify(i => i.AddFeedbackAsync(It.IsAny<Feedback>(),
|
||||||
|
It.IsAny<FeedbackReceiver>()));
|
||||||
|
tokensService.Verify(i => i.MarkTokenAsUsedAsync(It.IsAny<Token>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, AutoData]
|
||||||
|
public async Task GetFeedbacks_Happy(string guid, ListFeedbacksFiltersDto filters)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var mapper = TestUtils.GetMapper();
|
||||||
|
var feedbackReceiversService = new Mock<IFeedbackReceiversService>();
|
||||||
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
|
// 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<OkObjectResult>(result);
|
||||||
|
|
||||||
|
var listFilters = mapper.Map<FeedbacksListFilters>(filters);
|
||||||
|
listFilters.FeedbackReceiverId = guid;
|
||||||
|
feedbacksService.Verify(i => i.GetFeedbacksAsync(listFilters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -82,7 +82,7 @@ namespace Retroactiune.Controllers
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
public async Task<IActionResult> GetFeedbacks(string guid, [FromQuery] ListFeedbacksFiltersDto filters)
|
public async Task<IActionResult> GetFeedbacks(string guid, [FromQuery] ListFeedbacksFiltersDto filters)
|
||||||
{
|
{
|
||||||
// TODO: Unit & Integration test.
|
// TODO: Integration test.
|
||||||
var feedbacksListFilters = _mapper.Map<FeedbacksListFilters>(filters);
|
var feedbacksListFilters = _mapper.Map<FeedbacksListFilters>(filters);
|
||||||
feedbacksListFilters.FeedbackReceiverId = guid;
|
feedbacksListFilters.FeedbackReceiverId = guid;
|
||||||
var response = await _feedbacksService.GetFeedbacksAsync(feedbacksListFilters);
|
var response = await _feedbacksService.GetFeedbacksAsync(feedbacksListFilters);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -145,5 +146,41 @@ namespace Retroactiune.Controllers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a token is valid or not.
|
||||||
|
/// </summary>
|
||||||
|
/// <response code="200">The the result of the check.</response>
|
||||||
|
/// <response code="400">The request is invalid.</response>
|
||||||
|
[HttpGet("{guid}/check")]
|
||||||
|
[ProducesResponseType(typeof(CheckTokenDto), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
public async Task<IActionResult> 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
7
Retroactiune.WebAPI/DataTransferObjects/CheckTokenDto.cs
Normal file
7
Retroactiune.WebAPI/DataTransferObjects/CheckTokenDto.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Retroactiune.DataTransferObjects
|
||||||
|
{
|
||||||
|
public class CheckTokenDto
|
||||||
|
{
|
||||||
|
public bool IsValid { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ namespace Retroactiune
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
// TODO: External auth provider.
|
// TODO: External auth provider.
|
||||||
|
// TODO: Improve coverage.
|
||||||
// TODO: UI?
|
// TODO: UI?
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue