Add SFTP and Database management pages to new theme.

This commit is contained in:
Dane Everitt 2017-01-15 20:28:54 -05:00
parent c7f3bb5112
commit 515e543c7f
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
11 changed files with 375 additions and 23 deletions

View File

@ -61,16 +61,8 @@ class ServerController extends Controller
$node = Models\Node::find($server->node);
Javascript::put([
'server' => [
'uuid' => $server->uuid,
'daemonSecret' => $server->daemonSecret,
'username' => $server->username,
],
'node' => [
'scheme' => $node->scheme,
'fqdn' => $node->fqdn,
'daemonListen' => $node->daemonListen,
],
'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']),
'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'),
'meta' => [
'saveFile' => route('server.files.save', $server->uuidShort),
'csrfToken' => csrf_token(),
@ -255,6 +247,45 @@ class ServerController extends Controller
]);
}
public function getDatabases(Request $request, $uuid)
{
$server = Models\Server::getByUUID($uuid);
$this->authorize('view-databases', $server);
$node = Models\Node::find($server->node);
Javascript::put([
'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']),
'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'),
]);
return view('server.settings.databases', [
'server' => $server,
'node' => $node,
'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port')
->where('server_id', $server->id)
->join('database_servers', 'database_servers.id', '=', 'databases.db_server')
->get(),
]);
}
public function getSFTP(Request $request, $uuid)
{
$server = Models\Server::getByUUID($uuid);
$this->authorize('view-sftp', $server);
$node = Models\Node::find($server->node);
Javascript::put([
'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']),
'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'),
]);
return view('server.settings.sftp', [
'server' => $server,
'node' => $node,
]);
}
public function postSettingsSFTP(Request $request, $uuid)
{
$server = Models\Server::getByUUID($uuid);
@ -265,7 +296,7 @@ class ServerController extends Controller
$repo->updateSFTPPassword($server->id, $request->input('sftp_pass'));
Alert::success('Successfully updated this servers SFTP password.')->flash();
} catch (DisplayValidationException $ex) {
return redirect()->route('server.settings', $uuid)->withErrors(json_decode($ex->getMessage()));
return redirect()->route('server.settings.sftp', $uuid)->withErrors(json_decode($ex->getMessage()));
} catch (DisplayException $ex) {
Alert::danger($ex->getMessage())->flash();
} catch (\Exception $ex) {
@ -273,7 +304,7 @@ class ServerController extends Controller
Alert::danger('An unknown error occured while attempting to update this server\'s SFTP settings.')->flash();
}
return redirect()->route('server.settings', $uuid);
return redirect()->route('server.settings.sftp', $uuid);
}
public function postSettingsStartup(Request $request, $uuid)

View File

@ -51,8 +51,17 @@ class ServerRoutes
'uses' => 'Server\ServerController@getSettings',
]);
$router->post('/settings/sftp', [
$router->get('/settings/databases', [
'as' => 'server.settings.databases',
'uses' => 'Server\ServerController@getDatabases',
]);
$router->get('/settings/sftp', [
'as' => 'server.settings.sftp',
'uses' => 'Server\ServerController@getSFTP',
]);
$router->post('/settings/sftp', [
'uses' => 'Server\ServerController@postSettingsSFTP',
]);

File diff suppressed because one or more lines are too long

View File

@ -45,3 +45,15 @@
code {
font-size: 85%;
}
.control-sidebar-dark .control-sidebar-menu > li > a.active {
background: #1e282c;
}
.callout-nomargin {
margin: 0;
}
.table {
font-size: 14px !important;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -24,4 +24,8 @@ return [
'2fa_token' => 'Authentication Token',
'submit' => 'Submit',
'close' => 'Close',
'settings' => 'Settings',
'configuration' => 'Configuration',
'sftp' => 'SFTP',
'databases' => 'Databases',
];

View File

@ -29,6 +29,7 @@
{!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!}
{!! Theme::css('vendor/adminlte/admin.min.css') !!}
{!! Theme::css('vendor/adminlte/colors/skin-blue.min.css') !!}
{!! Theme::css('vendor/sweetalert/sweetalert.min.css') !!}
{!! Theme::css('css/pterodactyl.css') !!}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">
@ -161,7 +162,11 @@
</span>
</a>
</li>
<li class="treeview">
<li class="treeview
@if(in_array(Route::currentRouteName(), ['server.settings.sftp', 'server.settings.databases']))
active
@endif
">
<a href="#">
<i class="fa fa-gears"></i>
<span>Configuration</span>
@ -170,9 +175,10 @@
</span>
</a>
<ul class="treeview-menu">
<li><a href="{{ route('server.settings', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> SFTP Settings</a></li>
<li><a href=""><i class="fa fa-angle-right"></i> Port Allocations</a></li>
<li class="{{ Route::currentRouteName() !== 'server.settings.sftp' ?: 'active' }}"><a href="{{ route('server.settings.sftp', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> SFTP Settings</a></li>
<li><a href=""><i class="fa fa-angle-right"></i> Startup Parameters</a></li>
<li><a href=""><i class="fa fa-angle-right"></i> Databases</a></li>
<li class="{{ Route::currentRouteName() !== 'server.settings.databases' ?: 'active' }}"><a href="{{ route('server.settings.databases', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> Databases</a></li>
</ul>
</li>
@endif
@ -223,7 +229,13 @@
<ul class="control-sidebar-menu">
@foreach (Pterodactyl\Models\Server::getUserServers() as $s)
<li>
<a href="{{ route('server.index', $s->uuidShort) }}">
<a
@if(isset($server) && isset($node))
@if($server->uuidShort === $s->uuidShort)
class="active"
@endif
@endif
href="{{ route('server.index', $s->uuidShort) }}">
@if($s->owner === Auth::user()->id)
<i class="menu-icon fa fa-user bg-blue"></i>
@else
@ -231,7 +243,7 @@
@endif
<div class="menu-info">
<h4 class="control-sidebar-subheading">{{ $s->name }}</h4>
<p>{{ $s->uuidShort }}</p>
<p>{{ $s->username }}</p>
</div>
</a>
</li>
@ -245,6 +257,7 @@
@section('footer-scripts')
{!! Theme::js('js/laroute.js') !!}
{!! Theme::js('js/vendor/jquery/jquery.min.js') !!}
{!! Theme::js('vendor/sweetalert/sweetalert.min.js') !!}
{!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!}
{!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js') !!}
{!! Theme::js('vendor/adminlte/app.min.js') !!}

View File

@ -44,10 +44,10 @@
<div id="terminal" style="width:100%;"></div>
</div>
<div class="box-footer text-center">
<button class="btn btn-success" data-attr="power" data-action="start">Start</button>
<button class="btn btn-primary" data-attr="power" data-action="restart">Restart</button>
<button class="btn btn-danger" data-attr="power" data-action="stop">Stop</button>
<button class="btn btn-danger" data-attr="power" data-action="kill">Kill</button>
@can('power-start', $server)<button class="btn btn-success" data-attr="power" data-action="start">Start</button>@endcan
@can('power-off', $server)<button class="btn btn-primary" data-attr="power" data-action="restart">Restart</button>@endcan
@can('power-restart', $server)<button class="btn btn-danger" data-attr="power" data-action="stop">Stop</button>@endcan
@can('power-kill', $server)<button class="btn btn-danger" data-attr="power" data-action="kill">Kill</button>@endcan
</div>
</div>
</div>

View File

@ -0,0 +1,123 @@
{{-- Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}}
{{-- of this software and associated documentation files (the "Software"), to deal --}}
{{-- in the Software without restriction, including without limitation the rights --}}
{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}}
{{-- copies of the Software, and to permit persons to whom the Software is --}}
{{-- furnished to do so, subject to the following conditions: --}}
{{-- The above copyright notice and this permission notice shall be included in all --}}
{{-- copies or substantial portions of the Software. --}}
{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}}
{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}}
{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}}
{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}}
{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}}
{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}}
{{-- SOFTWARE. --}}
@extends('layouts.master')
@section('title')
Databases
@endsection
@section('content-header')
<h1>Databases<small>All databases available for this server.</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('index') }}">{{ trans('strings.home') }}</a></li>
<li><a href="{{ route('server.index', $server->uuidShort) }}">{{ $server->name }}</a></li>
<li>{{ trans('strings.configuration') }}</li>
<li class="active">{{ trans('strings.databases') }}</li>
</ol>
@endsection
@section('content')
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Your Databases</h3>
</div>
@if(count($databases) > 0)
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
<tbody>
<tr>
<th>Database</th>
<th>Username</th>
<th>Password</th>
<th>MySQL Host</th>
</tr>
@foreach($databases as $database)
<tr>
<td>{{ $database->database }}</td>
<td>{{ $database->username }}</td>
<td><code>{{ Crypt::decrypt($database->password) }}</code>
@can('reset-db-password', $server)
<button class="btn btn-xs btn-primary pull-right" data-action="reset-database-password" data-id="{{ $database->id }}"><i class="fa fa-fw fa-refresh"></i> Reset Password</button>
@endcan
</td>
<td><code>{{ $database->a_host }}:{{ $database->a_port }}</code></td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<div class="box-body">
<div class="callout callout-info callout-nomargin">
There are no databases listed for this server.
@if(Auth::user()->root_admin === 1)
<a href="{{ route('admin.servers.view', [
'id' => $server->id,
'tab' => 'tab_database'
]) }}" target="_blank">Add a new database.</a>
@endif
</div>
</div>
@endif
</div>
</div>
</div>
@endsection
@section('footer-scripts')
@parent
{!! Theme::js('js/frontend/server.socket.js') !!}
<script>
@can('reset-db-password', $server)
$('[data-action="reset-database-password"]').click(function (e) {
e.preventDefault();
var block = $(this);
$(this).find('i').addClass('fa-spin');
$.ajax({
type: 'POST',
url: Router.route('server.ajax.reset-database-password', { server: Pterodactyl.server.uuidShort }),
headers: {
'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content'),
},
data: {
'database': $(this).data('id')
}
}).done(function (data) {
block.parent().find('code').html(data);
}).fail(function(jqXHR, textStatus, errorThrown) {
console.error(jqXHR);
var error = 'An error occured while trying to process this request.';
if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {
error = jqXHR.responseJSON.error;
}
swal({
type: 'error',
title: 'Whoops!',
text: error
});
}).always(function () {
block.find('i').removeClass('fa-spin');
});
});
@endcan
</script>
@endsection

View File

@ -0,0 +1,114 @@
{{-- Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}}
{{-- of this software and associated documentation files (the "Software"), to deal --}}
{{-- in the Software without restriction, including without limitation the rights --}}
{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}}
{{-- copies of the Software, and to permit persons to whom the Software is --}}
{{-- furnished to do so, subject to the following conditions: --}}
{{-- The above copyright notice and this permission notice shall be included in all --}}
{{-- copies or substantial portions of the Software. --}}
{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}}
{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}}
{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}}
{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}}
{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}}
{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}}
{{-- SOFTWARE. --}}
@extends('layouts.master')
@section('title')
SFTP Settings
@endsection
@section('content-header')
<h1>SFTP Configuration<small>Account details for SFTP connections.</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('index') }}">{{ trans('strings.home') }}</a></li>
<li><a href="{{ route('server.index', $server->uuidShort) }}">{{ $server->name }}</a></li>
<li>{{ trans('strings.configuration') }}</li>
<li class="active">{{ trans('strings.sftp') }}</li>
</ol>
@endsection
@section('content')
<div class="row">
<div class="col-sm-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Change SFTP Password</h3>
</div>
@can('reset-sftp', $server)
<form action="{{ route('server.settings.sftp', $server->uuidShort) }}" method="post">
<div class="box-body">
<div class="form-group">
<label for="sftp_pass" class="control-label">{{ trans('base.account.new_password') }}</label>
<div>
<input type="password" class="form-control" name="sftp_pass" />
<p class="text-muted"><small>{{ trans('auth.password_requirements') }}</small></p>
</div>
</div>
</div>
<div class="box-footer">
{!! csrf_field() !!}
<input type="submit" class="btn btn-primary btn-sm" value="{{ trans('base.account.update_pass') }}" />
</div>
</form>
@else
<div class="box-body">
<div class="callout callout-warning callout-nomargin">
<p>You are not authorized to perform this action.</p>
</div>
</div>
@endcan
</div>
</div>
<div class="col-sm-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">SFTP Details</h3>
</div>
<div class="box-body">
<div class="row">
<div class="form-group col-md-8">
<label for="new_email" class="control-label">Connection Address</label>
<div>
<input type="text" class="form-control" readonly value="{{ $node->fqdn }}" />
</div>
</div>
<div class="form-group col-md-4">
<label for="new_email" class="control-label">Port</label>
<div>
<input type="text" class="form-control" readonly value="{{ $node->daemonSFTP }}" />
</div>
</div>
</div>
<div class="form-group">
<label for="password" class="control-label">Username</label>
<div>
<input type="text" class="form-control" readonly value="{{ $server->username }}" />
</div>
</div>
@can('view-sftp-password', $server)
<div class="form-group">
<label for="password" class="control-label">{{ trans('base.account.current_password') }}</label>
<div>
<input type="text" class="form-control" readonly @if(! is_null($server->sftp_password))value="{{ Crypt::decrypt($server->sftp_password) }}"@endif />
</div>
</div>
@endcan
</div>
<div class="box-footer">
<p class="small text-muted">Ensure that your client is set to use <strong>SFTP</strong> and not FTP or FTPS for connections, there is a difference between the protocols.</p>
</div>
</div>
</div>
</div>
@endsection
@section('footer-scripts')
@parent
{!! Theme::js('js/frontend/server.socket.js') !!}
@endsection