From 99bcab202c1501c997da3c1df5aafb67df996c91 Mon Sep 17 00:00:00 2001 From: StarryFolf Date: Wed, 14 Jun 2023 11:02:35 +0700 Subject: [PATCH 1/4] feat: implement get borrow request logs paginated + get borrow request log by id --- src/Api/Controllers/BorrowsController.cs | 47 +++++++++++++ .../GetAllLogsPaginatedQueryParameters.cs | 6 ++ .../GetAllBorrowRequestLogsPaginated.cs | 66 +++++++++++++++++++ .../Queries/GetBorrowRequestLogById.cs | 46 +++++++++++++ .../Models/Dtos/Logging/RequestLogDto.cs | 29 ++++++++ 5 files changed, 194 insertions(+) create mode 100644 src/Api/Controllers/Payload/Requests/GetAllLogsPaginatedQueryParameters.cs create mode 100644 src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs create mode 100644 src/Application/Borrows/Queries/GetBorrowRequestLogById.cs create mode 100644 src/Application/Common/Models/Dtos/Logging/RequestLogDto.cs diff --git a/src/Api/Controllers/BorrowsController.cs b/src/Api/Controllers/BorrowsController.cs index 484c3949..54e29a29 100644 --- a/src/Api/Controllers/BorrowsController.cs +++ b/src/Api/Controllers/BorrowsController.cs @@ -1,8 +1,10 @@ +using Api.Controllers.Payload.Requests; using Api.Controllers.Payload.Requests.Borrows; using Application.Borrows.Commands; using Application.Borrows.Queries; using Application.Common.Interfaces; using Application.Common.Models; +using Application.Common.Models.Dtos.Logging; using Application.Common.Models.Dtos.Physical; using Application.Identity; using Infrastructure.Identity.Authorization; @@ -305,4 +307,49 @@ public async Task>> Cancel([FromRoute] Guid borro var result = await Mediator.Send(command); return Ok(Result.Succeed(result)); } + + /// + /// Get all logs related to borrow requests. + /// + /// Query parameters + /// A list of RequestLogsDtos. + [RequiresRole(IdentityData.Roles.Admin)] + [HttpGet("logs")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task>>> GetAllBorrowRequestLogs( + [FromQuery] GetAllLogsPaginatedQueryParameters queryParameters) + { + var query = new GetAllBorrowRequestLogsPaginated.Query() + { + SearchTerm = queryParameters.SearchTerm, + Page = queryParameters.Page, + Size = queryParameters.Size, + SortBy = queryParameters.SortBy, + SortOrder = queryParameters.SortOrder, + }; + var result = await Mediator.Send(query); + return Ok(Result>.Succeed(result)); + } + + /// + /// Get a log related to borrow request by Id. + /// + /// Id of the requested log + /// A LockerLogDto of the requested log. + [RequiresRole(IdentityData.Roles.Admin)] + [HttpGet("log/{logId:guid}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task>> GetBorrowRequestLogById([FromRoute] Guid logId) + { + var query = new GetBorrowRequestLogById.Query() + { + LogId = logId + }; + + var result = await Mediator.Send(query); + return Ok(Result.Succeed(result)); + } } \ No newline at end of file diff --git a/src/Api/Controllers/Payload/Requests/GetAllLogsPaginatedQueryParameters.cs b/src/Api/Controllers/Payload/Requests/GetAllLogsPaginatedQueryParameters.cs new file mode 100644 index 00000000..0a6a2903 --- /dev/null +++ b/src/Api/Controllers/Payload/Requests/GetAllLogsPaginatedQueryParameters.cs @@ -0,0 +1,6 @@ +namespace Api.Controllers.Payload.Requests; + +public class GetAllLogsPaginatedQueryParameters : PaginatedQueryParameters +{ + public string? SearchTerm { get; set; } +} \ No newline at end of file diff --git a/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs b/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs new file mode 100644 index 00000000..64d043df --- /dev/null +++ b/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs @@ -0,0 +1,66 @@ +using Application.Common.Extensions; +using Application.Common.Interfaces; +using Application.Common.Models; +using Application.Common.Models.Dtos.Logging; +using AutoMapper; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace Application.Borrows.Queries; + +public class GetAllBorrowRequestLogsPaginated +{ + public record Query : IRequest> + { + public string? SearchTerm { get; init; } + public int? Page { get; init; } + public int? Size { get; init; } + public string? SortBy { get; init; } + public string? SortOrder { get; init; } + } + + public class QueryHandler : IRequestHandler> + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public QueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task> Handle(Query request, CancellationToken cancellationToken) + { + var logs = _context.RequestLogs + .Include(x => x.Object) + .AsQueryable(); + + if (!(request.SearchTerm is null || request.SearchTerm.Trim().Equals(string.Empty))) + { + logs = logs.Where(x => + x.Action.Trim().ToLower().Contains(request.SearchTerm.Trim().ToLower())); + } + + var sortBy = request.SortBy; + if (sortBy is null || !sortBy.MatchesPropertyName()) + { + sortBy = nameof(RequestLogDto.Time); + } + + var sortOrder = request.SortOrder ?? "dsc"; + var pageNumber = request.Page is null or <= 0 ? 1 : request.Page; + var sizeNumber = request.Size is null or <= 0 ? 5 : request.Size; + + var count = await logs.CountAsync(cancellationToken); + var list = await logs + .Paginate(pageNumber.Value, sizeNumber.Value) + .OrderByCustom(sortBy, sortOrder) + .ToListAsync(cancellationToken); + + var result = _mapper.Map>(list); + + return new PaginatedList(result, count, pageNumber.Value, sizeNumber.Value); + } + } +} \ No newline at end of file diff --git a/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs b/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs new file mode 100644 index 00000000..3bf9b1c6 --- /dev/null +++ b/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs @@ -0,0 +1,46 @@ +using Application.Common.Interfaces; +using Application.Common.Models.Dtos.Logging; +using AutoMapper; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace Application.Borrows.Queries; + +public class GetBorrowRequestLogById +{ + public record Query : IRequest + { + public Guid LogId { get; init; } + } + + public class QueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public QueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(Query request, CancellationToken cancellationToken) + { + var log = await _context.RequestLogs + .Include(x => x.Object) + .ThenInclude(x => x!.Importer) + .Include(x => x.Object) + .ThenInclude(x => x!.Folder) + .Include(x => x.User) + .ThenInclude(x => x.Department) + .FirstOrDefaultAsync(x => x.Id.Equals(request.LogId), cancellationToken); + + if (log is null) + { + throw new KeyNotFoundException("Log does not exist."); + } + + return _mapper.Map(log); + } + } +} \ No newline at end of file diff --git a/src/Application/Common/Models/Dtos/Logging/RequestLogDto.cs b/src/Application/Common/Models/Dtos/Logging/RequestLogDto.cs new file mode 100644 index 00000000..a291c228 --- /dev/null +++ b/src/Application/Common/Models/Dtos/Logging/RequestLogDto.cs @@ -0,0 +1,29 @@ +using Application.Common.Mappings; +using Application.Common.Models.Dtos.Physical; +using Application.Users.Queries; +using AutoMapper; +using Domain.Entities.Logging; + +namespace Application.Common.Models.Dtos.Logging; + +public class RequestLogDto : IMapFrom +{ + public Guid Id { get; set; } + public string Action { get; set; } = null!; + public DocumentDto? Object { get; set; } + public DateTime Time { get; set; } + public UserDto User { get; set; } = null!; + public string Reason { get; set; } = null!; + public string Type { get; set; } = null!; + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(dest => dest.Time, + opt => opt.MapFrom(src => src.Time.ToDateTimeUnspecified())) + .ForMember(dest => dest.Object, + opt => opt.MapFrom(src => src.Object)) + .ForMember(dest => dest.Type, + opt => opt.MapFrom(src => src.Type.ToString())); + } +} \ No newline at end of file From 746d707dd91a43c063185232ad1bcb01c2e2f536 Mon Sep 17 00:00:00 2001 From: StarryFolf Date: Wed, 14 Jun 2023 12:09:06 +0700 Subject: [PATCH 2/4] added borrow type filter --- .../Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs | 2 ++ .../Borrows/Queries/GetBorrowRequestLogById.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs b/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs index 64d043df..02e8eae2 100644 --- a/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs +++ b/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs @@ -3,6 +3,7 @@ using Application.Common.Models; using Application.Common.Models.Dtos.Logging; using AutoMapper; +using Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; @@ -34,6 +35,7 @@ public async Task> Handle(Query request, Cancellati { var logs = _context.RequestLogs .Include(x => x.Object) + .Where(x => x.Type == RequestType.Borrow) .AsQueryable(); if (!(request.SearchTerm is null || request.SearchTerm.Trim().Equals(string.Empty))) diff --git a/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs b/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs index 3bf9b1c6..e4c4a0a3 100644 --- a/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs +++ b/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs @@ -1,6 +1,8 @@ -using Application.Common.Interfaces; +using Application.Common.Exceptions; +using Application.Common.Interfaces; using Application.Common.Models.Dtos.Logging; using AutoMapper; +using Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; @@ -40,6 +42,11 @@ public async Task Handle(Query request, CancellationToken cancell throw new KeyNotFoundException("Log does not exist."); } + if (log.Type != RequestType.Borrow) + { + throw new ConflictException("This is not a borrow request log."); + } + return _mapper.Map(log); } } From 93328fb38049f430853029a21527261e4769a83c Mon Sep 17 00:00:00 2001 From: StarryFolf Date: Wed, 14 Jun 2023 19:22:04 +0700 Subject: [PATCH 3/4] refactoring --- src/Api/Controllers/BorrowsController.cs | 12 ++++++------ ...ogsPaginated.cs => GetAllRequestLogsPaginated.cs} | 3 +-- ...tBorrowRequestLogById.cs => GetRequestLogById.cs} | 7 +------ 3 files changed, 8 insertions(+), 14 deletions(-) rename src/Application/Borrows/Queries/{GetAllBorrowRequestLogsPaginated.cs => GetAllRequestLogsPaginated.cs} (95%) rename src/Application/Borrows/Queries/{GetBorrowRequestLogById.cs => GetRequestLogById.cs} (87%) diff --git a/src/Api/Controllers/BorrowsController.cs b/src/Api/Controllers/BorrowsController.cs index 54e29a29..d6199594 100644 --- a/src/Api/Controllers/BorrowsController.cs +++ b/src/Api/Controllers/BorrowsController.cs @@ -309,7 +309,7 @@ public async Task>> Cancel([FromRoute] Guid borro } /// - /// Get all logs related to borrow requests. + /// Get all logs related to requests. /// /// Query parameters /// A list of RequestLogsDtos. @@ -317,10 +317,10 @@ public async Task>> Cancel([FromRoute] Guid borro [HttpGet("logs")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task>>> GetAllBorrowRequestLogs( + public async Task>>> GetAllRequestLogs( [FromQuery] GetAllLogsPaginatedQueryParameters queryParameters) { - var query = new GetAllBorrowRequestLogsPaginated.Query() + var query = new GetAllRequestLogsPaginated.Query() { SearchTerm = queryParameters.SearchTerm, Page = queryParameters.Page, @@ -333,7 +333,7 @@ public async Task>>> GetAllBorr } /// - /// Get a log related to borrow request by Id. + /// Get a log related to request by Id. /// /// Id of the requested log /// A LockerLogDto of the requested log. @@ -342,9 +342,9 @@ public async Task>>> GetAllBorr [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetBorrowRequestLogById([FromRoute] Guid logId) + public async Task>> GetRequestLogById([FromRoute] Guid logId) { - var query = new GetBorrowRequestLogById.Query() + var query = new GetRequestLogById.Query() { LogId = logId }; diff --git a/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs b/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs similarity index 95% rename from src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs rename to src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs index 02e8eae2..fcb205fb 100644 --- a/src/Application/Borrows/Queries/GetAllBorrowRequestLogsPaginated.cs +++ b/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs @@ -9,7 +9,7 @@ namespace Application.Borrows.Queries; -public class GetAllBorrowRequestLogsPaginated +public class GetAllRequestLogsPaginated { public record Query : IRequest> { @@ -35,7 +35,6 @@ public async Task> Handle(Query request, Cancellati { var logs = _context.RequestLogs .Include(x => x.Object) - .Where(x => x.Type == RequestType.Borrow) .AsQueryable(); if (!(request.SearchTerm is null || request.SearchTerm.Trim().Equals(string.Empty))) diff --git a/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs b/src/Application/Borrows/Queries/GetRequestLogById.cs similarity index 87% rename from src/Application/Borrows/Queries/GetBorrowRequestLogById.cs rename to src/Application/Borrows/Queries/GetRequestLogById.cs index e4c4a0a3..4d53f316 100644 --- a/src/Application/Borrows/Queries/GetBorrowRequestLogById.cs +++ b/src/Application/Borrows/Queries/GetRequestLogById.cs @@ -8,7 +8,7 @@ namespace Application.Borrows.Queries; -public class GetBorrowRequestLogById +public class GetRequestLogById { public record Query : IRequest { @@ -42,11 +42,6 @@ public async Task Handle(Query request, CancellationToken cancell throw new KeyNotFoundException("Log does not exist."); } - if (log.Type != RequestType.Borrow) - { - throw new ConflictException("This is not a borrow request log."); - } - return _mapper.Map(log); } } From 4d0f6304d81480ba036bb49d06b81a3395bbbd46 Mon Sep 17 00:00:00 2001 From: StarryFolf <67864500+StarryFolf@users.noreply.github.com> Date: Wed, 14 Jun 2023 19:27:06 +0700 Subject: [PATCH 4/4] Update GetAllRequestLogsPaginated.cs --- src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs b/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs index fcb205fb..7a2002d1 100644 --- a/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs +++ b/src/Application/Borrows/Queries/GetAllRequestLogsPaginated.cs @@ -49,7 +49,7 @@ public async Task> Handle(Query request, Cancellati sortBy = nameof(RequestLogDto.Time); } - var sortOrder = request.SortOrder ?? "dsc"; + var sortOrder = request.SortOrder ?? "desc"; var pageNumber = request.Page is null or <= 0 ? 1 : request.Page; var sizeNumber = request.Size is null or <= 0 ? 5 : request.Size; @@ -64,4 +64,4 @@ public async Task> Handle(Query request, Cancellati return new PaginatedList(result, count, pageNumber.Value, sizeNumber.Value); } } -} \ No newline at end of file +}