Skip to content
This repository has been archived by the owner on Feb 17, 2025. It is now read-only.

fix: task routes and models #26

Closed
wants to merge 4 commits into from
Closed
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
152 changes: 114 additions & 38 deletions DotnetFoundation/DotnetFoundation.Api/Controllers/TaskController.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using DotnetFoundation.Application.Exceptions;
using DotnetFoundation.Application.Interfaces.Services;
using DotnetFoundation.Application.Models.Common;
using DotnetFoundation.Application.Models.DTOs.TaskDetailsDTO;
using DotnetFoundation.Application.Models.Enums;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace DotnetFoundation.Api.Controllers;

[ApiController]
[Route("api/tasks")]
[Route("api")]
public class TaskController : ControllerBase
{
private readonly ITaskDetailsService _taskDetailsService;
Expand All @@ -20,104 +20,180 @@ public TaskController(ITaskDetailsService TaskDetailsService)
/// <summary>
/// Get all tasks.
/// </summary>
[HttpGet]
[HttpGet("tasks")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<List<TaskDetailsResponse>>>> GetAllTasksAsync()
{
BaseResponse<List<TaskDetailsResponse>> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.GetAllTasksAsync().ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.GetAllTasksAsync().ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}

/// <summary>
/// Get all active tasks.
/// </summary>
[HttpGet("active")]
[HttpGet("tasks/active")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<List<TaskDetailsResponse>>>> GetActiveTasksAsync()
{
BaseResponse<List<TaskDetailsResponse>> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.GetActiveTasksAsync().ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.GetActiveTasksAsync().ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}

/// <summary>
/// Get task details by Id.
/// </summary>
/// <param name="taskId">Id of task record</param>
[HttpGet("{taskId}")]
[HttpGet("tasks/{taskId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<TaskDetailsResponse>>> GetTaskByIdAsync(int taskId)
{
BaseResponse<TaskDetailsResponse> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.GetTaskByIdAsync(taskId).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.GetTaskByIdAsync(taskId).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (NotFoundException ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return BadRequest(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}

/// <summary>
/// Add new task.
/// </summary>
/// <param name="detailRequest">Role request details</param>
[HttpPost]
[HttpPost("task")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task endpoint for adding a new task is correctly implemented as a POST operation, which aligns with RESTful design principles for creating resources. However, it's worth noting that the singular form task is used here, whereas other endpoints use the plural form tasks. While this is not incorrect, it's generally a good practice to maintain consistency in naming conventions across the API. Consider aligning this endpoint with others by using the plural form tasks for consistency.

- [HttpPost("task")]
+ [HttpPost("tasks")]

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
[HttpPost("task")]
[HttpPost("tasks")]

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<TaskDetailsResponse>>> InsertTaskAsync(TaskDetailsRequest detailRequest)
{
BaseResponse<TaskDetailsResponse> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.InsertTaskAsync(detailRequest).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.InsertTaskAsync(detailRequest).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (NotFoundException ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return BadRequest(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}

/// <summary>
/// Update details of a task when the Id is passed.
/// </summary>
/// <param name="taskId">Id of task record</param>
/// <param name="modifiedDetails">Modified details for task record</param>
[HttpPut("{taskId}")]
[HttpPut("tasks/{taskId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<TaskDetailsResponse>>> UpdateTaskAsync(int taskId, TaskDetailsRequest modifiedDetails)
{
BaseResponse<TaskDetailsResponse> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.UpdateTaskAsync(taskId, modifiedDetails).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.UpdateTaskAsync(taskId, modifiedDetails).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (NotFoundException ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return BadRequest(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}

/// <summary>
/// Change status of task to inactive.
/// </summary>
/// <param name="taskId">Id of task record</param>
[HttpDelete("{taskId}")]
[HttpDelete("tasks/{taskId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse<TaskDetailsResponse>>> InactiveTaskAsync(int taskId)
{
BaseResponse<TaskDetailsResponse> response = new(ResponseStatus.Fail);

response.Data = await _taskDetailsService.InactiveTaskAsync(taskId).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
try
{
response.Data = await _taskDetailsService.InactiveTaskAsync(taskId).ConfigureAwait(false);
response.Status = ResponseStatus.Success;

return Ok(response);
}
catch (NotFoundException ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return BadRequest(response);
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Status = ResponseStatus.Error;
return StatusCode(StatusCodes.Status500InternalServerError, response);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ public record TaskDetailsRequest
/// Gets the Description of the task.
/// </summary>
[Required(ErrorMessage = "Description is required")]
[StringLength(100, ErrorMessage = "Description Max Length is 100")]
public string Description { get; init; } = string.Empty;
/// <summary>
/// Gets the Budgeted Hours of the task.
/// </summary>
[Required(ErrorMessage = "BudgetedHours is required")]
[Range(0, int.MaxValue, ErrorMessage = "BudgetedHours should be in range of 0 to int.Maxvalue")]
[Range(0, 50, ErrorMessage = "BudgetedHours should be in range of 0 to 50")]
public int BudgetedHours { get; init; }
/// <summary>
/// Gets the user Id of the user the task is assigned to.
Expand All @@ -23,5 +24,6 @@ public record TaskDetailsRequest
/// <summary>
/// Gets the Category of the task.
/// </summary>
[StringLength(100, ErrorMessage = "Category Max Length is 100")]
public string? Category { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DotnetFoundation.Application.Exceptions;
using DotnetFoundation.Application.Interfaces.Persistence;
using DotnetFoundation.Application.Interfaces.Services;
using DotnetFoundation.Application.Models.DTOs.TaskDetailsDTO;
Expand Down Expand Up @@ -35,15 +36,15 @@ public async Task<List<TaskDetailsResponse>> GetActiveTasksAsync()

public async Task<TaskDetailsResponse> GetTaskByIdAsync(int id)
{
TaskDetails response = await _taskDetailsRepository.GetTaskByIdAsync(id).ConfigureAwait(false)
?? throw new Exception($"Task with Id={id} does not exist");
TaskDetails response = await _taskDetailsRepository.GetTaskByIdAsync(id).ConfigureAwait(false)
?? throw new NotFoundException($"Task with Id={id} does not exist");
return _mapper.Map<TaskDetailsResponse>(response);
}

public async Task<TaskDetailsResponse> InsertTaskAsync(TaskDetailsRequest detailsRequest)
{
User? user = await _userRepository.GetUserByIdAsync(detailsRequest.AssignedTo).ConfigureAwait(false)
?? throw new Exception($"AssignedTo with userId = \"{detailsRequest.AssignedTo}\" does not exist. Cannot add task.");
?? throw new NotFoundException($"AssignedTo with userId = \"{detailsRequest.AssignedTo}\" does not exist. Cannot add task.");

// Create new TaskDetails object and add relevant details
TaskDetails taskDetails = new TaskDetails
Expand All @@ -57,8 +58,8 @@ public async Task<TaskDetailsResponse> InsertTaskAsync(TaskDetailsRequest detail
ModifiedBy = detailsRequest.AssignedTo,
ModifiedOn = DateTime.UtcNow,
};
int? taskId = await _taskDetailsRepository.InsertTaskAsync(taskDetails).ConfigureAwait(false)

int? taskId = await _taskDetailsRepository.InsertTaskAsync(taskDetails).ConfigureAwait(false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of a generic Exception in InsertTaskAsync method when there is an error inserting task details is not ideal. It's recommended to define or use a more specific exception type for database operation failures to improve error handling and debugging.

Consider introducing a custom exception, such as DatabaseOperationException, to replace the generic Exception for more specific error handling.

?? throw new Exception($"Error inserting TaskDetails for \"{detailsRequest.Description}\"");

taskDetails.Id = (int)taskId;
Expand All @@ -69,10 +70,10 @@ public async Task<TaskDetailsResponse> InsertTaskAsync(TaskDetailsRequest detail
public async Task<TaskDetailsResponse> UpdateTaskAsync(int id, TaskDetailsRequest modifiedDetails)
{
TaskDetails? existingDetails = await _taskDetailsRepository.GetTaskByIdAsync(id).ConfigureAwait(false)
?? throw new Exception($"Task with Id={id} does not exist");
?? throw new NotFoundException($"Task with Id={id} does not exist");

User? user = await _userRepository.GetUserByIdAsync(modifiedDetails.AssignedTo).ConfigureAwait(false)
?? throw new Exception($"AssignedTo with userId = \"{modifiedDetails.AssignedTo}\" does not exist. Cannot add task.");
?? throw new NotFoundException($"AssignedTo with userId = \"{modifiedDetails.AssignedTo}\" does not exist. Cannot add task.");

TaskDetails? modifiedTask = await _taskDetailsRepository.UpdateTaskAsync(modifiedDetails, existingDetails).ConfigureAwait(false)
?? throw new Exception($"An error occurred while updating Task with id = \"{id}\"");
Expand All @@ -85,7 +86,7 @@ public async Task<TaskDetailsResponse> InactiveTaskAsync(int id)
TaskDetails? existingDetails = await _taskDetailsRepository.GetTaskByIdAsync(id).ConfigureAwait(false);
if (existingDetails == null)
{
throw new Exception($"Task with Id = \"{id}\" does not exist");
throw new NotFoundException($"Task with Id = \"{id}\" does not exist");
}

TaskDetails? response = await _taskDetailsRepository.InactiveTaskAsync(existingDetails).ConfigureAwait(false)
Expand Down
Loading