140 lines
5.8 KiB
PHP
140 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Actions\Projects;
|
|
|
|
use App\Actions\Git\BuildSuggestedTicketBranchName;
|
|
use App\Actions\Git\ResolveTicketBranchMatches;
|
|
use App\Actions\Git\ResolveTicketPullRequestMatches;
|
|
use App\Actions\Permissions\PermissionService;
|
|
use App\Enums\Permission;
|
|
use App\Http\Resources\ProjectResource;
|
|
use App\Http\Resources\TicketFieldDefinitionResource;
|
|
use App\Http\Resources\TicketLinkResource;
|
|
use App\Http\Resources\TicketLinkTypeResource;
|
|
use App\Http\Resources\TicketPriorityResource;
|
|
use App\Http\Resources\TicketReferenceResource;
|
|
use App\Http\Resources\TicketRepositoryBranchResource;
|
|
use App\Http\Resources\TicketRepositoryPullRequestResource;
|
|
use App\Http\Resources\TicketResource;
|
|
use App\Http\Resources\TicketTreeNodeResource;
|
|
use App\Http\Resources\TicketTypeResource;
|
|
use App\Http\Resources\UserResource;
|
|
use App\Models\Project;
|
|
use App\Models\Ticket;
|
|
use App\Models\TicketLink;
|
|
use App\Models\User;
|
|
|
|
class BuildProjectTicketDetailPayload
|
|
{
|
|
public function __construct(
|
|
private readonly BuildSuggestedTicketBranchName $buildSuggestedTicketBranchName,
|
|
private readonly PermissionService $permissionService,
|
|
private readonly ResolveTicketBranchMatches $resolveTicketBranchMatches,
|
|
private readonly ResolveTicketPullRequestMatches $resolveTicketPullRequestMatches,
|
|
) {}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function handle(Project $project, Ticket $ticket, User $user, mixed $status = null): array
|
|
{
|
|
$canEditTicket = $this->permissionService->allows($user, Permission::ProjectWrite, $project);
|
|
$canManageProject = $this->permissionService->allows($user, Permission::ProjectAdmin, $project);
|
|
$displayTicket = $ticket->load([
|
|
'assignee',
|
|
'author',
|
|
'fieldValues.ticketFieldDefinition',
|
|
'fieldValues.userValue',
|
|
'parentTicket',
|
|
'ticketPriority',
|
|
'ticketStatus.boardColumn',
|
|
'ticketType',
|
|
'worklogEntries.actor',
|
|
]);
|
|
|
|
if (! $project->show_author && ! $canManageProject) {
|
|
$displayTicket->setRelation('author', null);
|
|
$displayTicket->author_user_id = null;
|
|
}
|
|
|
|
return [
|
|
'canEditTicket' => $canEditTicket,
|
|
'canManageProject' => $canManageProject,
|
|
'childTicketTree' => TicketTreeNodeResource::collection(
|
|
$ticket->childTickets()
|
|
->with('ticketType')
|
|
->get(),
|
|
)->resolve(),
|
|
'linkedTickets' => TicketLinkResource::collection(
|
|
TicketLink::query()
|
|
->with(['sourceTicket', 'targetTicket', 'ticketLinkType'])
|
|
->where(function ($query) use ($ticket): void {
|
|
$query
|
|
->where('source_ticket_id', $ticket->id)
|
|
->orWhere('target_ticket_id', $ticket->id);
|
|
})
|
|
->orderBy('id')
|
|
->get()
|
|
->each(fn (TicketLink $ticketLink) => $ticketLink->setAttribute('current_ticket_id', $ticket->id)),
|
|
)->resolve(),
|
|
'parentTicketOptions' => TicketReferenceResource::collection(
|
|
Ticket::query()
|
|
->where('project_id', $project->id)
|
|
->whereKeyNot($ticket->id)
|
|
->whereHas('ticketType', fn ($query) => $query->where('is_parent', true))
|
|
->orderByDesc('sequence_number')
|
|
->get(),
|
|
)->resolve(),
|
|
'project' => ProjectResource::make($project)->resolve(),
|
|
'repositoryBranches' => TicketRepositoryBranchResource::collection(
|
|
$this->resolveTicketBranchMatches->handle(
|
|
$user,
|
|
$project,
|
|
$ticket,
|
|
),
|
|
)->resolve(),
|
|
'repositoryPullRequests' => TicketRepositoryPullRequestResource::collection(
|
|
$this->resolveTicketPullRequestMatches->handle(
|
|
$user,
|
|
$project,
|
|
$ticket,
|
|
),
|
|
)->resolve(),
|
|
'status' => $status,
|
|
'suggestedBranchName' => $this->buildSuggestedTicketBranchName->handle($ticket),
|
|
'ticket' => TicketResource::make($displayTicket)->resolve(),
|
|
'ticketFieldDefinitions' => TicketFieldDefinitionResource::collection($project->ticketFieldDefinitions()->get())->resolve(),
|
|
'ticketLinkOptions' => TicketReferenceResource::collection(
|
|
Ticket::query()
|
|
->where('project_id', $project->id)
|
|
->whereKeyNot($ticket->id)
|
|
->orderByDesc('sequence_number')
|
|
->get(),
|
|
)->resolve(),
|
|
'ticketLinkTypes' => TicketLinkTypeResource::collection($project->ticketLinkTypes()->get())->resolve(),
|
|
'ticketPriorities' => TicketPriorityResource::collection($project->ticketPriorities()->get())->resolve(),
|
|
'ticketTypes' => TicketTypeResource::collection($project->ticketTypes()->get())->resolve(),
|
|
'users' => UserResource::collection(
|
|
User::query()
|
|
->whereIn('id', $this->visibleUserIds($project))
|
|
->orderBy('name')
|
|
->get(),
|
|
)->resolve(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, int>
|
|
*/
|
|
private function visibleUserIds(Project $project): array
|
|
{
|
|
return User::query()
|
|
->get()
|
|
->filter(fn (User $candidate): bool => $this->permissionService->allows($candidate, Permission::ProjectRead, $project))
|
|
->pluck('id')
|
|
->map(fn (mixed $userId): int => (int) $userId)
|
|
->values()
|
|
->all();
|
|
}
|
|
}
|