Files
panel/app/Http/Controllers/Api/Client/Servers/DatabaseController.php
Dane Everitt ec7231bd4a Lock resources more explicitly when creating databases or backups (#5613)
Addresses an issue where the concept of a lock was there, but no actual
lock was acquired.
2026-04-01 18:46:01 -07:00

106 lines
3.9 KiB
PHP

<?php
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Illuminate\Http\Response;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database;
use Pterodactyl\Facades\Activity;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Services\Databases\DatabasePasswordService;
use Pterodactyl\Transformers\Api\Client\DatabaseTransformer;
use Pterodactyl\Services\Databases\DatabaseManagementService;
use Pterodactyl\Services\Databases\DeployServerDatabaseService;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Pterodactyl\Http\Requests\Api\Client\Servers\Databases\GetDatabasesRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Databases\StoreDatabaseRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Databases\DeleteDatabaseRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Databases\RotatePasswordRequest;
class DatabaseController extends ClientApiController
{
/**
* DatabaseController constructor.
*/
public function __construct(
private DeployServerDatabaseService $deployDatabaseService,
private DatabaseManagementService $managementService,
private DatabasePasswordService $passwordService,
) {
parent::__construct();
}
/**
* Return all the databases that belong to the given server.
*/
public function index(GetDatabasesRequest $request, Server $server): array
{
return $this->fractal->collection($server->databases)
->transformWith($this->getTransformer(DatabaseTransformer::class))
->toArray();
}
/**
* Create a new database for the given server and return it.
*
* @throws \Throwable
* @throws \Pterodactyl\Exceptions\Service\Database\TooManyDatabasesException
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
*/
public function store(StoreDatabaseRequest $request, Server $server): array
{
$database = Activity::event('server:database.create')->transaction(function ($log) use ($request, $server) {
if ($server->databases()->lockForUpdate()->count() >= $server->database_limit) {
throw new DisplayException('Cannot create additional databases on this server: limit has been reached.');
}
$database = $this->deployDatabaseService->handle($server, $request->validated());
$log->subject($database)->property('name', $database->database);
return $database;
});
return $this->fractal->item($database)
->parseIncludes(['password'])
->transformWith($this->getTransformer(DatabaseTransformer::class))
->toArray();
}
/**
* Rotates the password for the given server model and returns a fresh instance to
* the caller.
*
* @throws \Throwable
*/
public function rotatePassword(RotatePasswordRequest $request, Server $server, Database $database): array
{
Activity::event('server:database.rotate-password')
->subject($database)
->property('name', $database->database)
->transaction(fn () => $this->passwordService->handle($database));
return $this->fractal->item($database->refresh())
->parseIncludes(['password'])
->transformWith($this->getTransformer(DatabaseTransformer::class))
->toArray();
}
/**
* Removes a database from the server.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function delete(DeleteDatabaseRequest $request, Server $server, Database $database): Response
{
$this->managementService->delete($database);
Activity::event('server:database.delete')
->subject($database)
->property('name', $database->database)
->log();
return new Response('', Response::HTTP_NO_CONTENT);
}
}