Skip to content

Commit 07893ef

Browse files
committed
Add initial go at user created databases for servers, still needs cleaning
1 parent 87b96bd commit 07893ef

File tree

11 files changed

+314
-25
lines changed

11 files changed

+314
-25
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Pterodactyl\Exceptions\Service\Database;
4+
5+
use Pterodactyl\Exceptions\PterodactylException;
6+
7+
class DatabaseClientFeatureNotEnabledException extends PterodactylException
8+
{
9+
public function __construct()
10+
{
11+
parent::__construct('Client database creation is not enabled in this Panel.');
12+
}
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Pterodactyl\Exceptions\Service\Database;
4+
5+
use Pterodactyl\Exceptions\DisplayException;
6+
7+
class NoSuitableDatabaseHostException extends DisplayException
8+
{
9+
/**
10+
* NoSuitableDatabaseHostException constructor.
11+
*/
12+
public function __construct()
13+
{
14+
parent::__construct('No database host was found that meets the requirements for this server.');
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Pterodactyl\Exceptions\Service\Database;
4+
5+
use Pterodactyl\Exceptions\DisplayException;
6+
7+
class TooManyDatabasesException extends DisplayException
8+
{
9+
public function __construct()
10+
{
11+
parent::__construct('Operation aborted: creating a new database would put this server over the defined limit.');
12+
}
13+
}

app/Http/Controllers/Server/DatabaseController.php

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,64 @@
55
use Illuminate\View\View;
66
use Illuminate\Http\Request;
77
use Illuminate\Http\JsonResponse;
8+
use Illuminate\Http\RedirectResponse;
9+
use Prologue\Alerts\AlertsMessageBag;
810
use Pterodactyl\Http\Controllers\Controller;
911
use Pterodactyl\Traits\Controllers\JavascriptInjection;
1012
use Pterodactyl\Services\Databases\DatabasePasswordService;
13+
use Pterodactyl\Services\Databases\DeployServerDatabaseService;
1114
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
15+
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
16+
use Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest;
1217

1318
class DatabaseController extends Controller
1419
{
1520
use JavascriptInjection;
1621

22+
/**
23+
* @var \Prologue\Alerts\AlertsMessageBag
24+
*/
25+
private $alert;
26+
27+
/**
28+
* @var \Pterodactyl\Services\Databases\DeployServerDatabaseService
29+
*/
30+
private $deployServerDatabaseService;
31+
32+
/**
33+
* @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface
34+
*/
35+
private $databaseHostRepository;
36+
1737
/**
1838
* @var \Pterodactyl\Services\Databases\DatabasePasswordService
1939
*/
20-
protected $passwordService;
40+
private $passwordService;
2141

2242
/**
2343
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
2444
*/
25-
protected $repository;
45+
private $repository;
2646

2747
/**
2848
* DatabaseController constructor.
2949
*
30-
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
31-
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
50+
* @param \Prologue\Alerts\AlertsMessageBag $alert
51+
* @param \Pterodactyl\Services\Databases\DeployServerDatabaseService $deployServerDatabaseService
52+
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
53+
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
54+
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
3255
*/
33-
public function __construct(DatabasePasswordService $passwordService, DatabaseRepositoryInterface $repository)
34-
{
56+
public function __construct(
57+
AlertsMessageBag $alert,
58+
DeployServerDatabaseService $deployServerDatabaseService,
59+
DatabaseHostRepositoryInterface $databaseHostRepository,
60+
DatabasePasswordService $passwordService,
61+
DatabaseRepositoryInterface $repository
62+
) {
63+
$this->alert = $alert;
64+
$this->databaseHostRepository = $databaseHostRepository;
65+
$this->deployServerDatabaseService = $deployServerDatabaseService;
3566
$this->passwordService = $passwordService;
3667
$this->repository = $repository;
3768
}
@@ -50,11 +81,42 @@ public function index(Request $request): View
5081
$this->authorize('view-databases', $server);
5182
$this->setRequest($request)->injectJavascript();
5283

84+
$canCreateDatabase = config('pterodactyl.client_features.databases.enabled');
85+
$allowRandom = config('pterodactyl.client_features.databases.allow_random');
86+
87+
if ($this->databaseHostRepository->findCountWhere([['node_id', '=', $server->node_id]]) === 0) {
88+
if ($canCreateDatabase && ! $allowRandom) {
89+
$canCreateDatabase = false;
90+
}
91+
}
92+
93+
$databases = $this->repository->getDatabasesForServer($server->id);
94+
5395
return view('server.databases.index', [
54-
'databases' => $this->repository->getDatabasesForServer($server->id),
96+
'allowCreation' => $canCreateDatabase,
97+
'overLimit' => ! is_null($server->database_limit) && count($databases) >= $server->database_limit,
98+
'databases' => $databases,
5599
]);
56100
}
57101

102+
/**
103+
* Handle a request from a user to create a new database for the server.
104+
*
105+
* @param \Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest $request
106+
* @return \Illuminate\Http\RedirectResponse
107+
*
108+
* @throws \Exception
109+
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
110+
*/
111+
public function store(StoreServerDatabaseRequest $request): RedirectResponse
112+
{
113+
$this->deployServerDatabaseService->handle($request->getServer(), $request->validated());
114+
115+
$this->alert->success('Successfully created a new database.')->flash();
116+
117+
return redirect()->route('server.databases.index', $request->getServer()->uuidShort);
118+
}
119+
58120
/**
59121
* Handle a request to update the password for a specific database.
60122
*
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Server\Database;
4+
5+
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
6+
7+
class StoreServerDatabaseRequest extends ServerFormRequest
8+
{
9+
/**
10+
* @return bool
11+
*/
12+
public function authorize()
13+
{
14+
if (! parent::authorize()) {
15+
return false;
16+
}
17+
18+
return config('pterodactyl.client_features.databases.enabled');
19+
}
20+
21+
/**
22+
* Return the user permission to validate this request aganist.
23+
*
24+
* @return string
25+
*/
26+
protected function permission(): string
27+
{
28+
return 'create-database';
29+
}
30+
31+
/**
32+
* Rules to validate this request aganist.
33+
*
34+
* @return array
35+
*/
36+
public function rules()
37+
{
38+
return [
39+
'database' => 'required|string|min:1',
40+
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
41+
];
42+
}
43+
}

app/Http/Requests/Server/ServerFormRequest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Pterodactyl\Http\Requests\Server;
44

5+
use Pterodactyl\Models\Server;
56
use Pterodactyl\Http\Requests\FrontendUserFormRequest;
67

78
abstract class ServerFormRequest extends FrontendUserFormRequest
@@ -24,6 +25,11 @@ public function authorize()
2425
return false;
2526
}
2627

27-
return $this->user()->can($this->permission(), $this->attributes->get('server'));
28+
return $this->user()->can($this->permission(), $this->getServer());
29+
}
30+
31+
public function getServer(): Server
32+
{
33+
return $this->attributes->get('server');
2834
}
2935
}

app/Services/Databases/DatabaseManagementService.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,27 @@ class DatabaseManagementService
1313
/**
1414
* @var \Illuminate\Database\DatabaseManager
1515
*/
16-
protected $database;
16+
private $database;
1717

1818
/**
1919
* @var \Pterodactyl\Extensions\DynamicDatabaseConnection
2020
*/
21-
protected $dynamic;
21+
private $dynamic;
2222

2323
/**
2424
* @var \Illuminate\Contracts\Encryption\Encrypter
2525
*/
26-
protected $encrypter;
26+
private $encrypter;
2727

2828
/**
2929
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
3030
*/
31-
protected $repository;
31+
private $repository;
32+
33+
/**
34+
* @var bool
35+
*/
36+
protected $useRandomHost = false;
3237

3338
/**
3439
* CreationService constructor.
@@ -55,7 +60,7 @@ public function __construct(
5560
*
5661
* @param int $server
5762
* @param array $data
58-
* @return \Illuminate\Database\Eloquent\Model
63+
* @return \Pterodactyl\Models\Database
5964
*
6065
* @throws \Exception
6166
*/
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace Pterodactyl\Services\Databases;
4+
5+
use Pterodactyl\Models\Server;
6+
use Pterodactyl\Models\Database;
7+
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
8+
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
9+
use Pterodactyl\Exceptions\Service\Database\TooManyDatabasesException;
10+
use Pterodactyl\Exceptions\Service\Database\NoSuitableDatabaseHostException;
11+
use Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException;
12+
13+
class DeployServerDatabaseService
14+
{
15+
/**
16+
* @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface
17+
*/
18+
private $databaseHostRepository;
19+
20+
/**
21+
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
22+
*/
23+
private $managementService;
24+
/**
25+
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
26+
*/
27+
private $repository;
28+
29+
/**
30+
* ServerDatabaseCreationService constructor.
31+
*
32+
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
33+
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
34+
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $managementService
35+
*/
36+
public function __construct(
37+
DatabaseRepositoryInterface $repository,
38+
DatabaseHostRepositoryInterface $databaseHostRepository,
39+
DatabaseManagementService $managementService
40+
) {
41+
$this->databaseHostRepository = $databaseHostRepository;
42+
$this->managementService = $managementService;
43+
$this->repository = $repository;
44+
}
45+
46+
/**
47+
* @param \Pterodactyl\Models\Server $server
48+
* @param array $data
49+
* @return \Pterodactyl\Models\Database
50+
*
51+
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
52+
* @throws \Exception
53+
*/
54+
public function handle(Server $server, array $data): Database
55+
{
56+
if (! config('pterodactyl.client_features.databases.enabled')) {
57+
throw new DatabaseClientFeatureNotEnabledException;
58+
}
59+
60+
$databases = $this->repository->findCountWhere([['server_id', '=', $server->id]]);
61+
if (! is_null($server->database_limit) && $databases >= $server->database_limit) {
62+
throw new TooManyDatabasesException;
63+
}
64+
65+
$allowRandom = config('pterodactyl.client_features.databases.allow_random');
66+
$host = $this->databaseHostRepository->setColumns(['id'])->findWhere([
67+
['node_id', '=', $server->node_id],
68+
])->random();
69+
70+
if (empty($host) && ! $allowRandom) {
71+
throw new NoSuitableDatabaseHostException;
72+
}
73+
74+
if (empty($host)) {
75+
$host = $this->databaseHostRepository->setColumns(['id'])->all()->random();
76+
if (empty($host)) {
77+
throw new NoSuitableDatabaseHostException;
78+
}
79+
}
80+
81+
return $this->managementService->create($server->id, [
82+
'database_host_id' => $host->id,
83+
'database' => array_get($data, 'database'),
84+
'remote' => array_get($data, 'remote'),
85+
]);
86+
}
87+
}

config/pterodactyl.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,21 @@
163163
'in_context' => env('PHRASE_IN_CONTEXT', false),
164164
],
165165

166+
/*
167+
|--------------------------------------------------------------------------
168+
| Language Editor
169+
|--------------------------------------------------------------------------
170+
|
171+
| Set `PHRASE_IN_CONTEXT` to true to enable the PhaseApp in-context editor
172+
| on this site which allows you to translate the panel, from the panel.
173+
*/
174+
'client_features' => [
175+
'databases' => [
176+
'enabled' => env('PTERODACTYL_CLIENT_DATABASES_ENABLED', true),
177+
'allow_random' => env('PTERODACTYL_CLIENT_DATABASES_ALLOW_RANDOM', true),
178+
],
179+
],
180+
166181
/*
167182
|--------------------------------------------------------------------------
168183
| File Editor

0 commit comments

Comments
 (0)