Skip to content

Commit 32dec97

Browse files
committed
Improved database mechanics in admin CP for server view
1 parent 16aaf53 commit 32dec97

File tree

6 files changed

+355
-117
lines changed

6 files changed

+355
-117
lines changed

app/Http/Controllers/Admin/ServersController.php

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ public function viewDatabase(Request $request, $id)
211211
{
212212
$server = Models\Server::where('installed', 1)->with('databases.host')->findOrFail($id);
213213

214-
return view('admin.servers.view.build', ['server' => $server]);
214+
return view('admin.servers.view.database', [
215+
'hosts' => Models\DatabaseServer::all(),
216+
'server' => $server
217+
]);
215218
}
216219

217220
/**
@@ -503,29 +506,73 @@ public function saveStartup(Request $request, $id)
503506
return redirect()->route('admin.servers.view.startup', $id);
504507
}
505508

506-
//
507-
// public function postDatabase(Request $request, $id)
508-
// {
509-
// try {
510-
// $repo = new DatabaseRepository;
511-
// $repo->create($id, $request->only([
512-
// 'db_server', 'database', 'remote',
513-
// ]));
514-
// Alert::success('Added new database to this server.')->flash();
515-
// } catch (DisplayValidationException $ex) {
516-
// return redirect()->route('admin.servers.view', [
517-
// 'id' => $id,
518-
// 'tab' => 'tab_database',
519-
// ])->withInput()->withErrors(json_decode($ex->getMessage()))->withInput();
520-
// } catch (\Exception $ex) {
521-
// Log::error($ex);
522-
// Alert::danger('An exception occured while attempting to add a new database for this server.')->flash();
523-
// }
524-
//
525-
// return redirect()->route('admin.servers.view', [
526-
// 'id' => $id,
527-
// 'tab' => 'tab_database',
528-
// ])->withInput();
529-
// }
530-
// //
509+
/**
510+
* Creates a new database assigned to a specific server.
511+
* @param Request $request
512+
* @param int $id
513+
* @return \Illuminate\Response\RedirectResponse
514+
*/
515+
public function newDatabase(Request $request, $id)
516+
{
517+
$repo = new DatabaseRepository;
518+
519+
try {
520+
$repo->create($id, $request->only(['host', 'database', 'connection']));
521+
522+
Alert::success('A new database was assigned to this server successfully.')->flash();
523+
} catch (DisplayValidationException $ex) {
524+
return redirect()->route('admin.servers.view.database', $id)->withInput()->withErrors(json_decode($ex->getMessage()))->withInput();
525+
} catch(DisplayException $ex) {
526+
Alert::danger($ex->getMessage())->flash();
527+
} catch (\Exception $ex) {
528+
Log::error($ex);
529+
Alert::danger('An exception occured while attempting to add a new database for this server. This error has been logged.')->flash();
530+
}
531+
532+
return redirect()->route('admin.servers.view.database', $id)->withInput();
533+
}
534+
535+
/**
536+
* Resets the database password for a specific database on this server.
537+
* @param Request $request
538+
* @param int $id
539+
* @return \Illuminate\Response\RedirectResponse
540+
*/
541+
public function resetDatabasePassword(Request $request, $id)
542+
{
543+
$database = Models\Database::where('server_id', $id)->findOrFail($request->input('database'));
544+
$repo = new DatabaseRepository;
545+
546+
try {
547+
$repo->password($database->id, str_random(20));
548+
549+
return response('', 204);
550+
} catch (\Exception $ex) {
551+
Log::error($ex);
552+
553+
return response()->json(['error' => 'A unhandled exception occurred while attempting to reset this password. This error has been logged.'], 503);
554+
}
555+
}
556+
557+
/**
558+
* Deletes a database from a server.
559+
* @param Request $request
560+
* @param int $id
561+
* @return \Illuminate\Response\RedirectResponse
562+
*/
563+
public function deleteDatabase(Request $request, $id, $database)
564+
{
565+
$database = Models\Database::where('server_id', $id)->findOrFail($database);
566+
$repo = new DatabaseRepository;
567+
568+
try {
569+
$repo->drop($database->id);
570+
571+
return response('', 204);
572+
} catch (\Exception $ex) {
573+
Log::error($ex);
574+
575+
return response()->json(['error' => 'A unhandled exception occurred while attempting to drop this database. This error has been logged.'], 503);
576+
}
577+
}
531578
}

app/Http/Routes/AdminRoutes.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ public function map(Router $router)
183183
'uses' => 'Admin\ServersController@viewDatabase',
184184
]);
185185

186+
$router->post('/view/{id}/database', [
187+
'uses' => 'Admin\ServersController@newDatabase',
188+
]);
189+
190+
$router->patch('/view/{id}/database', [
191+
'uses' => 'Admin\ServersController@resetDatabasePassword',
192+
]);
193+
194+
$router->delete('/view/{id}/database/{database}/delete', [
195+
'as' => 'admin.servers.view.database.delete',
196+
'uses' => 'Admin\ServersController@deleteDatabase',
197+
]);
198+
186199
$router->get('/view/{id}/manage', [
187200
'as' => 'admin.servers.view.manage',
188201
'uses' => 'Admin\ServersController@viewManage',

app/Repositories/DatabaseRepository.php

Lines changed: 70 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -26,89 +26,98 @@
2626

2727
use DB;
2828
use Crypt;
29+
use Config;
2930
use Validator;
3031
use Pterodactyl\Models;
3132
use Pterodactyl\Exceptions\DisplayException;
32-
use Illuminate\Database\Capsule\Manager as Capsule;
3333
use Pterodactyl\Exceptions\DisplayValidationException;
3434

3535
class DatabaseRepository
3636
{
3737
/**
38-
* Adds a new database to a given database server.
38+
* Adds a new database to a specified database host server.
39+
*
3940
* @param int $server Id of the server to add a database for.
4041
* @param array $options Array of options for creating that database.
42+
*
43+
* @throws \Pterodactyl\Exceptions\DisplayException
44+
* @throws \Pterodactyl\Exceptions\DisplayValidationException
45+
* @throws \Exception
4146
* @return void
4247
*/
43-
public function create($server, $options)
48+
public function create($server, $data)
4449
{
4550
$server = Models\Server::findOrFail($server);
46-
$validator = Validator::make($options, [
47-
'db_server' => 'required|exists:database_servers,id',
51+
52+
$validator = Validator::make($data, [
53+
'host' => 'required|exists:database_servers,id',
4854
'database' => 'required|regex:/^\w{1,100}$/',
49-
'remote' => 'required|regex:/^[0-9%.]{1,15}$/',
55+
'connection' => 'required|regex:/^[0-9%.]{1,15}$/',
5056
]);
5157

5258
if ($validator->fails()) {
5359
throw new DisplayValidationException($validator->errors());
5460
}
5561

62+
$host = Models\DatabaseServer::findOrFail($data['host']);
5663
DB::beginTransaction();
64+
5765
try {
58-
$db = new Models\Database;
59-
$db->fill([
66+
$database = Models\Database::firstOrNew([
6067
'server_id' => $server->id,
61-
'db_server' => $options['db_server'],
62-
'database' => "s{$server->id}_{$options['database']}",
63-
'username' => $server->uuidShort . '_' . str_random(7),
64-
'remote' => $options['remote'],
65-
'password' => Crypt::encrypt(str_random(20)),
68+
'db_server' => $data['host'],
69+
'database' => sprintf('s%d_%s', $server->id, $data['database']),
6670
]);
67-
$db->save();
6871

69-
// Contact Remote
70-
$dbr = Models\DatabaseServer::findOrFail($options['db_server']);
72+
if ($database->exists) {
73+
throw new DisplayException('A database with those details already exists in the system.');
74+
}
7175

72-
$capsule = new Capsule;
73-
$capsule->addConnection([
74-
'driver' => 'mysql',
75-
'host' => $dbr->host,
76-
'port' => $dbr->port,
77-
'database' => 'mysql',
78-
'username' => $dbr->username,
79-
'password' => Crypt::decrypt($dbr->password),
80-
'charset' => 'utf8',
81-
'collation' => 'utf8_unicode_ci',
82-
'prefix' => '',
83-
'options' => [
84-
\PDO::ATTR_TIMEOUT => 3,
85-
],
86-
]);
76+
$database->username = sprintf('s%d_%s', $server->id, str_random(10));
77+
$database->remote = $data['connection'];
78+
$database->password = Crypt::encrypt(str_random(20));
8779

88-
$capsule->setAsGlobal();
80+
$database->save();
8981
} catch (\Exception $ex) {
9082
DB::rollBack();
91-
throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex);
83+
throw $ex;
9284
}
9385

86+
Config::set('database.connections.dynamic', [
87+
'driver' => 'mysql',
88+
'host' => $host->host,
89+
'port' => $host->port,
90+
'database' => 'mysql',
91+
'username' => $host->username,
92+
'password' => Crypt::decrypt($host->password),
93+
'charset' => 'utf8',
94+
'collation' => 'utf8_unicode_ci',
95+
]);
96+
9497
try {
95-
Capsule::statement('CREATE DATABASE `' . $db->database . '`');
96-
Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\'');
97-
Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`');
98-
Capsule::statement('FLUSH PRIVILEGES');
98+
DB::connection('dynamic')->statement(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database->database));
99+
DB::connection('dynamic')->statement(sprintf(
100+
'CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'',
101+
$database->username, $database->remote, Crypt::decrypt($database->password)
102+
));
103+
DB::connection('dynamic')->statement(sprintf(
104+
'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `%s`.* TO `%s`@`%s`',
105+
$database->database, $database->username, $database->remote
106+
));
107+
108+
DB::connection('dynamic')->statement('FLUSH PRIVILEGES');
109+
110+
// Save Everything
99111
DB::commit();
100112
} catch (\Exception $ex) {
101113
try {
102-
Capsule::statement('DROP DATABASE `' . $db->database . '`');
103-
Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`');
104-
} catch (\Exception $exi) {
105-
// ignore it, if it fails its probably
106-
// because we failed to ever make the DB
107-
// or the user on the system.
108-
} finally {
109-
DB::rollBack();
110-
throw $ex;
111-
}
114+
DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database));
115+
DB::connection('dynamic')->statement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $database->username, $database->remote));
116+
DB::connection('dynamic')->statement('FLUSH PRIVILEGES');
117+
} catch (\Exception $ex) {}
118+
119+
DB::rollBack();
120+
throw $ex;
112121
}
113122
}
114123

@@ -118,7 +127,7 @@ public function create($server, $options)
118127
* @param string $password The new password to use for the database.
119128
* @return bool
120129
*/
121-
public function modifyPassword($id, $password)
130+
public function password($id, $password)
122131
{
123132
$database = Models\Database::with('host')->findOrFail($id);
124133

@@ -127,33 +136,25 @@ public function modifyPassword($id, $password)
127136
$database->password = Crypt::encrypt($password);
128137
$database->save();
129138

130-
$capsule = new Capsule;
131-
$capsule->addConnection([
139+
Config::set('database.connections.dynamic', [
132140
'driver' => 'mysql',
133141
'host' => $database->host->host,
134142
'port' => $database->host->port,
135143
'database' => 'mysql',
136144
'username' => $database->host->username,
137145
'password' => Crypt::decrypt($database->host->password),
138-
'charset' => 'utf8',
146+
'charset' => 'utf8',
139147
'collation' => 'utf8_unicode_ci',
140-
'prefix' => '',
141-
'options' => [
142-
\PDO::ATTR_TIMEOUT => 3,
143-
],
144148
]);
145149

146-
$capsule->setAsGlobal();
147-
Capsule::statement(sprintf(
150+
DB::connection('dynamic')->statement(sprintf(
148151
'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')',
149-
$database->username,
150-
$database->remote,
151-
$password
152+
$database->username, $database->remote, $password
152153
));
153154

154155
DB::commit();
155156
} catch (\Exception $ex) {
156-
DB::rollback();
157+
DB::rollBack();
157158
throw $ex;
158159
}
159160
}
@@ -168,34 +169,25 @@ public function drop($id)
168169
$database = Models\Database::with('host')->findOrFail($id);
169170

170171
DB::beginTransaction();
171-
172172
try {
173-
$capsule = new Capsule;
174-
$capsule->addConnection([
173+
Config::set('database.connections.dynamic', [
175174
'driver' => 'mysql',
176175
'host' => $database->host->host,
177176
'port' => $database->host->port,
178177
'database' => 'mysql',
179178
'username' => $database->host->username,
180179
'password' => Crypt::decrypt($database->host->password),
181-
'charset' => 'utf8',
180+
'charset' => 'utf8',
182181
'collation' => 'utf8_unicode_ci',
183-
'prefix' => '',
184-
'options' => [
185-
\PDO::ATTR_TIMEOUT => 3,
186-
],
187182
]);
188183

189-
$capsule->setAsGlobal();
190-
191-
Capsule::statement('DROP USER `' . $database->username . '`@`' . $database->remote . '`');
192-
Capsule::statement('DROP DATABASE `' . $database->database . '`');
184+
DB::connection('dynamic')->statement(sprintf('DROP DATABASE IF EXISTS `%s`', $database->database));
185+
DB::connection('dynamic')->statement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $database->username, $database->remote));
186+
DB::connection('dynamic')->statement('FLUSH PRIVILEGES');
193187

194188
$database->delete();
195189

196190
DB::commit();
197-
198-
return true;
199191
} catch (\Exception $ex) {
200192
DB::rollback();
201193
throw $ex;
@@ -243,28 +235,20 @@ public function add(array $data)
243235
}
244236

245237
DB::beginTransaction();
246-
247238
try {
248-
$capsule = new Capsule;
249-
$capsule->addConnection([
239+
Config::set('database.connections.dynamic', [
250240
'driver' => 'mysql',
251241
'host' => $data['host'],
252242
'port' => $data['port'],
253243
'database' => 'mysql',
254244
'username' => $data['username'],
255245
'password' => $data['password'],
256-
'charset' => 'utf8',
246+
'charset' => 'utf8',
257247
'collation' => 'utf8_unicode_ci',
258-
'prefix' => '',
259-
'options' => [
260-
\PDO::ATTR_TIMEOUT => 3,
261-
],
262248
]);
263249

264-
$capsule->setAsGlobal();
265-
266250
// Allows us to check that we can connect to things.
267-
Capsule::select('SELECT 1 FROM dual');
251+
DB::connection('dynamic')->select('SELECT 1 FROM dual');
268252

269253
Models\DatabaseServer::create([
270254
'name' => $data['name'],

0 commit comments

Comments
 (0)