diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 5d658a641..51dd83ee6 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -23,9 +23,14 @@ */ namespace Pterodactyl\Http\Controllers\Admin; +use Alert; use DB; +use Log; use Pterodactyl\Models; +use Pterodactyl\Repositories\DatabaseRepository; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Http\Controllers\Controller; use Illuminate\Http\Request; @@ -62,4 +67,64 @@ class DatabaseController extends Controller ]); } + public function getNew(Request $request) + { + return view('admin.databases.new', [ + 'nodes' => Models\Node::select('nodes.id', 'nodes.name', 'locations.long as a_location') + ->join('locations', 'locations.id', '=', 'nodes.location') + ->get() + ]); + } + + public function postNew(Request $request) + { + try { + $repo = new DatabaseRepository; + $repo->add($request->except([ + '_token' + ])); + + Alert::success('Successfully added a new database server to the system.')->flash(); + return redirect()->route('admin.databases', [ + 'tab' => 'tab_dbservers' + ]); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.databases.new')->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (\Exception $ex) { + if ($ex instanceof DisplayException || $ex instanceof \PDOException) { + Alert::danger($ex->getMessage())->flash(); + } else { + Log::error($ex); + Alert::danger('An error occurred while attempting to delete this database server from the system.')->flash(); + } + return redirect()->route('admin.databases.new')->withInput(); + } + } + + public function deleteDatabase(Request $request, $id) + { + try { + $repo = new DatabaseRepository; + $repo->drop($id); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database from the system.' + ], 500); + } + } + + public function deleteServer(Request $request, $id) + { + try { + $repo = new DatabaseRepository; + $repo->delete($id); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => ($ex instanceof DisplayException) ? $ex->getMessage() : 'An error occurred while attempting to delete this database server from the system.' + ], 500); + } + } + } diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 348d852cb..2ba1253ed 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -413,18 +413,4 @@ class ServersController extends Controller ])->withInput(); } - public function deleteDatabase(Request $request, $id, $database) - { - try { - $repo = new DatabaseRepository; - $repo->drop($database); - return response('', 204); - } catch (\Exception $ex) { - Log::error($ex); - return response()->json([ - 'error' => 'An exception occured while attempting to delete this database.' - ], 500); - } - } - } diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 59903f8ee..125f7daa1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -228,6 +228,10 @@ class ServerController extends Controller return view('server.settings', [ 'server' => $server, + 'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port') + ->where('server', $server->id) + ->join('database_servers', 'database_servers.id', '=', 'databases.db_server') + ->get(), 'node' => Models\Node::find($server->node), 'variables' => $variables->where('user_viewable', 1), 'service' => $service, diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 09647db16..f4d12111c 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -158,10 +158,6 @@ class AdminRoutes { 'uses' => 'Admin\ServersController@postDatabase' ]); - $router->delete('/view/{id}/database/{database}', [ - 'uses' => 'Admin\ServersController@deleteDatabase' - ]); - // Change Server Details $router->post('/view/{id}/details', [ 'uses' => 'Admin\ServersController@postUpdateServerDetails' @@ -328,6 +324,14 @@ class AdminRoutes { $router->post('/new', [ 'uses' => 'Admin\DatabaseController@postNew' ]); + $router->delete('/delete/{id}', [ + 'as' => 'admin.databases.delete', + 'uses' => 'Admin\DatabaseController@deleteDatabase' + ]); + $router->delete('/delete-server/{id}', [ + 'as' => 'admin.databases.delete-server', + 'uses' => 'Admin\DatabaseController@deleteServer' + ]); }); } diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index b720ab3ec..b6a80fb0f 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -434,4 +434,20 @@ class ServerPolicy return $user->permissions()->server($server)->permission('reset-sftp')->exists(); } + /** + * Check if user has permission to view databases for a server. + * + * @param Pterodactyl\Models\User $user + * @param Pterodactyl\Models\Server $server + * @return boolean + */ + public function viewDatabases(User $user, Server $server) + { + if ($this->isOwner($user, $server)) { + return true; + } + + return $user->permissions()->server($server)->permission('view-databases')->exists(); + } + } diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index e911a02a5..085b56253 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Repositories; use Crypt; +use Log; use DB; use Validator; @@ -56,21 +57,20 @@ class DatabaseRepository { DB::beginTransaction(); - $db = new Models\Database; - $db->fill([ - 'server' => $server->id, - 'db_server' => $options['db_server'], - 'database' => $server->uuidShort . '_' . $options['database'], - 'username' => $server->uuidShort . '_' . str_random(7), - 'remote' => $options['remote'], - 'password' => Crypt::encrypt(str_random(20)) - ]); - $db->save(); - - // Contact Remote - $dbr = Models\DatabaseServer::findOrFail($options['db_server']); - try { + $db = new Models\Database; + $db->fill([ + 'server' => $server->id, + 'db_server' => $options['db_server'], + 'database' => $server->uuidShort . '_' . $options['database'], + 'username' => $server->uuidShort . '_' . str_random(7), + 'remote' => $options['remote'], + 'password' => Crypt::encrypt(str_random(20)) + ]); + $db->save(); + + // Contact Remote + $dbr = Models\DatabaseServer::findOrFail($options['db_server']); $capsule = new Capsule; $capsule->addConnection([ @@ -82,7 +82,10 @@ class DatabaseRepository { 'password' => Crypt::decrypt($dbr->password), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', - 'prefix' => '' + 'prefix' => '', + 'options' => [ + \PDO::ATTR_TIMEOUT => 3, + ] ]); $capsule->setAsGlobal(); @@ -110,10 +113,9 @@ class DatabaseRepository { $db = Models\Database::findOrFail($database); $dbr = Models\DatabaseServer::findOrFail($db->db_server); + DB::beginTransaction(); + try { - - DB::beginTransaction(); - $capsule = new Capsule; $capsule->addConnection([ 'driver' => 'mysql', @@ -124,7 +126,10 @@ class DatabaseRepository { 'password' => Crypt::decrypt($dbr->password), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', - 'prefix' => '' + 'prefix' => '', + 'options' => [ + \PDO::ATTR_TIMEOUT => 3, + ] ]); $capsule->setAsGlobal(); @@ -143,4 +148,83 @@ class DatabaseRepository { } + /** + * Deletes a database server from the system if it is empty. + * @param int $server The ID of the Database Server. + * @return + */ + public function delete($server) + { + $dbh = Models\DatabaseServer::findOrFail($server); + $databases = Models\Database::where('db_server', $dbh->id)->count(); + + if ($databases > 0) { + throw new DisplayException('You cannot delete a database server that has active databases attached to it.'); + } + + return $dbh->delete(); + } + + /** + * Adds a new Database Server to the system. + * @param array $data + */ + public function add(array $data) + { + $validator = Validator::make($data, [ + 'name' => 'required|string|max:255', + 'host' => 'required|ip|unique:database_servers,host', + 'port' => 'required|numeric|between:1,65535', + 'username' => 'required|string|max:32', + 'password' => 'required|string', + 'linked_node' => 'sometimes', + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + DB::beginTransaction(); + + try { + $capsule = new Capsule; + $capsule->addConnection([ + 'driver' => 'mysql', + 'host' => $data['host'], + 'port' => $data['port'], + 'database' => 'mysql', + 'username' => $data['username'], + 'password' => $data['password'], + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + 'options' => [ + \PDO::ATTR_TIMEOUT => 3, + ] + ]); + + $capsule->setAsGlobal(); + + // Allows us to check that we can connect to things. + Capsule::select('SELECT 1 FROM dual'); + + $dbh = new Models\DatabaseServer; + $dbh->fill([ + 'name' => $data['name'], + 'host' => $data['host'], + 'port' => $data['port'], + 'username' => $data['username'], + 'password' => Crypt::encrypt($data['password']), + 'max_databases' => NULL, + 'linked_node' => (!empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : NULL + ]); + $dbh->save(); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollBack(); + throw $ex; + } + } + } diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index 1c145c856..00e176609 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -20,7 +20,7 @@ @extends('layouts.admin') @section('title') - Server List + Database Management @endsection @section('content') @@ -32,7 +32,8 @@
Database | +User (Connections From) | +Password | +DB Server | + +
---|---|---|---|
{{ $database->database }} | +{{ $database->username }} ({{ $database->remote }}) | +{{ Crypt::decrypt($database->password) }} |
+ {{ $database->a_host }}:{{ $database->a_port }} |
+