authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectRead, $project), 403, ); return TicketResource::collection( $project->tickets() ->with([ 'ticketPriority', 'ticketStatus.allowedTargetStatuses.boardColumn', 'ticketStatus.boardColumn', 'ticketType', ]) ->get(), ); } public function options(Request $request, Project $project): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectWrite, $project), 403, ); return response()->json([ 'data' => $this->buildProjectTicketOptionsPayload->handle( $project, Arr::get($request->query(), 'source') === 'board' ? 'board' : 'backlog', ), ]); } public function store(StoreProjectTicketRequest $request, Project $project): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectWrite, $project), 403, ); $ticket = $this->createProjectTicket->handle($project, $request->validated(), $user); return TicketResource::make($ticket->load(['ticketPriority', 'ticketStatus.boardColumn', 'ticketType'])) ->additional([ 'meta' => [ 'message' => "{$ticket->ticket_key} was created.", ], ]) ->response() ->setStatusCode(201); } public function show(Request $request, Project $project, Ticket $ticket): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectRead, $project), 403, ); return response()->json([ 'data' => $this->buildProjectTicketDetailPayload->handle($project, $ticket, $user), ]); } public function update( UpdateProjectTicketRequest $request, Project $project, Ticket $ticket, ): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectWrite, $project), 403, ); $wasUpdated = $this->updateProjectTicket->handle($ticket, $user, $request->validated()); $statusMessage = $wasUpdated ? "{$ticket->ticket_key} was updated." : 'No ticket changes were detected.'; $canManageProject = $this->permissionService->allows($user, Permission::ProjectAdmin, $project); $displayTicket = $ticket->fresh([ 'assignee', 'author', 'fieldValues.ticketFieldDefinition', 'fieldValues.userValue', 'ticketPriority', 'ticketStatus.boardColumn', 'ticketType', 'worklogEntries.actor', ]) ?? $ticket->load([ 'assignee', 'author', 'fieldValues.ticketFieldDefinition', 'fieldValues.userValue', 'ticketPriority', 'ticketStatus.boardColumn', 'ticketType', 'worklogEntries.actor', ]); if (! $project->show_author && ! $canManageProject) { $displayTicket->setRelation('author', null); $displayTicket->author_user_id = null; } return TicketResource::make($displayTicket) ->additional([ 'meta' => [ 'message' => $statusMessage, ], ]) ->response(); } public function statusTargets(Request $request, Project $project, Ticket $ticket): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectRead, $project), 403, ); return response()->json([ 'data' => $this->buildProjectTicketStatusTargetsPayload->handle($ticket), ]); } public function move( MoveProjectTicketRequest $request, Project $project, Ticket $ticket, ): JsonResponse { $user = $this->authenticatedUser($request); abort_unless( $this->permissionService->allows($user, Permission::ProjectWrite, $project), 403, ); $result = $this->moveProjectTicket->handle($project, $ticket, $user, $request->validated()); $message = $result['moved'] ? "{$ticket->ticket_key} moved to {$result['destination_label']}." : "{$ticket->ticket_key} already belongs to {$result['destination_label']}."; return TicketResource::make($ticket->fresh()->load(['ticketPriority', 'ticketStatus.boardColumn', 'ticketType'])) ->additional([ 'meta' => [ 'message' => $message, ], ]) ->response(); } }