Files
coolify/app/Http/Controllers/V5/Concerns/ResolvesProjectSelection.php
Andras Bacsai a4ab69df56 feat(v5): authorize creates, deep-link selection, list apps in v4
Restrict V5 application and resource-connection creation to team admins.
Resolve project, environment, and application from query params and keep
session selection in sync. Surface V5 apps on the v4 resource index and
count them for project/environment emptiness. Create the flux data dir
on install and upgrade.
2026-07-18 15:55:47 +02:00

123 lines
4.1 KiB
PHP

<?php
namespace App\Http\Controllers\V5\Concerns;
use App\Models\Environment;
use App\Models\Project;
use App\Models\Team;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
trait ResolvesProjectSelection
{
protected const SELECTED_PROJECT_SESSION_KEY = 'v5.selectedProjectUuid';
protected const SELECTED_ENVIRONMENT_SESSION_KEY = 'v5.selectedEnvironmentUuid';
/**
* @return array{id: int}|null
*/
protected function serializeCurrentTeam(mixed $currentTeam): ?array
{
if (! $currentTeam instanceof Team) {
return null;
}
return [
'id' => $currentTeam->id,
];
}
/**
* @param array<int, array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}> $projects
* @return array{0: array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}|null, 1: array{uuid: string, name: string}|null}
*/
protected function selectedProjectAndEnvironment(Request $request, array $projects): array
{
$selectedProjectUuid = $request->query('project', $request->session()->get(self::SELECTED_PROJECT_SESSION_KEY));
$selectedEnvironmentUuid = $request->query('environment', $request->session()->get(self::SELECTED_ENVIRONMENT_SESSION_KEY));
$selectedProject = null;
foreach ($projects as $project) {
if ($project['uuid'] === $selectedProjectUuid) {
$selectedProject = $project;
break;
}
}
$selectedProject ??= $projects[0] ?? null;
$selectedEnvironment = null;
foreach ($selectedProject['environments'] ?? [] as $environment) {
if ($environment['uuid'] === $selectedEnvironmentUuid) {
$selectedEnvironment = $environment;
break;
}
}
$selectedEnvironment ??= $selectedProject['environments'][0] ?? null;
if ($request->query->has('project') || $request->query->has('environment')) {
$request->session()->put([
self::SELECTED_PROJECT_SESSION_KEY => $selectedProject['uuid'] ?? null,
self::SELECTED_ENVIRONMENT_SESSION_KEY => $selectedEnvironment['uuid'] ?? null,
]);
}
return [$selectedProject, $selectedEnvironment];
}
protected function selectedEnvironment(Project $project, ?string $environmentUuid): ?Environment
{
if ($environmentUuid === null) {
return $project->environments->first();
}
$environment = $project->environments->firstWhere('uuid', $environmentUuid);
if (! $environment instanceof Environment) {
abort(422, 'The selected environment is not available for the selected project.');
}
return $environment;
}
/**
* @return array<int, array{uuid: string, name: string, environments: array<int, array{uuid: string, name: string}>}>
*/
protected function projects(mixed $currentTeam): array
{
if (! $currentTeam instanceof Team) {
return [];
}
return $this->projectQuery($currentTeam)
->get()
->map(fn (Project $project) => [
'uuid' => $project->uuid,
'name' => $project->name,
'environments' => $project->environments
->map(fn ($environment) => [
'uuid' => $environment->uuid,
'name' => $environment->name,
])
->all(),
])
->all();
}
protected function projectQuery(Team $currentTeam): Builder
{
return Project::query()
->select(['id', 'uuid', 'name', 'team_id'])
->where('team_id', $currentTeam->id)
->with(['environments' => fn ($query) => $query
->select(['id', 'uuid', 'name', 'project_id'])
->orderByRaw("CASE WHEN LOWER(name) = 'production' THEN 0 ELSE 1 END")
->orderByRaw('LOWER(name)')])
->orderByRaw('LOWER(name)');
}
}