Skip to content

Commit 060c642

Browse files
committed
Merge branch 'feature/user-databases' into develop
2 parents f3144b8 + e39353a commit 060c642

File tree

27 files changed

+822
-87
lines changed

27 files changed

+822
-87
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
1818
* Adds back client API for sending commands or power toggles to a server though the Panel API: `/api/client/servers/<identifier>`
1919
* Added proper transformer for Packs and re-enabled missing includes on server.
2020
* Added support for using Filesystem as a caching driver, although not recommended.
21+
* Added support for user management of server databases.
2122

2223
## v0.7.3 (Derelict Dermodactylus)
2324
### Fixed
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: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,76 @@
44

55
use Illuminate\View\View;
66
use Illuminate\Http\Request;
7+
use Illuminate\Http\Response;
78
use Illuminate\Http\JsonResponse;
9+
use Illuminate\Http\RedirectResponse;
10+
use Prologue\Alerts\AlertsMessageBag;
811
use Pterodactyl\Http\Controllers\Controller;
912
use Pterodactyl\Traits\Controllers\JavascriptInjection;
1013
use Pterodactyl\Services\Databases\DatabasePasswordService;
14+
use Pterodactyl\Services\Databases\DatabaseManagementService;
15+
use Pterodactyl\Services\Databases\DeployServerDatabaseService;
1116
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
17+
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
18+
use Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest;
19+
use Pterodactyl\Http\Requests\Server\Database\DeleteServerDatabaseRequest;
1220

1321
class DatabaseController extends Controller
1422
{
1523
use JavascriptInjection;
1624

25+
/**
26+
* @var \Prologue\Alerts\AlertsMessageBag
27+
*/
28+
private $alert;
29+
30+
/**
31+
* @var \Pterodactyl\Services\Databases\DeployServerDatabaseService
32+
*/
33+
private $deployServerDatabaseService;
34+
35+
/**
36+
* @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface
37+
*/
38+
private $databaseHostRepository;
39+
40+
/**
41+
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
42+
*/
43+
private $managementService;
44+
1745
/**
1846
* @var \Pterodactyl\Services\Databases\DatabasePasswordService
1947
*/
20-
protected $passwordService;
48+
private $passwordService;
2149

2250
/**
2351
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
2452
*/
25-
protected $repository;
53+
private $repository;
2654

2755
/**
2856
* DatabaseController constructor.
2957
*
30-
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
31-
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
58+
* @param \Prologue\Alerts\AlertsMessageBag $alert
59+
* @param \Pterodactyl\Services\Databases\DeployServerDatabaseService $deployServerDatabaseService
60+
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
61+
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $managementService
62+
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
63+
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
3264
*/
33-
public function __construct(DatabasePasswordService $passwordService, DatabaseRepositoryInterface $repository)
34-
{
65+
public function __construct(
66+
AlertsMessageBag $alert,
67+
DeployServerDatabaseService $deployServerDatabaseService,
68+
DatabaseHostRepositoryInterface $databaseHostRepository,
69+
DatabaseManagementService $managementService,
70+
DatabasePasswordService $passwordService,
71+
DatabaseRepositoryInterface $repository
72+
) {
73+
$this->alert = $alert;
74+
$this->databaseHostRepository = $databaseHostRepository;
75+
$this->deployServerDatabaseService = $deployServerDatabaseService;
76+
$this->managementService = $managementService;
3577
$this->passwordService = $passwordService;
3678
$this->repository = $repository;
3779
}
@@ -50,11 +92,42 @@ public function index(Request $request): View
5092
$this->authorize('view-databases', $server);
5193
$this->setRequest($request)->injectJavascript();
5294

95+
$canCreateDatabase = config('pterodactyl.client_features.databases.enabled');
96+
$allowRandom = config('pterodactyl.client_features.databases.allow_random');
97+
98+
if ($this->databaseHostRepository->findCountWhere([['node_id', '=', $server->node_id]]) === 0) {
99+
if ($canCreateDatabase && ! $allowRandom) {
100+
$canCreateDatabase = false;
101+
}
102+
}
103+
104+
$databases = $this->repository->getDatabasesForServer($server->id);
105+
53106
return view('server.databases.index', [
54-
'databases' => $this->repository->getDatabasesForServer($server->id),
107+
'allowCreation' => $canCreateDatabase,
108+
'overLimit' => ! is_null($server->database_limit) && count($databases) >= $server->database_limit,
109+
'databases' => $databases,
55110
]);
56111
}
57112

113+
/**
114+
* Handle a request from a user to create a new database for the server.
115+
*
116+
* @param \Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest $request
117+
* @return \Illuminate\Http\RedirectResponse
118+
*
119+
* @throws \Exception
120+
* @throws \Pterodactyl\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException
121+
*/
122+
public function store(StoreServerDatabaseRequest $request): RedirectResponse
123+
{
124+
$this->deployServerDatabaseService->handle($request->getServer(), $request->validated());
125+
126+
$this->alert->success('Successfully created a new database.')->flash();
127+
128+
return redirect()->route('server.databases.index', $request->getServer()->uuidShort);
129+
}
130+
58131
/**
59132
* Handle a request to update the password for a specific database.
60133
*
@@ -74,4 +147,19 @@ public function update(Request $request): JsonResponse
74147

75148
return response()->json(['password' => $password]);
76149
}
150+
151+
/**
152+
* Delete a database for this server from the SQL server and Panel database.
153+
*
154+
* @param \Pterodactyl\Http\Requests\Server\Database\DeleteServerDatabaseRequest $request
155+
* @return \Illuminate\Http\Response
156+
*
157+
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
158+
*/
159+
public function delete(DeleteServerDatabaseRequest $request): Response
160+
{
161+
$this->managementService->delete($request->attributes->get('database')->id);
162+
163+
return response('', Response::HTTP_NO_CONTENT);
164+
}
77165
}

app/Http/Middleware/Server/DatabaseBelongsToServer.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,13 @@ public function __construct(DatabaseRepositoryInterface $repository)
3838
public function handle(Request $request, Closure $next)
3939
{
4040
$server = $request->attributes->get('server');
41+
$database = $request->input('database') ?? $request->route()->parameter('database');
4142

42-
$database = $this->repository->find($request->input('database'));
43+
if (! is_digit($database)) {
44+
throw new NotFoundHttpException;
45+
}
46+
47+
$database = $this->repository->find($database);
4348
if (is_null($database) || $database->server_id !== $server->id) {
4449
throw new NotFoundHttpException;
4550
}

app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
1313
*/
1414
public function rules(): array
1515
{
16-
$rules = Server::getUpdateRulesForId($this->route()->parameter('server')->id);
16+
$rules = Server::getUpdateRulesForId($this->getModel(Server::class)->id);
1717

1818
return [
1919
'allocation' => $rules['allocation_id'],
@@ -26,6 +26,9 @@ public function rules(): array
2626
'add_allocations.*' => 'integer',
2727
'remove_allocations' => 'bail|array',
2828
'remove_allocations.*' => 'integer',
29+
'feature_limits' => 'required|array',
30+
'feature_limits.databases' => $rules['database_limit'],
31+
'feature_limits.allocations' => $rules['allocation_limit'],
2932
];
3033
}
3134

@@ -39,7 +42,9 @@ public function validated()
3942
$data = parent::validated();
4043

4144
$data['allocation_id'] = $data['allocation'];
42-
unset($data['allocation']);
45+
$data['database_limit'] = $data['feature_limits']['databases'];
46+
$data['allocation_limit'] = $data['feature_limits']['allocations'];
47+
unset($data['allocation'], $data['feature_limits']);
4348

4449
return $data;
4550
}
@@ -56,6 +61,8 @@ public function attributes()
5661
'remove_allocations' => 'allocations to remove',
5762
'add_allocations.*' => 'allocation to add',
5863
'remove_allocations.*' => 'allocation to remove',
64+
'feature_limits.databases' => 'Database Limit',
65+
'feature_limits.allocations' => 'Allocation Limit',
5966
];
6067
}
6168
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Server\Database;
4+
5+
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
6+
7+
class DeleteServerDatabaseRequest 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 'delete-database';
29+
}
30+
31+
/**
32+
* Rules to validate this request aganist.
33+
*
34+
* @return array
35+
*/
36+
public function rules()
37+
{
38+
return [];
39+
}
40+
}
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
}

0 commit comments

Comments
 (0)