Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
193 changes: 191 additions & 2 deletions src/Api/Controllers/DocumentsController.cs
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
using Api.Controllers.Payload.Requests.Documents;
using Application.Common.Interfaces;
using Application.Common.Models;
using Application.Common.Models.Dtos;
using Application.Common.Models.Dtos.ImportDocument;
using Application.Common.Models.Dtos.Physical;
using Application.Documents.Commands;
using Application.Documents.Queries;
using Application.Identity;
using Domain.Enums;
using Infrastructure.Identity.Authorization;
using Microsoft.AspNetCore.Mvc;

Expand DownExpand Up@@ -43,12 +46,45 @@ public async Task<ActionResult<Result<DocumentDto>>> GetById([FromRoute] Guid do
/// </summary>
/// <param name="queryParameters">Get all documents query parameters</param>
/// <returns>A paginated list of DocumentDto</returns>
[RequiresRole(IdentityData.Roles.Staff)]
[HttpGet("issued")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<PaginatedList<IssuedDocumentDto>>>> GetAllIssuedPaginated(
[FromQuery] GetAllIssuedPaginatedQueryParameters queryParameters)
{
var departmentId = _currentUserService.GetCurrentDepartmentForStaff();
if (departmentId is null)
{
return Result<PaginatedList<IssuedDocumentDto>>.Fail(new Exception("Staff does not have a room"));
}
var query = new GetAllIssuedDocumentsPaginated.Query()
{
DepartmentId = departmentId.Value,
SearchTerm = queryParameters.SearchTerm,
Page = queryParameters.Page,
Size = queryParameters.Size,
SortBy = queryParameters.SortBy,
SortOrder = queryParameters.SortOrder,
};
var result = await Mediator.Send(query);
return Ok(Result<PaginatedList<IssuedDocumentDto>>.Succeed(result));
}

/// <summary>
/// Get all documents paginated
/// </summary>
/// <param name="queryParameters">Get all documents query parameters</param>
/// <returns>A paginated list of DocumentDto</returns>
[RequiresRole(IdentityData.Roles.Admin)]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<PaginatedList<DocumentDto>>>> GetAllPaginated(
public async Task<ActionResult<Result<PaginatedList<DocumentDto>>>> GetAllForAdminPaginated(
[FromQuery] GetAllDocumentsPaginatedQueryParameters queryParameters)
{
var query = new GetAllDocumentsPaginated.Query()
Expand All@@ -66,6 +102,36 @@ public async Task<ActionResult<Result<PaginatedList<DocumentDto>>>> GetAllPagina
return Ok(Result<PaginatedList<DocumentDto>>.Succeed(result));
}

/// <summary>
/// Get all documents for staff paginated
/// </summary>
/// <param name="queryParameters">Get all documents for staff query parameters</param>
/// <returns>A paginated list of DocumentDto</returns>
[RequiresRole(IdentityData.Roles.Staff)]
[HttpGet("staff")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<PaginatedList<DocumentDto>>>> GetAllForStaffPaginated(
[FromQuery] GetAllDocumentsForStaffPaginatedQueryParameters queryParameters)
{
var roomId = _currentUserService.GetCurrentRoomForStaff();
var query = new GetAllDocumentsPaginated.Query()
{
RoomId = roomId,
LockerId = queryParameters.LockerId,
FolderId = queryParameters.FolderId,
SearchTerm = queryParameters.SearchTerm,
Page = queryParameters.Page,
Size = queryParameters.Size,
SortBy = queryParameters.SortBy,
SortOrder = queryParameters.SortOrder,
};
var result = await Mediator.Send(query);
return Ok(Result<PaginatedList<DocumentDto>>.Succeed(result));
}

/// <summary>
/// Get all document types
/// </summary>
Expand DownExpand Up@@ -120,17 +186,43 @@ public async Task<ActionResult<Result<DocumentDto>>> Import([FromBody] ImportDoc
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<DocumentDto>>> RequestImport([FromBody] RequestImportDocumentRequest request)
public async Task<ActionResult<Result<IssuedDocumentDto>>> RequestImport([FromBody] RequestImportDocumentRequest request)
{
var performingUserId = _currentUserService.GetId();
var command = new RequestImportDocument.Command()
{
Title = request.Title,
Description = request.Description,
DocumentType = request.DocumentType,
IsPrivate = request.IsPrivate,
IssuerId = performingUserId,
};
var result = await Mediator.Send(command);
return Ok(Result<IssuedDocumentDto>.Succeed(result));
}

/// <summary>
/// Checkin a document
/// </summary>
/// <param name="documentId"></param>
/// <returns>A DocumentDto of the imported document</returns>
[RequiresRole(IdentityData.Roles.Staff)]
[HttpPost("checkin{documentId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<DocumentDto>>> Checkin(
[FromRoute] Guid documentId)
{
var performingUserId = _currentUserService.GetId();
var command = new CheckinDocument.Command()
{
PerformingUserId = performingUserId,
DocumentId = documentId,
};
var result = await Mediator.Send(command);
return Ok(Result<DocumentDto>.Succeed(result));
}

Expand DownExpand Up@@ -177,4 +269,101 @@ public async Task<ActionResult<Result<DocumentDto>>> Delete([FromRoute] Guid doc
var result = await Mediator.Send(query);
return Ok(Result<DocumentDto>.Succeed(result));
}

/// <summary>
/// Approve a document request
/// </summary>
/// <param name="documentId">Id of the document to be approved</param>
/// <param name="request"></param>
/// <returns>A DocumentDto of the approved document</returns>
[HttpPost("approve/{documentId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DocumentDto>>> Approve(
[FromRoute] Guid documentId,
[FromBody] ApproveImportRequest request)
{
var performingUserId = _currentUserService.GetId();
var query = new ApproveDocument.Command()
{
PerformingUserId = performingUserId,
DocumentId = documentId,
Reason = request.Reason,
};
var result = await Mediator.Send(query);
return Ok(Result<DocumentDto>.Succeed(result));
}

/// <summary>
/// Reject a document request
/// </summary>
/// <param name="documentId">Id of the document to be rejected</param>
/// <param name="request"></param>
/// <returns>A DocumentDto of the rejected document</returns>
[HttpPost("reject/{documentId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DocumentDto>>> Reject(
[FromRoute] Guid documentId,
[FromBody] RejectImportRequest request)
{
var performingUserId = _currentUserService.GetId();
var query = new RejectDocument.Command()
{
PerformingUserId = performingUserId,
DocumentId = documentId,
Reason = request.Reason,
};
var result = await Mediator.Send(query);
return Ok(Result<DocumentDto>.Succeed(result));
}

/// <summary>
/// Get a document request reason
/// </summary>
/// <param name="documentId">Id of the document to be rejected</param>
/// <returns>A DocumentDto of the rejected document</returns>
[RequiresRole(IdentityData.Roles.Staff)]
[HttpPost("reason/{documentId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<ReasonDto>>> Reason(
[FromRoute] Guid documentId)
{
var query = new GetDocumentReason.Query()
{
DocumentId = documentId,
Type = RequestType.Import,
};
var result = await Mediator.Send(query);
return Ok(Result<ReasonDto>.Succeed(result));
}

/// <summary>
/// Assign a document to
/// </summary>
/// <param name="documentId">Id of the document to be rejected</param>
/// <param name="request"></param>
/// <returns>A DocumentDto of the rejected document</returns>
[HttpPost("{documentId:guid}/assign")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DocumentDto>>> Assign(
[FromRoute] Guid documentId,
[FromBody] AssignDocumentToFolderRequest request)
{
var performingUserId = _currentUserService.GetId();
var query = new AssignDocument.Command()
{
PerformingUserId = performingUserId,
DocumentId = documentId,
FolderId = request.FolderId,
};
var result = await Mediator.Send(query);
return Ok(Result<DocumentDto>.Succeed(result));
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
namespace Api.Controllers.Payload.Requests.Documents;

public class ApproveImportRequest
{
public string Reason { get; set; } = null!;
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
namespace Api.Controllers.Payload.Requests.Documents;

public class AssignDocumentToFolderRequest
{
public Guid FolderId { get; set; }
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
namespace Api.Controllers.Payload.Requests.Documents;

public class GetAllDocumentsForStaffPaginatedQueryParameters : PaginatedQueryParameters
{
/// <summary>
/// Id of the room to find documents in
/// </summary>
public Guid? RoomId { get; set; }
/// <summary>
/// Id of the locker to find documents in
/// </summary>
public Guid? LockerId { get; set; }
/// <summary>
/// Id of the folder to find documents in
/// </summary>
public Guid? FolderId { get; set; }
/// <summary>
/// Search term
/// </summary>
public string? SearchTerm { get; set; }
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
namespace Api.Controllers.Payload.Requests.Documents;

public class GetAllIssuedPaginatedQueryParameters : PaginatedQueryParameters
{
public string? SearchTerm { get; set; }
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
namespace Api.Controllers.Payload.Requests.Documents;

public class RejectImportRequest
{
public string Reason { get; set; } = null!;
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,4 +17,5 @@ public class RequestImportDocumentRequest
/// Document type of the document to be imported
/// </summary>
public string DocumentType { get; set; } = null!;
public bool IsPrivate { get; set; }
}
4 changes: 4 additions & 0 deletions src/Application/Common/Messages/DocumentLogMessages.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,5 +6,9 @@ public static class Import
{
public const string NewImport = "Imported new document";
public const string NewImportRequest = "Created new import request";
public const string Checkin = "Checked in document";
public const string Approve = "Approved import request";
public const string Reject = "Rejected import request";
public const string Assign = "Assigned to a folder";
}
}
1 change: 1 addition & 0 deletions src/Application/Common/Messages/FolderLogMessage.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,4 +4,5 @@ public static class FolderLogMessage
{
public const string Add = "Added folder";
public const string Update = "Updated folder";
public const string AssignDocument = "Assigned document to folder";
}
7 changes: 7 additions & 0 deletions src/Application/Common/Messages/RequestLogMessages.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
namespace Application.Common.Messages;

public static class RequestLogMessages
{
public const string ApproveImport = "Approved import request";
public const string RejectImport = "Rejected import request";
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
using Application.Common.Mappings;
using AutoMapper;
using Domain.Entities.Physical;

namespace Application.Common.Models.Dtos.ImportDocument;

public class IssuedDocumentDto : IMapFrom<Document>
{
public Guid Id { get; set; }
public string Title { get; set; } = null!;
public string? Description { get; set; }
public string DocumentType { get; set; } = null!;
public IssuerDto? Issuer { get; set; }
public string Status { get; set; } = null!;
public bool IsPrivate { get; set; }

public void Mapping(Profile profile)
{
profile.CreateMap<Document, IssuedDocumentDto>()
.ForMember(dest => dest.Status,
opt => opt.MapFrom(src => src.Status.ToString()))
.ForMember(dest => dest.Issuer,
opt => opt.MapFrom(x => x.Importer));
}
}
17 changes: 17 additions & 0 deletions src/Application/Common/Models/Dtos/ImportDocument/IssuerDto.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
using Application.Common.Mappings;
using Domain.Entities;

namespace Application.Common.Models.Dtos.ImportDocument;

public class IssuerDto : IMapFrom<User>
{
public Guid Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Role { get; set; }
public string Position { get; set; }
public bool IsActive { get; set; }
public bool IsActivated { get; set; }
}
11 changes: 11 additions & 0 deletions src/Application/Common/Models/Dtos/ReasonDto.cs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
using Application.Common.Mappings;
using Domain.Entities.Logging;
using Domain.Enums;

namespace Application.Common.Models.Dtos;

public class ReasonDto : IMapFrom<RequestLog>
{
public RequestType Type { get; set; }
public string Reason { get; set; } = null!;
}
Loading