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 6 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,29 @@
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
{
private readonly OutOfSchoolDbContext db;

public ChatMessageRepository(OutOfSchoolDbContext dbContext)
: base(dbContext)
{
db = dbContext;
VadymLevkovskyi marked this conversation as resolved.
Show resolved Hide resolved
}

public async Task<int> CountUnreadMessagesAsync(Guid workshopId)
VadymLevkovskyi marked this conversation as resolved.
Show resolved Hide resolved
{
return await db.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 @@ -35,7 +35,8 @@ public class ChatMessageWorkshopServiceTests
WorkshopId = Guid.NewGuid(),
};

private IEntityRepository<Guid, ChatMessageWorkshop> messageRepository;
//private IEntityRepository<Guid, ChatMessageWorkshop> messageRepository;
VadymLevkovskyi marked this conversation as resolved.
Show resolved Hide resolved
private IChatMessageRepository messageRepository;
private Mock<IChatRoomWorkshopService> roomServiceMock;
private Mock<IHubContext<ChatWorkshopHub>> workshopHub;
private Mock<ILogger<ChatMessageWorkshopService>> loggerMock;
Expand All @@ -60,7 +61,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
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
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,18 @@ public async Task<IActionResult> GetById(Guid id)
/// </summary>
/// <param name="id">Provider's id.</param>
/// <param name="filter">Filter to get specified portion of workshops for specified provider. Ids of the excluded workshops could be specified.</param>
/// <returns><see cref="SearchResult{WorkshopCard}"/>, 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="500">If any server error occures. For example: Id was less than one.</response>
[AllowAnonymous]
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SearchResult<WorkshopCard>))]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SearchResult<WorkshopProviderViewCard>))]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetByProviderId(Guid id, [FromQuery] ExcludeIdFilter filter)
{
var workshopCards = await combinedWorkshopService.GetByProviderId<WorkshopBaseCard>(id, filter).ConfigureAwait(false);
var workshopCards = await combinedWorkshopService.GetByProviderId(id, filter).ConfigureAwait(false);

if (workshopCards.TotalAmount == 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,6 @@ public class WorkshopProviderViewCard : WorkshopBaseCard
public int AmountOfPendingApplications { get; set; }

public WorkshopStatus Status { get; set; }

public int UnreadMessages { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Linq.Expressions;
using AutoMapper;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore.Storage;
using Nest;
using Newtonsoft.Json;
using OutOfSchool.Services.Enums;
using OutOfSchool.Services.Repository;
using OutOfSchool.WebApi.Models;
using OutOfSchool.WebApi.Models.ChatWorkshop;

Expand All @@ -13,7 +16,7 @@ namespace OutOfSchool.WebApi.Services;
/// </summary>
public class ChatMessageWorkshopService : IChatMessageWorkshopService
{
private readonly IEntityRepository<Guid, ChatMessageWorkshop> messageRepository;
private readonly IChatMessageRepository messageRepository;
private readonly IChatRoomWorkshopService roomService;
private readonly IHubContext<ChatWorkshopHub> workshopHub;
private readonly ILogger<ChatMessageWorkshopService> logger;
Expand All @@ -28,7 +31,7 @@ public class ChatMessageWorkshopService : IChatMessageWorkshopService
/// <param name="logger">Logger.</param>
/// <param name="mapper">Mapper.</param>
public ChatMessageWorkshopService(
IEntityRepository<Guid, ChatMessageWorkshop> chatMessageRepository,
IChatMessageRepository chatMessageRepository,
IChatRoomWorkshopService roomRepository,
IHubContext<ChatWorkshopHub> workshopHub,
ILogger<ChatMessageWorkshopService> logger,
Expand Down Expand Up @@ -124,6 +127,19 @@ public async Task<List<ChatMessageWorkshopDto>> GetMessagesForChatRoomAndSetRead
}
}

public async Task<int> CountUnreadMessagesAsync(Guid workshopId)
{
try
{
return await messageRepository.CountUnreadMessagesAsync(workshopId).ConfigureAwait(false);
}
catch (Exception exception)
{
logger.LogError($"Getting number of unread messages with {nameof(workshopId)}:{workshopId} failed. Exception: {exception.Message}");
throw;
}
}

private async Task<List<ChatMessageWorkshop>> GetMessagesForChatRoomDomainModelAsync(Guid chatRoomId, OffsetFilter offsetFilter)
{
if (offsetFilter is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ public interface IWorkshopService
/// <typeparam name="T">Type of entity that must be return.</typeparam>
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.
/// The task result contains a <see cref="SearchResult{WorkshopCard}"/> that contains elements from the input sequence.</returns>
Task<SearchResult<T>> GetByProviderId<T>(Guid id, ExcludeIdFilter filter)
where T : WorkshopBaseCard;
Task<SearchResult<WorkshopProviderViewCard>> GetByProviderId(Guid id, ExcludeIdFilter filter);

/// <summary>
/// Get entities from the database that match filter's parameters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Castle.Core.Internal;
using H3Lib;
using H3Lib.Extensions;
using Microsoft.Extensions.Logging;
using Nest;
using OutOfSchool.Common.Enums;
using OutOfSchool.Services.Enums;
Expand Down Expand Up @@ -38,6 +39,7 @@ public class WorkshopService : IWorkshopService
private readonly IProviderAdminRepository providerAdminRepository;
private readonly IAverageRatingService averageRatingService;
private readonly IProviderRepository providerRepository;
private readonly IChatMessageWorkshopService chatMessageWorkshopService;

/// <summary>
/// Initializes a new instance of the <see cref="WorkshopService"/> class.
Expand All @@ -61,7 +63,8 @@ public WorkshopService(
IImageDependentEntityImagesInteractionService<Workshop> workshopImagesService,
IProviderAdminRepository providerAdminRepository,
IAverageRatingService averageRatingService,
IProviderRepository providerRepository)
IProviderRepository providerRepository,
IChatMessageWorkshopService chatMessageWorkshopService)
{
this.workshopRepository = workshopRepository;
this.dateTimeRangeRepository = dateTimeRangeRepository;
Expand All @@ -72,6 +75,7 @@ public WorkshopService(
this.providerAdminRepository = providerAdminRepository;
this.averageRatingService = averageRatingService;
this.providerRepository = providerRepository;
this.chatMessageWorkshopService = chatMessageWorkshopService;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -254,8 +258,7 @@ public async Task<List<ShortEntityDto>> GetWorkshopListByProviderAdminId(string
}

/// <inheritdoc/>
public async Task<SearchResult<T>> GetByProviderId<T>(Guid id, ExcludeIdFilter filter)
where T : WorkshopBaseCard
public async Task<SearchResult<WorkshopProviderViewCard>> GetByProviderId(Guid id, ExcludeIdFilter filter)
{
logger.LogInformation($"Getting Workshop by organization started. Looking ProviderId = {id}.");

Expand All @@ -280,11 +283,22 @@ public async Task<SearchResult<T>> GetByProviderId<T>(Guid id, ExcludeIdFilter f
? $"There aren't Workshops for Provider with Id = {id}."
: $"From Workshop table were successfully received {workshops.Count} records.");

var workshopBaseCards = mapper.Map<List<T>>(workshops).ToList();
var result = new SearchResult<T>()
var workshopBaseCards = mapper.Map<List<WorkshopProviderViewCard>>(workshops).ToList();

if (workshopBaseCards.Any())
{
foreach (var workshop in workshopBaseCards)
{
var messages = await chatMessageWorkshopService.CountUnreadMessagesAsync(workshop.WorkshopId).ConfigureAwait(false);
logger.LogInformation($"Workshop.Id: {workshop.WorkshopId} has {messages} unread messages.");
workshop.UnreadMessages = messages;
}
}

var result = new SearchResult<WorkshopProviderViewCard>()
{
TotalAmount = workshopBaseCardsCount,
Entities = await GetWorkshopsWithAverageRating(workshopBaseCards).ConfigureAwait(false),
Entities = await GetWorkshopsWithAverageRating<WorkshopProviderViewCard>(workshopBaseCards).ConfigureAwait(false),
};

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ public interface IChatMessageWorkshopService
/// <param name="userRole">Role of current user.</param>
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation. The task result contains a <see cref="IEnumerable{ChatMessageDTO}"/> that contains elements from the input sequence.</returns>
Task<List<ChatMessageWorkshopDto>> GetMessagesForChatRoomAndSetReadDateTimeIfItIsNullAsync(Guid chatRoomId, OffsetFilter offsetFilter, Role userRole);

/// <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 @@ -82,8 +82,7 @@ public interface IWorkshopServicesCombiner
/// <typeparam name="T">Type of entity that must be return.</typeparam>
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.
/// The task result contains a <see cref="List{WorkshopBaseCard}"/> that contains elements from the input sequence.</returns>
Task<SearchResult<T>> GetByProviderId<T>(Guid id, ExcludeIdFilter filter)
where T : WorkshopBaseCard;
Task<SearchResult<WorkshopProviderViewCard>> GetByProviderId(Guid id, ExcludeIdFilter filter);

/// <summary>
/// Get all entities that matches filter's parameters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ public async Task<SearchResult<WorkshopProviderViewCard>> GetWorkshopsThatProvid
}

var filter = new ExcludeIdFilter() { From = 0, Size = int.MaxValue };
return await workshopService.GetByProviderId<WorkshopProviderViewCard>(providerAdmin.ProviderId, filter).ConfigureAwait(false);
return await workshopService.GetByProviderId(providerAdmin.ProviderId, filter).ConfigureAwait(false);
}

var pa = providersAdmins.SingleOrDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,9 @@ public async Task<List<ShortEntityDto>> GetWorkshopListByProviderAdminId(string
}

/// <inheritdoc/>
public async Task<SearchResult<T>> GetByProviderId<T>(Guid id, ExcludeIdFilter filter)
where T : WorkshopBaseCard
public async Task<SearchResult<WorkshopProviderViewCard>> GetByProviderId(Guid id, ExcludeIdFilter filter)
{
var workshopBaseCards = await workshopService.GetByProviderId<T>(id, filter).ConfigureAwait(false);
var workshopBaseCards = await workshopService.GetByProviderId(id, filter).ConfigureAwait(false);

return workshopBaseCards;
}
Expand Down
3 changes: 2 additions & 1 deletion OutOfSchool/OutOfSchool.WebApi/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ public static void AddApplicationServices(this WebApplicationBuilder builder)

// entities services
services.AddTransient<IApplicationService, ApplicationService>();
services.AddTransient<IChatMessageWorkshopService, ChatMessageWorkshopService>();
services.AddTransient<IChatRoomWorkshopService, ChatRoomWorkshopService>();
services.AddTransient<IChatMessageWorkshopService, ChatMessageWorkshopService>();
services.AddTransient<IChildService, ChildService>();
services.AddTransient<IDirectionService, DirectionService>();
services.AddTransient<IFavoriteService, FavoriteService>();
Expand Down Expand Up @@ -279,6 +279,7 @@ public static void AddApplicationServices(this WebApplicationBuilder builder)
services
.AddTransient<IChatRoomWorkshopModelForChatListRepository, ChatRoomWorkshopModelForChatListRepository
>();
services.AddTransient<IChatMessageRepository, ChatMessageRepository>();
services.AddTransient<IParentRepository, ParentRepository>();
services.AddTransient<IProviderRepository, ProviderRepository>();
services.AddTransient<IWorkshopRepository, WorkshopRepository>();
Expand Down
Loading