Skip to content

Commit

Permalink
Get Reports for Organization details feature in Aggregator hamed-shir…
Browse files Browse the repository at this point in the history
  • Loading branch information
amirhossein18121380 committed Jun 4, 2024
1 parent ebe75ec commit e80d0e7
Show file tree
Hide file tree
Showing 19 changed files with 442 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/1-BuildingBlocks/Contracts/Dtos/Tasks/GetTaskDto.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Common;
using TaskoMask.BuildingBlocks.Contracts.Enums;
using TaskoMask.BuildingBlocks.Contracts.Resources;

namespace TaskoMask.BuildingBlocks.Contracts.Dtos.Tasks;
Expand All @@ -8,6 +9,7 @@ public class GetTaskDto : TaskBaseDto
{
[Display(Name = nameof(ContractsMetadata.OrganizationName), ResourceType = typeof(ContractsMetadata))]
public string CardName { get; set; }
public BoardCardType CardType { get; set; }

public string BoardId { get; set; }

Expand Down
10 changes: 10 additions & 0 deletions src/1-BuildingBlocks/Contracts/Protos/base.proto
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,14 @@ message GetCardGrpcResponse {
string ownerId = 8;
}

message GetOrganizationReportGrpcResponse {

CreationTimeGrpcResponse creationTime=1;
string projectsCount = 2;
string boardsCount = 3;
string toDoTasksCount = 4;
string doingTasksCount = 5;
string doneTasksCount = 6;
string backlogTasksCount = 7;
string id = 8;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";

package TaskoMask.BuildingBlocks.Contracts.Protos;

import "base.proto";

service GetOrganizationReportIdGrpcService {
rpc Handle (GetOrganizationReportIdGrpcRequest) returns (GetOrganizationReportGrpcResponse);
}

message GetOrganizationReportIdGrpcRequest {
string organizationId = 1;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using TaskoMask.BuildingBlocks.Contracts.Protos;
using TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationReportById;
using TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationsByOwnerId;
using TaskoMask.Services.Owners.Read.Api.Features.Projects.GetProjectById;
using TaskoMask.Services.Owners.Read.Api.Features.Projects.GetProjectsByOrganizationId;
Expand All @@ -16,5 +21,26 @@ public static void MapGrpcServices(this IEndpointRouteBuilder endpoints)
endpoints.MapGrpcService<GetOrganizationsByOwnerIdGrpcEndpoint>();
endpoints.MapGrpcService<GetProjectsByOrganizationIdGrpcEndpoint>();
endpoints.MapGrpcService<GetProjectByIdGrpcEndpoint>();
endpoints.MapGrpcService<GetOrganizationReportByIdGrpcEndpoint>();
}


public static void AddGrpcClients(this IServiceCollection services, IConfiguration configuration)
{
services.AddGrpcClient<GetBoardsByOrganizationIdGrpcService.GetBoardsByOrganizationIdGrpcServiceClient>(options =>
{
options.Address = new Uri(configuration["Url:Board-Read-Service"]);
});

services.AddGrpcClient<GetCardsByBoardIdGrpcService.GetCardsByBoardIdGrpcServiceClient>(options =>
{
options.Address = new Uri(configuration["Url:Board-Read-Service"]);
});

services.AddGrpcClient<GetTasksByCardIdGrpcService.GetTasksByCardIdGrpcServiceClient>(options =>
{
options.Address = new Uri(configuration["Url:Task-Read-Service"]);
});

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde

builder.Services.AddGrpcPreConfigured();

builder.Services.AddGrpcClients(builder.Configuration);

return builder.Build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using AutoMapper;
using Grpc.Core;
using System.Threading.Tasks;
using TaskoMask.BuildingBlocks.Application.Bus;
using TaskoMask.BuildingBlocks.Contracts.Protos;

namespace TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationReportById;


public class GetOrganizationReportByIdGrpcEndpoint : GetOrganizationReportIdGrpcService.GetOrganizationReportIdGrpcServiceBase
{
private readonly IInMemoryBus _inMemoryBus;
private readonly IMapper _mapper;

public GetOrganizationReportByIdGrpcEndpoint(IInMemoryBus inMemoryBus, IMapper mapper)
{
_inMemoryBus = inMemoryBus;
_mapper = mapper;
}

public override async Task<GetOrganizationReportGrpcResponse> Handle(GetOrganizationReportIdGrpcRequest request, ServerCallContext context)
{
var report = await _inMemoryBus.SendQuery(new GetOrganizationReportByIdRequest(request.OrganizationId));
return _mapper.Map<GetOrganizationReportGrpcResponse>(report.Value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
using AutoMapper;
using Grpc.Core;
using MediatR;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TaskoMask.BuildingBlocks.Application.Exceptions;
using TaskoMask.BuildingBlocks.Application.Queries;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Boards;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Cards;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Organizations;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Tasks;
using TaskoMask.BuildingBlocks.Contracts.Enums;
using TaskoMask.BuildingBlocks.Contracts.Protos;
using TaskoMask.BuildingBlocks.Contracts.Resources;
using TaskoMask.BuildingBlocks.Contracts.ViewModels;
using TaskoMask.BuildingBlocks.Domain.Resources;
using TaskoMask.Services.Owners.Read.Api.Infrastructure.DbContext;
using static TaskoMask.BuildingBlocks.Contracts.Protos.GetBoardsByOrganizationIdGrpcService;
using static TaskoMask.BuildingBlocks.Contracts.Protos.GetCardsByBoardIdGrpcService;
using static TaskoMask.BuildingBlocks.Contracts.Protos.GetTasksByCardIdGrpcService;


namespace TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationReportById;

public class GetOrganizationReportByIdHandler : BaseQueryHandler, IRequestHandler<GetOrganizationReportByIdRequest, OrganizationReportDto>
{
#region Fields

private readonly OwnerReadDbContext _ownerReadDbContext;
private readonly GetBoardsByOrganizationIdGrpcServiceClient _getBoardsByOrganizationIdGrpcServiceClient;
private readonly GetCardsByBoardIdGrpcServiceClient _getCardsByBoardIdGrpcServiceClient;
private readonly GetTasksByCardIdGrpcServiceClient _getTasksByCardIdGrpcServiceClient;
#endregion

#region Ctors

public GetOrganizationReportByIdHandler(OwnerReadDbContext ownerReadDbContext,
GetBoardsByOrganizationIdGrpcServiceClient getBoardsByOrganizationIdGrpcServiceClient,
GetCardsByBoardIdGrpcServiceClient getCardsByBoardIdGrpcServiceClient,
GetTasksByCardIdGrpcServiceClient getTasksByCardIdGrpcServiceClient,
IMapper mapper)
: base(mapper)
{
_ownerReadDbContext = ownerReadDbContext;
_getBoardsByOrganizationIdGrpcServiceClient = getBoardsByOrganizationIdGrpcServiceClient;
_getCardsByBoardIdGrpcServiceClient = getCardsByBoardIdGrpcServiceClient;
_getTasksByCardIdGrpcServiceClient = getTasksByCardIdGrpcServiceClient;
}

#endregion

#region Handlers



/// <summary>
///
/// </summary>
public async Task<OrganizationReportDto> Handle(GetOrganizationReportByIdRequest request, CancellationToken cancellationToken)
{
var organizationReportDto = new OrganizationReportDto();
var organization = await _ownerReadDbContext.Organizations
.Find(e => e.Id == request.Id)
.FirstOrDefaultAsync(cancellationToken: cancellationToken);

if (organization == null)
throw new ApplicationException(ContractsMessages.Data_Not_exist, DomainMetadata.Organization);

#region Project Reports
var organizationProjects = await _ownerReadDbContext.Projects.Find(e => e.Id == organization.Id).ToListAsync(cancellationToken);
organizationReportDto.ProjectsCount = organizationProjects?.Count ?? 0;
#endregion

#region Board Reports
var boards = new List<GetBoardDto>();
var boardsGrpcCall = _getBoardsByOrganizationIdGrpcServiceClient.Handle(
new GetBoardsByOrganizationIdGrpcRequest { OrganizationId = organization.Id }
);

await foreach (var response in boardsGrpcCall.ResponseStream.ReadAllAsync())
boards.Add(_mapper.Map<GetBoardDto>(response));

organizationReportDto.BoardsCount = boards?.Count ?? 0;
#endregion

#region Task Reports
long toDoTasksCount = 0;
long doingTasksCount = 0;
long doneTasksCount = 0;
long backlogTasksCount = 0;

var allBoardTasks = await GetAllTasksForBoardsAsync(boards, cancellationToken);

foreach (var boardTask in allBoardTasks)
{
foreach (var cardTask in boardTask.CardTasks)
{
foreach (var task in cardTask.Tasks)
{
switch (task.CardType)
{
case BoardCardType.ToDo:
toDoTasksCount++;
break;
case BoardCardType.Doing:
doingTasksCount++;
break;
case BoardCardType.Done:
doneTasksCount++;
break;
case BoardCardType.Backlog:
backlogTasksCount++;
break;
}
}
}
}

organizationReportDto.ToDoTasksCount = toDoTasksCount;
organizationReportDto.DoingTasksCount = doingTasksCount;
organizationReportDto.DoneTasksCount = doneTasksCount;
organizationReportDto.BacklogTasksCount = backlogTasksCount;


#endregion

return _mapper.Map<OrganizationReportDto>(organizationReportDto);
}

#endregion

#region Private Methods
private async Task<IEnumerable<BoardTasksViewModel>> GetAllTasksForBoardsAsync(IEnumerable<GetBoardDto> boards, CancellationToken cancellationToken)
{
var boardTasks = new List<BoardTasksViewModel>();

foreach (var board in boards)
{
var cards = await GetCardsAsync(board.Id, cancellationToken);
var cardTasks = new List<CardDetailsViewModel>();

foreach (var card in cards)
{
var tasks = await GetTasksAsync(card.Card.Id);
cardTasks.Add(new CardDetailsViewModel
{
Card = card.Card,
Tasks = tasks
});
}

boardTasks.Add(new BoardTasksViewModel
{
Board = board,
CardTasks = cardTasks
});
}

return boardTasks;
}

public class BoardTasksViewModel
{
public GetBoardDto Board { get; set; }
public IEnumerable<CardDetailsViewModel> CardTasks { get; set; }
}

private async Task<IEnumerable<CardDetailsViewModel>> GetCardsAsync(string boardId, CancellationToken cancellationToken)
{
var cards = new List<CardDetailsViewModel>();

var cardsGrpcCall = _getCardsByBoardIdGrpcServiceClient.Handle(new GetCardsByBoardIdGrpcRequest { BoardId = boardId });

while (await cardsGrpcCall.ResponseStream.MoveNext(cancellationToken))
{
var currentCardGrpcResponse = cardsGrpcCall.ResponseStream.Current;

cards.Add(
new CardDetailsViewModel { Card = MapToCard(currentCardGrpcResponse), Tasks = await GetTasksAsync(currentCardGrpcResponse.Id), }
);
}

return cards.AsEnumerable();
}

private async Task<IEnumerable<GetTaskDto>> GetTasksAsync(string cardId)
{
var tasks = new List<GetTaskDto>();

var tasksGrpcCall = _getTasksByCardIdGrpcServiceClient.Handle(new GetTasksByCardIdGrpcRequest { CardId = cardId });

await foreach (var response in tasksGrpcCall.ResponseStream.ReadAllAsync())
tasks.Add(_mapper.Map<GetTaskDto>(response));

return tasks;
}

private GetCardDto MapToCard(GetCardGrpcResponse cardGrpcResponse)
{
return _mapper.Map<GetCardDto>(cardGrpcResponse);
}

#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using TaskoMask.BuildingBlocks.Application.Queries;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Organizations;

namespace TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationReportById;


public class GetOrganizationReportByIdRequest : BaseQuery<OrganizationReportDto>
{
public GetOrganizationReportByIdRequest(string id)
{
Id = id;
}

public string Id { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using TaskoMask.BuildingBlocks.Application.Bus;
using TaskoMask.BuildingBlocks.Contracts.Dtos.Organizations;
using TaskoMask.BuildingBlocks.Contracts.Helpers;
using TaskoMask.BuildingBlocks.Contracts.Services;
using TaskoMask.BuildingBlocks.Web.MVC.Controllers;

namespace TaskoMask.Services.Owners.Read.Api.Features.Organizations.GetOrganizationReportById;



[Authorize("user-read-access")]
[Tags("Organizations")]
public class GetOrganizationReportByIdRestEndpoint : BaseApiController
{
public GetOrganizationReportByIdRestEndpoint(IAuthenticatedUserService authenticatedUserService, IInMemoryBus inMemoryBus)
: base(authenticatedUserService, inMemoryBus) { }

/// <summary>
/// get organization Report
/// </summary>
[HttpGet]
[Route("organizations/report")]
public async Task<Result<OrganizationReportDto>> Get(string organizationId)
{
return await _inMemoryBus.SendQuery(new GetOrganizationReportByIdRequest(organizationId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public MappingProfile()

CreateMap<Owner, GetOwnerDto>();

CreateMap<GetOrganizationReportGrpcResponse, OrganizationReportDto>();

CreateMap<Organization, GetOrganizationDto>();

CreateMap<GetOrganizationDto, GetOrganizationGrpcResponse>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@
<ItemGroup>
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\base.proto" GrpcServices="Server" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_organizations_by_owner_id.proto" GrpcServices="Server" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_organizationReport_by_id.proto" GrpcServices="Server" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_projects_by_organization_id.proto" GrpcServices="Server" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_project_by_id.proto" GrpcServices="Server" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_boards_by_organization_id.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_cards_by_board_id.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\..\1-BuildingBlocks\Contracts\Protos\get_tasks_by_card_id.proto" GrpcServices="Client" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit e80d0e7

Please sign in to comment.