fix(api/destinations): use whereHas instead of ownedByCurrentTeamAPI for back-compat
The ownedByCurrentTeamAPI scope was added to StandaloneDocker/SwarmDocker
*after* 4.0.0-beta.470 — running containers on that beta hit a
BadMethodCallException. Rewrites all team scoping to use
whereHas('server', whereTeamId) which works against any v4.x of
Coolify (StandaloneDocker.server_id -> Server.team_id has been there
since the multi-team change).
Also guards attachedTo() with method_exists and falls back to a manual
attached-resource check covering applications + every standalone DB
relation, so delete() doesn't crash on older versions either.
This commit is contained in:
parent
789e2c5cab
commit
68e9184b57
1 changed files with 51 additions and 11 deletions
|
|
@ -25,6 +25,9 @@ private function transform($d): array
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the calling token's team id, or return a 403 response.
|
||||||
|
*/
|
||||||
private function teamIdOrAbort(): int|\Illuminate\Http\JsonResponse
|
private function teamIdOrAbort(): int|\Illuminate\Http\JsonResponse
|
||||||
{
|
{
|
||||||
$teamId = getTeamIdFromToken();
|
$teamId = getTeamIdFromToken();
|
||||||
|
|
@ -35,16 +38,33 @@ private function teamIdOrAbort(): int|\Illuminate\Http\JsonResponse
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StandaloneDocker / SwarmDocker scoped to a team via their parent server.
|
||||||
|
* Uses whereHas instead of the model's ownedByCurrentTeamAPI() scope so the
|
||||||
|
* controller works on Coolify versions that pre-date that scope being added
|
||||||
|
* to the destination models (e.g. 4.0.0-beta.470).
|
||||||
|
*/
|
||||||
|
private function teamScopedDockers(int $teamId)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'standalone' => StandaloneDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->get(),
|
||||||
|
'swarm' => SwarmDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->get(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$teamId = $this->teamIdOrAbort();
|
$teamId = $this->teamIdOrAbort();
|
||||||
if (! is_int($teamId)) {
|
if (! is_int($teamId)) {
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
$standalone = StandaloneDocker::ownedByCurrentTeamAPI($teamId)->get();
|
$sets = $this->teamScopedDockers($teamId);
|
||||||
$swarm = SwarmDocker::ownedByCurrentTeamAPI($teamId)->get();
|
|
||||||
|
|
||||||
return response()->json($standalone->concat($swarm)->map(fn ($d) => $this->transform($d))->values());
|
return response()->json(
|
||||||
|
$sets['standalone']->concat($sets['swarm'])
|
||||||
|
->map(fn ($d) => $this->transform($d))
|
||||||
|
->values()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index_by_server(Request $request, string $server_uuid)
|
public function index_by_server(Request $request, string $server_uuid)
|
||||||
|
|
@ -53,7 +73,7 @@ public function index_by_server(Request $request, string $server_uuid)
|
||||||
if (! is_int($teamId)) {
|
if (! is_int($teamId)) {
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
$server = Server::ownedByCurrentTeamAPI($teamId)->whereUuid($server_uuid)->firstOrFail();
|
$server = Server::whereTeamId($teamId)->whereUuid($server_uuid)->firstOrFail();
|
||||||
$list = $server->standaloneDockers->concat($server->swarmDockers);
|
$list = $server->standaloneDockers->concat($server->swarmDockers);
|
||||||
|
|
||||||
return response()->json($list->map(fn ($d) => $this->transform($d))->values());
|
return response()->json($list->map(fn ($d) => $this->transform($d))->values());
|
||||||
|
|
@ -65,8 +85,8 @@ public function show(Request $request, string $uuid)
|
||||||
if (! is_int($teamId)) {
|
if (! is_int($teamId)) {
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
$d = StandaloneDocker::ownedByCurrentTeamAPI($teamId)->whereUuid($uuid)->first()
|
$d = StandaloneDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->whereUuid($uuid)->first()
|
||||||
?? SwarmDocker::ownedByCurrentTeamAPI($teamId)->whereUuid($uuid)->firstOrFail();
|
?? SwarmDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->whereUuid($uuid)->firstOrFail();
|
||||||
|
|
||||||
return response()->json($this->transform($d));
|
return response()->json($this->transform($d));
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +97,7 @@ public function create(Request $request, string $server_uuid)
|
||||||
if (! is_int($teamId)) {
|
if (! is_int($teamId)) {
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
$server = Server::ownedByCurrentTeamAPI($teamId)->whereUuid($server_uuid)->firstOrFail();
|
$server = Server::whereTeamId($teamId)->whereUuid($server_uuid)->firstOrFail();
|
||||||
|
|
||||||
$allowed = ['name', 'network', 'type'];
|
$allowed = ['name', 'network', 'type'];
|
||||||
$extra = array_diff(array_keys($request->all()), $allowed);
|
$extra = array_diff(array_keys($request->all()), $allowed);
|
||||||
|
|
@ -118,10 +138,30 @@ public function delete(Request $request, string $uuid)
|
||||||
if (! is_int($teamId)) {
|
if (! is_int($teamId)) {
|
||||||
return $teamId;
|
return $teamId;
|
||||||
}
|
}
|
||||||
$d = StandaloneDocker::ownedByCurrentTeamAPI($teamId)->whereUuid($uuid)->first()
|
$d = StandaloneDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->whereUuid($uuid)->first()
|
||||||
?? SwarmDocker::ownedByCurrentTeamAPI($teamId)->whereUuid($uuid)->firstOrFail();
|
?? SwarmDocker::whereHas('server', fn ($q) => $q->whereTeamId($teamId))->whereUuid($uuid)->firstOrFail();
|
||||||
if ($d->attachedTo()) {
|
|
||||||
return response()->json(['message' => 'Destination has attached resources, detach first.'], 409);
|
// Guard against deleting destinations with attached resources. attachedTo()
|
||||||
|
// is recent on the destination models; fall back to a manual check for
|
||||||
|
// older Coolify versions (e.g. 4.0.0-beta.470).
|
||||||
|
if (method_exists($d, 'attachedTo')) {
|
||||||
|
if ($d->attachedTo()) {
|
||||||
|
return response()->json(['message' => 'Destination has attached resources, detach first.'], 409);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$hasAttached = $d->applications()->exists()
|
||||||
|
|| $d->postgresqls()->exists()
|
||||||
|
|| (method_exists($d, 'mysqls') && $d->mysqls()->exists())
|
||||||
|
|| (method_exists($d, 'mariadbs') && $d->mariadbs()->exists())
|
||||||
|
|| (method_exists($d, 'mongodbs') && $d->mongodbs()->exists())
|
||||||
|
|| (method_exists($d, 'redis') && $d->redis()->exists())
|
||||||
|
|| (method_exists($d, 'keydbs') && $d->keydbs()->exists())
|
||||||
|
|| (method_exists($d, 'dragonflies') && $d->dragonflies()->exists())
|
||||||
|
|| (method_exists($d, 'clickhouses') && $d->clickhouses()->exists())
|
||||||
|
|| (method_exists($d, 'services') && $d->services()->exists());
|
||||||
|
if ($hasAttached) {
|
||||||
|
return response()->json(['message' => 'Destination has attached resources, detach first.'], 409);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$d->delete();
|
$d->delete();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue