Finish mount admin view page, add unique index to migration
This commit is contained in:
parent
0db7debb46
commit
34f718a8b1
4 changed files with 276 additions and 3 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Mount;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
@ -11,6 +12,8 @@ use Pterodactyl\Services\Mounts\MountCreationService;
|
|||
use Pterodactyl\Services\Mounts\MountDeletionService;
|
||||
use Pterodactyl\Http\Requests\Admin\MountFormRequest;
|
||||
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||
|
||||
class MountController extends Controller
|
||||
{
|
||||
|
@ -19,6 +22,16 @@ class MountController extends Controller
|
|||
*/
|
||||
protected $alert;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
|
||||
*/
|
||||
protected $nestRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface
|
||||
*/
|
||||
protected $locationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||
*/
|
||||
|
@ -43,6 +56,8 @@ class MountController extends Controller
|
|||
* MountController constructor.
|
||||
*
|
||||
* @param \Prologue\Alerts\AlertsMessageBag $alert
|
||||
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $nestRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $locationRepository
|
||||
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $repository
|
||||
* @param \Pterodactyl\Services\Mounts\MountCreationService $creationService
|
||||
* @param \Pterodactyl\Services\Mounts\MountDeletionService $deletionService
|
||||
|
@ -50,12 +65,16 @@ class MountController extends Controller
|
|||
*/
|
||||
public function __construct(
|
||||
AlertsMessageBag $alert,
|
||||
NestRepositoryInterface $nestRepository,
|
||||
LocationRepositoryInterface $locationRepository,
|
||||
MountRepository $repository,
|
||||
MountCreationService $creationService,
|
||||
MountDeletionService $deletionService,
|
||||
MountUpdateService $updateService
|
||||
) {
|
||||
$this->alert = $alert;
|
||||
$this->nestRepository = $nestRepository;
|
||||
$this->locationRepository = $locationRepository;
|
||||
$this->repository = $repository;
|
||||
$this->creationService = $creationService;
|
||||
$this->deletionService = $deletionService;
|
||||
|
@ -84,8 +103,16 @@ class MountController extends Controller
|
|||
*/
|
||||
public function view($id)
|
||||
{
|
||||
$nests = $this->nestRepository->all();
|
||||
$nests->load('eggs');
|
||||
|
||||
$locations = $this->locationRepository->all();
|
||||
$locations->load('nodes');
|
||||
|
||||
return view('admin.mounts.view', [
|
||||
'mount' => $this->repository->getWithRelations($id),
|
||||
'nests' => $nests,
|
||||
'locations' => $locations,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -146,4 +173,74 @@ class MountController extends Controller
|
|||
|
||||
return redirect()->route('admin.mounts.view', $mount->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds eggs to the mount's many to many relation.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Mount $mount
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function addEggs(Request $request, Mount $mount)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'eggs' => 'required|exists:eggs,id',
|
||||
]);
|
||||
|
||||
$eggs = $validatedData['eggs'] ?? [];
|
||||
if (sizeof($eggs) > 0) {
|
||||
$mount->eggs()->attach(array_map('intval', $eggs));
|
||||
$this->alert->success('Mount was updated successfully.')->flash();
|
||||
}
|
||||
|
||||
return redirect()->route('admin.mounts.view', $mount->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds nodes to the mount's many to many relation.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Pterodactyl\Models\Mount $mount
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function addNodes(Request $request, Mount $mount)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'nodes' => 'required|exists:nodes,id',
|
||||
]);
|
||||
|
||||
$nodes = $validatedData['nodes'] ?? [];
|
||||
if (sizeof($nodes) > 0) {
|
||||
$mount->nodes()->attach(array_map('intval', $nodes));
|
||||
$this->alert->success('Mount was updated successfully.')->flash();
|
||||
}
|
||||
|
||||
return redirect()->route('admin.mounts.view', $mount->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an egg from the mount's many to many relation.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Mount $mount
|
||||
* @param int $egg_id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function deleteEgg(Mount $mount, int $egg_id)
|
||||
{
|
||||
$mount->eggs()->detach($egg_id);
|
||||
return response('', 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an node from the mount's many to many relation.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Mount $mount
|
||||
* @param int $node_id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function deleteNode(Mount $mount, int $node_id)
|
||||
{
|
||||
$mount->nodes()->detach($node_id);
|
||||
return response('', 204);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,15 @@ class AddMountsTable extends Migration
|
|||
Schema::create('egg_mount', function (Blueprint $table) {
|
||||
$table->integer('egg_id');
|
||||
$table->char('mount_id', 36);
|
||||
|
||||
$table->unique(['egg_id', 'mount_id']);
|
||||
});
|
||||
|
||||
Schema::create('mount_node', function (Blueprint $table) {
|
||||
$table->integer('node_id');
|
||||
$table->char('mount_id', 36);
|
||||
|
||||
$table->unique(['node_id', 'mount_id']);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<div class="col-sm-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Location Details</h3>
|
||||
<h3 class="box-title">Mount Details</h3>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('admin.mounts.view', $mount->id) }}" method="POST">
|
||||
|
@ -101,6 +101,10 @@
|
|||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Eggs</h3>
|
||||
|
||||
<div class="box-tools">
|
||||
<button class="btn btn-sm btn-primary" data-toggle="modal" data-target="#addEggsModal">Add Eggs</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body table-responsive no-padding">
|
||||
|
@ -108,12 +112,16 @@
|
|||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
@foreach($mount->eggs as $egg)
|
||||
@foreach ($mount->eggs as $egg)
|
||||
<tr>
|
||||
<td><code>{{ $egg->id }}</code></td>
|
||||
<td><a href="{{ route('admin.nests.egg.view', $egg->id) }}">{{ $egg->name }}</a></td>
|
||||
<td class="col-sm-1 middle">
|
||||
<button data-action="detach-egg" data-id="{{ $egg->id }}" class="btn btn-sm btn-danger"><i class="fa fa-trash-o"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
|
@ -123,6 +131,10 @@
|
|||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Nodes</h3>
|
||||
|
||||
<div class="box-tools">
|
||||
<button class="btn btn-sm btn-primary" data-toggle="modal" data-target="#addNodesModal">Add Nodes</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body table-responsive no-padding">
|
||||
|
@ -131,13 +143,17 @@
|
|||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>FQDN</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
@foreach($mount->nodes as $node)
|
||||
@foreach ($mount->nodes as $node)
|
||||
<tr>
|
||||
<td><code>{{ $node->id }}</code></td>
|
||||
<td><a href="{{ route('admin.nodes.view', $node->id) }}">{{ $node->name }}</a></td>
|
||||
<td><code>{{ $node->fqdn }}</code></td>
|
||||
<td class="col-sm-1 middle">
|
||||
<button data-action="detach-node" data-id="{{ $node->id }}" class="btn btn-sm btn-danger"><i class="fa fa-trash-o"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
|
@ -145,4 +161,154 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="addEggsModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form action="{{ route('admin.mounts.eggs', $mount->id) }}" method="POST">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true" style="color: #FFFFFF">×</span>
|
||||
</button>
|
||||
|
||||
<h4 class="modal-title">Add Eggs</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="pEggs">Eggs</label>
|
||||
<select id="pEggs" name="eggs[]" class="form-control" multiple>
|
||||
@foreach ($nests as $nest)
|
||||
<optgroup label="{{ $nest->name }}">
|
||||
@foreach ($nest->eggs as $egg)
|
||||
|
||||
@if (! in_array($egg->id, $mount->eggs->pluck('id')->toArray()))
|
||||
<option value="{{ $egg->id }}">{{ $egg->name }}</option>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
{!! csrf_field() !!}
|
||||
|
||||
<button type="button" class="btn btn-default btn-sm pull-left" data-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="addNodesModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form action="{{ route('admin.mounts.nodes', $mount->id) }}" method="POST">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true" style="color: #FFFFFF">×</span>
|
||||
</button>
|
||||
|
||||
<h4 class="modal-title">Add Nodes</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="pNodes">Nodes</label>
|
||||
<select id="pNodes" name="nodes[]" class="form-control" multiple>
|
||||
@foreach ($locations as $location)
|
||||
<optgroup label="{{ $location->long }} ({{ $location->short }})">
|
||||
@foreach ($location->nodes as $node)
|
||||
|
||||
@if (! in_array($node->id, $mount->nodes->pluck('id')->toArray()))
|
||||
<option value="{{ $node->id }}">{{ $node->name }}</option>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
{!! csrf_field() !!}
|
||||
|
||||
<button type="button" class="btn btn-default btn-sm pull-left" data-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('footer-scripts')
|
||||
@parent
|
||||
|
||||
<script type="application/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#pEggs').select2({
|
||||
placeholder: 'Select eggs..',
|
||||
});
|
||||
|
||||
$('#pNodes').select2({
|
||||
placeholder: 'Select nodes..',
|
||||
});
|
||||
|
||||
$('button[data-action="detach-egg"]').click(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
const element = $(this);
|
||||
const eggId = $(this).data('id');
|
||||
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: '/admin/mounts/' + {{ $mount->id }} + '/eggs/' + eggId,
|
||||
headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') },
|
||||
}).done(function () {
|
||||
element.parent().parent().addClass('warning').delay(100).fadeOut();
|
||||
swal({ type: 'success', title: 'Egg detached.' });
|
||||
}).fail(function (jqXHR) {
|
||||
console.error(jqXHR);
|
||||
swal({
|
||||
title: 'Whoops!',
|
||||
text: jqXHR.responseJSON.error,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('button[data-action="detach-node"]').click(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
const element = $(this);
|
||||
const nodeId = $(this).data('id');
|
||||
|
||||
$.ajax({
|
||||
method: 'DELETE',
|
||||
url: '/admin/mounts/' + {{ $mount->id }} + '/nodes/' + nodeId,
|
||||
headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') },
|
||||
}).done(function () {
|
||||
element.parent().parent().addClass('warning').delay(100).fadeOut();
|
||||
swal({ type: 'success', title: 'Node detached.' });
|
||||
}).fail(function (jqXHR) {
|
||||
console.error(jqXHR);
|
||||
swal({
|
||||
title: 'Whoops!',
|
||||
text: jqXHR.responseJSON.error,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
@ -178,7 +178,13 @@ Route::group(['prefix' => 'mounts'], function () {
|
|||
Route::get('/view/{mount}', 'MountController@view')->name('admin.mounts.view');
|
||||
|
||||
Route::post('/', 'MountController@create');
|
||||
Route::post('/{mount}/eggs', 'MountController@addEggs')->name('admin.mounts.eggs');
|
||||
Route::post('/{mount}/nodes', 'MountController@addNodes')->name('admin.mounts.nodes');
|
||||
|
||||
Route::patch('/view/{mount}', 'MountController@update');
|
||||
|
||||
Route::delete('/{mount}/eggs/{egg_id}', 'MountController@deleteEgg');
|
||||
Route::delete('/{mount}/nodes/{node_id}', 'MountController@deleteNode');
|
||||
});
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue