Implement add feedback operation in FeedbackReceiversController.cs.
This commit is contained in:
parent
eca110d669
commit
398f1c7e2f
20 changed files with 214 additions and 102 deletions
|
@ -10,28 +10,23 @@ namespace Retroactiune.Core.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Feedback
|
public class Feedback
|
||||||
{
|
{
|
||||||
private uint _rating;
|
|
||||||
|
public Feedback()
|
||||||
|
{
|
||||||
|
Id = ObjectId.GenerateNewId().ToString();
|
||||||
|
CreatedAt = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
[BsonId, JsonPropertyName("id")]
|
[BsonId, JsonPropertyName("id")]
|
||||||
[BsonRepresentation(BsonType.ObjectId)]
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("feedback_receiver_id")]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string FeedbackReceiverId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("rating")]
|
[JsonPropertyName("rating")]
|
||||||
public uint Rating
|
public uint Rating { get; set; }
|
||||||
{
|
|
||||||
get => _rating;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value <= 5)
|
|
||||||
{
|
|
||||||
_rating = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("description")] public string Description { get; set; }
|
[JsonPropertyName("description")] public string Description { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ namespace Retroactiune.Core.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FeedbackReceiver
|
public class FeedbackReceiver
|
||||||
{
|
{
|
||||||
|
public FeedbackReceiver()
|
||||||
|
{
|
||||||
|
Id = ObjectId.GenerateNewId().ToString();
|
||||||
|
CreatedAt = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
[BsonId, JsonPropertyName("id")]
|
[BsonId, JsonPropertyName("id")]
|
||||||
[BsonRepresentation(BsonType.ObjectId)]
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Ardalis.GuardClauses;
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Bson.Serialization.Attributes;
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
@ -12,6 +13,13 @@ namespace Retroactiune.Core.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Token
|
public class Token
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public Token()
|
||||||
|
{
|
||||||
|
Id = ObjectId.GenerateNewId().ToString();
|
||||||
|
CreatedAt = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
[BsonId, JsonPropertyName("id")]
|
[BsonId, JsonPropertyName("id")]
|
||||||
[BsonRepresentation(BsonType.ObjectId)]
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
@ -41,5 +49,14 @@ namespace Retroactiune.Core.Entities
|
||||||
{
|
{
|
||||||
return RuntimeHelpers.GetHashCode(this);
|
return RuntimeHelpers.GetHashCode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
17
Retroactiune.Core/Interfaces/IFeedbacksService.cs
Normal file
17
Retroactiune.Core/Interfaces/IFeedbacksService.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Retroactiune.Core.Entities;
|
||||||
|
|
||||||
|
namespace Retroactiune.Core.Interfaces
|
||||||
|
{
|
||||||
|
public interface IFeedbacksService
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds Feedback to a FeedbackReceiver.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="feedback">The feedback.</param>
|
||||||
|
/// <param name="receiver">The feedback receiver.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task AddFeedbackAsync(Feedback feedback, FeedbackReceiver receiver);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,14 +23,14 @@ namespace Retroactiune.Core.Interfaces
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tokenIds">A list of tokens to delete.</param>
|
/// <param name="tokenIds">A list of tokens to delete.</param>
|
||||||
/// <returns>The result of the delete operation.</returns>
|
/// <returns>The result of the delete operation.</returns>
|
||||||
public Task DeleteTokens(IEnumerable<string> tokenIds);
|
public Task DeleteTokensAsync(IEnumerable<string> tokenIds);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List and filters tokens.
|
/// Finds and filters tokens.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filters">Filters object for filtering results.</param>
|
/// <param name="filters">Filters object for filtering results.</param>
|
||||||
/// <returns>A list of tokens matching the filters.</returns>
|
/// <returns>A list of tokens matching the filters.</returns>
|
||||||
public Task<IEnumerable<Token>> ListTokens(TokenListFilters filters);
|
public Task<IEnumerable<Token>> FindAsync(TokenListFilters filters);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes tokens, by their associated FeedbackReceiverId.
|
/// Deletes tokens, by their associated FeedbackReceiverId.
|
||||||
|
@ -38,5 +38,11 @@ namespace Retroactiune.Core.Interfaces
|
||||||
/// <param name="feedbackReceiverIds">A list of FeedbackReceiverIDs.</param>
|
/// <param name="feedbackReceiverIds">A list of FeedbackReceiverIDs.</param>
|
||||||
/// <returns>The result of the delete operation.</returns>
|
/// <returns>The result of the delete operation.</returns>
|
||||||
public Task DeleteManyByFeedbackReceiverIdAsync(IEnumerable<string> feedbackReceiverIds);
|
public Task DeleteManyByFeedbackReceiverIdAsync(IEnumerable<string> feedbackReceiverIds);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks the token as being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token.</param>
|
||||||
|
public Task MarkTokenAsUsedAsync(Token token);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Ardalis.GuardClauses" Version="3.2.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.12.3" />
|
<PackageReference Include="MongoDB.Driver" Version="2.12.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
29
Retroactiune.Core/Services/FeedbacksService.cs
Normal file
29
Retroactiune.Core/Services/FeedbacksService.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ardalis.GuardClauses;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using Retroactiune.Core.Entities;
|
||||||
|
using Retroactiune.Core.Interfaces;
|
||||||
|
|
||||||
|
namespace Retroactiune.Core.Services
|
||||||
|
{
|
||||||
|
public class FeedbacksService : IFeedbacksService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<Feedback> _collection;
|
||||||
|
|
||||||
|
public FeedbacksService(IMongoClient client, IDatabaseSettings settings)
|
||||||
|
{
|
||||||
|
var database = client.GetDatabase(settings.DatabaseName);
|
||||||
|
_collection = database.GetCollection<Feedback>(settings.FeedbackCollectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddFeedbackAsync(Feedback feedback, FeedbackReceiver receiver)
|
||||||
|
{
|
||||||
|
// TODO: Unit test.
|
||||||
|
Guard.Against.Null(feedback, nameof(feedback));
|
||||||
|
Guard.Against.Null(receiver, nameof(receiver));
|
||||||
|
|
||||||
|
feedback.FeedbackReceiverId = receiver.Id;
|
||||||
|
await _collection.InsertOneAsync(feedback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ardalis.GuardClauses;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using Retroactiune.Core.Entities;
|
using Retroactiune.Core.Entities;
|
||||||
using Retroactiune.Core.Interfaces;
|
using Retroactiune.Core.Interfaces;
|
||||||
|
@ -21,10 +22,7 @@ namespace Retroactiune.Core.Services
|
||||||
public async Task GenerateTokensAsync(int numberOfTokens, string feedbackReceiverGuid,
|
public async Task GenerateTokensAsync(int numberOfTokens, string feedbackReceiverGuid,
|
||||||
DateTime? expiryTime = null)
|
DateTime? expiryTime = null)
|
||||||
{
|
{
|
||||||
if (numberOfTokens <= 0)
|
Guard.Against.Negative(numberOfTokens, nameof(numberOfTokens));
|
||||||
{
|
|
||||||
throw new ArgumentException("numberOfTokens must be positive");
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = new List<Token>();
|
var token = new List<Token>();
|
||||||
for (var i = 0; i < numberOfTokens; i++)
|
for (var i = 0; i < numberOfTokens; i++)
|
||||||
|
@ -41,7 +39,7 @@ namespace Retroactiune.Core.Services
|
||||||
await _collection.InsertManyAsync(token);
|
await _collection.InsertManyAsync(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteTokens(IEnumerable<string> tokenIds)
|
public async Task DeleteTokensAsync(IEnumerable<string> tokenIds)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -54,7 +52,7 @@ namespace Retroactiune.Core.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Token>> ListTokens(TokenListFilters filters)
|
public async Task<IEnumerable<Token>> FindAsync(TokenListFilters filters)
|
||||||
{
|
{
|
||||||
var filterBuilder = new FilterDefinitionBuilder<Token>();
|
var filterBuilder = new FilterDefinitionBuilder<Token>();
|
||||||
var activeFilters = new List<FilterDefinition<Token>>();
|
var activeFilters = new List<FilterDefinition<Token>>();
|
||||||
|
@ -119,5 +117,14 @@ namespace Retroactiune.Core.Services
|
||||||
throw new GenericServiceException($"Operation failed: {e.Message} {e.StackTrace}");
|
throw new GenericServiceException($"Operation failed: {e.Message} {e.StackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MarkTokenAsUsedAsync(Token token)
|
||||||
|
{
|
||||||
|
// TODO: Unit test.
|
||||||
|
var filterBuilder = new FilterDefinitionBuilder<Token>();
|
||||||
|
var updateBuilder = new UpdateDefinitionBuilder<Token>();
|
||||||
|
await _collection.UpdateOneAsync(filterBuilder.Eq(i => i.Id, token.Id),
|
||||||
|
updateBuilder.Set(i => i.TimeUsed, DateTime.UtcNow));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -68,16 +68,8 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services
|
||||||
await service.GenerateTokensAsync(3, "Hello", expiryTime);
|
await service.GenerateTokensAsync(3, "Hello", expiryTime);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var item = new Token
|
|
||||||
{
|
|
||||||
Id = null,
|
|
||||||
ExpiryTime = expiryTime,
|
|
||||||
TimeUsed = null,
|
|
||||||
FeedbackReceiverId = "Hello",
|
|
||||||
CreatedAt = expiryTime
|
|
||||||
};
|
|
||||||
mongoCollectionMock.Verify(
|
mongoCollectionMock.Verify(
|
||||||
i => i.InsertManyAsync(new[] {item, item, item},
|
i => i.InsertManyAsync(It.IsAny<IEnumerable<Token>>(),
|
||||||
It.IsAny<InsertManyOptions>(),
|
It.IsAny<InsertManyOptions>(),
|
||||||
It.IsAny<CancellationToken>()), Times.Once);
|
It.IsAny<CancellationToken>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +98,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
||||||
await service.DeleteTokens(new[] {"test_id"});
|
await service.DeleteTokensAsync(new[] {"test_id"});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
mongoCollectionMock.Verify(
|
mongoCollectionMock.Verify(
|
||||||
|
@ -145,7 +137,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
||||||
var result = await service.ListTokens(new TokenListFilters());
|
var result = await service.FindAsync(new TokenListFilters());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<List<Token>>(result);
|
Assert.IsType<List<Token>>(result);
|
||||||
|
@ -185,7 +177,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object);
|
||||||
var result = await service.ListTokens(new TokenListFilters
|
var result = await service.FindAsync(new TokenListFilters
|
||||||
{
|
{
|
||||||
Ids = new[] {"a", "b"},
|
Ids = new[] {"a", "b"},
|
||||||
FeedbackReceiverId = "abc",
|
FeedbackReceiverId = "abc",
|
||||||
|
|
|
@ -23,10 +23,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.Post(new List<FeedbackReceiverInDto>());
|
var result = await controller.Post(new List<FeedbackReceiverInDto>());
|
||||||
|
|
||||||
|
@ -42,10 +44,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.Post(items);
|
var result = await controller.Post(items);
|
||||||
|
|
||||||
|
@ -61,10 +65,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.Delete("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
var result = await controller.Delete("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
||||||
|
|
||||||
|
@ -84,10 +90,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"};
|
var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"};
|
||||||
var result = await controller.DeleteMany(items);
|
var result = await controller.DeleteMany(items);
|
||||||
|
@ -106,12 +114,14 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
mockService.Setup(i => i.DeleteManyAsync(It.IsAny<IEnumerable<string>>()))
|
mockService.Setup(i => i.DeleteManyAsync(It.IsAny<IEnumerable<string>>()))
|
||||||
.ThrowsAsync(new GenericServiceException("op failed"));
|
.ThrowsAsync(new GenericServiceException("op failed"));
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"};
|
var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"};
|
||||||
var result = await controller.DeleteMany(items);
|
var result = await controller.DeleteMany(items);
|
||||||
|
@ -129,12 +139,14 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
mockService.Setup(i => i.FindAsync(It.IsAny<IEnumerable<string>>(), null, null))
|
mockService.Setup(i => i.FindAsync(It.IsAny<IEnumerable<string>>(), null, null))
|
||||||
.ReturnsAsync(new[] {new FeedbackReceiver()});
|
.ReturnsAsync(new[] {new FeedbackReceiver()});
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
||||||
|
|
||||||
|
@ -152,10 +164,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
var result = await controller.Get("bad_guid_but_unit_test_works_cause_validation_doesnt");
|
||||||
|
|
||||||
|
@ -173,11 +187,13 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var mapper = TestUtils.GetMapper();
|
var mapper = TestUtils.GetMapper();
|
||||||
var mockService = new Mock<IFeedbackReceiversService>();
|
var mockService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokensService = new Mock<ITokensService>();
|
var tokensService = new Mock<ITokensService>();
|
||||||
|
var feedbacksService = new Mock<IFeedbacksService>();
|
||||||
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
var logger = new Mock<ILogger<FeedbackReceiversController>>();
|
||||||
var filterArr = filter as string[] ?? filter.ToArray();
|
var filterArr = filter as string[] ?? filter.ToArray();
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, mapper, null,
|
var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object,
|
||||||
|
feedbacksService.Object, mapper, null,
|
||||||
logger.Object);
|
logger.Object);
|
||||||
var result = await controller.List(filterArr, offset, limit);
|
var result = await controller.List(filterArr, offset, limit);
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<NoContentResult>(result);
|
Assert.IsType<NoContentResult>(result);
|
||||||
tokens.Verify(i => i.DeleteTokens(new[] {"my_guid"}), Times.Once);
|
tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid"}), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -85,7 +85,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var feedbackService = new Mock<IFeedbackReceiversService>();
|
var feedbackService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokens = new Mock<ITokensService>();
|
var tokens = new Mock<ITokensService>();
|
||||||
var logger = new Mock<ILogger<TokensController>>();
|
var logger = new Mock<ILogger<TokensController>>();
|
||||||
tokens.Setup(i => i.DeleteTokens(It.IsAny<IEnumerable<string>>()))
|
tokens.Setup(i => i.DeleteTokensAsync(It.IsAny<IEnumerable<string>>()))
|
||||||
.Throws(new GenericServiceException("op fail"));
|
.Throws(new GenericServiceException("op fail"));
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
|
@ -94,7 +94,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<BadRequestObjectResult>(result);
|
Assert.IsType<BadRequestObjectResult>(result);
|
||||||
tokens.Verify(i => i.DeleteTokens(new[] {"my_guid"}), Times.Once);
|
tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid"}), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -112,7 +112,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<NoContentResult>(result);
|
Assert.IsType<NoContentResult>(result);
|
||||||
tokens.Verify(i => i.DeleteTokens(new[] {"my_guid", "b"}), Times.Once);
|
tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid", "b"}), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -123,7 +123,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var feedbackService = new Mock<IFeedbackReceiversService>();
|
var feedbackService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokens = new Mock<ITokensService>();
|
var tokens = new Mock<ITokensService>();
|
||||||
var logger = new Mock<ILogger<TokensController>>();
|
var logger = new Mock<ILogger<TokensController>>();
|
||||||
tokens.Setup(i => i.DeleteTokens(It.IsAny<IEnumerable<string>>()))
|
tokens.Setup(i => i.DeleteTokensAsync(It.IsAny<IEnumerable<string>>()))
|
||||||
.Throws(new GenericServiceException("op fail"));
|
.Throws(new GenericServiceException("op fail"));
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
|
@ -132,7 +132,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<BadRequestObjectResult>(result);
|
Assert.IsType<BadRequestObjectResult>(result);
|
||||||
tokens.Verify(i => i.DeleteTokens(new[] {"my_guid", "b"}), Times.Once);
|
tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid", "b"}), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -150,7 +150,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<OkObjectResult>(result);
|
Assert.IsType<OkObjectResult>(result);
|
||||||
tokens.Verify(i => i.ListTokens(It.IsAny<TokenListFilters>()), Times.Once);
|
tokens.Verify(i => i.FindAsync(It.IsAny<TokenListFilters>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -161,7 +161,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
var feedbackService = new Mock<IFeedbackReceiversService>();
|
var feedbackService = new Mock<IFeedbackReceiversService>();
|
||||||
var tokens = new Mock<ITokensService>();
|
var tokens = new Mock<ITokensService>();
|
||||||
var logger = new Mock<ILogger<TokensController>>();
|
var logger = new Mock<ILogger<TokensController>>();
|
||||||
tokens.Setup(i => i.ListTokens(It.IsAny<TokenListFilters>()))
|
tokens.Setup(i => i.FindAsync(It.IsAny<TokenListFilters>()))
|
||||||
.Throws(new GenericServiceException("op fail"));
|
.Throws(new GenericServiceException("op fail"));
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
|
@ -170,7 +170,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<BadRequestObjectResult>(result);
|
Assert.IsType<BadRequestObjectResult>(result);
|
||||||
tokens.Verify(i => i.ListTokens(It.IsAny<TokenListFilters>()), Times.Once);
|
tokens.Verify(i => i.FindAsync(It.IsAny<TokenListFilters>()), Times.Once);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Retroactiune.Controllers
|
|
||||||
{
|
|
||||||
public class FeedbackController : ControllerBase
|
|
||||||
{
|
|
||||||
// TODO Add feedback, list feedback, delete feedback, ged feedback.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
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;
|
||||||
|
@ -24,15 +23,17 @@ namespace Retroactiune.Controllers
|
||||||
// Note: Probably refactor this to use an Aggregate object, need to learn more about aggregates..
|
// Note: Probably refactor this to use an Aggregate object, need to learn more about aggregates..
|
||||||
private readonly IFeedbackReceiversService _feedbackReceiversService;
|
private readonly IFeedbackReceiversService _feedbackReceiversService;
|
||||||
private readonly ITokensService _tokensService;
|
private readonly ITokensService _tokensService;
|
||||||
|
private readonly IFeedbacksService _feedbacksService;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public FeedbackReceiversController(IFeedbackReceiversService feedbackReceiversService,
|
public FeedbackReceiversController(IFeedbackReceiversService feedbackReceiversService,
|
||||||
ITokensService tokensService, IMapper mapper,
|
ITokensService tokensService, IFeedbacksService feedbacksService, IMapper mapper,
|
||||||
IOptions<ApiBehaviorOptions> apiBehaviorOptions, ILogger<FeedbackReceiversController> logger)
|
IOptions<ApiBehaviorOptions> apiBehaviorOptions, ILogger<FeedbackReceiversController> logger)
|
||||||
{
|
{
|
||||||
_feedbackReceiversService = feedbackReceiversService;
|
_feedbackReceiversService = feedbackReceiversService;
|
||||||
_tokensService = tokensService;
|
_tokensService = tokensService;
|
||||||
|
_feedbacksService = feedbacksService;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
_apiBehaviorOptions = apiBehaviorOptions;
|
_apiBehaviorOptions = apiBehaviorOptions;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -59,12 +60,7 @@ namespace Retroactiune.Controllers
|
||||||
return _apiBehaviorOptions?.Value.InvalidModelStateResponseFactory(ControllerContext);
|
return _apiBehaviorOptions?.Value.InvalidModelStateResponseFactory(ControllerContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mappedItems = feedbackReceiversDto.Select(i =>
|
var mappedItems = feedbackReceiversDto.Select(i => _mapper.Map<FeedbackReceiver>(i));
|
||||||
{
|
|
||||||
var result = _mapper.Map<FeedbackReceiver>(i);
|
|
||||||
result.CreatedAt = DateTime.UtcNow;
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
|
|
||||||
await _feedbackReceiversService.CreateManyAsync(mappedItems);
|
await _feedbackReceiversService.CreateManyAsync(mappedItems);
|
||||||
|
|
||||||
|
@ -171,5 +167,57 @@ namespace Retroactiune.Controllers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add Feedback to a FeedbackReceiver.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">The guid of the FeedbackReceiver to add feedback.</param>
|
||||||
|
/// <param name="feedbackInDto">The feedback dto.</param>
|
||||||
|
/// <response code="200">The feedback has been added.</response>
|
||||||
|
/// <response code="404">The request is invalid.</response>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("{guid}/feedbacks")]
|
||||||
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
|
public async Task<IActionResult> AddFeedback(string guid, [FromBody] FeedbackInDto feedbackInDto)
|
||||||
|
{
|
||||||
|
// TODO: Unit & integration test.
|
||||||
|
var receivers = await _feedbackReceiversService.FindAsync(new[] {guid}, limit: 1);
|
||||||
|
var tokenEnum = await _tokensService.FindAsync(new TokenListFilters
|
||||||
|
{
|
||||||
|
Ids = new[] {feedbackInDto.TokenId}
|
||||||
|
});
|
||||||
|
var feedbackReceivers = receivers as FeedbackReceiver[] ?? receivers.ToArray();
|
||||||
|
var tokens = (tokenEnum as Token[] ?? tokenEnum.ToArray());
|
||||||
|
if (!feedbackReceivers.Any())
|
||||||
|
{
|
||||||
|
return BadRequest(new BasicResponse
|
||||||
|
{
|
||||||
|
Message = $"FeedbackReceiver with id {guid} not found."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens.Length == 0)
|
||||||
|
{
|
||||||
|
return BadRequest(new BasicResponse
|
||||||
|
{
|
||||||
|
Message = "Token not found."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = tokens[0];
|
||||||
|
if (!token.IsValid(feedbackReceivers[0]))
|
||||||
|
{
|
||||||
|
return BadRequest(new BasicResponse
|
||||||
|
{
|
||||||
|
Message = "Token is invalid."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var feedback = _mapper.Map<Feedback>(feedbackInDto);
|
||||||
|
await Task.WhenAll(_tokensService.MarkTokenAsUsedAsync(token),
|
||||||
|
_feedbacksService.AddFeedbackAsync(feedback, feedbackReceivers[0]));
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -45,7 +45,7 @@ namespace Retroactiune.Controllers
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tokenFilters = _mapper.Map<TokenListFilters>(filtersDto);
|
var tokenFilters = _mapper.Map<TokenListFilters>(filtersDto);
|
||||||
var response = await _tokensService.ListTokens(tokenFilters);
|
var response = await _tokensService.FindAsync(tokenFilters);
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
catch (GenericServiceException e)
|
catch (GenericServiceException e)
|
||||||
|
@ -104,7 +104,7 @@ namespace Retroactiune.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _tokensService.DeleteTokens(tokenIds);
|
await _tokensService.DeleteTokensAsync(tokenIds);
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
catch (GenericServiceException e)
|
catch (GenericServiceException e)
|
||||||
|
@ -133,7 +133,7 @@ namespace Retroactiune.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _tokensService.DeleteTokens(new[] {guid});
|
await _tokensService.DeleteTokensAsync(new[] {guid});
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
catch (GenericServiceException e)
|
catch (GenericServiceException e)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Retroactiune.DataTransferObjects
|
namespace Retroactiune.DataTransferObjects
|
||||||
{
|
{
|
||||||
|
@ -8,27 +7,12 @@ namespace Retroactiune.DataTransferObjects
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FeedbackInDto
|
public class FeedbackInDto
|
||||||
{
|
{
|
||||||
private uint _rating;
|
|
||||||
|
|
||||||
[Required, StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
[Required, StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
||||||
public string FeedbackReceiverId { get; set; }
|
public string TokenId { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required, Range(0, 5, ErrorMessage = "The rating is out of range. [0-5]")]
|
||||||
public uint Rating
|
public uint Rating { get; set; }
|
||||||
{
|
|
||||||
get => _rating;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value <= 5)
|
|
||||||
{
|
|
||||||
_rating = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Required] public string Description { get; set; }
|
[Required] public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Retroactiune
|
||||||
CreateMap<ListTokensFiltersDto, TokenListFilters>();
|
CreateMap<ListTokensFiltersDto, TokenListFilters>();
|
||||||
CreateMap<FeedbackReceiver, FeedbackReceiverInDto>().ReverseMap();
|
CreateMap<FeedbackReceiver, FeedbackReceiverInDto>().ReverseMap();
|
||||||
CreateMap<FeedbackReceiver, FeedbackReceiverOutDto>();
|
CreateMap<FeedbackReceiver, FeedbackReceiverOutDto>();
|
||||||
|
CreateMap<FeedbackInDto, Feedback>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,6 +40,7 @@ namespace Retroactiune
|
||||||
// Services
|
// Services
|
||||||
services.AddSingleton<IFeedbackReceiversService, FeedbackReceiversService>();
|
services.AddSingleton<IFeedbackReceiversService, FeedbackReceiversService>();
|
||||||
services.AddSingleton<ITokensService, TokensService>();
|
services.AddSingleton<ITokensService, TokensService>();
|
||||||
|
services.AddSingleton<IFeedbacksService, FeedbacksService>();
|
||||||
services.AddSingleton<IMongoClient, MongoClient>(i =>
|
services.AddSingleton<IMongoClient, MongoClient>(i =>
|
||||||
{
|
{
|
||||||
var settings = i.GetService<IOptions<DatabaseSettings>>();
|
var settings = i.GetService<IOptions<DatabaseSettings>>();
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace Retroactiune
|
||||||
// Services
|
// Services
|
||||||
services.AddSingleton<IFeedbackReceiversService, FeedbackReceiversService>();
|
services.AddSingleton<IFeedbackReceiversService, FeedbackReceiversService>();
|
||||||
services.AddSingleton<ITokensService, TokensService>();
|
services.AddSingleton<ITokensService, TokensService>();
|
||||||
|
services.AddSingleton<IFeedbacksService, FeedbacksService>();
|
||||||
services.AddSingleton<IMongoClient, MongoClient>(i =>
|
services.AddSingleton<IMongoClient, MongoClient>(i =>
|
||||||
{
|
{
|
||||||
var settings = i.GetService<IOptions<DatabaseSettings>>();
|
var settings = i.GetService<IOptions<DatabaseSettings>>();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"DatabaseSettings": {
|
"DatabaseSettings": {
|
||||||
"FeedbackCollectionName": "feedback",
|
"FeedbackCollectionName": "feedbacks",
|
||||||
"TokensCollectionName": "tokens",
|
"TokensCollectionName": "tokens",
|
||||||
"FeedbackReceiverCollectionName": "feedback_receiver",
|
"FeedbackReceiverCollectionName": "feedback_receivers",
|
||||||
"ConnectionString": "mongodb://localhost:27017",
|
"ConnectionString": "mongodb://localhost:27017",
|
||||||
"DatabaseName": "RetroactiuneTesting"
|
"DatabaseName": "RetroactiuneTesting"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"DatabaseSettings": {
|
"DatabaseSettings": {
|
||||||
"FeedbackCollectionName": "feedback",
|
"FeedbackCollectionName": "feedbacks",
|
||||||
"TokensCollectionName": "tokens",
|
"TokensCollectionName": "tokens",
|
||||||
"FeedbackReceiverCollectionName": "feedback_receiver",
|
"FeedbackReceiverCollectionName": "feedback_receivers",
|
||||||
"ConnectionString": "mongodb://localhost:27017",
|
"ConnectionString": "mongodb://localhost:27017",
|
||||||
"DatabaseName": "Retroactiune"
|
"DatabaseName": "Retroactiune"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue