Files
KanbanGit/app/Http/Controllers/Api/ProjectBoardSettingsController.php
Twyco 8b25421e7c
linter / quality (pull_request) Successful in 1m18s
tests / ci (8.4) (pull_request) Successful in 1m28s
Add application API and OpenAPI docs
2026-04-20 13:22:56 +02:00

168 lines
5.9 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Actions\Permissions\PermissionService;
use App\Actions\ProjectBoard\DeleteBoardColumn;
use App\Actions\ProjectBoard\DeleteTicketStatus;
use App\Actions\ProjectBoard\StoreBoardColumn;
use App\Actions\ProjectBoard\StoreTicketStatus;
use App\Actions\ProjectBoard\UpdateBoardColumn;
use App\Actions\ProjectBoard\UpdateTicketStatus;
use App\Actions\ProjectBoard\UpdateTicketStatusTransitions;
use App\Actions\Projects\BuildProjectBoardSettingsPayload;
use App\Enums\Permission;
use App\Http\Requests\StoreBoardColumnRequest;
use App\Http\Requests\StoreTicketStatusRequest;
use App\Http\Requests\UpdateBoardColumnRequest;
use App\Http\Requests\UpdateTicketStatusRequest;
use App\Http\Requests\UpdateTicketStatusTransitionsRequest;
use App\Http\Resources\BoardColumnResource;
use App\Http\Resources\TicketStatusResource;
use App\Models\BoardColumn;
use App\Models\Project;
use App\Models\TicketStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ProjectBoardSettingsController extends ApiController
{
public function __construct(
private readonly BuildProjectBoardSettingsPayload $buildProjectBoardSettingsPayload,
private readonly DeleteBoardColumn $deleteBoardColumn,
private readonly DeleteTicketStatus $deleteTicketStatus,
private readonly PermissionService $permissionService,
private readonly StoreBoardColumn $storeBoardColumn,
private readonly StoreTicketStatus $storeTicketStatus,
private readonly UpdateBoardColumn $updateBoardColumn,
private readonly UpdateTicketStatus $updateTicketStatus,
private readonly UpdateTicketStatusTransitions $updateTicketStatusTransitions,
) {}
public function show(Request $request, Project $project): JsonResponse
{
$this->abortUnlessCanManage($request, $project);
return response()->json([
'data' => $this->buildProjectBoardSettingsPayload->handle($project),
]);
}
public function storeColumn(StoreBoardColumnRequest $request, Project $project): JsonResponse
{
$this->abortUnlessCanManage($request, $project);
$boardColumn = $this->storeBoardColumn->handle($project, $request->validated());
return BoardColumnResource::make($boardColumn->load('ticketStatuses'))
->additional([
'meta' => [
'message' => "{$boardColumn->name} was added to the board workflow.",
],
])
->response()
->setStatusCode(201);
}
public function updateColumn(
UpdateBoardColumnRequest $request,
Project $project,
BoardColumn $boardColumn,
): JsonResponse {
$this->abortUnlessCanManage($request, $project);
$boardColumn = $this->updateBoardColumn->handle($project, $boardColumn, $request->validated());
return BoardColumnResource::make($boardColumn->load('ticketStatuses'))
->additional([
'meta' => [
'message' => "{$boardColumn->name} was updated.",
],
])
->response();
}
public function destroyColumn(Request $request, Project $project, BoardColumn $boardColumn): JsonResponse
{
$this->abortUnlessCanManage($request, $project);
$this->deleteBoardColumn->handle($project, $boardColumn);
return response()->json(null, 204);
}
public function storeStatus(StoreTicketStatusRequest $request, Project $project): JsonResponse
{
$this->abortUnlessCanManage($request, $project);
$ticketStatus = $this->storeTicketStatus->handle($project, $request->validated());
return TicketStatusResource::make($ticketStatus)
->additional([
'meta' => [
'message' => "{$ticketStatus->name} was added to {$this->statusContextLabel($ticketStatus)}.",
],
])
->response()
->setStatusCode(201);
}
public function updateStatus(
UpdateTicketStatusRequest $request,
Project $project,
TicketStatus $ticketStatus,
): JsonResponse {
$this->abortUnlessCanManage($request, $project);
$ticketStatus = $this->updateTicketStatus->handle($ticketStatus, $request->validated());
return TicketStatusResource::make($ticketStatus->load('boardColumn'))
->additional([
'meta' => [
'message' => "{$ticketStatus->name} was updated.",
],
])
->response();
}
public function destroyStatus(Request $request, Project $project, TicketStatus $ticketStatus): JsonResponse
{
$this->abortUnlessCanManage($request, $project);
$this->deleteTicketStatus->handle($project, $ticketStatus);
return response()->json(null, 204);
}
public function updateStatusTransitions(
UpdateTicketStatusTransitionsRequest $request,
Project $project,
TicketStatus $ticketStatus,
): JsonResponse {
$this->abortUnlessCanManage($request, $project);
$ticketStatus = $this->updateTicketStatusTransitions->handle($ticketStatus, $request->validated());
return TicketStatusResource::make($ticketStatus->load(['allowedTargetStatuses.boardColumn', 'boardColumn']))
->additional([
'meta' => [
'message' => "{$ticketStatus->name} move targets were updated.",
],
])
->response();
}
private function abortUnlessCanManage(Request $request, Project $project): void
{
abort_unless(
$this->permissionService->allows($this->authenticatedUser($request), Permission::ProjectAdmin, $project),
403,
);
}
private function statusContextLabel(TicketStatus $ticketStatus): string
{
return $ticketStatus->boardColumn?->name ?? 'Backlog';
}
}