Add initial go at user created databases for servers, still needs cleaning

This commit is contained in:
Dane Everitt 2018-03-01 21:27:37 -06:00
parent 87b96bdfc8
commit 07893effa3
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
11 changed files with 314 additions and 25 deletions

View file

@ -0,0 +1,13 @@
<?php
namespace Pterodactyl\Exceptions\Service\Database;
use Pterodactyl\Exceptions\PterodactylException;
class DatabaseClientFeatureNotEnabledException extends PterodactylException
{
public function __construct()
{
parent::__construct('Client database creation is not enabled in this Panel.');
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Pterodactyl\Exceptions\Service\Database;
use Pterodactyl\Exceptions\DisplayException;
class NoSuitableDatabaseHostException extends DisplayException
{
/**
* NoSuitableDatabaseHostException constructor.
*/
public function __construct()
{
parent::__construct('No database host was found that meets the requirements for this server.');
}
}

View file

@ -0,0 +1,13 @@
<?php
namespace Pterodactyl\Exceptions\Service\Database;
use Pterodactyl\Exceptions\DisplayException;
class TooManyDatabasesException extends DisplayException
{
public function __construct()
{
parent::__construct('Operation aborted: creating a new database would put this server over the defined limit.');
}
}

View file

@ -5,33 +5,64 @@ namespace Pterodactyl\Http\Controllers\Server;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Services\Databases\DatabasePasswordService;
use Pterodactyl\Services\Databases\DeployServerDatabaseService;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
use Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest;
class DatabaseController extends Controller
{
use JavascriptInjection;
/**
* @var \Prologue\Alerts\AlertsMessageBag
*/
private $alert;
/**
* @var \Pterodactyl\Services\Databases\DeployServerDatabaseService
*/
private $deployServerDatabaseService;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface
*/
private $databaseHostRepository;
/**
* @var \Pterodactyl\Services\Databases\DatabasePasswordService
*/
protected $passwordService;
private $passwordService;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
*/
protected $repository;
private $repository;
/**
* DatabaseController constructor.
*
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
* @param \Prologue\Alerts\AlertsMessageBag $alert
* @param \Pterodactyl\Services\Databases\DeployServerDatabaseService $deployServerDatabaseService
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
*/
public function __construct(DatabasePasswordService $passwordService, DatabaseRepositoryInterface $repository)
{
public function __construct(
AlertsMessageBag $alert,
DeployServerDatabaseService $deployServerDatabaseService,
DatabaseHostRepositoryInterface $databaseHostRepository,
DatabasePasswordService $passwordService,
DatabaseRepositoryInterface $repository
) {
$this->alert = $alert;
$this->databaseHostRepository = $databaseHostRepository;
$this->deployServerDatabaseService = $deployServerDatabaseService;
$this->passwordService = $passwordService;
$this->repository = $repository;
}
@ -50,11 +81,42 @@ class DatabaseController extends Controller
$this->authorize('view-databases', $server);
$this->setRequest($request)->injectJavascript();
$canCreateDatabase = config('pterodactyl.client_features.databases.enabled');
$allowRandom = config('pterodactyl.client_features.databases.allow_random');
if ($this->databaseHostRepository->findCountWhere([['node_id', '=', $server->node_id]]) === 0) {
if ($canCreateDatabase && ! $allowRandom) {
$canCreateDatabase = false;
}
}
$databases = $this->repository->getDatabasesForServer($server->id);
return view('server.databases.index', [
'databases' => $this->repository->getDatabasesForServer($server->id),
'allowCreation' => $canCreateDatabase,
'overLimit' => ! is_null($server->database_limit) && count($databases) >= $server->database_limit,
'databases' => $databases,
]);
}
/**
* Handle a request from a user to create a new database for the server.
*
* @param \Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
*/
public function store(StoreServerDatabaseRequest $request): RedirectResponse
{
$this->deployServerDatabaseService->handle($request->getServer(), $request->validated());
$this->alert->success('Successfully created a new database.')->flash();
return redirect()->route('server.databases.index', $request->getServer()->uuidShort);
}
/**
* Handle a request to update the password for a specific database.
*

View file

@ -0,0 +1,43 @@
<?php
namespace Pterodactyl\Http\Requests\Server\Database;
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
class StoreServerDatabaseRequest extends ServerFormRequest
{
/**
* @return bool
*/
public function authorize()
{
if (! parent::authorize()) {
return false;
}
return config('pterodactyl.client_features.databases.enabled');
}
/**
* Return the user permission to validate this request aganist.
*
* @return string
*/
protected function permission(): string
{
return 'create-database';
}
/**
* Rules to validate this request aganist.
*
* @return array
*/
public function rules()
{
return [
'database' => 'required|string|min:1',
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
];
}
}

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Http\Requests\Server;
use Pterodactyl\Models\Server;
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
abstract class ServerFormRequest extends FrontendUserFormRequest
@ -24,6 +25,11 @@ abstract class ServerFormRequest extends FrontendUserFormRequest
return false;
}
return $this->user()->can($this->permission(), $this->attributes->get('server'));
return $this->user()->can($this->permission(), $this->getServer());
}
public function getServer(): Server
{
return $this->attributes->get('server');
}
}

View file

@ -13,22 +13,27 @@ class DatabaseManagementService
/**
* @var \Illuminate\Database\DatabaseManager
*/
protected $database;
private $database;
/**
* @var \Pterodactyl\Extensions\DynamicDatabaseConnection
*/
protected $dynamic;
private $dynamic;
/**
* @var \Illuminate\Contracts\Encryption\Encrypter
*/
protected $encrypter;
private $encrypter;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
*/
protected $repository;
private $repository;
/**
* @var bool
*/
protected $useRandomHost = false;
/**
* CreationService constructor.
@ -55,7 +60,7 @@ class DatabaseManagementService
*
* @param int $server
* @param array $data
* @return \Illuminate\Database\Eloquent\Model
* @return \Pterodactyl\Models\Database
*
* @throws \Exception
*/

View file

@ -0,0 +1,87 @@
<?php
namespace Pterodactyl\Services\Databases;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
use Pterodactyl\Exceptions\Service\Database\TooManyDatabasesException;
use Pterodactyl\Exceptions\Service\Database\NoSuitableDatabaseHostException;
use Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException;
class DeployServerDatabaseService
{
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface
*/
private $databaseHostRepository;
/**
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
*/
private $managementService;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
*/
private $repository;
/**
* ServerDatabaseCreationService constructor.
*
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $managementService
*/
public function __construct(
DatabaseRepositoryInterface $repository,
DatabaseHostRepositoryInterface $databaseHostRepository,
DatabaseManagementService $managementService
) {
$this->databaseHostRepository = $databaseHostRepository;
$this->managementService = $managementService;
$this->repository = $repository;
}
/**
* @param \Pterodactyl\Models\Server $server
* @param array $data
* @return \Pterodactyl\Models\Database
*
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
* @throws \Exception
*/
public function handle(Server $server, array $data): Database
{
if (! config('pterodactyl.client_features.databases.enabled')) {
throw new DatabaseClientFeatureNotEnabledException;
}
$databases = $this->repository->findCountWhere([['server_id', '=', $server->id]]);
if (! is_null($server->database_limit) && $databases >= $server->database_limit) {
throw new TooManyDatabasesException;
}
$allowRandom = config('pterodactyl.client_features.databases.allow_random');
$host = $this->databaseHostRepository->setColumns(['id'])->findWhere([
['node_id', '=', $server->node_id],
])->random();
if (empty($host) && ! $allowRandom) {
throw new NoSuitableDatabaseHostException;
}
if (empty($host)) {
$host = $this->databaseHostRepository->setColumns(['id'])->all()->random();
if (empty($host)) {
throw new NoSuitableDatabaseHostException;
}
}
return $this->managementService->create($server->id, [
'database_host_id' => $host->id,
'database' => array_get($data, 'database'),
'remote' => array_get($data, 'remote'),
]);
}
}