diff --git a/OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/AchievementControllerTest.cs b/OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/AchievementControllerTest.cs new file mode 100644 index 0000000000..f725264b98 --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/AchievementControllerTest.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Moq; +using NUnit.Framework; +using OutOfSchool.WebApi.Controllers.V1; +using OutOfSchool.WebApi.Models; +using OutOfSchool.WebApi.Models.Achievement; +using OutOfSchool.WebApi.Services; + +namespace OutOfSchool.WebApi.Tests.Controllers; + +[TestFixture] +internal class AchievementControllerTest +{ + private AchievementController controller; + private Mock achievementService; + private Mock providerService; + private Mock providerAdminService; + private Mock workshopService; + + [SetUp] + public void Setup() + { + achievementService = new Mock(); + providerService = new Mock(); + providerAdminService = new Mock(); + workshopService = new Mock(); + + controller = new AchievementController(achievementService.Object, providerService.Object, providerAdminService.Object, workshopService.Object); + } + + [Test] + public async Task GetByWorkshopId_Valid_ReturnsOkObject() + { + // Arrange + achievementService.Setup(a => a.GetByFilter(It.IsAny())).ReturnsAsync(SearchResult()); + + // Act + var result = await controller.GetByWorkshopId(It.IsAny()).ConfigureAwait(false) as OkObjectResult; + var resultValue = result.Value as SearchResult; + + // Assert + Assert.That(result, Is.Not.Null); + Assert.AreEqual(200, result.StatusCode); + Assert.AreEqual(10, resultValue.TotalAmount); + Assert.AreEqual(6, resultValue.Entities.Count); + } + + [Test] + public async Task GetByWorkshopId_NotValid_RetunsNoCententResult() + { + // Arrange + achievementService.Setup(a => a.GetByFilter(It.IsAny())).ReturnsAsync(new SearchResult()); + + var result = await controller.GetByWorkshopId(It.IsAny()).ConfigureAwait(false) as NoContentResult; + + Assert.That(result, Is.Not.Null); + Assert.AreEqual(204, result.StatusCode); + } + + private static SearchResult SearchResult() + { + return new SearchResult + { + TotalAmount = 10, + Entities = new List() + { + new AchievementDto(), + new AchievementDto(), + new AchievementDto(), + new AchievementDto(), + new AchievementDto(), + new AchievementDto(), + }, + }; + } +} diff --git a/OutOfSchool/OutOfSchool.WebApi.Tests/Services/AchievementServiceTest.cs b/OutOfSchool/OutOfSchool.WebApi.Tests/Services/AchievementServiceTest.cs new file mode 100644 index 0000000000..75c7e65f2f --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi.Tests/Services/AchievementServiceTest.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using OutOfSchool.Services; +using OutOfSchool.Services.Enums; +using OutOfSchool.Services.Models; +using OutOfSchool.Services.Repository; +using OutOfSchool.Tests.Common; +using OutOfSchool.WebApi.Models; +using OutOfSchool.WebApi.Models.Achievement; +using OutOfSchool.WebApi.Services; + +namespace OutOfSchool.WebApi.Tests.Services; + +[TestFixture] +public class AchievementServiceTest +{ + private readonly Guid validWorkshopGuid = new Guid("08da8474-a754-4d37-879e-4932d389b27a"); + private readonly Guid notValidWorkshopGuid = new Guid("05da8774-d754-1d37-979e-4135d389c27a"); + private DbContextOptions options; + private OutOfSchoolDbContext context; + private AchievementService service; + private IAchievementRepository achievementRepository; + private Mock> logger; + private Mock> localizer; + private IMapper mapper; + + [SetUp] + public void SetUp() + { + var builder = + new DbContextOptionsBuilder().UseInMemoryDatabase( + databaseName: "OutOfSchoolTestDB"); + + options = builder.Options; + context = new OutOfSchoolDbContext(options); + + achievementRepository = new AchievementRepository(context); + logger = new Mock>(); + localizer = new Mock>(); + mapper = TestHelper.CreateMapperInstanceOfProfileType(); + service = new AchievementService(achievementRepository, logger.Object, localizer.Object, mapper); + + SeedDatabase(); + } + + [Test] + public async Task GetByFilter_Valid_ReturnsSearchResult() + { + // Arrange + var expected = Achievements(); + var filter = new AchievementsFilter() { WorkshopId = validWorkshopGuid }; + + // Act + var result = await service.GetByFilter(filter); + + // Assert + Assert.IsNotNull(result.Entities); + Assert.AreEqual(expected.First().Id, result.Entities.First().Id); + Assert.AreEqual(expected.Count, result.TotalAmount); + Assert.IsInstanceOf>(result.Entities); + } + + [Test] + public async Task GetByFilter_NotValidWorkshopId_ReturnsEmpty() + { + // Arrange + var expexted = new List(); + var filter = new AchievementsFilter() { WorkshopId = notValidWorkshopGuid }; + + // Act + var result = await service.GetByFilter(filter); + + // Assert + Assert.That(result.Entities, Is.Empty); + Assert.AreEqual(result.TotalAmount, expexted.Count); + } + + private void SeedDatabase() + { + using var ctx = new OutOfSchoolDbContext(options); + { + ctx.Database.EnsureDeleted(); + ctx.Database.EnsureCreated(); + + ctx.Achievements.AddRange(Achievements()); + + ctx.SaveChanges(); + } + } + + private List Achievements() + { + return new List() + { + new Achievement() + { + AchievementDate = DateTime.Now, + AchievementTypeId = 1, + Id = validWorkshopGuid, + WorkshopId = new Guid("08da8474-a754-4d37-879e-4932d389b27a"), + Title = "Назва1", + Children = new List() + { + new Child + { + DateOfBirth = DateTime.Now, + FirstName = "Арієль", + Gender = Gender.Female, + Id = new Guid("0d3a847c-2f7a-482f-89f2-417b98c6d02a"), + IsParent = true, + LastName = "Русалонька", + MiddleName = "Моряка", + Parent = new Parent + { + User = new User + { + Email = "sea@gmail.com", + FirstName = "Арієль", + Id = "08da847c-2f6d-4327-8184-b1a11c8f7008", + LastName = "Русалонька", + MiddleName = "Моряка", + PhoneNumber = "498344943", + }, + Gender = Gender.Female, + DateOfBirth = DateTime.Now, + UserId = "06da847c-2f6d-4327-8184-b1a11c8f7008", + Id = new Guid("05da847c-2f6d-4327-8184-b1a11c8f7008"), + }, + ParentId = new Guid("05da847c-2f6d-4327-8184-b1a11c8f7008"), + PlaceOfStudy = null, + SocialGroups = new List(), + }, + new Child() + { + DateOfBirth = DateTime.Now, + FirstName = "Валентина", + Gender = Gender.Female, + Id = new Guid("08da8b0f-fccd-496a-8288-b02729234229"), + IsParent = true, + LastName = "Русалонька", + MiddleName = "Моряка", + Parent = new Parent + { + User = new User + { + Email = "sea@gmail.com", + FirstName = "Арієль", + Id = "09da847c-2f6d-5327-8184-b1a11c8f7808", + LastName = "Русалонька", + MiddleName = "Моряка", + PhoneNumber = "498344943", + }, + Gender = Gender.Female, + DateOfBirth = DateTime.Now, + UserId = "09da847c-2f6d-5327-8184-b1a11c8f7808", + Id = new Guid("09da847c-2f6d-5327-8184-b1a11c8f7808"), + }, + ParentId = new Guid("09da847c-2f6d-5327-8184-b1a11c8f7808"), + PlaceOfStudy = null, + SocialGroups = new List(), + }, + }, + }, + new Achievement() + { + AchievementDate = DateTime.Now, + AchievementTypeId = 1, + WorkshopId = validWorkshopGuid, + Id = new Guid("08da8b47-f4c8-46f7-8376-3aa4d947a1e1"), + Title = "Назва2", + Children = new List() + { + new Child + { + DateOfBirth = DateTime.Now, + FirstName = "Арієль", + Gender = Gender.Female, + Id = new Guid("08da847c-2f7a-482f-89f2-417b98c6d02a"), + IsParent = true, + LastName = "Русалонька", + MiddleName = "Моряка", + Parent = new Parent + { + User = new User + { + Email = "sea@gmail.com", + FirstName = "Арієль", + Id = "06da847c-2f6d-4327-8184-b1a11c8f7008", + LastName = "Русалонька", + MiddleName = "Моряка", + PhoneNumber = "498344943", + }, + Gender = Gender.Female, + DateOfBirth = DateTime.Now, + UserId = "06da847c-2f6d-4327-8184-b1a11c8f7008", + Id = new Guid("02da847c-2f6d-4327-8184-b1a11c8f7008"), + }, + ParentId = new Guid("02da847c-2f6d-4327-8184-b1a11c8f7008"), + PlaceOfStudy = null, + SocialGroups = new List(), + }, + new Child() + { + DateOfBirth = DateTime.Now, + FirstName = "Валентина", + Gender = Gender.Female, + Id = new Guid("08da8b0f-fccd-436a-8288-b02829234229"), + IsParent = true, + LastName = "Русалонька", + MiddleName = "Моряка", + Parent = new Parent + { + User = new User + { + Email = "sea@gmail.com", + FirstName = "Арієль", + Id = "03da847c-2f6d-4327-8184-b1a11c8f7008", + LastName = "Русалонька", + MiddleName = "Моряка", + PhoneNumber = "498344943", + }, + DateOfBirth = DateTime.Now, + Gender = Gender.Female, + UserId = "578b8827-9985-4839-a3ab-258abef30a54", + }, + ParentId = new Guid("03da847c-2f6d-4327-8184-b1a11c8f7008"), + PlaceOfStudy = null, + SocialGroups = new List(), + }, + }, + }, + }; + } +} diff --git a/OutOfSchool/OutOfSchool.WebApi/Controllers/V1/AchievementController.cs b/OutOfSchool/OutOfSchool.WebApi/Controllers/V1/AchievementController.cs index 5155f64d01..3556ec3ea2 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Controllers/V1/AchievementController.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Controllers/V1/AchievementController.cs @@ -1,7 +1,6 @@ using System.Net.Mime; using Microsoft.AspNetCore.Mvc; using OutOfSchool.Services.Enums; -using OutOfSchool.Services.Models; using OutOfSchool.WebApi.Common; using OutOfSchool.WebApi.Models; using OutOfSchool.WebApi.Models.Achievement; @@ -60,19 +59,20 @@ public async Task GetById(Guid id) /// /// To recieve the Achievement list by Workshop id. /// - /// Key of the Workshop in the table. - /// List of achievements. + /// Entity that represents searching parameters. + /// . /// The entity was found by given Id. /// If any server error occures. For example: Id was wrong. [AllowAnonymous] - [HttpGet("{workshopId}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SearchResult))] + [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetByWorkshopId(Guid workshopId) + public async Task GetByWorkshopId([FromQuery] AchievementsFilter filter) { - var achievements = await achievementService.GetByWorkshopId(workshopId).ConfigureAwait(false); + var achievements = await achievementService.GetByFilter(filter).ConfigureAwait(false); - if (!achievements.Any()) + if (achievements.TotalAmount < 1) { return NoContent(); } @@ -106,7 +106,7 @@ public async Task Create(AchievementCreateDTO achievementDto) } var userHasRights = await this.IsUserProvidersOwnerOrAdmin(achievementDto.WorkshopId).ConfigureAwait(false); - + if (!userHasRights) { return StatusCode(403, "Forbidden to create achievement for another providers."); diff --git a/OutOfSchool/OutOfSchool.WebApi/Models/Achievement/AchivementsFilter.cs b/OutOfSchool/OutOfSchool.WebApi/Models/Achievement/AchivementsFilter.cs new file mode 100644 index 0000000000..5926b0c080 --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi/Models/Achievement/AchivementsFilter.cs @@ -0,0 +1,6 @@ +namespace OutOfSchool.WebApi.Models.Achievement; + +public class AchievementsFilter : SearchStringFilter +{ + public Guid WorkshopId { get; set; } = Guid.Empty; +} diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/AchievementService.cs b/OutOfSchool/OutOfSchool.WebApi/Services/AchievementService.cs index d8073ca346..2b5c963c1e 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/AchievementService.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/AchievementService.cs @@ -1,23 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper; -using Microsoft.EntityFrameworkCore; +using AutoMapper; using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; -using OutOfSchool.Services; -using OutOfSchool.Services.Models; -using OutOfSchool.Services.Repository; -using OutOfSchool.WebApi.Common; -using OutOfSchool.WebApi.Extensions; using OutOfSchool.WebApi.Models; using OutOfSchool.WebApi.Models.Achievement; -using OutOfSchool.WebApi.Util; namespace OutOfSchool.WebApi.Services; -public class AchievementService: IAchievementService +public class AchievementService : IAchievementService { private readonly IAchievementRepository achievementRepository; private readonly ILogger logger; @@ -63,17 +51,44 @@ public async Task GetById(Guid id) } /// - public async Task> GetByWorkshopId(Guid id) + public async Task> GetByFilter(AchievementsFilter filter) { - logger.LogInformation("Getting all Achievements by Workshop Id started."); + logger.LogInformation("Getting all Achievements started (by filter)"); - var achievements = await achievementRepository.GetByWorkshopId(id).ConfigureAwait(false); + filter ??= new AchievementsFilter(); + ModelValidationHelper.ValidateOffsetFilter(filter); + + var predicate = PredicateBuilder.True(); + + if (filter.WorkshopId != Guid.Empty) + { + predicate = predicate.And(a => a.WorkshopId == filter.WorkshopId); + } + + int count = await achievementRepository.Count(predicate).ConfigureAwait(false); + + var achievements = await achievementRepository + .Get( + skip: filter.From, + take: filter.Size, + includeProperties: "Children", + where: predicate) + .ToListAsync() + .ConfigureAwait(false); logger.LogInformation(!achievements.Any() ? "This Workshop has no achievements." - : $"All {achievements.Count()} records were successfully received"); + : $"All {achievements.Count} records were successfully received"); + + var achievementsDto = achievements.Select(achievement => mapper.Map(achievement)).ToList(); + + var result = new SearchResult() + { + TotalAmount = count, + Entities = achievementsDto, + }; - return mapper.Map>(achievements); + return result; } /// diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/IAchievementService.cs b/OutOfSchool/OutOfSchool.WebApi/Services/IAchievementService.cs index e09051ab6e..ee4a91941c 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/IAchievementService.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/IAchievementService.cs @@ -22,11 +22,12 @@ public interface IAchievementService Task GetById(Guid id); /// - /// To recieve all Achievement objects by Workshop id. + /// Get all Achievement objects that match filter's parameters. /// - /// Workshop Key in the table. - /// List of Achievement objects. - Task> GetByWorkshopId(Guid id); + /// Filter with specified searching parametrs. + /// A representing the result of the asybcronous operation. + /// The task result contains a that contains found elements. + Task> GetByFilter(AchievementsFilter filter); /// /// Add new Achievement to the DB.