coolify/app/Models/Project.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

186 lines
5.3 KiB
PHP

<?php
namespace App\Models;
use App\Models\V5\Application as V5Application;
use App\Models\V5\ResourceConnection as V5ResourceConnection;
use App\Traits\ClearsGlobalSearchCache;
use App\Traits\HasSafeStringAttribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Collection;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'Project model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
]
)]
class Project extends BaseModel
{
use ClearsGlobalSearchCache;
use HasFactory;
use HasSafeStringAttribute;
protected $fillable = [
'name',
'description',
'team_id',
'uuid',
];
/**
* Get query builder for projects owned by current team.
* If you need all projects without further query chaining, use ownedByCurrentTeamCached() instead.
*/
public static function ownedByCurrentTeam()
{
return Project::whereTeamId(currentTeam()->id)->orderByRaw('LOWER(name)');
}
/**
* Get all projects owned by current team (cached for request duration).
*/
public static function ownedByCurrentTeamCached()
{
return once(function () {
return Project::ownedByCurrentTeam()->get();
});
}
protected static function booted()
{
static::created(function ($project) {
ProjectSetting::create([
'project_id' => $project->id,
]);
Environment::create([
'name' => 'production',
'project_id' => $project->id,
'uuid' => new_public_id(),
]);
});
static::deleting(function ($project) {
$project->environments()->delete();
$project->settings()->delete();
$shared_variables = $project->environment_variables();
foreach ($shared_variables as $shared_variable) {
$shared_variable->delete();
}
});
}
public function environment_variables()
{
return $this->hasMany(SharedEnvironmentVariable::class)->where('type', 'project');
}
public function environments()
{
return $this->hasMany(Environment::class);
}
public function settings()
{
return $this->hasOne(ProjectSetting::class);
}
public function team()
{
return $this->belongsTo(Team::class);
}
public function services()
{
return $this->hasManyThrough(Service::class, Environment::class);
}
public function applications()
{
return $this->hasManyThrough(Application::class, Environment::class);
}
public function postgresqls()
{
return $this->hasManyThrough(StandalonePostgresql::class, Environment::class);
}
public function redis()
{
return $this->hasManyThrough(StandaloneRedis::class, Environment::class);
}
public function keydbs()
{
return $this->hasManyThrough(StandaloneKeydb::class, Environment::class);
}
public function dragonflies()
{
return $this->hasManyThrough(StandaloneDragonfly::class, Environment::class);
}
public function clickhouses()
{
return $this->hasManyThrough(StandaloneClickhouse::class, Environment::class);
}
public function mongodbs()
{
return $this->hasManyThrough(StandaloneMongodb::class, Environment::class);
}
public function mysqls()
{
return $this->hasManyThrough(StandaloneMysql::class, Environment::class);
}
public function mariadbs()
{
return $this->hasManyThrough(StandaloneMariadb::class, Environment::class);
}
public function isEmpty()
{
return ! V5Application::query()->where('project_id', $this->id)->exists() &&
! V5ResourceConnection::query()->where('project_id', $this->id)->exists() &&
$this->applications()->count() == 0 &&
$this->redis()->count() == 0 &&
$this->postgresqls()->count() == 0 &&
$this->mysqls()->count() == 0 &&
$this->keydbs()->count() == 0 &&
$this->dragonflies()->count() == 0 &&
$this->clickhouses()->count() == 0 &&
$this->mariadbs()->count() == 0 &&
$this->mongodbs()->count() == 0 &&
$this->services()->count() == 0;
}
public function databases(array $with = []): Collection
{
return $this->postgresqls()->with($with)->get()
->merge($this->redis()->with($with)->get())
->merge($this->mongodbs()->with($with)->get())
->merge($this->mysqls()->with($with)->get())
->merge($this->mariadbs()->with($with)->get())
->merge($this->keydbs()->with($with)->get())
->merge($this->dragonflies()->with($with)->get())
->merge($this->clickhouses()->with($with)->get());
}
public function navigateTo()
{
if ($this->environments->count() === 1) {
return route('project.resource.index', [
'project_uuid' => $this->uuid,
'environment_uuid' => $this->environments->first()->uuid,
]);
}
return route('project.show', ['project_uuid' => $this->uuid]);
}
}