validate([ 'status_name' => ['nullable', 'string'], 'status_slug' => ['nullable', 'string'], 'ticket_id' => ['required', 'integer'], 'ticket_status_id' => ['nullable', 'integer'], ]); $user = $this->kanbanGitMcp->user($request); $ticket = $this->kanbanGitMcp->ticketForWrite($user, (int) $validated['ticket_id']); $ticketStatuses = $this->kanbanGitMcp->resolveTicketStatuses($user, $validated, $ticket->project); if ($ticketStatuses instanceof Response) { return $ticketStatuses; } if ($ticketStatuses->isEmpty()) { return Response::error('Ticket status was not found in this ticket project.'); } $destinationStatus = $ticketStatuses->first(); if ($destinationStatus->project_id !== $ticket->project_id) { return Response::error('Ticket status must belong to the same project as the ticket.'); } $ticket->loadMissing('ticketStatus'); if ( $ticket->ticket_status_id !== $destinationStatus->id && ! ($ticket->ticketStatus?->allowedTargetStatuses()->whereKey($destinationStatus->id)->exists() ?? false) ) { return Response::error('Choose a status this ticket is allowed to move to.'); } $result = $this->moveProjectTicket->handle($ticket->project, $ticket, $user, [ 'ticket_status_id' => $destinationStatus->id, ]); return Response::structured([ 'data' => $this->kanbanGitMcp->ticketPayload($ticket->fresh()), 'meta' => [ 'destination_label' => $result['destination_label'], 'message' => $result['moved'] ? "{$ticket->ticket_key} moved to {$result['destination_label']}." : "{$ticket->ticket_key} already belongs to {$result['destination_label']}.", 'moved' => $result['moved'], ], ]); } /** * @return array */ public function schema(JsonSchema $schema): array { return [ 'status_name' => $schema->string() ->nullable() ->description('Exact target status name. Must resolve to one status in the ticket project.'), 'status_slug' => $schema->string() ->nullable() ->description('Target status slug. Must resolve to one status in the ticket project.'), 'ticket_id' => $schema->integer() ->description('Ticket ID.') ->required(), 'ticket_status_id' => $schema->integer() ->nullable() ->description('Stable target status ID. Preferred when available.'), ]; } }