From 398f1c7e2fc15d2fdec9c075c651b89440cd46fc Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sun, 4 Jul 2021 20:34:10 +0300 Subject: [PATCH] Implement add feedback operation in FeedbackReceiversController.cs. --- Retroactiune.Core/Entities/Feedback.cs | 27 ++++---- .../Entities/FeedbackReceiver.cs | 6 ++ Retroactiune.Core/Entities/Token.cs | 17 +++++ .../Interfaces/IFeedbacksService.cs | 17 +++++ .../Interfaces/ITokensService.cs | 12 +++- Retroactiune.Core/Retroactiune.Core.csproj | 1 + .../Services/FeedbacksService.cs | 29 ++++++++ Retroactiune.Core/Services/TokensService.cs | 19 ++++-- .../Services/TestTokensService.cs | 16 ++--- .../TestFeedbackReceiverController.cs | 32 ++++++--- .../Controllers/TestTokensController.cs | 18 ++--- .../Controllers/FeedbackController.cs | 9 --- .../FeedbackReceiversController.cs | 66 ++++++++++++++++--- .../Controllers/TokensController.cs | 6 +- .../DataTransferObjects/FeedbackInDto.cs | 30 ++------- Retroactiune.WebAPI/MappingProfile.cs | 1 + Retroactiune.WebAPI/Startup.cs | 1 + Retroactiune.WebAPI/TestingStartup.cs | 1 + Retroactiune.WebAPI/appsettings.Testing.json | 4 +- Retroactiune.WebAPI/appsettings.json | 4 +- 20 files changed, 214 insertions(+), 102 deletions(-) create mode 100644 Retroactiune.Core/Interfaces/IFeedbacksService.cs create mode 100644 Retroactiune.Core/Services/FeedbacksService.cs delete mode 100644 Retroactiune.WebAPI/Controllers/FeedbackController.cs diff --git a/Retroactiune.Core/Entities/Feedback.cs b/Retroactiune.Core/Entities/Feedback.cs index 1e1c181..3475e58 100644 --- a/Retroactiune.Core/Entities/Feedback.cs +++ b/Retroactiune.Core/Entities/Feedback.cs @@ -10,28 +10,23 @@ namespace Retroactiune.Core.Entities /// public class Feedback { - private uint _rating; + public Feedback() + { + Id = ObjectId.GenerateNewId().ToString(); + CreatedAt = DateTime.UtcNow; + } + [BsonId, JsonPropertyName("id")] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } + [JsonPropertyName("feedback_receiver_id")] + [BsonRepresentation(BsonType.ObjectId)] + public string FeedbackReceiverId { get; set; } + [JsonPropertyName("rating")] - public uint Rating - { - get => _rating; - set - { - if (value <= 5) - { - _rating = value; - } - else - { - throw new ArgumentException(); - } - } - } + public uint Rating { get; set; } [JsonPropertyName("description")] public string Description { get; set; } diff --git a/Retroactiune.Core/Entities/FeedbackReceiver.cs b/Retroactiune.Core/Entities/FeedbackReceiver.cs index 6980ea3..9245bcd 100644 --- a/Retroactiune.Core/Entities/FeedbackReceiver.cs +++ b/Retroactiune.Core/Entities/FeedbackReceiver.cs @@ -11,6 +11,12 @@ namespace Retroactiune.Core.Entities /// public class FeedbackReceiver { + public FeedbackReceiver() + { + Id = ObjectId.GenerateNewId().ToString(); + CreatedAt = DateTime.UtcNow; + } + [BsonId, JsonPropertyName("id")] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } diff --git a/Retroactiune.Core/Entities/Token.cs b/Retroactiune.Core/Entities/Token.cs index 90f75ae..702d182 100644 --- a/Retroactiune.Core/Entities/Token.cs +++ b/Retroactiune.Core/Entities/Token.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using System.Text.Json.Serialization; +using Ardalis.GuardClauses; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; @@ -12,6 +13,13 @@ namespace Retroactiune.Core.Entities /// public class Token { + + public Token() + { + Id = ObjectId.GenerateNewId().ToString(); + CreatedAt = DateTime.UtcNow; + } + [BsonId, JsonPropertyName("id")] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } @@ -41,5 +49,14 @@ namespace Retroactiune.Core.Entities { 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); + } } } \ No newline at end of file diff --git a/Retroactiune.Core/Interfaces/IFeedbacksService.cs b/Retroactiune.Core/Interfaces/IFeedbacksService.cs new file mode 100644 index 0000000..fc124d1 --- /dev/null +++ b/Retroactiune.Core/Interfaces/IFeedbacksService.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using Retroactiune.Core.Entities; + +namespace Retroactiune.Core.Interfaces +{ + public interface IFeedbacksService + { + + /// + /// Adds Feedback to a FeedbackReceiver. + /// + /// The feedback. + /// The feedback receiver. + /// + public Task AddFeedbackAsync(Feedback feedback, FeedbackReceiver receiver); + } +} \ No newline at end of file diff --git a/Retroactiune.Core/Interfaces/ITokensService.cs b/Retroactiune.Core/Interfaces/ITokensService.cs index f57d37f..5518d0b 100644 --- a/Retroactiune.Core/Interfaces/ITokensService.cs +++ b/Retroactiune.Core/Interfaces/ITokensService.cs @@ -23,14 +23,14 @@ namespace Retroactiune.Core.Interfaces /// /// A list of tokens to delete. /// The result of the delete operation. - public Task DeleteTokens(IEnumerable tokenIds); + public Task DeleteTokensAsync(IEnumerable tokenIds); /// - /// List and filters tokens. + /// Finds and filters tokens. /// /// Filters object for filtering results. /// A list of tokens matching the filters. - public Task> ListTokens(TokenListFilters filters); + public Task> FindAsync(TokenListFilters filters); /// /// Deletes tokens, by their associated FeedbackReceiverId. @@ -38,5 +38,11 @@ namespace Retroactiune.Core.Interfaces /// A list of FeedbackReceiverIDs. /// The result of the delete operation. public Task DeleteManyByFeedbackReceiverIdAsync(IEnumerable feedbackReceiverIds); + + /// + /// Marks the token as being used. + /// + /// The token. + public Task MarkTokenAsUsedAsync(Token token); } } \ No newline at end of file diff --git a/Retroactiune.Core/Retroactiune.Core.csproj b/Retroactiune.Core/Retroactiune.Core.csproj index 02f0260..792b4db 100644 --- a/Retroactiune.Core/Retroactiune.Core.csproj +++ b/Retroactiune.Core/Retroactiune.Core.csproj @@ -5,6 +5,7 @@ + diff --git a/Retroactiune.Core/Services/FeedbacksService.cs b/Retroactiune.Core/Services/FeedbacksService.cs new file mode 100644 index 0000000..6020956 --- /dev/null +++ b/Retroactiune.Core/Services/FeedbacksService.cs @@ -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 _collection; + + public FeedbacksService(IMongoClient client, IDatabaseSettings settings) + { + var database = client.GetDatabase(settings.DatabaseName); + _collection = database.GetCollection(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); + } + } +} \ No newline at end of file diff --git a/Retroactiune.Core/Services/TokensService.cs b/Retroactiune.Core/Services/TokensService.cs index 5257e78..6ad22c4 100644 --- a/Retroactiune.Core/Services/TokensService.cs +++ b/Retroactiune.Core/Services/TokensService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ardalis.GuardClauses; using MongoDB.Driver; using Retroactiune.Core.Entities; using Retroactiune.Core.Interfaces; @@ -21,10 +22,7 @@ namespace Retroactiune.Core.Services public async Task GenerateTokensAsync(int numberOfTokens, string feedbackReceiverGuid, DateTime? expiryTime = null) { - if (numberOfTokens <= 0) - { - throw new ArgumentException("numberOfTokens must be positive"); - } + Guard.Against.Negative(numberOfTokens, nameof(numberOfTokens)); var token = new List(); for (var i = 0; i < numberOfTokens; i++) @@ -41,7 +39,7 @@ namespace Retroactiune.Core.Services await _collection.InsertManyAsync(token); } - public async Task DeleteTokens(IEnumerable tokenIds) + public async Task DeleteTokensAsync(IEnumerable tokenIds) { try { @@ -54,7 +52,7 @@ namespace Retroactiune.Core.Services } } - public async Task> ListTokens(TokenListFilters filters) + public async Task> FindAsync(TokenListFilters filters) { var filterBuilder = new FilterDefinitionBuilder(); var activeFilters = new List>(); @@ -119,5 +117,14 @@ namespace Retroactiune.Core.Services throw new GenericServiceException($"Operation failed: {e.Message} {e.StackTrace}"); } } + + public async Task MarkTokenAsUsedAsync(Token token) + { + // TODO: Unit test. + var filterBuilder = new FilterDefinitionBuilder(); + var updateBuilder = new UpdateDefinitionBuilder(); + await _collection.UpdateOneAsync(filterBuilder.Eq(i => i.Id, token.Id), + updateBuilder.Set(i => i.TimeUsed, DateTime.UtcNow)); + } } } \ No newline at end of file diff --git a/Retroactiune.UnitTests/Retroactiune.Core/Services/TestTokensService.cs b/Retroactiune.UnitTests/Retroactiune.Core/Services/TestTokensService.cs index 001fec4..a69e1ea 100644 --- a/Retroactiune.UnitTests/Retroactiune.Core/Services/TestTokensService.cs +++ b/Retroactiune.UnitTests/Retroactiune.Core/Services/TestTokensService.cs @@ -68,16 +68,8 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services await service.GenerateTokensAsync(3, "Hello", expiryTime); // Assert - var item = new Token - { - Id = null, - ExpiryTime = expiryTime, - TimeUsed = null, - FeedbackReceiverId = "Hello", - CreatedAt = expiryTime - }; mongoCollectionMock.Verify( - i => i.InsertManyAsync(new[] {item, item, item}, + i => i.InsertManyAsync(It.IsAny>(), It.IsAny(), It.IsAny()), Times.Once); } @@ -106,7 +98,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services // Test var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object); - await service.DeleteTokens(new[] {"test_id"}); + await service.DeleteTokensAsync(new[] {"test_id"}); // Assert mongoCollectionMock.Verify( @@ -145,7 +137,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services // Test var service = new TokensService(mongoClientMock.Object, mongoSettingsMock.Object); - var result = await service.ListTokens(new TokenListFilters()); + var result = await service.FindAsync(new TokenListFilters()); // Assert Assert.IsType>(result); @@ -185,7 +177,7 @@ namespace Retroactiune.Tests.Retroactiune.Core.Services // Test 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"}, FeedbackReceiverId = "abc", diff --git a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs index d159e05..624bac0 100644 --- a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs +++ b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestFeedbackReceiverController.cs @@ -23,10 +23,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var mapper = TestUtils.GetMapper(); var mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); // 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); var result = await controller.Post(new List()); @@ -42,10 +44,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var mapper = TestUtils.GetMapper(); var mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); // 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); var result = await controller.Post(items); @@ -61,10 +65,12 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var mapper = TestUtils.GetMapper(); var mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); // 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); 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 mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); // 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); var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"}; var result = await controller.DeleteMany(items); @@ -106,12 +114,14 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var mapper = TestUtils.GetMapper(); var mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); mockService.Setup(i => i.DeleteManyAsync(It.IsAny>())) .ThrowsAsync(new GenericServiceException("op failed")); // 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); var items = new[] {"bad_guid_but_unit_test_works_cause_validation_doesnt", "2", "3"}; var result = await controller.DeleteMany(items); @@ -129,12 +139,14 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var mapper = TestUtils.GetMapper(); var mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = 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, tokensService.Object, mapper, null, + var controller = new FeedbackReceiversController(mockService.Object, tokensService.Object, + feedbacksService.Object, mapper, null, logger.Object); 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 mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); // 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); 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 mockService = new Mock(); var tokensService = new Mock(); + var feedbacksService = new Mock(); var logger = new Mock>(); var filterArr = filter as string[] ?? filter.ToArray(); // 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); var result = await controller.List(filterArr, offset, limit); diff --git a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs index 5d29719..0722866 100644 --- a/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs +++ b/Retroactiune.UnitTests/Retroactiune.WebAPI/Controllers/TestTokensController.cs @@ -74,7 +74,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.DeleteTokens(new[] {"my_guid"}), Times.Once); + tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid"}), Times.Once); } [Fact] @@ -85,7 +85,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var feedbackService = new Mock(); var tokens = new Mock(); var logger = new Mock>(); - tokens.Setup(i => i.DeleteTokens(It.IsAny>())) + tokens.Setup(i => i.DeleteTokensAsync(It.IsAny>())) .Throws(new GenericServiceException("op fail")); // Test @@ -94,7 +94,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.DeleteTokens(new[] {"my_guid"}), Times.Once); + tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid"}), Times.Once); } [Fact] @@ -112,7 +112,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.DeleteTokens(new[] {"my_guid", "b"}), Times.Once); + tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid", "b"}), Times.Once); } [Fact] @@ -123,7 +123,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var feedbackService = new Mock(); var tokens = new Mock(); var logger = new Mock>(); - tokens.Setup(i => i.DeleteTokens(It.IsAny>())) + tokens.Setup(i => i.DeleteTokensAsync(It.IsAny>())) .Throws(new GenericServiceException("op fail")); // Test @@ -132,7 +132,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.DeleteTokens(new[] {"my_guid", "b"}), Times.Once); + tokens.Verify(i => i.DeleteTokensAsync(new[] {"my_guid", "b"}), Times.Once); } [Fact] @@ -150,7 +150,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.ListTokens(It.IsAny()), Times.Once); + tokens.Verify(i => i.FindAsync(It.IsAny()), Times.Once); } [Fact] @@ -161,7 +161,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers var feedbackService = new Mock(); var tokens = new Mock(); var logger = new Mock>(); - tokens.Setup(i => i.ListTokens(It.IsAny())) + tokens.Setup(i => i.FindAsync(It.IsAny())) .Throws(new GenericServiceException("op fail")); // Test @@ -170,7 +170,7 @@ namespace Retroactiune.Tests.Retroactiune.WebAPI.Controllers // Assert Assert.IsType(result); - tokens.Verify(i => i.ListTokens(It.IsAny()), Times.Once); + tokens.Verify(i => i.FindAsync(It.IsAny()), Times.Once); } } } \ No newline at end of file diff --git a/Retroactiune.WebAPI/Controllers/FeedbackController.cs b/Retroactiune.WebAPI/Controllers/FeedbackController.cs deleted file mode 100644 index 1d7e1f1..0000000 --- a/Retroactiune.WebAPI/Controllers/FeedbackController.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace Retroactiune.Controllers -{ - public class FeedbackController : ControllerBase - { - // TODO Add feedback, list feedback, delete feedback, ged feedback. - } -} \ No newline at end of file diff --git a/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs b/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs index 340c3d4..0b519d3 100644 --- a/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs +++ b/Retroactiune.WebAPI/Controllers/FeedbackReceiversController.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; 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.. private readonly IFeedbackReceiversService _feedbackReceiversService; private readonly ITokensService _tokensService; + private readonly IFeedbacksService _feedbacksService; private readonly IMapper _mapper; private readonly ILogger _logger; public FeedbackReceiversController(IFeedbackReceiversService feedbackReceiversService, - ITokensService tokensService, IMapper mapper, + ITokensService tokensService, IFeedbacksService feedbacksService, IMapper mapper, IOptions apiBehaviorOptions, ILogger logger) { _feedbackReceiversService = feedbackReceiversService; _tokensService = tokensService; + _feedbacksService = feedbacksService; _mapper = mapper; _apiBehaviorOptions = apiBehaviorOptions; _logger = logger; @@ -59,12 +60,7 @@ namespace Retroactiune.Controllers return _apiBehaviorOptions?.Value.InvalidModelStateResponseFactory(ControllerContext); } - var mappedItems = feedbackReceiversDto.Select(i => - { - var result = _mapper.Map(i); - result.CreatedAt = DateTime.UtcNow; - return result; - }); + var mappedItems = feedbackReceiversDto.Select(i => _mapper.Map(i)); await _feedbackReceiversService.CreateManyAsync(mappedItems); @@ -171,5 +167,57 @@ namespace Retroactiune.Controllers }); } } + + /// + /// Add Feedback to a FeedbackReceiver. + /// + /// The guid of the FeedbackReceiver to add feedback. + /// The feedback dto. + /// The feedback has been added. + /// The request is invalid. + /// + [HttpPost("{guid}/feedbacks")] + [ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)] + public async Task 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(feedbackInDto); + await Task.WhenAll(_tokensService.MarkTokenAsUsedAsync(token), + _feedbacksService.AddFeedbackAsync(feedback, feedbackReceivers[0])); + return Ok(); + } } } \ No newline at end of file diff --git a/Retroactiune.WebAPI/Controllers/TokensController.cs b/Retroactiune.WebAPI/Controllers/TokensController.cs index d12a116..a50a5e7 100644 --- a/Retroactiune.WebAPI/Controllers/TokensController.cs +++ b/Retroactiune.WebAPI/Controllers/TokensController.cs @@ -45,7 +45,7 @@ namespace Retroactiune.Controllers try { var tokenFilters = _mapper.Map(filtersDto); - var response = await _tokensService.ListTokens(tokenFilters); + var response = await _tokensService.FindAsync(tokenFilters); return Ok(response); } catch (GenericServiceException e) @@ -104,7 +104,7 @@ namespace Retroactiune.Controllers { try { - await _tokensService.DeleteTokens(tokenIds); + await _tokensService.DeleteTokensAsync(tokenIds); return NoContent(); } catch (GenericServiceException e) @@ -133,7 +133,7 @@ namespace Retroactiune.Controllers { try { - await _tokensService.DeleteTokens(new[] {guid}); + await _tokensService.DeleteTokensAsync(new[] {guid}); return NoContent(); } catch (GenericServiceException e) diff --git a/Retroactiune.WebAPI/DataTransferObjects/FeedbackInDto.cs b/Retroactiune.WebAPI/DataTransferObjects/FeedbackInDto.cs index 63c7ca0..5e53702 100644 --- a/Retroactiune.WebAPI/DataTransferObjects/FeedbackInDto.cs +++ b/Retroactiune.WebAPI/DataTransferObjects/FeedbackInDto.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace Retroactiune.DataTransferObjects { @@ -8,27 +7,12 @@ namespace Retroactiune.DataTransferObjects /// public class FeedbackInDto { - private uint _rating; - - [Required, StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)] - public string FeedbackReceiverId { get; set; } - - [Required] - public uint Rating - { - get => _rating; - set - { - if (value <= 5) - { - _rating = value; - } - else - { - throw new ArgumentException(); - } - } - } + + [Required, StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)] + public string TokenId { get; set; } + + [Required, Range(0, 5, ErrorMessage = "The rating is out of range. [0-5]")] + public uint Rating { get; set; } [Required] public string Description { get; set; } } diff --git a/Retroactiune.WebAPI/MappingProfile.cs b/Retroactiune.WebAPI/MappingProfile.cs index c3e5a07..0f9a54a 100644 --- a/Retroactiune.WebAPI/MappingProfile.cs +++ b/Retroactiune.WebAPI/MappingProfile.cs @@ -12,6 +12,7 @@ namespace Retroactiune CreateMap(); CreateMap().ReverseMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/Retroactiune.WebAPI/Startup.cs b/Retroactiune.WebAPI/Startup.cs index 61a5e6a..c877a75 100644 --- a/Retroactiune.WebAPI/Startup.cs +++ b/Retroactiune.WebAPI/Startup.cs @@ -40,6 +40,7 @@ namespace Retroactiune // Services services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(i => { var settings = i.GetService>(); diff --git a/Retroactiune.WebAPI/TestingStartup.cs b/Retroactiune.WebAPI/TestingStartup.cs index 0a3b32d..b33feaf 100644 --- a/Retroactiune.WebAPI/TestingStartup.cs +++ b/Retroactiune.WebAPI/TestingStartup.cs @@ -36,6 +36,7 @@ namespace Retroactiune // Services services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(i => { var settings = i.GetService>(); diff --git a/Retroactiune.WebAPI/appsettings.Testing.json b/Retroactiune.WebAPI/appsettings.Testing.json index ddce3c1..a9d7170 100644 --- a/Retroactiune.WebAPI/appsettings.Testing.json +++ b/Retroactiune.WebAPI/appsettings.Testing.json @@ -1,8 +1,8 @@ { "DatabaseSettings": { - "FeedbackCollectionName": "feedback", + "FeedbackCollectionName": "feedbacks", "TokensCollectionName": "tokens", - "FeedbackReceiverCollectionName": "feedback_receiver", + "FeedbackReceiverCollectionName": "feedback_receivers", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "RetroactiuneTesting" } diff --git a/Retroactiune.WebAPI/appsettings.json b/Retroactiune.WebAPI/appsettings.json index 115992e..7415215 100644 --- a/Retroactiune.WebAPI/appsettings.json +++ b/Retroactiune.WebAPI/appsettings.json @@ -1,8 +1,8 @@ { "DatabaseSettings": { - "FeedbackCollectionName": "feedback", + "FeedbackCollectionName": "feedbacks", "TokensCollectionName": "tokens", - "FeedbackReceiverCollectionName": "feedback_receiver", + "FeedbackReceiverCollectionName": "feedback_receivers", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "Retroactiune" },