Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kymachynskyi / Add number of unreaded messages on workshop card #1205

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using OutOfSchool.Services.Models;
using OutOfSchool.Services.Models.ChatWorkshop;

namespace OutOfSchool.Services.Repository;

public class ChatMessageRepository : SensitiveEntityRepository<ChatMessageWorkshop>, IChatMessageRepository
{
public ChatMessageRepository(OutOfSchoolDbContext dbContext)
: base(dbContext)
{
}

public Task<int> CountUnreadMessagesAsync(Guid workshopId)
{
return dbContext.ChatMessageWorkshops
.Include(chr => chr.ChatRoom)
.Where(x => x.ChatRoom.WorkshopId == workshopId && x.ReadDateTime == null && !x.SenderRoleIsProvider)
.CountAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OutOfSchool.Services.Models.ChatWorkshop;

namespace OutOfSchool.Services.Repository;

public interface IChatMessageRepository : ISensitiveEntityRepository<ChatMessageWorkshop>
{
/// <summary>
/// Get a number of unread ChatMessages with specified WorkshopId.
/// </summary>
/// <param name="workshopId">Workshop's key.</param>
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation. The task result contains a <see cref="int"/> that contains the number of unread messages for the specified Workshop.</returns>
Task<int> CountUnreadMessagesAsync(Guid workshopId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class WorkshopControllerTests
private string userId;
private Mock<HttpContext> httpContextMoq;
private List<WorkshopBaseCard> workshopBaseCards;
private List<WorkshopProviderViewCard> workshopProviderViewCards;
private List<ShortEntityDto> workshopShortEntitiesList;
private List<WorkshopProviderViewCard> workshopProviderViewCardList;

Expand All @@ -65,6 +66,8 @@ public void OneTimeSetup()
provider = WithProvider();
workshopCards = WithWorkshopCards();
workshopBaseCards = WorkshopBaseCardGenerator.Generate(5);
workshopProviderViewCards = WorkshopProviderViewCardGenerator.Generate(5);

workshopShortEntitiesList = ShortEntityDtoGenerator.Generate(10);
workshopProviderViewCardList = WithWorkshopProviderViewCards();

Expand Down Expand Up @@ -132,8 +135,8 @@ public async Task GetByProviderId_WhenThereAreWorkshops_ShouldReturnOkResultObje
{
// Arrange
var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue };
var searchResult = new SearchResult<WorkshopBaseCard>() { TotalAmount = 5, Entities = workshopBaseCards };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopBaseCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 5, Entities = workshopProviderViewCards };
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(searchResult);

// Act
Expand All @@ -143,16 +146,16 @@ public async Task GetByProviderId_WhenThereAreWorkshops_ShouldReturnOkResultObje
workshopServiceMoq.VerifyAll();
Assert.That(result, Is.Not.Null);
Assert.AreEqual(Ok, result.StatusCode);
Assert.AreEqual(workshops.Count, (result.Value as SearchResult<WorkshopBaseCard>).TotalAmount);
Assert.AreEqual(workshops.Count, (result.Value as SearchResult<WorkshopProviderViewCard>).TotalAmount);
}

[Test]
public async Task GetByProviderId_WhenThereIsNoWorkshops_ShouldReturnNoContentResult([Random(uint.MinValue, uint.MaxValue, 1)] long randomNumber)
{
// Arrange
var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue };
var emptySearchResult = new SearchResult<WorkshopBaseCard>() { TotalAmount = 0, Entities = new List<WorkshopBaseCard>() };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopBaseCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
var emptySearchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 0, Entities = new List<WorkshopProviderViewCard>() };
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(emptySearchResult);

// Act
Expand Down Expand Up @@ -182,8 +185,8 @@ public async Task GetByProviderId_WhenThereIsExcludedId_ShouldReturnOkResultObje
var expectedWorkshopCount = workshopBaseCards.Count - 1;
var excludedId = workshopBaseCards.FirstOrDefault().WorkshopId;
var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue, ExcludedId = excludedId };
var searchResult = new SearchResult<WorkshopBaseCard>() { TotalAmount = 4, Entities = workshopBaseCards.Skip(1).ToList() };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopBaseCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 4, Entities = workshopProviderViewCards.Skip(1).ToList() };
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(searchResult);

// Act
Expand All @@ -193,7 +196,7 @@ public async Task GetByProviderId_WhenThereIsExcludedId_ShouldReturnOkResultObje
workshopServiceMoq.VerifyAll();
Assert.That(result, Is.Not.Null);
Assert.AreEqual(Ok, result.StatusCode);
Assert.AreEqual(expectedWorkshopCount, (result.Value as SearchResult<WorkshopBaseCard>).TotalAmount);
Assert.AreEqual(expectedWorkshopCount, (result.Value as SearchResult<WorkshopProviderViewCard>).TotalAmount);
}

#endregion
Expand Down Expand Up @@ -323,8 +326,8 @@ public async Task GetWorkshopProviderViewCardsByProviderId_WhenThereAreWorkshops
{
// Arrange
var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue };
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 5, Entities = workshopProviderViewCardList };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopProviderViewCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 5, Entities = workshopProviderViewCards };
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(searchResult);

// Act
Expand All @@ -343,7 +346,7 @@ public async Task GetWorkshopProviderViewCardsByProviderId_WhenThereIsNoWorkshop
// Arrange
var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue };
var emptySearchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = 0, Entities = new List<WorkshopProviderViewCard>() };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopProviderViewCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(emptySearchResult);

// Act
Expand All @@ -363,7 +366,7 @@ public async Task GetWorkshopProviderViewCardsByProviderId_WhenSizeFilterIsProvi
var filter = new ExcludeIdFilter() { From = 0, Size = expectedCount };
var expectedTotalAmount = 5;
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = expectedTotalAmount, Entities = workshopProviderViewCardList.Take(expectedCount).ToList() };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopProviderViewCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(searchResult);

// Act
Expand All @@ -387,7 +390,7 @@ public async Task GetWorkshopProviderViewCardsByProviderId_WhenFromFilterIsProvi
var expectedResult = workshopProviderViewCardList.Skip(skipCount).Take(expectedCount).ToList();
var filter = new ExcludeIdFilter() { From = skipCount, Size = expectedCount };
var searchResult = new SearchResult<WorkshopProviderViewCard>() { TotalAmount = expectedTotalAmount, Entities = expectedResult };
workshopServiceMoq.Setup(x => x.GetByProviderId<WorkshopProviderViewCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
workshopServiceMoq.Setup(x => x.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()))
.ReturnsAsync(searchResult);

// Act
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class ChatMessageWorkshopServiceTests
WorkshopId = Guid.NewGuid(),
};

private IEntityRepository<Guid, ChatMessageWorkshop> messageRepository;
private IChatMessageRepository messageRepository;
private Mock<IChatRoomWorkshopService> roomServiceMock;
private Mock<IHubContext<ChatWorkshopHub>> workshopHub;
private Mock<ILogger<ChatMessageWorkshopService>> loggerMock;
Expand All @@ -60,7 +60,7 @@ public void SetUp()
options = builder.Options;
dbContext = new OutOfSchoolDbContext(options);

messageRepository = new EntityRepository<Guid, ChatMessageWorkshop>(dbContext);
messageRepository = new ChatMessageRepository(dbContext);
roomServiceMock = new Mock<IChatRoomWorkshopService>();
workshopHub = new Mock<IHubContext<ChatWorkshopHub>>();
loggerMock = new Mock<ILogger<ChatMessageWorkshopService>>();
Expand Down Expand Up @@ -195,6 +195,51 @@ public async Task GetMessagesForChatRoomAndSetReadDateTimeIfItIsNullAsync_WhenCa
}
#endregion

#region CountUnreadMessagesAsync
[Test]
public async Task CountUnreadMessagesAsync_WhenCalledWithValidWorkshopId_ShouldReturnNumberOfUnreadMessages()
{
// Arrange
var workshopId = Guid.NewGuid();
int expectedUnreadMessages = 7;
var messageRepositoryMock = new Mock<IChatMessageRepository>();
messageRepositoryMock.Setup(x => x.CountUnreadMessagesAsync(workshopId)).Returns(Task.FromResult(expectedUnreadMessages));
var messageService = new ChatMessageWorkshopService(
messageRepositoryMock.Object,
roomServiceMock.Object,
workshopHub.Object,
loggerMock.Object,
mapper);

// Act
var result = await messageService.CountUnreadMessagesAsync(workshopId).ConfigureAwait(false);

// Assert
Assert.AreEqual(expectedUnreadMessages, result);
}

[Test]
public void CountUnreadMessagesAsync_ThrowsException()
{
// Arrange
var exceptionText = "Test exception";
var workshopId = Guid.NewGuid();
var messageRepositoryMock = new Mock<IChatMessageRepository>();
messageRepositoryMock.Setup(x => x.CountUnreadMessagesAsync(workshopId))
.Throws(new Exception(exceptionText));
var messageService = new ChatMessageWorkshopService(
messageRepositoryMock.Object,
roomServiceMock.Object,
workshopHub.Object,
loggerMock.Object,
mapper);

// Act and Assert
Exception ex = Assert.ThrowsAsync<Exception>(async () => await messageService.CountUnreadMessagesAsync(workshopId));
Assert.That(ex.Message, Is.EqualTo(exceptionText));
}
#endregion

private void SeedDatabase()
{
using var context = new OutOfSchoolDbContext(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class WorkshopServiceTests
private Mock<IProviderAdminRepository> providerAdminRepository;
private Mock<IAverageRatingService> averageRatingServiceMock;
private Mock<IProviderRepository> providerRepositoryMock;
private Mock<IChatMessageWorkshopService> chatMessageWorkshopServiceMock;

[SetUp]
public void SetUp()
Expand All @@ -54,6 +55,7 @@ public void SetUp()
providerAdminRepository = new Mock<IProviderAdminRepository>();
averageRatingServiceMock = new Mock<IAverageRatingService>();
providerRepositoryMock = new Mock<IProviderRepository>();
chatMessageWorkshopServiceMock = new Mock<IChatMessageWorkshopService>();

workshopService =
new WorkshopService(
Expand All @@ -65,7 +67,8 @@ public void SetUp()
workshopImagesMediator.Object,
providerAdminRepository.Object,
averageRatingServiceMock.Object,
providerRepositoryMock.Object);
providerRepositoryMock.Object,
chatMessageWorkshopServiceMock.Object);
}

#region Create
Expand Down Expand Up @@ -190,34 +193,34 @@ public async Task GetByProviderId_WhenProviderWithIdExists_ShouldReturnEntities(
{
// Arrange
var workshops = WithWorkshopsList().ToList();
var expectedWorkshopBaseCards = workshops.Select(w => new WorkshopBaseCard() { ProviderId = w.ProviderId, WorkshopId = w.Id, }).ToList();
var expectedWorkshopBaseCards = workshops.Select(w => new WorkshopProviderViewCard() { ProviderId = w.ProviderId, WorkshopId = w.Id, }).ToList();

SetupGetRepositoryCount(10);
SetupGetByProviderById(workshops);

mapperMock.Setup(m => m.Map<List<WorkshopBaseCard>>(It.IsAny<List<Workshop>>())).Returns(expectedWorkshopBaseCards);
mapperMock.Setup(m => m.Map<List<WorkshopProviderViewCard>>(It.IsAny<List<Workshop>>())).Returns(expectedWorkshopBaseCards);

// Act
var result = await workshopService.GetByProviderId<WorkshopBaseCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);
var result = await workshopService.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);

// Assert
workshopRepository.VerifyAll();
mapperMock.VerifyAll();
(result as SearchResult<WorkshopBaseCard>).TotalAmount.Should().Be(workshops.Count);
(result as SearchResult<WorkshopBaseCard>).Entities.Should().BeEquivalentTo(expectedWorkshopBaseCards);
(result as SearchResult<WorkshopProviderViewCard>).TotalAmount.Should().Be(workshops.Count);
(result as SearchResult<WorkshopProviderViewCard>).Entities.Should().BeEquivalentTo(expectedWorkshopBaseCards);
}

[Test]
public async Task GetByProviderId_WhenThereIsNoEntityWithId_ShouldReturnEmptyList()
{
// Arrange
var emptyListWorkshopCards = new List<WorkshopBaseCard>();
var emptyListWorkshopCards = new List<WorkshopProviderViewCard>();
SetupGetRepositoryCount(0);
SetupGetByProviderById(new List<Workshop>());
mapperMock.Setup(m => m.Map<List<WorkshopBaseCard>>(It.IsAny<List<Workshop>>())).Returns(emptyListWorkshopCards);
mapperMock.Setup(m => m.Map<List<WorkshopProviderViewCard>>(It.IsAny<List<Workshop>>())).Returns(emptyListWorkshopCards);

// Act
var result = await workshopService.GetByProviderId<WorkshopBaseCard>(Guid.NewGuid(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);
var result = await workshopService.GetByProviderId(Guid.NewGuid(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);

// Assert
workshopRepository.VerifyAll();
Expand All @@ -232,22 +235,22 @@ public async Task GetByProviderId_WhenThereIsExcludedIds_ShouldReturnList()
// Arrange
var workshops = WithWorkshopsList().ToList();
var excludedIds = new List<Guid>() { new Guid("b94f1989-c4e7-4878-ac86-21c4a402fb43"), new Guid("8c14044b-e30d-4b14-a18b-5b3b859ad676") };
var expectedWorkshopBaseCards = workshops.Select(w => new WorkshopBaseCard() { ProviderId = w.ProviderId })
var expectedWorkshopBaseCards = workshops.Select(w => new WorkshopProviderViewCard() { ProviderId = w.ProviderId })
.Where(w => !excludedIds.Any(excluded => w.WorkshopId != excluded)).ToList();

SetupGetRepositoryCount(10);
SetupGetByProviderById(workshops);

mapperMock.Setup(m => m.Map<List<WorkshopBaseCard>>(It.IsAny<List<Workshop>>())).Returns(expectedWorkshopBaseCards);
mapperMock.Setup(m => m.Map<List<WorkshopProviderViewCard>>(It.IsAny<List<Workshop>>())).Returns(expectedWorkshopBaseCards);

// Act
var result = await workshopService.GetByProviderId<WorkshopBaseCard>(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);
var result = await workshopService.GetByProviderId(It.IsAny<Guid>(), It.IsAny<ExcludeIdFilter>()).ConfigureAwait(false);

// Assert
workshopRepository.VerifyAll();
mapperMock.VerifyAll();
(result as SearchResult<WorkshopBaseCard>).TotalAmount.Should().Be(workshops.Count);
(result as SearchResult<WorkshopBaseCard>).Entities.Should().BeEquivalentTo(expectedWorkshopBaseCards);
(result as SearchResult<WorkshopProviderViewCard>).TotalAmount.Should().Be(workshops.Count);
(result as SearchResult<WorkshopProviderViewCard>).Entities.Should().BeEquivalentTo(expectedWorkshopBaseCards);
}
#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ public async Task<IActionResult> GetWorkshopListByProviderAdminId(string provide
/// <param name="id">Provider's id.</param>
/// <param name="filter">Filter to get specified portion of workshop view cards for specified provider.
/// Id of the excluded workshop could be specified.</param>
/// <returns><see cref="SearchResult{WorkshopBaseCard}"/>, or no content.</returns>
/// <returns><see cref="SearchResult{WorkshopProviderViewCard}"/>, or no content.</returns>
/// <response code="200">The list of found entities by given Id.</response>
/// <response code="204">No entity with given Id was found.</response>
/// <response code="400">Provider id is empty.</response>
/// <response code="500">If any server error occures. For example: Id was less than one.</response>
[AllowAnonymous]
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SearchResult<WorkshopBaseCard>))]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SearchResult<WorkshopProviderViewCard>))]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
Expand All @@ -153,7 +153,7 @@ public async Task<IActionResult> GetByProviderId(Guid id, [FromQuery] ExcludeIdF
return BadRequest("Provider id is empty.");
}

var workshopCards = await combinedWorkshopService.GetByProviderId<WorkshopBaseCard>(id, filter)
var workshopCards = await combinedWorkshopService.GetByProviderId(id, filter)
.ConfigureAwait(false);

if (workshopCards.TotalAmount == 0)
Expand Down Expand Up @@ -183,7 +183,7 @@ public async Task<IActionResult> GetWorkshopProviderViewCardsByProviderId(Guid i
return BadRequest("Provider id is empty.");
}

var workshopProviderViewCards = await combinedWorkshopService.GetByProviderId<WorkshopProviderViewCard>(id, filter).ConfigureAwait(false);
var workshopProviderViewCards = await combinedWorkshopService.GetByProviderId(id, filter).ConfigureAwait(false);

if (workshopProviderViewCards.TotalAmount == 0)
{
Expand Down
Loading
Loading