Files
nexus/backend/Controllers/ProjectsController.cs
T
AzuTear f5552218bc
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s
feat: ship agent-first mission control v0.2.57
2026-07-31 22:39:47 +02:00

122 lines
4.4 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Nexus.Api.DTOs;
using Nexus.Api.Models;
using Nexus.Api.Services;
namespace Nexus.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/v1/projects")]
public class ProjectsController(IProjectService projectService) : ControllerBase
{
[HttpGet]
[ProducesResponseType(typeof(IReadOnlyList<ProjectDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<IReadOnlyList<ProjectDto>>> GetAll(CancellationToken ct)
=> Ok((await projectService.GetAllAsync(ct)).Select(project => Map(project)).ToArray());
[HttpGet("{id:guid}")]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ProjectDto>> GetById(Guid id, CancellationToken ct)
{
var project = await projectService.GetByIdAsync(id, ct);
return project is null ? NotFound() : Ok(Map(project));
}
[HttpGet("{id:guid}/tasks")]
[ProducesResponseType(typeof(IReadOnlyList<ProjectTaskDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<ActionResult<IReadOnlyList<ProjectTaskDto>>> GetTasks(
Guid id,
CancellationToken ct)
{
if (await projectService.GetByIdAsync(id, ct) is null)
return NotFound();
var tasks = await projectService.GetTasksAsync(id, ct);
return Ok(tasks.Select(task => new ProjectTaskDto(
task.Id,
task.Title,
task.State,
task.Priority,
id,
task.AssignedTo,
task.ExpectedFrom,
task.IsAgentTask,
task.UpdatedAt)).ToArray());
}
[HttpPost]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<ProjectDto>> Create(
[FromBody] CreateProjectRequest request,
CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(request.Name))
{
ModelState.AddModelError("name", "Name is required.");
return ValidationProblem(ModelState);
}
var project = await projectService.CreateAsync(request, ct);
return Created(
$"/api/v1/projects/{project.Id}",
Map(project, ProjectOperation(project, "created")));
}
[HttpPatch("{id:guid}")]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ProjectDto>> Update(
Guid id,
[FromBody] UpdateProjectRequest request,
CancellationToken ct)
{
var project = await projectService.UpdateAsync(id, request, ct);
return project is null
? NotFound()
: Ok(Map(project, ProjectOperation(project, "updated")));
}
[HttpDelete("{id:guid}")]
[ProducesResponseType(typeof(ProjectDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{
var result = await projectService.DeleteAsync(id, ct);
return result.Outcome switch
{
ProjectDeleteOutcome.NotFound => NotFound(),
ProjectDeleteOutcome.Archived => Ok(Map(
result.Project!,
ProjectOperation(result.Project!, "archived"))),
_ => Ok(Map(
result.Project!,
ProjectOperation(result.Project!, "deleted")))
};
}
private OperationResultDto ProjectOperation(
Nexus.Api.Data.Project project,
string status)
=> OperationResultFactory.FromHttpContext(
HttpContext,
status,
new EntityRefDto("project", project.Id.ToString(), project.Name));
private static ProjectDto Map(
Nexus.Api.Data.Project project,
OperationResultDto? operation = null)
=> new(
project.Id,
project.Name,
project.Description,
project.Status.ToString(),
project.Progress,
project.UpdatedAt,
operation);
}