Add support for user management of databases

This commit is contained in:
Dane Everitt 2018-03-02 19:03:55 -06:00
parent aaccf38640
commit bcb69603ad
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
9 changed files with 132 additions and 7 deletions

View File

@ -18,6 +18,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
* Adds back client API for sending commands or power toggles to a server though the Panel API: `/api/client/servers/<identifier>` * Adds back client API for sending commands or power toggles to a server though the Panel API: `/api/client/servers/<identifier>`
* Added proper transformer for Packs and re-enabled missing includes on server. * Added proper transformer for Packs and re-enabled missing includes on server.
* Added support for using Filesystem as a caching driver, although not recommended. * Added support for using Filesystem as a caching driver, although not recommended.
* Added support for user management of server databases.
## v0.7.3 (Derelict Dermodactylus) ## v0.7.3 (Derelict Dermodactylus)
### Fixed ### Fixed

View File

@ -4,16 +4,19 @@ namespace Pterodactyl\Http\Controllers\Server;
use Illuminate\View\View; use Illuminate\View\View;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag; use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Traits\Controllers\JavascriptInjection; use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Services\Databases\DatabasePasswordService; use Pterodactyl\Services\Databases\DatabasePasswordService;
use Pterodactyl\Services\Databases\DatabaseManagementService;
use Pterodactyl\Services\Databases\DeployServerDatabaseService; use Pterodactyl\Services\Databases\DeployServerDatabaseService;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
use Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest; use Pterodactyl\Http\Requests\Server\Database\StoreServerDatabaseRequest;
use Pterodactyl\Http\Requests\Server\Database\DeleteServerDatabaseRequest;
class DatabaseController extends Controller class DatabaseController extends Controller
{ {
@ -34,6 +37,11 @@ class DatabaseController extends Controller
*/ */
private $databaseHostRepository; private $databaseHostRepository;
/**
* @var \Pterodactyl\Services\Databases\DatabaseManagementService
*/
private $managementService;
/** /**
* @var \Pterodactyl\Services\Databases\DatabasePasswordService * @var \Pterodactyl\Services\Databases\DatabasePasswordService
*/ */
@ -50,6 +58,7 @@ class DatabaseController extends Controller
* @param \Prologue\Alerts\AlertsMessageBag $alert * @param \Prologue\Alerts\AlertsMessageBag $alert
* @param \Pterodactyl\Services\Databases\DeployServerDatabaseService $deployServerDatabaseService * @param \Pterodactyl\Services\Databases\DeployServerDatabaseService $deployServerDatabaseService
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository * @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $databaseHostRepository
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $managementService
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService * @param \Pterodactyl\Services\Databases\DatabasePasswordService $passwordService
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository * @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
*/ */
@ -57,12 +66,14 @@ class DatabaseController extends Controller
AlertsMessageBag $alert, AlertsMessageBag $alert,
DeployServerDatabaseService $deployServerDatabaseService, DeployServerDatabaseService $deployServerDatabaseService,
DatabaseHostRepositoryInterface $databaseHostRepository, DatabaseHostRepositoryInterface $databaseHostRepository,
DatabaseManagementService $managementService,
DatabasePasswordService $passwordService, DatabasePasswordService $passwordService,
DatabaseRepositoryInterface $repository DatabaseRepositoryInterface $repository
) { ) {
$this->alert = $alert; $this->alert = $alert;
$this->databaseHostRepository = $databaseHostRepository; $this->databaseHostRepository = $databaseHostRepository;
$this->deployServerDatabaseService = $deployServerDatabaseService; $this->deployServerDatabaseService = $deployServerDatabaseService;
$this->managementService = $managementService;
$this->passwordService = $passwordService; $this->passwordService = $passwordService;
$this->repository = $repository; $this->repository = $repository;
} }
@ -136,4 +147,19 @@ class DatabaseController extends Controller
return response()->json(['password' => $password]); return response()->json(['password' => $password]);
} }
/**
* Delete a database for this server from the SQL server and Panel database.
*
* @param \Pterodactyl\Http\Requests\Server\Database\DeleteServerDatabaseRequest $request
* @return \Illuminate\Http\Response
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function delete(DeleteServerDatabaseRequest $request): Response
{
$this->managementService->delete($request->attributes->get('database')->id);
return response('', Response::HTTP_NO_CONTENT);
}
} }

View File

@ -38,8 +38,13 @@ class DatabaseBelongsToServer
public function handle(Request $request, Closure $next) public function handle(Request $request, Closure $next)
{ {
$server = $request->attributes->get('server'); $server = $request->attributes->get('server');
$database = $request->input('database') ?? $request->route()->parameter('database');
$database = $this->repository->find($request->input('database')); if (! is_digit($database)) {
throw new NotFoundHttpException;
}
$database = $this->repository->find($database);
if (is_null($database) || $database->server_id !== $server->id) { if (is_null($database) || $database->server_id !== $server->id) {
throw new NotFoundHttpException; throw new NotFoundHttpException;
} }

View File

@ -0,0 +1,40 @@
<?php
namespace Pterodactyl\Http\Requests\Server\Database;
use Pterodactyl\Http\Requests\Server\ServerFormRequest;
class DeleteServerDatabaseRequest 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 'delete-database';
}
/**
* Rules to validate this request aganist.
*
* @return array
*/
public function rules()
{
return [];
}
}

View File

@ -93,6 +93,8 @@ class Permission extends Model implements CleansAttributes, ValidableContract
'database' => [ 'database' => [
'view-databases' => null, 'view-databases' => null,
'reset-db-password' => null, 'reset-db-password' => null,
'delete-database' => null,
'create-database' => null,
], ],
'file' => [ 'file' => [
'access-sftp' => null, 'access-sftp' => null,

File diff suppressed because one or more lines are too long

View File

@ -248,6 +248,14 @@ return [
'title' => 'Reset Database Password', 'title' => 'Reset Database Password',
'description' => 'Allows a user to reset passwords for databases.', 'description' => 'Allows a user to reset passwords for databases.',
], ],
'delete_database' => [
'title' => 'Delete Databases',
'description' => 'Allows a user to delete databases for this server from the Panel.',
],
'create_database' => [
'title' => 'Create Database',
'description' => 'Allows a user to create additional databases for this server.',
],
], ],
], ],
'files' => [ 'files' => [

View File

@ -21,7 +21,7 @@
@section('content') @section('content')
<div class="row"> <div class="row">
<div class="{{ $allowCreation ? 'col-xs-12 col-sm-8' : 'col-xs-12' }}"> <div class="{{ $allowCreation && Gate::allows('create-database', $server) ? 'col-xs-12 col-sm-8' : 'col-xs-12' }}">
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">@lang('server.config.database.your_dbs')</h3> <h3 class="box-title">@lang('server.config.database.your_dbs')</h3>
@ -50,11 +50,20 @@
</code> </code>
</td> </td>
<td class="middle"><code>{{ $database->host->host }}:{{ $database->host->port }}</code></td> <td class="middle"><code>{{ $database->host->host }}:{{ $database->host->port }}</code></td>
@can('reset-db-password', $server) @if(Gate::allows('reset-db-password', $server) || Gate::allows('delete-database', $server))
<td> <td>
<button class="btn btn-xs btn-primary pull-right" data-action="reset-password" data-id="{{ $database->id }}"><i class="fa fa-fw fa-refresh"></i> @lang('server.config.database.reset_password')</button> @can('delete-database', $server)
<button class="btn btn-xs btn-danger pull-right" data-action="delete-database" data-id="{{ $database->id }}">
<i class="fa fa-fw fa-trash-o"></i>
</button>
@endcan
@can('reset-db-password', $server)
<button class="btn btn-xs btn-primary pull-right" style="margin-right:10px;" data-action="reset-password" data-id="{{ $database->id }}">
<i class="fa fa-fw fa-refresh"></i> @lang('server.config.database.reset_password')
</button>
@endcan
</td> </td>
@endcan @endif
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
@ -69,7 +78,7 @@
@endif @endif
</div> </div>
</div> </div>
@if($allowCreation) @if($allowCreation && Gate::allows('create-database', $server))
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<div class="box box-success"> <div class="box box-success">
<div class="box-header with-border"> <div class="box-header with-border">
@ -153,5 +162,37 @@
}); });
}); });
@endcan @endcan
@can('delete-database', $server)
$('[data-action="delete-database"]').click(function (event) {
event.preventDefault();
var self = $(this);
swal({
title: '',
type: 'warning',
text: 'Are you sure that you want to delete this database? There is no going back, all data will immediately be removed.',
showCancelButton: true,
confirmButtonText: 'Delete',
confirmButtonColor: '#d9534f',
closeOnConfirm: false,
showLoaderOnConfirm: true,
}, function () {
$.ajax({
method: 'DELETE',
url: Router.route('server.databases.delete', { server: '{{ $server->uuidShort }}', database: self.data('id') }),
headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') },
}).done(function () {
self.parent().parent().slideUp();
swal.close();
}).fail(function (jqXHR) {
console.error(jqXHR);
swal({
type: 'error',
title: 'Whoops!',
text: (typeof jqXHR.responseJSON.error !== 'undefined') ? jqXHR.responseJSON.error : 'An error occured while processing this request.'
});
});
});
});
@endcan
</script> </script>
@endsection @endsection

View File

@ -41,6 +41,8 @@ Route::group(['prefix' => 'databases'], function () {
Route::post('/new', 'DatabaseController@store')->name('server.databases.new'); Route::post('/new', 'DatabaseController@store')->name('server.databases.new');
Route::patch('/password', 'DatabaseController@update')->middleware('server..database')->name('server.databases.password'); Route::patch('/password', 'DatabaseController@update')->middleware('server..database')->name('server.databases.password');
Route::delete('/delete/{database}', 'DatabaseController@delete')->middleware('server..database')->name('server.databases.delete');
}); });
/* /*