Merge pull request #1915 from pterodactyl/feature/server-mounts
Add configurable server mounts
This commit is contained in:
commit
0d35ab95fd
20 changed files with 1383 additions and 10 deletions
248
app/Http/Controllers/Admin/MountController.php
Normal file
248
app/Http/Controllers/Admin/MountController.php
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Pterodactyl\Models\Mount;
|
||||||
|
use Prologue\Alerts\AlertsMessageBag;
|
||||||
|
use Pterodactyl\Exceptions\DisplayException;
|
||||||
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
|
use Pterodactyl\Services\Mounts\MountUpdateService;
|
||||||
|
use Pterodactyl\Http\Requests\Admin\MountFormRequest;
|
||||||
|
use Pterodactyl\Services\Mounts\MountCreationService;
|
||||||
|
use Pterodactyl\Services\Mounts\MountDeletionService;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
|
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
|
||||||
|
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||||
|
|
||||||
|
class MountController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Prologue\Alerts\AlertsMessageBag
|
||||||
|
*/
|
||||||
|
protected $alert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $nestRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $locationRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Mounts\MountCreationService
|
||||||
|
*/
|
||||||
|
protected $creationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Mounts\MountDeletionService
|
||||||
|
*/
|
||||||
|
protected $deletionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Mounts\MountUpdateService
|
||||||
|
*/
|
||||||
|
protected $updateService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @param \Pterodactyl\Services\Mounts\MountUpdateService $updateService
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
$this->updateService = $updateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mount overview page.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\View\View
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('admin.mounts.index', [
|
||||||
|
'mounts' => $this->repository->getAllWithDetails(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mount view page.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return \Illuminate\View\View
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle request to create new mount.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Http\Requests\Admin\MountFormRequest $request
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function create(MountFormRequest $request)
|
||||||
|
{
|
||||||
|
$mount = $this->creationService->handle($request->normalize());
|
||||||
|
$this->alert->success('Mount was created successfully.')->flash();
|
||||||
|
|
||||||
|
return redirect()->route('admin.mounts.view', $mount->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle request to update or delete location.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Http\Requests\Admin\MountFormRequest $request
|
||||||
|
* @param \Pterodactyl\Models\Mount $mount
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function update(MountFormRequest $request, Mount $mount)
|
||||||
|
{
|
||||||
|
if ($request->input('action') === 'delete') {
|
||||||
|
return $this->delete($mount);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updateService->handle($mount->id, $request->normalize());
|
||||||
|
$this->alert->success('Mount was updated successfully.')->flash();
|
||||||
|
|
||||||
|
return redirect()->route('admin.mounts.view', $mount->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a location from the system.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Models\Mount $mount
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function delete(Mount $mount)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->deletionService->handle($mount->id);
|
||||||
|
|
||||||
|
return redirect()->route('admin.mounts');
|
||||||
|
} catch (DisplayException $ex) {
|
||||||
|
$this->alert->danger($ex->getMessage())->flash();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ use Pterodactyl\Exceptions\DisplayException;
|
||||||
use Pterodactyl\Http\Controllers\Controller;
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||||
|
@ -35,6 +36,11 @@ class ServerViewController extends Controller
|
||||||
*/
|
*/
|
||||||
private $repository;
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $mountRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Pterodactyl\Repositories\Eloquent\NestRepository
|
* @var \Pterodactyl\Repositories\Eloquent\NestRepository
|
||||||
*/
|
*/
|
||||||
|
@ -53,27 +59,30 @@ class ServerViewController extends Controller
|
||||||
/**
|
/**
|
||||||
* ServerViewController constructor.
|
* ServerViewController constructor.
|
||||||
*
|
*
|
||||||
|
* @param \Illuminate\Contracts\View\Factory $view
|
||||||
* @param \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository $databaseHostRepository
|
* @param \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository $databaseHostRepository
|
||||||
* @param \Pterodactyl\Repositories\Eloquent\NestRepository $nestRepository
|
|
||||||
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
|
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $mountRepository
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\NestRepository $nestRepository
|
||||||
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
|
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
|
||||||
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
|
||||||
* @param \Illuminate\Contracts\View\Factory $view
|
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
Factory $view,
|
||||||
DatabaseHostRepository $databaseHostRepository,
|
DatabaseHostRepository $databaseHostRepository,
|
||||||
NestRepository $nestRepository,
|
|
||||||
LocationRepository $locationRepository,
|
LocationRepository $locationRepository,
|
||||||
|
MountRepository $mountRepository,
|
||||||
|
NestRepository $nestRepository,
|
||||||
NodeRepository $nodeRepository,
|
NodeRepository $nodeRepository,
|
||||||
ServerRepository $repository,
|
ServerRepository $repository
|
||||||
Factory $view
|
|
||||||
) {
|
) {
|
||||||
$this->view = $view;
|
$this->view = $view;
|
||||||
$this->databaseHostRepository = $databaseHostRepository;
|
$this->databaseHostRepository = $databaseHostRepository;
|
||||||
$this->repository = $repository;
|
$this->locationRepository = $locationRepository;
|
||||||
|
$this->mountRepository = $mountRepository;
|
||||||
$this->nestRepository = $nestRepository;
|
$this->nestRepository = $nestRepository;
|
||||||
$this->nodeRepository = $nodeRepository;
|
$this->nodeRepository = $nodeRepository;
|
||||||
$this->locationRepository = $locationRepository;
|
$this->repository = $repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,6 +169,23 @@ class ServerViewController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all of the mounts that exist for the server.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Pterodactyl\Models\Server $server
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
*/
|
||||||
|
public function mounts(Request $request, Server $server)
|
||||||
|
{
|
||||||
|
$server->load('mounts');
|
||||||
|
|
||||||
|
return $this->view->make('admin.servers.view.mounts', [
|
||||||
|
'mounts' => $this->mountRepository->getMountListForServer($server),
|
||||||
|
'server' => $server,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the base server management page, or an exception if the server
|
* Returns the base server management page, or an exception if the server
|
||||||
* is in a state that cannot be recovered from.
|
* is in a state that cannot be recovered from.
|
||||||
|
@ -169,7 +195,6 @@ class ServerViewController extends Controller
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*
|
*
|
||||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
|
||||||
*/
|
*/
|
||||||
public function manage(Request $request, Server $server)
|
public function manage(Request $request, Server $server)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,17 +9,21 @@
|
||||||
|
|
||||||
namespace Pterodactyl\Http\Controllers\Admin;
|
namespace Pterodactyl\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Pterodactyl\Models\User;
|
use Pterodactyl\Models\User;
|
||||||
use Pterodactyl\Models\Server;
|
use Pterodactyl\Models\Server;
|
||||||
use Prologue\Alerts\AlertsMessageBag;
|
use Prologue\Alerts\AlertsMessageBag;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
use Pterodactyl\Exceptions\DisplayException;
|
use Pterodactyl\Exceptions\DisplayException;
|
||||||
use Pterodactyl\Http\Controllers\Controller;
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Pterodactyl\Services\Servers\SuspensionService;
|
use Pterodactyl\Services\Servers\SuspensionService;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
use Pterodactyl\Services\Servers\ServerDeletionService;
|
use Pterodactyl\Services\Servers\ServerDeletionService;
|
||||||
use Pterodactyl\Services\Servers\ReinstallServerService;
|
use Pterodactyl\Services\Servers\ReinstallServerService;
|
||||||
use Pterodactyl\Exceptions\Model\DataValidationException;
|
use Pterodactyl\Exceptions\Model\DataValidationException;
|
||||||
|
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
||||||
use Pterodactyl\Services\Servers\BuildModificationService;
|
use Pterodactyl\Services\Servers\BuildModificationService;
|
||||||
use Pterodactyl\Services\Databases\DatabasePasswordService;
|
use Pterodactyl\Services\Databases\DatabasePasswordService;
|
||||||
use Pterodactyl\Services\Servers\DetailsModificationService;
|
use Pterodactyl\Services\Servers\DetailsModificationService;
|
||||||
|
@ -31,6 +35,8 @@ use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
|
||||||
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
|
||||||
|
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||||
|
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||||
use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest;
|
use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest;
|
||||||
|
|
||||||
class ServersController extends Controller
|
class ServersController extends Controller
|
||||||
|
@ -55,6 +61,11 @@ class ServersController extends Controller
|
||||||
*/
|
*/
|
||||||
protected $config;
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
||||||
|
*/
|
||||||
|
private $daemonServerRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
|
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
|
||||||
*/
|
*/
|
||||||
|
@ -85,6 +96,11 @@ class ServersController extends Controller
|
||||||
*/
|
*/
|
||||||
protected $detailsModificationService;
|
protected $detailsModificationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $mountRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
|
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
|
||||||
*/
|
*/
|
||||||
|
@ -100,6 +116,11 @@ class ServersController extends Controller
|
||||||
*/
|
*/
|
||||||
protected $repository;
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||||
|
*/
|
||||||
|
private $serverConfigurationStructureService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Pterodactyl\Services\Servers\StartupModificationService
|
* @var \Pterodactyl\Services\Servers\StartupModificationService
|
||||||
*/
|
*/
|
||||||
|
@ -117,6 +138,7 @@ class ServersController extends Controller
|
||||||
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
|
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
|
||||||
* @param \Pterodactyl\Services\Servers\BuildModificationService $buildModificationService
|
* @param \Pterodactyl\Services\Servers\BuildModificationService $buildModificationService
|
||||||
* @param \Illuminate\Contracts\Config\Repository $config
|
* @param \Illuminate\Contracts\Config\Repository $config
|
||||||
|
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
||||||
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $databaseManagementService
|
* @param \Pterodactyl\Services\Databases\DatabaseManagementService $databaseManagementService
|
||||||
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $databasePasswordService
|
* @param \Pterodactyl\Services\Databases\DatabasePasswordService $databasePasswordService
|
||||||
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository
|
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository
|
||||||
|
@ -125,7 +147,9 @@ class ServersController extends Controller
|
||||||
* @param \Pterodactyl\Services\Servers\DetailsModificationService $detailsModificationService
|
* @param \Pterodactyl\Services\Servers\DetailsModificationService $detailsModificationService
|
||||||
* @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallService
|
* @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallService
|
||||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $mountRepository
|
||||||
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $nestRepository
|
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $nestRepository
|
||||||
|
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $serverConfigurationStructureService
|
||||||
* @param \Pterodactyl\Services\Servers\StartupModificationService $startupModificationService
|
* @param \Pterodactyl\Services\Servers\StartupModificationService $startupModificationService
|
||||||
* @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService
|
* @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService
|
||||||
*/
|
*/
|
||||||
|
@ -134,6 +158,7 @@ class ServersController extends Controller
|
||||||
AllocationRepositoryInterface $allocationRepository,
|
AllocationRepositoryInterface $allocationRepository,
|
||||||
BuildModificationService $buildModificationService,
|
BuildModificationService $buildModificationService,
|
||||||
ConfigRepository $config,
|
ConfigRepository $config,
|
||||||
|
DaemonServerRepository $daemonServerRepository,
|
||||||
DatabaseManagementService $databaseManagementService,
|
DatabaseManagementService $databaseManagementService,
|
||||||
DatabasePasswordService $databasePasswordService,
|
DatabasePasswordService $databasePasswordService,
|
||||||
DatabaseRepositoryInterface $databaseRepository,
|
DatabaseRepositoryInterface $databaseRepository,
|
||||||
|
@ -142,7 +167,9 @@ class ServersController extends Controller
|
||||||
DetailsModificationService $detailsModificationService,
|
DetailsModificationService $detailsModificationService,
|
||||||
ReinstallServerService $reinstallService,
|
ReinstallServerService $reinstallService,
|
||||||
ServerRepositoryInterface $repository,
|
ServerRepositoryInterface $repository,
|
||||||
|
MountRepository $mountRepository,
|
||||||
NestRepositoryInterface $nestRepository,
|
NestRepositoryInterface $nestRepository,
|
||||||
|
ServerConfigurationStructureService $serverConfigurationStructureService,
|
||||||
StartupModificationService $startupModificationService,
|
StartupModificationService $startupModificationService,
|
||||||
SuspensionService $suspensionService
|
SuspensionService $suspensionService
|
||||||
) {
|
) {
|
||||||
|
@ -150,6 +177,7 @@ class ServersController extends Controller
|
||||||
$this->allocationRepository = $allocationRepository;
|
$this->allocationRepository = $allocationRepository;
|
||||||
$this->buildModificationService = $buildModificationService;
|
$this->buildModificationService = $buildModificationService;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->daemonServerRepository = $daemonServerRepository;
|
||||||
$this->databaseHostRepository = $databaseHostRepository;
|
$this->databaseHostRepository = $databaseHostRepository;
|
||||||
$this->databaseManagementService = $databaseManagementService;
|
$this->databaseManagementService = $databaseManagementService;
|
||||||
$this->databasePasswordService = $databasePasswordService;
|
$this->databasePasswordService = $databasePasswordService;
|
||||||
|
@ -159,6 +187,8 @@ class ServersController extends Controller
|
||||||
$this->nestRepository = $nestRepository;
|
$this->nestRepository = $nestRepository;
|
||||||
$this->reinstallService = $reinstallService;
|
$this->reinstallService = $reinstallService;
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
|
$this->mountRepository = $mountRepository;
|
||||||
|
$this->serverConfigurationStructureService = $serverConfigurationStructureService;
|
||||||
$this->startupModificationService = $startupModificationService;
|
$this->startupModificationService = $startupModificationService;
|
||||||
$this->suspensionService = $suspensionService;
|
$this->suspensionService = $suspensionService;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +200,6 @@ class ServersController extends Controller
|
||||||
* @param \Pterodactyl\Models\Server $server
|
* @param \Pterodactyl\Models\Server $server
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*
|
*
|
||||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
|
||||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
*/
|
*/
|
||||||
|
@ -378,4 +407,59 @@ class ServersController extends Controller
|
||||||
|
|
||||||
return response('', 204);
|
return response('', 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a mount to a server.
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @param int $mount_id
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function addMount(Server $server, int $mount_id)
|
||||||
|
{
|
||||||
|
$server->mounts()->attach($mount_id);
|
||||||
|
|
||||||
|
$data = $this->serverConfigurationStructureService->handle($server);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->daemonServerRepository
|
||||||
|
->setServer($server)
|
||||||
|
->update(Arr::only($data, ['mounts']));
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
throw new DaemonConnectionException($exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->alert->success('Mount was added successfully.')->flash();
|
||||||
|
|
||||||
|
return redirect()->route('admin.servers.view.mounts', $server->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a mount from a server.
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @param int $mount_id
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*
|
||||||
|
* @throws DaemonConnectionException
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function deleteMount(Server $server, int $mount_id)
|
||||||
|
{
|
||||||
|
$server->mounts()->detach($mount_id);
|
||||||
|
|
||||||
|
$data = $this->serverConfigurationStructureService->handle($server);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->daemonServerRepository
|
||||||
|
->setServer($server)
|
||||||
|
->update(Arr::only($data, ['mounts']));
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
throw new DaemonConnectionException($exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->alert->success('Mount was removed successfully.')->flash();
|
||||||
|
|
||||||
|
return redirect()->route('admin.servers.view.mounts', $server->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
29
app/Http/Requests/Admin/MountFormRequest.php
Normal file
29
app/Http/Requests/Admin/MountFormRequest.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the MIT license.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Http\Requests\Admin;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\Mount;
|
||||||
|
|
||||||
|
class MountFormRequest extends AdminFormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Setup the validation rules to use for these requests.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
if ($this->method() === 'PATCH') {
|
||||||
|
return Mount::getRulesForUpdate($this->route()->parameter('mount')->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mount::getRules();
|
||||||
|
}
|
||||||
|
}
|
108
app/Models/Mount.php
Normal file
108
app/Models/Mount.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $uuid
|
||||||
|
* @property string $name
|
||||||
|
* @property string $description
|
||||||
|
* @property string $source
|
||||||
|
* @property string $target
|
||||||
|
* @property bool $read_only
|
||||||
|
* @property bool $user_mountable
|
||||||
|
*
|
||||||
|
* @property \Pterodactyl\Models\Egg[]|\Illuminate\Database\Eloquent\Collection $eggs
|
||||||
|
* @property \Pterodactyl\Models\Node[]|\Illuminate\Database\Eloquent\Collection $nodes
|
||||||
|
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
|
||||||
|
*/
|
||||||
|
class Mount extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The resource name for this model when it is transformed into an
|
||||||
|
* API representation using fractal.
|
||||||
|
*/
|
||||||
|
const RESOURCE_NAME = 'mount';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'mounts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fields that are not mass assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $guarded = ['id', 'uuid'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default values for specific fields in the database.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $attributes = [
|
||||||
|
'id' => 'int',
|
||||||
|
'uuid' => 'string',
|
||||||
|
'name' => 'string',
|
||||||
|
'description' => 'string',
|
||||||
|
'source' => 'string',
|
||||||
|
'target' => 'string',
|
||||||
|
'read_only' => 'bool',
|
||||||
|
'user_mountable' => 'bool',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules verifying that the data being stored matches the expectations of the database.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $validationRules = [
|
||||||
|
// 'uuid' => 'required|string|size:36|unique:mounts,uuid',
|
||||||
|
'name' => 'required|string|min:2|max:64|unique:mounts,name',
|
||||||
|
'description' => 'nullable|string|max:255',
|
||||||
|
'source' => 'required|string',
|
||||||
|
'target' => 'required|string',
|
||||||
|
'read_only' => 'sometimes|boolean',
|
||||||
|
'user_mountable' => 'sometimes|boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable timestamps on this model.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all eggs that have this mount assigned.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function eggs()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Egg::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all nodes that have this mount assigned.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function nodes()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Node::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all servers that have this mount assigned.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function servers()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Server::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
||||||
* @property \Pterodactyl\Models\DaemonKey[]|\Illuminate\Database\Eloquent\Collection $keys
|
* @property \Pterodactyl\Models\DaemonKey[]|\Illuminate\Database\Eloquent\Collection $keys
|
||||||
* @property \Pterodactyl\Models\ServerTransfer $transfer
|
* @property \Pterodactyl\Models\ServerTransfer $transfer
|
||||||
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
|
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
|
||||||
|
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
|
||||||
*/
|
*/
|
||||||
class Server extends Model
|
class Server extends Model
|
||||||
{
|
{
|
||||||
|
@ -351,4 +352,14 @@ class Server extends Model
|
||||||
{
|
{
|
||||||
return $this->hasMany(Backup::class);
|
return $this->hasMany(Backup::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all mounts that have this server has mounted.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||||
|
*/
|
||||||
|
public function mounts()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Mount::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
70
app/Repositories/Eloquent/MountRepository.php
Normal file
70
app/Repositories/Eloquent/MountRepository.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Repositories\Eloquent;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\Mount;
|
||||||
|
use Pterodactyl\Models\Server;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Pterodactyl\Repositories\Concerns\Searchable;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||||
|
|
||||||
|
class MountRepository extends EloquentRepository
|
||||||
|
{
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the model backing this repository.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function model()
|
||||||
|
{
|
||||||
|
return Mount::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return mounts with a count of eggs, nodes, and servers attached to it.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function getAllWithDetails(): Collection
|
||||||
|
{
|
||||||
|
return $this->getBuilder()->withCount('eggs', 'nodes')->get($this->getColumns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all of the mounts and their respective relations.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return mixed
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function getWithRelations(string $id): Mount
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->getBuilder()->with('eggs', 'nodes')->findOrFail($id, $this->getColumns());
|
||||||
|
} catch (ModelNotFoundException $exception) {
|
||||||
|
throw new RecordNotFoundException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return mounts available to a server (ignoring if they are or are not mounted).
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function getMountListForServer(Server $server): Collection
|
||||||
|
{
|
||||||
|
return $this->getBuilder()
|
||||||
|
->whereHas('eggs', function ($q) use ($server) {
|
||||||
|
$q->where('id', '=', $server->egg_id);
|
||||||
|
})
|
||||||
|
->whereHas('nodes', function ($q) use ($server) {
|
||||||
|
$q->where('id', '=', $server->node_id);
|
||||||
|
})
|
||||||
|
->get($this->getColumns());
|
||||||
|
}
|
||||||
|
}
|
40
app/Services/Mounts/MountCreationService.php
Normal file
40
app/Services/Mounts/MountCreationService.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Services\Mounts;
|
||||||
|
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
|
|
||||||
|
class MountCreationService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MountCreationService constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $repository
|
||||||
|
*/
|
||||||
|
public function __construct(MountRepository $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new mount.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return \Pterodactyl\Models\Mount
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||||
|
*/
|
||||||
|
public function handle(array $data)
|
||||||
|
{
|
||||||
|
return $this->repository->create(array_merge($data, [
|
||||||
|
'uuid' => Uuid::uuid4()->toString(),
|
||||||
|
]), true, true);
|
||||||
|
}
|
||||||
|
}
|
40
app/Services/Mounts/MountDeletionService.php
Normal file
40
app/Services/Mounts/MountDeletionService.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Services\Mounts;
|
||||||
|
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
use Pterodactyl\Models\Mount;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
|
|
||||||
|
class MountDeletionService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MountDeletionService constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $repository
|
||||||
|
*/
|
||||||
|
public function __construct(MountRepository $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing location.
|
||||||
|
*
|
||||||
|
* @param int|\Pterodactyl\Models\Mount $mount
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function handle($mount)
|
||||||
|
{
|
||||||
|
$mount = ($mount instanceof Mount) ? $mount->id : $mount;
|
||||||
|
|
||||||
|
Assert::integerish($mount, 'First argument passed to handle must be numeric or an instance of ' . Mount::class . ', received %s.');
|
||||||
|
|
||||||
|
return $this->repository->delete($mount);
|
||||||
|
}
|
||||||
|
}
|
41
app/Services/Mounts/MountUpdateService.php
Normal file
41
app/Services/Mounts/MountUpdateService.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Services\Mounts;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\Mount;
|
||||||
|
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||||
|
|
||||||
|
class MountUpdateService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Repositories\Eloquent\MountRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MountUpdateService constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Repositories\Eloquent\MountRepository $repository
|
||||||
|
*/
|
||||||
|
public function __construct(MountRepository $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing location.
|
||||||
|
*
|
||||||
|
* @param int|\Pterodactyl\Models\Mount $mount
|
||||||
|
* @param array $data
|
||||||
|
* @return \Pterodactyl\Models\Mount
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
|
*/
|
||||||
|
public function handle($mount, array $data)
|
||||||
|
{
|
||||||
|
$mount = ($mount instanceof Mount) ? $mount->id : $mount;
|
||||||
|
|
||||||
|
return $this->repository->update($mount, $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,6 +71,17 @@ class ServerConfigurationStructureService
|
||||||
*/
|
*/
|
||||||
protected function returnCurrentFormat(Server $server)
|
protected function returnCurrentFormat(Server $server)
|
||||||
{
|
{
|
||||||
|
$mounts = $server->mounts;
|
||||||
|
foreach ($mounts as $mount) {
|
||||||
|
unset($mount->id);
|
||||||
|
unset($mount->uuid);
|
||||||
|
unset($mount->name);
|
||||||
|
unset($mount->description);
|
||||||
|
$mount->read_only = $mount->read_only == 1;
|
||||||
|
unset($mount->user_mountable);
|
||||||
|
unset($mount->pivot);
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'uuid' => $server->uuid,
|
'uuid' => $server->uuid,
|
||||||
'suspended' => (bool) $server->suspended,
|
'suspended' => (bool) $server->suspended,
|
||||||
|
@ -101,6 +112,7 @@ class ServerConfigurationStructureService
|
||||||
],
|
],
|
||||||
'mappings' => $server->getAllocationMappings(),
|
'mappings' => $server->getAllocationMappings(),
|
||||||
],
|
],
|
||||||
|
'mounts' => $mounts,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
53
database/migrations/2020_05_20_234655_add_mounts_table.php
Normal file
53
database/migrations/2020_05_20_234655_add_mounts_table.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddMountsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('mounts', function (Blueprint $table) {
|
||||||
|
$table->increments('id')->unique();
|
||||||
|
$table->char('uuid', 36)->unique();
|
||||||
|
$table->string('name')->unique();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->string('source');
|
||||||
|
$table->string('target');
|
||||||
|
$table->tinyInteger('read_only')->unsigned();
|
||||||
|
$table->tinyInteger('user_mountable')->unsigned();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('egg_mount', function (Blueprint $table) {
|
||||||
|
$table->integer('egg_id');
|
||||||
|
$table->integer('mount_id');
|
||||||
|
|
||||||
|
$table->unique(['egg_id', 'mount_id']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('mount_node', function (Blueprint $table) {
|
||||||
|
$table->integer('node_id');
|
||||||
|
$table->integer('mount_id');
|
||||||
|
|
||||||
|
$table->unique(['node_id', 'mount_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mount_node');
|
||||||
|
Schema::dropIfExists('egg_mount');
|
||||||
|
Schema::dropIfExists('mounts');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddMountServerTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('mount_server', function (Blueprint $table) {
|
||||||
|
$table->integer('server_id');
|
||||||
|
$table->integer('mount_id');
|
||||||
|
|
||||||
|
$table->unique(['server_id', 'mount_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mount_server');
|
||||||
|
}
|
||||||
|
}
|
149
resources/views/admin/mounts/index.blade.php
Normal file
149
resources/views/admin/mounts/index.blade.php
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
{{-- Pterodactyl - Panel --}}
|
||||||
|
{{-- Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com> --}}
|
||||||
|
|
||||||
|
{{-- This software is licensed under the terms of the MIT license. --}}
|
||||||
|
{{-- https://opensource.org/licenses/MIT --}}
|
||||||
|
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Mounts
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content-header')
|
||||||
|
<h1>Mounts<small>SoonTM</small></h1>
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{{ route('admin.index') }}">Admin</a></li>
|
||||||
|
<li class="active">Mounts</li>
|
||||||
|
</ol>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="box box-primary">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Mount List</h3>
|
||||||
|
|
||||||
|
<div class="box-tools">
|
||||||
|
<button class="btn btn-sm btn-primary" data-toggle="modal" data-target="#newMountModal">Create New</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-body table-responsive no-padding">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Source</th>
|
||||||
|
<th>Target</th>
|
||||||
|
<th class="text-center">Eggs</th>
|
||||||
|
<th class="text-center">Nodes</th>
|
||||||
|
<th class="text-center">Servers</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@foreach ($mounts as $mount)
|
||||||
|
<tr>
|
||||||
|
<td><code>{{ $mount->id }}</code></td>
|
||||||
|
<td><a href="{{ route('admin.mounts.view', $mount->id) }}">{{ $mount->name }}</a></td>
|
||||||
|
<td><code>{{ $mount->source }}</code></td>
|
||||||
|
<td><code>{{ $mount->target }}</code></td>
|
||||||
|
<td class="text-center">{{ $mount->eggs_count }}</td>
|
||||||
|
<td class="text-center">{{ $mount->nodes_count }}</td>
|
||||||
|
<td class="text-center">{{ $mount->servers_count }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="newMountModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form action="{{ route('admin.mounts') }}" 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">Create Mount</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label for="pName" class="form-label">Name</label>
|
||||||
|
<input type="text" id="pName" name="name" class="form-control" />
|
||||||
|
<p class="text-muted small">Unique name used to separate this mount from another.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label for="pDescription" class="form-label">Description</label>
|
||||||
|
<textarea id="pDescription" name="description" class="form-control" rows="4"></textarea>
|
||||||
|
<p class="text-muted small">A longer description for this mount, must be less than 255 characters.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="pSource" class="form-label">Source</label>
|
||||||
|
<input type="text" id="pSource" name="source" class="form-control" />
|
||||||
|
<p class="text-muted small">File path on the host system to mount to a container.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="pTarget" class="form-label">Target</label>
|
||||||
|
<input type="text" id="pTarget" name="target" class="form-control" />
|
||||||
|
<p class="text-muted small">Where the mount will be accessible inside a container.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">Read Only</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="radio radio-success radio-inline">
|
||||||
|
<input type="radio" id="pReadOnlyFalse" name="read_only" value="0" checked>
|
||||||
|
<label for="pReadOnlyFalse">False</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio radio-warning radio-inline">
|
||||||
|
<input type="radio" id="pReadOnly" name="read_only" value="1">
|
||||||
|
<label for="pReadOnly">True</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-muted small">Is the mount read only inside the container?</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">User Mountable</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="radio radio-success radio-inline">
|
||||||
|
<input type="radio" id="pUserMountableFalse" name="user_mountable" value="0" checked>
|
||||||
|
<label for="pUserMountableFalse">False</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio radio-warning radio-inline">
|
||||||
|
<input type="radio" id="pUserMountable" name="user_mountable" value="1">
|
||||||
|
<label for="pUserMountable">True</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-muted small">Should users be able to mount this themselves?</p>
|
||||||
|
</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-success btn-sm">Create</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
319
resources/views/admin/mounts/view.blade.php
Normal file
319
resources/views/admin/mounts/view.blade.php
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
{{-- Pterodactyl - Panel --}}
|
||||||
|
{{-- Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com> --}}
|
||||||
|
|
||||||
|
{{-- This software is licensed under the terms of the MIT license. --}}
|
||||||
|
{{-- https://opensource.org/licenses/MIT --}}
|
||||||
|
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Mounts → View → {{ $mount->id }}
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content-header')
|
||||||
|
<h1>{{ $mount->name }}<small>{{ str_limit($mount->description, 75) }}</small></h1>
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{{ route('admin.index') }}">Admin</a></li>
|
||||||
|
<li><a href="{{ route('admin.mounts') }}">Mounts</a></li>
|
||||||
|
<li class="active">{{ $mount->name }}</li>
|
||||||
|
</ol>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="box box-primary">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Mount Details</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('admin.mounts.view', $mount->id) }}" method="POST">
|
||||||
|
<div class="box-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="PUniqueID" class="form-label">Unique ID</label>
|
||||||
|
<input type="text" id="PUniqueID" class="form-control" value="{{ $mount->uuid }}" disabled />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="pName" class="form-label">Name</label>
|
||||||
|
<input type="text" id="pName" name="name" class="form-control" value="{{ $mount->name }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="pDescription" class="form-label">Description</label>
|
||||||
|
<textarea id="pDescription" name="description" class="form-control" rows="4">{{ $mount->description }}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="pSource" class="form-label">Source</label>
|
||||||
|
<input type="text" id="pSource" name="source" class="form-control" value="{{ $mount->source }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="pTarget" class="form-label">Target</label>
|
||||||
|
<input type="text" id="pTarget" name="target" class="form-control" value="{{ $mount->target }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label class="form-label">Read Only</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="radio radio-success radio-inline">
|
||||||
|
<input type="radio" id="pReadOnlyFalse" name="read_only" value="0" @if(!$mount->read_only) checked @endif>
|
||||||
|
<label for="pReadOnlyFalse">False</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio radio-warning radio-inline">
|
||||||
|
<input type="radio" id="pReadOnly" name="read_only" value="1" @if($mount->read_only) checked @endif>
|
||||||
|
<label for="pReadOnly">True</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label class="form-label">User Mountable</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="radio radio-success radio-inline">
|
||||||
|
<input type="radio" id="pUserMountableFalse" name="user_mountable" value="0" @if(!$mount->user_mountable) checked @endif>
|
||||||
|
<label for="pUserMountableFalse">False</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio radio-warning radio-inline">
|
||||||
|
<input type="radio" id="pUserMountable" name="user_mountable" value="1" @if($mount->user_mountable) checked @endif>
|
||||||
|
<label for="pUserMountable">True</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-footer">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
{!! method_field('PATCH') !!}
|
||||||
|
|
||||||
|
<button name="action" value="edit" class="btn btn-sm btn-primary pull-right">Save</button>
|
||||||
|
<button name="action" value="delete" class="btn btn-sm btn-danger pull-left muted muted-hover"><i class="fa fa-trash-o"></i></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<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">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@foreach ($mount->eggs as $egg)
|
||||||
|
<tr>
|
||||||
|
<td class="col-sm-2 middle"><code>{{ $egg->id }}</code></td>
|
||||||
|
<td class="middle"><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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>FQDN</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@foreach ($mount->nodes as $node)
|
||||||
|
<tr>
|
||||||
|
<td class="col-sm-2 middle"><code>{{ $node->id }}</code></td>
|
||||||
|
<td class="middle"><a href="{{ route('admin.nodes.view', $node->id) }}">{{ $node->name }}</a></td>
|
||||||
|
<td class="middle"><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>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
$(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
|
|
@ -21,6 +21,9 @@
|
||||||
<li class="{{ $router->currentRouteNamed('admin.servers.view.database') ? 'active' : '' }}">
|
<li class="{{ $router->currentRouteNamed('admin.servers.view.database') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.servers.view.database', $server->id) }}">Database</a>
|
<a href="{{ route('admin.servers.view.database', $server->id) }}">Database</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="{{ $router->currentRouteNamed('admin.servers.view.mounts') ? 'active' : '' }}">
|
||||||
|
<a href="{{ route('admin.servers.view.mounts', $server->id) }}">Mounts</a>
|
||||||
|
</li>
|
||||||
@endif
|
@endif
|
||||||
<li class="{{ $router->currentRouteNamed('admin.servers.view.manage') ? 'active' : '' }}">
|
<li class="{{ $router->currentRouteNamed('admin.servers.view.manage') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.servers.view.manage', $server->id) }}">Manage</a>
|
<a href="{{ route('admin.servers.view.manage', $server->id) }}">Manage</a>
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Connections From</th>
|
<th>Connections From</th>
|
||||||
<th>Host</th>
|
<th>Host</th>
|
||||||
<th>Max Conenctions</th>
|
<th>Max Connections</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
@foreach($server->databases as $database)
|
@foreach($server->databases as $database)
|
||||||
|
|
78
resources/views/admin/servers/view/mounts.blade.php
Normal file
78
resources/views/admin/servers/view/mounts.blade.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Server — {{ $server->name }}: Mounts
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content-header')
|
||||||
|
<h1>{{ $server->name }}<small>Manage server mounts.</small></h1>
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{{ route('admin.index') }}">Admin</a></li>
|
||||||
|
<li><a href="{{ route('admin.servers') }}">Servers</a></li>
|
||||||
|
<li><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></li>
|
||||||
|
<li class="active">Mounts</li>
|
||||||
|
</ol>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
@include('admin.servers.partials.navigation')
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="box box-primary">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Available Mounts</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-body table-responsible no-padding">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Source</th>
|
||||||
|
<th>Target</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@foreach ($mounts as $mount)
|
||||||
|
<tr>
|
||||||
|
<td class="col-sm-1 middle"><code>{{ $mount->id }}</code></td>
|
||||||
|
<td class="middle"><a href="{{ route('admin.mounts.view', $mount->id) }}">{{ $mount->name }}</a></td>
|
||||||
|
<td class="middle"><code>{{ $mount->source }}</code></td>
|
||||||
|
<td class="col-sm-2 middle"><code>{{ $mount->target }}</code></td>
|
||||||
|
|
||||||
|
@if (! in_array($mount->id, $server->mounts->pluck('id')->toArray()))
|
||||||
|
<td class="col-sm-2 middle">
|
||||||
|
<span class="label label-primary">Unmounted</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="col-sm-1 middle">
|
||||||
|
<form action="{{ route('admin.servers.view.mounts.toggle', [ 'server' => $server->id, 'mount' => $mount->id ]) }}" method="POST">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-xs btn-success"><i class="fa fa-plus"></i></button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@else
|
||||||
|
<td class="col-sm-2 middle">
|
||||||
|
<span class="label label-success">Mounted</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="col-sm-1 middle">
|
||||||
|
<form action="{{ route('admin.servers.view.mounts.toggle', [ 'server' => $server->id, 'mount' => $mount->id ]) }}" method="POST">
|
||||||
|
@method('DELETE')
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-xs btn-danger"><i class="fa fa-times"></i></button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endif
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -117,6 +117,11 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="header">SERVICE MANAGEMENT</li>
|
<li class="header">SERVICE MANAGEMENT</li>
|
||||||
|
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.mounts') ?: 'active' }}">
|
||||||
|
<a href="{{ route('admin.mounts') }}">
|
||||||
|
<i class="fa fa-magic"></i> <span>Mounts</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.nests') ?: 'active' }}">
|
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.nests') ?: 'active' }}">
|
||||||
<a href="{{ route('admin.nests') }}">
|
<a href="{{ route('admin.nests') }}">
|
||||||
<i class="fa fa-th-large"></i> <span>Nests</span>
|
<i class="fa fa-th-large"></i> <span>Nests</span>
|
||||||
|
|
|
@ -113,6 +113,7 @@ Route::group(['prefix' => 'servers'], function () {
|
||||||
Route::get('/view/{server}/build', 'Servers\ServerViewController@build')->name('admin.servers.view.build');
|
Route::get('/view/{server}/build', 'Servers\ServerViewController@build')->name('admin.servers.view.build');
|
||||||
Route::get('/view/{server}/startup', 'Servers\ServerViewController@startup')->name('admin.servers.view.startup');
|
Route::get('/view/{server}/startup', 'Servers\ServerViewController@startup')->name('admin.servers.view.startup');
|
||||||
Route::get('/view/{server}/database', 'Servers\ServerViewController@database')->name('admin.servers.view.database');
|
Route::get('/view/{server}/database', 'Servers\ServerViewController@database')->name('admin.servers.view.database');
|
||||||
|
Route::get('/view/{server}/mounts', 'Servers\ServerViewController@mounts')->name('admin.servers.view.mounts');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/view/{server}/manage', 'Servers\ServerViewController@manage')->name('admin.servers.view.manage');
|
Route::get('/view/{server}/manage', 'Servers\ServerViewController@manage')->name('admin.servers.view.manage');
|
||||||
|
@ -122,6 +123,7 @@ Route::group(['prefix' => 'servers'], function () {
|
||||||
Route::post('/view/{server}/build', 'ServersController@updateBuild');
|
Route::post('/view/{server}/build', 'ServersController@updateBuild');
|
||||||
Route::post('/view/{server}/startup', 'ServersController@saveStartup');
|
Route::post('/view/{server}/startup', 'ServersController@saveStartup');
|
||||||
Route::post('/view/{server}/database', 'ServersController@newDatabase');
|
Route::post('/view/{server}/database', 'ServersController@newDatabase');
|
||||||
|
Route::post('/view/{server}/mounts/{mount}', 'ServersController@addMount')->name('admin.servers.view.mounts.toggle');
|
||||||
Route::post('/view/{server}/manage/toggle', 'ServersController@toggleInstall')->name('admin.servers.view.manage.toggle');
|
Route::post('/view/{server}/manage/toggle', 'ServersController@toggleInstall')->name('admin.servers.view.manage.toggle');
|
||||||
Route::post('/view/{server}/manage/suspension', 'ServersController@manageSuspension')->name('admin.servers.view.manage.suspension');
|
Route::post('/view/{server}/manage/suspension', 'ServersController@manageSuspension')->name('admin.servers.view.manage.suspension');
|
||||||
Route::post('/view/{server}/manage/reinstall', 'ServersController@reinstallServer')->name('admin.servers.view.manage.reinstall');
|
Route::post('/view/{server}/manage/reinstall', 'ServersController@reinstallServer')->name('admin.servers.view.manage.reinstall');
|
||||||
|
@ -132,6 +134,7 @@ Route::group(['prefix' => 'servers'], function () {
|
||||||
Route::patch('/view/{server}/database', 'ServersController@resetDatabasePassword');
|
Route::patch('/view/{server}/database', 'ServersController@resetDatabasePassword');
|
||||||
|
|
||||||
Route::delete('/view/{server}/database/{database}/delete', 'ServersController@deleteDatabase')->name('admin.servers.view.database.delete');
|
Route::delete('/view/{server}/database/{database}/delete', 'ServersController@deleteDatabase')->name('admin.servers.view.database.delete');
|
||||||
|
Route::delete('/view/{server}/mounts/{mount}', 'ServersController@deleteMount');
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -165,6 +168,28 @@ Route::group(['prefix' => 'nodes'], function () {
|
||||||
Route::delete('/view/{node}/allocations', 'NodesController@allocationRemoveMultiple')->name('admin.nodes.view.allocation.removeMultiple');
|
Route::delete('/view/{node}/allocations', 'NodesController@allocationRemoveMultiple')->name('admin.nodes.view.allocation.removeMultiple');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Mount Controller Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Endpoint: /admin/mounts
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
Route::group(['prefix' => 'mounts'], function () {
|
||||||
|
Route::get('/', 'MountController@index')->name('admin.mounts');
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Nest Controller Routes
|
| Nest Controller Routes
|
||||||
|
|
Loading…
Reference in a new issue