1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-21 16:42:29 +01:00
This commit is contained in:
Matthew Penner 2022-12-14 14:36:07 -07:00
parent 7fde336036
commit 4cd0bee231
No known key found for this signature in database
195 changed files with 3 additions and 22376 deletions

View File

@ -1,7 +1,6 @@
APP_ENV=production APP_ENV=production
APP_DEBUG=false APP_DEBUG=false
APP_KEY= APP_KEY=
APP_THEME=pterodactyl
APP_TIMEZONE=UTC APP_TIMEZONE=UTC
APP_URL=http://panel.example.com APP_URL=http://panel.example.com
APP_LOCALE=en APP_LOCALE=en

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Extensions\Backups; namespace Pterodactyl\Extensions\Backups;
use Closure;
use Aws\S3\S3Client; use Aws\S3\S3Client;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Str; use Illuminate\Support\Str;

View File

@ -1,13 +0,0 @@
<?php
namespace Pterodactyl\Extensions\Facades;
use Illuminate\Support\Facades\Facade;
class Theme extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'extensions.themes';
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Pterodactyl\Extensions\Themes;
class Theme
{
public function js($path): string
{
return sprintf('<script src="%s"></script>' . PHP_EOL, $this->getUrl($path));
}
public function css($path): string
{
return sprintf('<link media="all" type="text/css" rel="stylesheet" href="%s"/>' . PHP_EOL, $this->getUrl($path));
}
protected function getUrl($path): string
{
return '/themes/pterodactyl/' . ltrim($path, '/');
}
}

View File

@ -1,85 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Pterodactyl\Models\ApiKey;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Api\KeyCreationService;
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Api\StoreApplicationApiKeyRequest;
class ApiController extends Controller
{
/**
* ApiController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private ApiKeyRepositoryInterface $repository,
private KeyCreationService $keyCreationService
) {
}
/**
* Render view showing all of a user's application API keys.
*/
public function index(Request $request): View
{
return view('admin.api.index', [
'keys' => $this->repository->getApplicationKeys($request->user()),
]);
}
/**
* Render view allowing an admin to create a new application API key.
*
* @throws \ReflectionException
*/
public function create(): View
{
$resources = AdminAcl::getResourceList();
sort($resources);
return view('admin.api.new', [
'resources' => $resources,
'permissions' => [
'r' => AdminAcl::READ,
'rw' => AdminAcl::READ | AdminAcl::WRITE,
'n' => AdminAcl::NONE,
],
]);
}
/**
* Store the new key and redirect the user back to the application key listing.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function store(StoreApplicationApiKeyRequest $request): RedirectResponse
{
$this->keyCreationService->setKeyType(ApiKey::TYPE_APPLICATION)->handle([
'memo' => $request->input('memo'),
'user_id' => $request->user()->id,
], $request->getKeyPermissions());
$this->alert->success('A new application API key has been generated for your account.')->flash();
return redirect()->route('admin.api.index');
}
/**
* Delete an application API key from the database.
*/
public function delete(Request $request, string $identifier): Response
{
$this->repository->deleteApplicationKey($request->user(), $identifier);
return response('', 204);
}
}

View File

@ -4,22 +4,11 @@ namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View; use Illuminate\View\View;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
class BaseController extends Controller class BaseController extends Controller
{ {
/**
* BaseController constructor.
*/
public function __construct(private SoftwareVersionService $version)
{
}
/**
* Return the admin index view.
*/
public function index(): View public function index(): View
{ {
return view('admin.index', ['version' => $this->version]); return view('templates/base.core');
} }
} }

View File

@ -1,127 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Exception;
use Illuminate\View\View;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Databases\Hosts\HostUpdateService;
use Pterodactyl\Http\Requests\Admin\DatabaseHostFormRequest;
use Pterodactyl\Services\Databases\Hosts\HostCreationService;
use Pterodactyl\Services\Databases\Hosts\HostDeletionService;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
class DatabaseController extends Controller
{
/**
* DatabaseController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private DatabaseHostRepositoryInterface $repository,
private DatabaseRepositoryInterface $databaseRepository,
private HostCreationService $creationService,
private HostDeletionService $deletionService,
private HostUpdateService $updateService,
private LocationRepositoryInterface $locationRepository
) {
}
/**
* Display database host index.
*/
public function index(): View
{
return view('admin.databases.index', [
'locations' => $this->locationRepository->getAllWithNodes(),
'hosts' => $this->repository->getWithViewDetails(),
]);
}
/**
* Display database host to user.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function view(int $host): View
{
return view('admin.databases.view', [
'locations' => $this->locationRepository->getAllWithNodes(),
'host' => $this->repository->find($host),
'databases' => $this->databaseRepository->getDatabasesForHost($host),
]);
}
/**
* Handle request to create a new database host.
*
* @throws \Throwable
*/
public function create(DatabaseHostFormRequest $request): RedirectResponse
{
try {
$host = $this->creationService->handle($request->normalize());
} catch (\Exception $exception) {
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
$this->alert->danger(
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
)->flash();
return redirect()->route('admin.databases')->withInput($request->validated());
} else {
throw $exception;
}
}
$this->alert->success('Successfully created a new database host on the system.')->flash();
return redirect()->route('admin.databases.view', $host->id);
}
/**
* Handle updating database host.
*
* @throws \Throwable
*/
public function update(DatabaseHostFormRequest $request, DatabaseHost $host): RedirectResponse
{
$redirect = redirect()->route('admin.databases.view', $host->id);
try {
$this->updateService->handle($host->id, $request->normalize());
$this->alert->success('Database host was updated successfully.')->flash();
} catch (\Exception $exception) {
// Catch any SQL related exceptions and display them back to the user, otherwise just
// throw the exception like normal and move on with it.
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
$this->alert->danger(
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
)->flash();
return $redirect->withInput($request->normalize());
} else {
throw $exception;
}
}
return $redirect;
}
/**
* Handle request to delete a database host.
*
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/
public function delete(int $host): RedirectResponse
{
$this->deletionService->handle($host);
$this->alert->success('The requested database host has been deleted from the system.')->flash();
return redirect()->route('admin.databases');
}
}

View File

@ -1,103 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Pterodactyl\Models\Location;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Http\Requests\Admin\LocationFormRequest;
use Pterodactyl\Services\Locations\LocationUpdateService;
use Pterodactyl\Services\Locations\LocationCreationService;
use Pterodactyl\Services\Locations\LocationDeletionService;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
class LocationController extends Controller
{
/**
* LocationController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected LocationCreationService $creationService,
protected LocationDeletionService $deletionService,
protected LocationRepositoryInterface $repository,
protected LocationUpdateService $updateService,
protected ViewFactory $view
) {
}
/**
* Return the location overview page.
*/
public function index(): View
{
return view('admin.locations.index', [
'locations' => $this->repository->getAllWithDetails(),
]);
}
/**
* Return the location view page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function view(int $id): View
{
return view('admin.locations.view', [
'location' => $this->repository->getWithNodes($id),
]);
}
/**
* Handle request to create new location.
*
* @throws \Throwable
*/
public function create(LocationFormRequest $request): RedirectResponse
{
$location = $this->creationService->handle($request->normalize());
$this->alert->success('Location was created successfully.')->flash();
return redirect()->route('admin.locations.view', $location->id);
}
/**
* Handle request to update or delete location.
*
* @throws \Throwable
*/
public function update(LocationFormRequest $request, Location $location): RedirectResponse
{
if ($request->input('action') === 'delete') {
return $this->delete($location);
}
$this->updateService->handle($location->id, $request->normalize());
$this->alert->success('Location was updated successfully.')->flash();
return redirect()->route('admin.locations.view', $location->id);
}
/**
* Delete a location from the system.
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete(Location $location): RedirectResponse
{
try {
$this->deletionService->handle($location->id);
return redirect()->route('admin.locations');
} catch (DisplayException $ex) {
$this->alert->danger($ex->getMessage())->flash();
}
return redirect()->route('admin.locations.view', $location->id);
}
}

View File

@ -1,165 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Ramsey\Uuid\Uuid;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Nest;
use Illuminate\Http\Response;
use Pterodactyl\Models\Mount;
use Pterodactyl\Models\Location;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
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
{
/**
* MountController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected NestRepositoryInterface $nestRepository,
protected LocationRepositoryInterface $locationRepository,
protected MountRepository $repository,
protected ViewFactory $view
) {
}
/**
* Return the mount overview page.
*/
public function index(): View
{
return view('admin.mounts.index', [
'mounts' => $this->repository->getAllWithDetails(),
]);
}
/**
* Return the mount view page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function view(string $id): View
{
$nests = Nest::query()->with('eggs')->get();
$locations = Location::query()->with('nodes')->get();
return view('admin.mounts.view', [
'mount' => $this->repository->getWithRelations($id),
'nests' => $nests,
'locations' => $locations,
]);
}
/**
* Handle request to create new mount.
*
* @throws \Throwable
*/
public function create(MountFormRequest $request): RedirectResponse
{
$model = (new Mount())->fill($request->validated());
$model->forceFill(['uuid' => Uuid::uuid4()->toString()]);
$model->saveOrFail();
$mount = $model->fresh();
$this->alert->success('Mount was created successfully.')->flash();
return redirect()->route('admin.mounts.view', $mount->id);
}
/**
* Handle request to update or delete location.
*
* @throws \Throwable
*/
public function update(MountFormRequest $request, Mount $mount): RedirectResponse
{
if ($request->input('action') === 'delete') {
return $this->delete($mount);
}
$mount->forceFill($request->validated())->save();
$this->alert->success('Mount was updated successfully.')->flash();
return redirect()->route('admin.mounts.view', $mount->id);
}
/**
* Delete a location from the system.
*
* @throws \Exception
*/
public function delete(Mount $mount): RedirectResponse
{
$mount->delete();
return redirect()->route('admin.mounts');
}
/**
* Adds eggs to the mount's many-to-many relation.
*/
public function addEggs(Request $request, Mount $mount): RedirectResponse
{
$validatedData = $request->validate([
'eggs' => 'required|exists:eggs,id',
]);
$eggs = $validatedData['eggs'] ?? [];
if (count($eggs) > 0) {
$mount->eggs()->attach($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.
*/
public function addNodes(Request $request, Mount $mount): RedirectResponse
{
$data = $request->validate(['nodes' => 'required|exists:nodes,id']);
$nodes = $data['nodes'] ?? [];
if (count($nodes) > 0) {
$mount->nodes()->attach($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.
*/
public function deleteEgg(Mount $mount, int $egg_id): Response
{
$mount->eggs()->detach($egg_id);
return response('', 204);
}
/**
* Deletes a node from the mount's many-to-many relation.
*/
public function deleteNode(Mount $mount, int $node_id): Response
{
$mount->nodes()->detach($node_id);
return response('', 204);
}
}

View File

@ -1,128 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use Illuminate\View\View;
use Pterodactyl\Models\Egg;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Eggs\EggUpdateService;
use Pterodactyl\Services\Eggs\EggCreationService;
use Pterodactyl\Services\Eggs\EggDeletionService;
use Pterodactyl\Http\Requests\Admin\Egg\EggFormRequest;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
class EggController extends Controller
{
/**
* EggController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected EggCreationService $creationService,
protected EggDeletionService $deletionService,
protected EggRepositoryInterface $repository,
protected EggUpdateService $updateService,
protected NestRepositoryInterface $nestRepository,
protected ViewFactory $view
) {
}
/**
* Handle a request to display the Egg creation page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function create(): View
{
$nests = $this->nestRepository->getWithEggs();
\JavaScript::put(['nests' => $nests->keyBy('id')]);
return view('admin.eggs.new', ['nests' => $nests]);
}
/**
* Handle request to store a new Egg.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Service\Egg\NoParentConfigurationFoundException
*/
public function store(EggFormRequest $request): RedirectResponse
{
$data = $request->validated();
$data['docker_images'] = $this->normalizeDockerImages($data['docker_images'] ?? null);
$egg = $this->creationService->handle($data);
$this->alert->success(trans('admin/nests.eggs.notices.egg_created'))->flash();
return redirect()->route('admin.nests.egg.view', $egg->id);
}
/**
* Handle request to view a single Egg.
*/
public function view(Egg $egg): View
{
return view('admin.eggs.view', [
'egg' => $egg,
'images' => array_map(
fn ($key, $value) => $key === $value ? $value : "$key|$value",
array_keys($egg->docker_images),
$egg->docker_images,
),
]);
}
/**
* Handle request to update an Egg.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\NoParentConfigurationFoundException
*/
public function update(EggFormRequest $request, Egg $egg): RedirectResponse
{
$data = $request->validated();
$data['docker_images'] = $this->normalizeDockerImages($data['docker_images'] ?? null);
$this->updateService->handle($egg, $data);
$this->alert->success(trans('admin/nests.eggs.notices.updated'))->flash();
return redirect()->route('admin.nests.egg.view', $egg->id);
}
/**
* Handle request to destroy an egg.
*
* @throws \Pterodactyl\Exceptions\Service\Egg\HasChildrenException
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/
public function destroy(Egg $egg): RedirectResponse
{
$this->deletionService->handle($egg->id);
$this->alert->success(trans('admin/nests.eggs.notices.deleted'))->flash();
return redirect()->route('admin.nests.view', $egg->nest_id);
}
/**
* Normalizes a string of docker image data into the expected egg format.
*/
protected function normalizeDockerImages(string $input = null): array
{
$data = array_map(fn ($value) => trim($value), explode("\n", $input ?? ''));
$images = [];
// Iterate over the image data provided and convert it into a name => image
// pairing that is used to improve the display on the front-end.
foreach ($data as $value) {
$parts = explode('|', $value, 2);
$images[$parts[0]] = empty($parts[1]) ? $parts[0] : $parts[1];
}
return $images;
}
}

View File

@ -1,65 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use Illuminate\View\View;
use Pterodactyl\Models\Egg;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Eggs\Scripts\InstallScriptService;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Egg\EggScriptFormRequest;
class EggScriptController extends Controller
{
/**
* EggScriptController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected EggRepositoryInterface $repository,
protected InstallScriptService $installScriptService,
protected ViewFactory $view
) {
}
/**
* Handle requests to render installation script for an Egg.
*/
public function index(int $egg): View
{
$egg = $this->repository->getWithCopyAttributes($egg);
$copy = $this->repository->findWhere([
['copy_script_from', '=', null],
['nest_id', '=', $egg->nest_id],
['id', '!=', $egg],
]);
$rely = $this->repository->findWhere([
['copy_script_from', '=', $egg->id],
]);
return view('admin.eggs.scripts', [
'copyFromOptions' => $copy,
'relyOnScript' => $rely,
'egg' => $egg,
]);
}
/**
* Handle a request to update the installation script for an Egg.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\InvalidCopyFromException
*/
public function update(EggScriptFormRequest $request, Egg $egg): RedirectResponse
{
$this->installScriptService->handle($egg, $request->normalize());
$this->alert->success(trans('admin/nests.eggs.notices.script_updated'))->flash();
return redirect()->route('admin.nests.egg.scripts', $egg);
}
}

View File

@ -1,74 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use Pterodactyl\Models\Egg;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller;
use Symfony\Component\HttpFoundation\Response;
use Pterodactyl\Services\Eggs\Sharing\EggExporterService;
use Pterodactyl\Services\Eggs\Sharing\EggImporterService;
use Pterodactyl\Http\Requests\Admin\Egg\EggImportFormRequest;
use Pterodactyl\Services\Eggs\Sharing\EggUpdateImporterService;
class EggShareController extends Controller
{
/**
* EggShareController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected EggExporterService $exporterService,
protected EggImporterService $importerService,
protected EggUpdateImporterService $updateImporterService
) {
}
/**
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function export(Egg $egg): Response
{
$filename = trim(preg_replace('/\W/', '-', kebab_case($egg->name)), '-');
return response($this->exporterService->handle($egg->id), 200, [
'Content-Transfer-Encoding' => 'binary',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename=egg-' . $filename . '.json',
'Content-Type' => 'application/json',
]);
}
/**
* Import a new service option using an XML file.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException
* @throws \Pterodactyl\Exceptions\Service\InvalidFileUploadException
*/
public function import(EggImportFormRequest $request): RedirectResponse
{
$egg = $this->importerService->handle($request->file('import_file'), $request->input('import_to_nest'));
$this->alert->success(trans('admin/nests.eggs.notices.imported'))->flash();
return redirect()->route('admin.nests.egg.view', ['egg' => $egg->id]);
}
/**
* Update an existing Egg using a new imported file.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\BadJsonFormatException
* @throws \Pterodactyl\Exceptions\Service\InvalidFileUploadException
*/
public function update(EggImportFormRequest $request, Egg $egg): RedirectResponse
{
$this->updateImporterService->handle($egg, $request->file('import_file'));
$this->alert->success(trans('admin/nests.eggs.notices.updated_via_import'))->flash();
return redirect()->route('admin.nests.egg.view', ['egg' => $egg]);
}
}

View File

@ -1,90 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use Illuminate\View\View;
use Pterodactyl\Models\Egg;
use Pterodactyl\Models\EggVariable;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Services\Eggs\Variables\VariableUpdateService;
use Pterodactyl\Http\Requests\Admin\Egg\EggVariableFormRequest;
use Pterodactyl\Services\Eggs\Variables\VariableCreationService;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
class EggVariableController extends Controller
{
/**
* EggVariableController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected VariableCreationService $creationService,
protected VariableUpdateService $updateService,
protected EggRepositoryInterface $repository,
protected EggVariableRepositoryInterface $variableRepository,
protected ViewFactory $view
) {
}
/**
* Handle request to view the variables attached to an Egg.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function view(int $egg): View
{
$egg = $this->repository->getWithVariables($egg);
return view('admin.eggs.variables', ['egg' => $egg]);
}
/**
* Handle a request to create a new Egg variable.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Service\Egg\Variable\BadValidationRuleException
* @throws \Pterodactyl\Exceptions\Service\Egg\Variable\ReservedVariableNameException
*/
public function store(EggVariableFormRequest $request, Egg $egg): RedirectResponse
{
$this->creationService->handle($egg->id, $request->normalize());
$this->alert->success(trans('admin/nests.variables.notices.variable_created'))->flash();
return redirect()->route('admin.nests.egg.variables', $egg->id);
}
/**
* Handle a request to update an existing Egg variable.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Egg\Variable\ReservedVariableNameException
*/
public function update(EggVariableFormRequest $request, Egg $egg, EggVariable $variable): RedirectResponse
{
$this->updateService->handle($variable, $request->normalize());
$this->alert->success(trans('admin/nests.variables.notices.variable_updated', [
'variable' => $variable->name,
]))->flash();
return redirect()->route('admin.nests.egg.variables', $egg->id);
}
/**
* Handle a request to delete an existing Egg variable from the Panel.
*/
public function destroy(int $egg, EggVariable $variable): RedirectResponse
{
$this->variableRepository->delete($variable->id);
$this->alert->success(trans('admin/nests.variables.notices.variable_deleted', [
'variable' => $variable->name,
]))->flash();
return redirect()->route('admin.nests.egg.variables', $egg);
}
}

View File

@ -1,102 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Nests\NestUpdateService;
use Pterodactyl\Services\Nests\NestCreationService;
use Pterodactyl\Services\Nests\NestDeletionService;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Nest\StoreNestFormRequest;
class NestController extends Controller
{
/**
* NestController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected NestCreationService $nestCreationService,
protected NestDeletionService $nestDeletionService,
protected NestRepositoryInterface $repository,
protected NestUpdateService $nestUpdateService,
protected ViewFactory $view
) {
}
/**
* Render nest listing page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function index(): View
{
return view('admin.nests.index', [
'nests' => $this->repository->getWithCounts(),
]);
}
/**
* Render nest creation page.
*/
public function create(): View
{
return view('admin.nests.new');
}
/**
* Handle the storage of a new nest.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function store(StoreNestFormRequest $request): RedirectResponse
{
$nest = $this->nestCreationService->handle($request->normalize());
$this->alert->success(trans('admin/nests.notices.created', ['name' => $nest->name]))->flash();
return redirect()->route('admin.nests.view', $nest->id);
}
/**
* Return details about a nest including all the eggs and servers per egg.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function view(int $nest): View
{
return view('admin.nests.view', [
'nest' => $this->repository->getWithEggServers($nest),
]);
}
/**
* Handle request to update a nest.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(StoreNestFormRequest $request, int $nest): RedirectResponse
{
$this->nestUpdateService->handle($nest, $request->normalize());
$this->alert->success(trans('admin/nests.notices.updated'))->flash();
return redirect()->route('admin.nests.view', $nest);
}
/**
* Handle request to delete a nest.
*
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/
public function destroy(int $nest): RedirectResponse
{
$this->nestDeletionService->handle($nest);
$this->alert->success(trans('admin/nests.notices.deleted'))->flash();
return redirect()->route('admin.nests');
}
}

View File

@ -1,62 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\ApiKey;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Services\Api\KeyCreationService;
use Pterodactyl\Repositories\Eloquent\ApiKeyRepository;
class NodeAutoDeployController extends Controller
{
/**
* NodeAutoDeployController constructor.
*/
public function __construct(
private ApiKeyRepository $repository,
private Encrypter $encrypter,
private KeyCreationService $keyCreationService
) {
}
/**
* Generates a new API key for the logged-in user with only permission to read
* nodes, and returns that as the deployment key for a node.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function __invoke(Request $request, Node $node): JsonResponse
{
/** @var \Pterodactyl\Models\ApiKey|null $key */
$key = $this->repository->getApplicationKeys($request->user())
->filter(function (ApiKey $key) {
foreach ($key->getAttributes() as $permission => $value) {
if ($permission === 'r_nodes' && $value === 1) {
return true;
}
}
return false;
})
->first();
// We couldn't find a key that exists for this user with only permission for
// reading nodes. Go ahead and create it now.
if (!$key) {
$key = $this->keyCreationService->setKeyType(ApiKey::TYPE_APPLICATION)->handle([
'user_id' => $request->user()->id,
'memo' => 'Automatically generated node deployment key.',
'allowed_ips' => [],
], ['r_nodes' => 1]);
}
return new JsonResponse([
'node' => $node->id,
'token' => $key->identifier . $this->encrypter->decrypt($key->token),
]);
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Spatie\QueryBuilder\QueryBuilder;
use Pterodactyl\Http\Controllers\Controller;
class NodeController extends Controller
{
/**
* Returns a listing of nodes on the system.
*/
public function index(Request $request): View
{
$nodes = QueryBuilder::for(
Node::query()->with('location')->withCount('servers')
)
->allowedFilters(['uuid', 'name'])
->allowedSorts(['id'])
->paginate(25);
return view('admin.nodes.index', ['nodes' => $nodes]);
}
}

View File

@ -1,98 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Illuminate\Support\Collection;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
class NodeViewController extends Controller
{
use JavascriptInjection;
/**
* NodeViewController constructor.
*/
public function __construct(
private LocationRepository $locationRepository,
private NodeRepository $repository,
private ServerRepository $serverRepository,
private SoftwareVersionService $versionService
) {
}
/**
* Returns index view for a specific node on the system.
*/
public function index(Request $request, Node $node): View
{
$node = $this->repository->loadLocationAndServerCount($node);
return view('admin.nodes.view.index', [
'node' => $node,
'stats' => $this->repository->getUsageStats($node),
'version' => $this->versionService,
]);
}
/**
* Returns the settings page for a specific node.
*/
public function settings(Request $request, Node $node): View
{
return view('admin.nodes.view.settings', [
'node' => $node,
'locations' => $this->locationRepository->all(),
]);
}
/**
* Return the node configuration page for a specific node.
*/
public function configuration(Request $request, Node $node): View
{
return view('admin.nodes.view.configuration', compact('node'));
}
/**
* Return the node allocation management page.
*/
public function allocations(Request $request, Node $node): View
{
$node = $this->repository->loadNodeAllocations($node);
$this->plainInject(['node' => Collection::wrap($node)->only(['id'])]);
return view('admin.nodes.view.allocation', [
'node' => $node,
'allocations' => Allocation::query()->where('node_id', $node->id)
->groupBy('ip')
->orderByRaw('INET_ATON(ip) ASC')
->get(['ip']),
]);
}
/**
* Return a listing of servers that exist for this specific node.
*/
public function servers(Request $request, Node $node): View
{
$this->plainInject([
'node' => Collection::wrap($node->makeVisible(['daemon_token_id', 'daemon_token']))
->only(['scheme', 'fqdn', 'daemonListen', 'daemon_token_id', 'daemon_token']),
]);
return view('admin.nodes.view.servers', [
'node' => $node,
'servers' => $this->serverRepository->loadAllServersForNode($node->id, 25),
]);
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Nodes;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
class SystemInformationController extends Controller
{
/**
* SystemInformationController constructor.
*/
public function __construct(private DaemonConfigurationRepository $repository)
{
}
/**
* Returns system information from the Daemon.
*
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
*/
public function __invoke(Request $request, Node $node): JsonResponse
{
$data = $this->repository->setNode($node)->getSystemInformation();
return new JsonResponse([
'version' => $data['version'] ?? '',
'system' => [
'type' => Str::title($data['os'] ?? 'Unknown'),
'arch' => $data['architecture'] ?? '--',
'release' => $data['kernel_version'] ?? '--',
'cpus' => $data['cpu_count'] ?? 0,
],
]);
}
}

View File

@ -1,183 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Illuminate\Http\Response;
use Pterodactyl\Models\Allocation;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Nodes\NodeUpdateService;
use Illuminate\Cache\Repository as CacheRepository;
use Pterodactyl\Services\Nodes\NodeCreationService;
use Pterodactyl\Services\Nodes\NodeDeletionService;
use Pterodactyl\Services\Allocations\AssignmentService;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Node\AllocationFormRequest;
use Pterodactyl\Services\Allocations\AllocationDeletionService;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Node\AllocationAliasFormRequest;
class NodesController extends Controller
{
/**
* NodesController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected AllocationDeletionService $allocationDeletionService,
protected AllocationRepositoryInterface $allocationRepository,
protected AssignmentService $assignmentService,
protected CacheRepository $cache,
protected NodeCreationService $creationService,
protected NodeDeletionService $deletionService,
protected LocationRepositoryInterface $locationRepository,
protected NodeRepositoryInterface $repository,
protected ServerRepositoryInterface $serverRepository,
protected NodeUpdateService $updateService,
protected SoftwareVersionService $versionService,
protected ViewFactory $view
) {
}
/**
* Displays create new node page.
*/
public function create(): View|RedirectResponse
{
$locations = $this->locationRepository->all();
if (count($locations) < 1) {
$this->alert->warning(trans('admin/node.notices.location_required'))->flash();
return redirect()->route('admin.locations');
}
return view('admin.nodes.new', ['locations' => $locations]);
}
/**
* Post controller to create a new node on the system.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function store(NodeFormRequest $request): RedirectResponse
{
$node = $this->creationService->handle($request->normalize());
$this->alert->info(trans('admin/node.notices.node_created'))->flash();
return redirect()->route('admin.nodes.view.allocation', $node->id);
}
/**
* Updates settings for a node.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function updateSettings(NodeFormRequest $request, Node $node): RedirectResponse
{
$this->updateService->handle($node, $request->normalize(), $request->input('reset_secret') === 'on');
$this->alert->success(trans('admin/node.notices.node_updated'))->flash();
return redirect()->route('admin.nodes.view.settings', $node->id)->withInput();
}
/**
* Removes a single allocation from a node.
*
* @throws \Pterodactyl\Exceptions\Service\Allocation\ServerUsingAllocationException
*/
public function allocationRemoveSingle(int $node, Allocation $allocation): Response
{
$this->allocationDeletionService->handle($allocation);
return response('', 204);
}
/**
* Removes multiple individual allocations from a node.
*
* @throws \Pterodactyl\Exceptions\Service\Allocation\ServerUsingAllocationException
*/
public function allocationRemoveMultiple(Request $request, int $node): Response
{
$allocations = $request->input('allocations');
foreach ($allocations as $rawAllocation) {
$allocation = new Allocation();
$allocation->id = $rawAllocation['id'];
$this->allocationRemoveSingle($node, $allocation);
}
return response('', 204);
}
/**
* Remove all allocations for a specific IP at once on a node.
*/
public function allocationRemoveBlock(Request $request, int $node): RedirectResponse
{
$this->allocationRepository->deleteWhere([
['node_id', '=', $node],
['server_id', '=', null],
['ip', '=', $request->input('ip')],
]);
$this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => $request->input('ip')]))
->flash();
return redirect()->route('admin.nodes.view.allocation', $node);
}
/**
* Sets an alias for a specific allocation on a node.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function allocationSetAlias(AllocationAliasFormRequest $request): \Symfony\Component\HttpFoundation\Response
{
$this->allocationRepository->update($request->input('allocation_id'), [
'ip_alias' => (empty($request->input('alias'))) ? null : $request->input('alias'),
]);
return response('', 204);
}
/**
* Creates new allocations on a node.
*
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
*/
public function createAllocation(AllocationFormRequest $request, Node $node): RedirectResponse
{
$this->assignmentService->handle($node, $request->normalize());
$this->alert->success(trans('admin/node.notices.allocations_added'))->flash();
return redirect()->route('admin.nodes.view.allocation', $node->id);
}
/**
* Deletes a node from the system.
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete(int|Node $node): RedirectResponse
{
$this->deletionService->handle($node);
$this->alert->success(trans('admin/node.notices.node_deleted'))->flash();
return redirect()->route('admin.nodes');
}
}

View File

@ -1,84 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Illuminate\View\View;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Location;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Http\Requests\Admin\ServerFormRequest;
use Pterodactyl\Services\Servers\ServerCreationService;
class CreateServerController extends Controller
{
/**
* CreateServerController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private ServerCreationService $creationService
) {
}
/**
* Displays the create server page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function index(): View|RedirectResponse
{
$nodes = Node::all();
if (count($nodes) < 1) {
$this->alert->warning(trans('admin/server.alerts.node_required'))->flash();
return redirect()->route('admin.nodes');
}
$nests = $this->nestRepository->getWithEggs();
\JavaScript::put([
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
'nests' => $nests->map(function (Nest $item) {
return array_merge($item->toArray(), [
'eggs' => $item->eggs->keyBy('id')->toArray(),
]);
})->keyBy('id'),
]);
return view('admin.servers.new', [
'locations' => Location::all(),
'nests' => $nests,
]);
}
/**
* Create a new server on the remote system.
*
* @throws \Illuminate\Validation\ValidationException
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableAllocationException
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
* @throws \Throwable
*/
public function store(ServerFormRequest $request): RedirectResponse
{
$data = $request->except(['_token']);
if (!empty($data['custom_image'])) {
$data['image'] = $data['custom_image'];
unset($data['custom_image']);
}
$server = $this->creationService->handle($data);
$this->alert->success(trans('admin/server.alerts.server_created'))->flash();
return new RedirectResponse('/admin/servers/view/' . $server->id);
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Server;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Models\Filters\AdminServerFilter;
class ServerController extends Controller
{
/**
* Returns all the servers that exist on the system using a paginated result set. If
* a query is passed along in the request it is also passed to the repository function.
*/
public function index(Request $request): View
{
$servers = QueryBuilder::for(Server::query()->with('node', 'user', 'allocation'))
->allowedFilters([
AllowedFilter::exact('owner_id'),
AllowedFilter::custom('*', new AdminServerFilter()),
])
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
return view('admin.servers.index', ['servers' => $servers]);
}
}

View File

@ -1,115 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Server;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Models\ServerTransfer;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Nodes\NodeJWTService;
use Pterodactyl\Repositories\Wings\DaemonTransferRepository;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
class ServerTransferController extends Controller
{
/**
* ServerTransferController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private AllocationRepositoryInterface $allocationRepository,
private ConnectionInterface $connection,
private DaemonTransferRepository $daemonTransferRepository,
private NodeJWTService $nodeJWTService
) {
}
/**
* Starts a transfer of a server to a new node.
*
* @throws \Throwable
*/
public function transfer(Request $request, Server $server): RedirectResponse
{
$validatedData = $request->validate([
'node_id' => 'required|exists:nodes,id',
'allocation_id' => 'required|bail|unique:servers|exists:allocations,id',
'allocation_additional' => 'nullable',
]);
$node_id = $validatedData['node_id'];
$allocation_id = intval($validatedData['allocation_id']);
$additional_allocations = array_map('intval', $validatedData['allocation_additional'] ?? []);
// Check if the node is viable for the transfer.
$node = Node::query()->findOrFail($node_id);
if (!$node->isViable($server->memory, $server->disk)) {
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
return redirect()->route('admin.servers.view.manage', $server->id);
}
$server->validateTransferState();
$this->connection->transaction(function () use ($server, $node_id, $allocation_id, $additional_allocations) {
$transfer = new ServerTransfer();
$transfer->server_id = $server->id;
$transfer->old_node = $server->node_id;
$transfer->new_node = $node_id;
$transfer->old_allocation = $server->allocation_id;
$transfer->new_allocation = $allocation_id;
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->all();
$transfer->new_additional_allocations = $additional_allocations;
$transfer->save();
// Add the allocations to the server, so they cannot be automatically assigned while the transfer is in progress.
$this->assignAllocationsToServer($server, $node_id, $allocation_id, $additional_allocations);
// Generate a token for the destination node that the source node can use to authenticate with.
$token = $this->nodeJWTService
->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
->setSubject($server->uuid)
->handle($transfer->newNode, $server->uuid, 'sha256');
// Notify the source node of the pending outgoing transfer.
$this->daemonTransferRepository->setServer($server)->notify($transfer->newNode, $token);
return $transfer;
});
$this->alert->success(trans('admin/server.alerts.transfer_started'))->flash();
return redirect()->route('admin.servers.view.manage', $server->id);
}
/**
* Assigns the specified allocations to the specified server.
*/
private function assignAllocationsToServer(Server $server, int $node_id, int $allocation_id, array $additional_allocations)
{
$allocations = $additional_allocations;
$allocations[] = $allocation_id;
$unassigned = $this->allocationRepository->getUnassignedAllocationIds($node_id);
$updateIds = [];
foreach ($allocations as $allocation) {
if (!in_array($allocation, $unassigned)) {
continue;
}
$updateIds[] = $allocation;
}
if (!empty($updateIds)) {
$this->allocationRepository->updateWhereIn('id', $updateIds, ['server_id' => $server->id]);
}
}
}

View File

@ -1,150 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Server;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Servers\EnvironmentService;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\MountRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
class ServerViewController extends Controller
{
use JavascriptInjection;
/**
* ServerViewController constructor.
*/
public function __construct(
private DatabaseHostRepository $databaseHostRepository,
private LocationRepository $locationRepository,
private MountRepository $mountRepository,
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private EnvironmentService $environmentService
) {
}
/**
* Returns the index view for a server.
*/
public function index(Request $request, Server $server): View
{
return view('admin.servers.view.index', compact('server'));
}
/**
* Returns the server details page.
*/
public function details(Request $request, Server $server): View
{
return view('admin.servers.view.details', compact('server'));
}
/**
* Returns a view of server build settings.
*/
public function build(Request $request, Server $server): View
{
$allocations = $server->node->allocations->toBase();
return view('admin.servers.view.build', [
'server' => $server,
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
]);
}
/**
* Returns the server startup management page.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function startup(Request $request, Server $server): View
{
$nests = $this->nestRepository->getWithEggs();
$variables = $this->environmentService->handle($server);
$this->plainInject([
'server' => $server,
'server_variables' => $variables,
'nests' => $nests->map(function (Nest $item) {
return array_merge($item->toArray(), [
'eggs' => $item->eggs->keyBy('id')->toArray(),
]);
})->keyBy('id'),
]);
return view('admin.servers.view.startup', compact('server', 'nests'));
}
/**
* Returns all the databases that exist for the server.
*/
public function database(Request $request, Server $server): View
{
return view('admin.servers.view.database', [
'hosts' => $this->databaseHostRepository->all(),
'server' => $server,
]);
}
/**
* Returns all the mounts that exist for the server.
*/
public function mounts(Request $request, Server $server): View
{
$server->load('mounts');
return view('admin.servers.view.mounts', [
'mounts' => $this->mountRepository->getMountListForServer($server),
'server' => $server,
]);
}
/**
* Returns the base server management page, or an exception if the server
* is in a state that cannot be recovered from.
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function manage(Request $request, Server $server): View
{
if ($server->status === Server::STATUS_INSTALL_FAILED) {
throw new DisplayException('This server is in a failed install state and cannot be recovered. Please delete and re-create the server.');
}
// Check if the panel doesn't have at least 2 nodes configured.
$nodes = $this->nodeRepository->all();
$canTransfer = false;
if (count($nodes) >= 2) {
$canTransfer = true;
}
\JavaScript::put([
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
]);
return view('admin.servers.view.manage', [
'server' => $server,
'locations' => $this->locationRepository->all(),
'canTransfer' => $canTransfer,
]);
}
/**
* Returns the server deletion page.
*/
public function delete(Request $request, Server $server): View
{
return view('admin.servers.view.delete', compact('server'));
}
}

View File

@ -1,273 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Illuminate\Http\Response;
use Pterodactyl\Models\Mount;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database;
use Pterodactyl\Models\MountServer;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Validation\ValidationException;
use Pterodactyl\Services\Servers\SuspensionService;
use Pterodactyl\Repositories\Eloquent\MountRepository;
use Pterodactyl\Services\Servers\ServerDeletionService;
use Pterodactyl\Services\Servers\ReinstallServerService;
use Pterodactyl\Exceptions\Model\DataValidationException;
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
use Pterodactyl\Services\Servers\BuildModificationService;
use Pterodactyl\Services\Databases\DatabasePasswordService;
use Pterodactyl\Services\Servers\DetailsModificationService;
use Pterodactyl\Services\Servers\StartupModificationService;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
use Pterodactyl\Services\Databases\DatabaseManagementService;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest;
class ServersController extends Controller
{
/**
* ServersController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected AllocationRepositoryInterface $allocationRepository,
protected BuildModificationService $buildModificationService,
protected ConfigRepository $config,
protected DaemonServerRepository $daemonServerRepository,
protected DatabaseManagementService $databaseManagementService,
protected DatabasePasswordService $databasePasswordService,
protected DatabaseRepositoryInterface $databaseRepository,
protected DatabaseHostRepository $databaseHostRepository,
protected ServerDeletionService $deletionService,
protected DetailsModificationService $detailsModificationService,
protected ReinstallServerService $reinstallService,
protected ServerRepositoryInterface $repository,
protected MountRepository $mountRepository,
protected NestRepositoryInterface $nestRepository,
protected ServerConfigurationStructureService $serverConfigurationStructureService,
protected StartupModificationService $startupModificationService,
protected SuspensionService $suspensionService
) {
}
/**
* Update the details for a server.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function setDetails(Request $request, Server $server): RedirectResponse
{
$this->detailsModificationService->handle($server, $request->only([
'owner_id', 'external_id', 'name', 'description',
]));
$this->alert->success(trans('admin/server.alerts.details_updated'))->flash();
return redirect()->route('admin.servers.view.details', $server->id);
}
/**
* Toggles the installation status for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function toggleInstall(Server $server): RedirectResponse
{
if ($server->status === Server::STATUS_INSTALL_FAILED) {
throw new DisplayException(trans('admin/server.exceptions.marked_as_failed'));
}
$this->repository->update($server->id, [
'status' => $server->isInstalled() ? Server::STATUS_INSTALLING : null,
], true, true);
$this->alert->success(trans('admin/server.alerts.install_toggled'))->flash();
return redirect()->route('admin.servers.view.manage', $server->id);
}
/**
* Reinstalls the server with the currently assigned service.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function reinstallServer(Server $server): RedirectResponse
{
$this->reinstallService->handle($server);
$this->alert->success(trans('admin/server.alerts.server_reinstalled'))->flash();
return redirect()->route('admin.servers.view.manage', $server->id);
}
/**
* Manage the suspension status for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function manageSuspension(Request $request, Server $server): RedirectResponse
{
$this->suspensionService->toggle($server, $request->input('action'));
$this->alert->success(trans('admin/server.alerts.suspension_toggled', [
'status' => $request->input('action') . 'ed',
]))->flash();
return redirect()->route('admin.servers.view.manage', $server->id);
}
/**
* Update the build configuration for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Illuminate\Validation\ValidationException
*/
public function updateBuild(Request $request, Server $server): RedirectResponse
{
try {
$this->buildModificationService->handle($server, $request->only([
'allocation_id', 'add_allocations', 'remove_allocations',
'memory', 'swap', 'io', 'cpu', 'threads', 'disk',
'database_limit', 'allocation_limit', 'backup_limit', 'oom_disabled',
]));
} catch (DataValidationException $exception) {
throw new ValidationException($exception->getValidator());
}
$this->alert->success(trans('admin/server.alerts.build_updated'))->flash();
return redirect()->route('admin.servers.view.build', $server->id);
}
/**
* Start the server deletion process.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Throwable
*/
public function delete(Request $request, Server $server): RedirectResponse
{
$this->deletionService->withForce($request->filled('force_delete'))->handle($server);
$this->alert->success(trans('admin/server.alerts.server_deleted'))->flash();
return redirect()->route('admin.servers');
}
/**
* Update the startup command as well as variables.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function saveStartup(Request $request, Server $server): RedirectResponse
{
$data = $request->except('_token');
if (!empty($data['custom_docker_image'])) {
$data['docker_image'] = $data['custom_docker_image'];
unset($data['custom_docker_image']);
}
try {
$this->startupModificationService
->setUserLevel(User::USER_LEVEL_ADMIN)
->handle($server, $data);
} catch (DataValidationException $exception) {
throw new ValidationException($exception->getValidator());
}
$this->alert->success(trans('admin/server.alerts.startup_changed'))->flash();
return redirect()->route('admin.servers.view.startup', $server->id);
}
/**
* Creates a new database assigned to a specific server.
*
* @throws \Throwable
*/
public function newDatabase(StoreServerDatabaseRequest $request, Server $server): RedirectResponse
{
$this->databaseManagementService->create($server, [
'database' => DatabaseManagementService::generateUniqueDatabaseName($request->input('database'), $server->id),
'remote' => $request->input('remote'),
'database_host_id' => $request->input('database_host_id'),
'max_connections' => $request->input('max_connections'),
]);
return redirect()->route('admin.servers.view.database', $server->id)->withInput();
}
/**
* Resets the database password for a specific database on this server.
*
* @throws \Throwable
*/
public function resetDatabasePassword(Request $request, Server $server): Response
{
/** @var \Pterodactyl\Models\Database $database */
$database = $server->databases()->findOrFail($request->input('database'));
$this->databasePasswordService->handle($database);
return response('', 204);
}
/**
* Deletes a database from a server.
*
* @throws \Exception
*/
public function deleteDatabase(Server $server, Database $database): Response
{
$this->databaseManagementService->delete($database);
return response('', 204);
}
/**
* Add a mount to a server.
*
* @throws \Throwable
*/
public function addMount(Request $request, Server $server): RedirectResponse
{
$mountServer = (new MountServer())->forceFill([
'mount_id' => $request->input('mount_id'),
'server_id' => $server->id,
]);
$mountServer->saveOrFail();
$this->alert->success('Mount was added successfully.')->flash();
return redirect()->route('admin.servers.view.mounts', $server->id);
}
/**
* Remove a mount from a server.
*/
public function deleteMount(Server $server, Mount $mount): RedirectResponse
{
MountServer::where('mount_id', $mount->id)->where('server_id', $server->id)->delete();
$this->alert->success('Mount was removed successfully.')->flash();
return redirect()->route('admin.servers.view.mounts', $server->id);
}
}

View File

@ -1,60 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Settings;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Settings\AdvancedSettingsFormRequest;
class AdvancedController extends Controller
{
/**
* AdvancedController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private ConfigRepository $config,
private Kernel $kernel,
private SettingsRepositoryInterface $settings
) {
}
/**
* Render advanced Panel settings UI.
*/
public function index(): View
{
$showRecaptchaWarning = false;
if (
$this->config->get('recaptcha._shipped_secret_key') === $this->config->get('recaptcha.secret_key')
|| $this->config->get('recaptcha._shipped_website_key') === $this->config->get('recaptcha.website_key')
) {
$showRecaptchaWarning = true;
}
return view('admin.settings.advanced', [
'showRecaptchaWarning' => $showRecaptchaWarning,
]);
}
/**
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(AdvancedSettingsFormRequest $request): RedirectResponse
{
foreach ($request->normalize() as $key => $value) {
$this->settings->set('settings::' . $key, $value);
}
$this->kernel->call('queue:restart');
$this->alert->success('Advanced settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
return redirect()->route('admin.settings.advanced');
}
}

View File

@ -1,58 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Settings;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Settings\BaseSettingsFormRequest;
class IndexController extends Controller
{
use AvailableLanguages;
/**
* IndexController constructor.
*/
public function __construct(
private AlertsMessageBag $alert,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private SoftwareVersionService $versionService
) {
}
/**
* Render the UI for basic Panel settings.
*/
public function index(): View
{
return view('admin.settings.index', [
'version' => $this->versionService,
'languages' => $this->getAvailableLanguages(true),
]);
}
/**
* Handle settings update.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(BaseSettingsFormRequest $request): RedirectResponse
{
foreach ($request->normalize() as $key => $value) {
$this->settings->set('settings::' . $key, $value);
}
$this->kernel->call('queue:restart');
$this->alert->success('Panel settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash();
return redirect()->route('admin.settings');
}
}

View File

@ -1,88 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin\Settings;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Notifications\MailTested;
use Illuminate\Support\Facades\Notification;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Providers\SettingsServiceProvider;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Settings\MailSettingsFormRequest;
class MailController extends Controller
{
/**
* MailController constructor.
*/
public function __construct(
private ConfigRepository $config,
private Encrypter $encrypter,
private Kernel $kernel,
private SettingsRepositoryInterface $settings
) {
}
/**
* Render UI for editing mail settings. This UI should only display if
* the server is configured to send mail using SMTP.
*/
public function index(): View
{
return view('admin.settings.mail', [
'disabled' => $this->config->get('mail.default') !== 'smtp',
]);
}
/**
* Handle request to update SMTP mail settings.
*
* @throws DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(MailSettingsFormRequest $request): Response
{
if ($this->config->get('mail.default') !== 'smtp') {
throw new DisplayException('This feature is only available if SMTP is the selected email driver for the Panel.');
}
$values = $request->normalize();
if (array_get($values, 'mail:mailers:smtp:password') === '!e') {
$values['mail:mailers:smtp:password'] = '';
}
foreach ($values as $key => $value) {
if (in_array($key, SettingsServiceProvider::getEncryptedKeys()) && !empty($value)) {
$value = $this->encrypter->encrypt($value);
}
$this->settings->set('settings::' . $key, $value);
}
$this->kernel->call('queue:restart');
return response('', 204);
}
/**
* Submit a request to send a test mail message.
*/
public function test(Request $request): Response
{
try {
Notification::route('mail', $request->user()->email)
->notify(new MailTested($request->user()));
} catch (\Exception $exception) {
return response($exception->getMessage(), 500);
}
return response('', 204);
}
}

View File

@ -1,144 +0,0 @@
<?php
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Model;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Spatie\QueryBuilder\QueryBuilder;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\Translation\Translator;
use Pterodactyl\Services\Users\UserUpdateService;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Services\Users\UserCreationService;
use Pterodactyl\Services\Users\UserDeletionService;
use Pterodactyl\Http\Requests\Admin\UserFormRequest;
use Pterodactyl\Http\Requests\Admin\NewUserFormRequest;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class UserController extends Controller
{
use AvailableLanguages;
/**
* UserController constructor.
*/
public function __construct(
protected AlertsMessageBag $alert,
protected UserCreationService $creationService,
protected UserDeletionService $deletionService,
protected Translator $translator,
protected UserUpdateService $updateService,
protected UserRepositoryInterface $repository,
protected ViewFactory $view
) {
}
/**
* Display user index page.
*/
public function index(Request $request): View
{
$users = QueryBuilder::for(
User::query()->select('users.*')
->selectRaw('COUNT(DISTINCT(subusers.id)) as subuser_of_count')
->selectRaw('COUNT(DISTINCT(servers.id)) as servers_count')
->leftJoin('subusers', 'subusers.user_id', '=', 'users.id')
->leftJoin('servers', 'servers.owner_id', '=', 'users.id')
->groupBy('users.id')
)
->allowedFilters(['username', 'email', 'uuid'])
->allowedSorts(['id', 'uuid'])
->paginate(50);
return view('admin.users.index', ['users' => $users]);
}
/**
* Display new user page.
*/
public function create(): View
{
return view('admin.users.new', [
'languages' => $this->getAvailableLanguages(true),
]);
}
/**
* Display user view page.
*/
public function view(User $user): View
{
return view('admin.users.view', [
'user' => $user,
'languages' => $this->getAvailableLanguages(true),
]);
}
/**
* Delete a user from the system.
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete(Request $request, User $user): RedirectResponse
{
if ($request->user()->id === $user->id) {
throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
}
$this->deletionService->handle($user);
return redirect()->route('admin.users');
}
/**
* Create a user.
*
* @throws \Exception
* @throws \Throwable
*/
public function store(NewUserFormRequest $request): RedirectResponse
{
$user = $this->creationService->handle($request->normalize());
$this->alert->success($this->translator->get('admin/user.notices.account_created'))->flash();
return redirect()->route('admin.users.view', $user->id);
}
/**
* Update a user on the system.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(UserFormRequest $request, User $user): RedirectResponse
{
$this->updateService
->setUserLevel(User::USER_LEVEL_ADMIN)
->handle($user, $request->normalize());
$this->alert->success(trans('admin/user.notices.account_updated'))->flash();
return redirect()->route('admin.users.view', $user->id);
}
/**
* Get a JSON response of users on the system.
*/
public function json(Request $request): Model|LengthAwarePaginator
{
// Handle single user requests.
if ($request->query('user_id')) {
return User::query()->findOrFail($request->input('user_id'));
}
return QueryBuilder::for(User::query())->allowedFilters(['email'])->paginate(25);
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace Pterodactyl\Http\Middleware\Admin\Servers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Pterodactyl\Models\Server;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ServerInstalled
{
/**
* Checks that the server is installed before allowing access through the route.
*/
public function handle(Request $request, \Closure $next): mixed
{
/** @var \Pterodactyl\Models\Server|null $server */
$server = $request->route()->parameter('server');
if (!$server instanceof Server) {
throw new NotFoundHttpException('No server resource was located in the request parameters.');
}
if (!$server->isInstalled()) {
throw new HttpException(Response::HTTP_FORBIDDEN, 'Access to this resource is not allowed due to the current installation state.');
}
return $next($request);
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
abstract class AdminFormRequest extends FormRequest
{
/**
* The rules to apply to the incoming form request.
*/
abstract public function rules(): array;
/**
* Determine if the user is an admin and has permission to access this
* form controller in the first place.
*/
public function authorize(): bool
{
if (is_null($this->user())) {
return false;
}
return (bool) $this->user()->root_admin;
}
/**
* Return only the fields that we are interested in from the request.
* This will include empty fields as a null value.
*/
public function normalize(array $only = null): array
{
return $this->only($only ?? array_keys($this->rules()));
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Api;
use Pterodactyl\Models\ApiKey;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class StoreApplicationApiKeyRequest extends AdminFormRequest
{
/**
* @throws \ReflectionException
* @throws \ReflectionException
*/
public function rules(): array
{
$modelRules = ApiKey::getRules();
return collect(AdminAcl::getResourceList())->mapWithKeys(function ($resource) use ($modelRules) {
return [AdminAcl::COLUMN_IDENTIFIER . $resource => $modelRules['r_' . $resource]];
})->merge(['memo' => $modelRules['memo']])->toArray();
}
public function attributes(): array
{
return [
'memo' => 'Description',
];
}
public function getKeyPermissions(): array
{
return collect($this->validated())->filter(function ($value, $key) {
return substr($key, 0, strlen(AdminAcl::COLUMN_IDENTIFIER)) === AdminAcl::COLUMN_IDENTIFIER;
})->toArray();
}
}

View File

@ -1,13 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
class BaseFormRequest extends AdminFormRequest
{
public function rules(): array
{
return [
'company' => 'required|between:1,256',
];
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Contracts\Validation\Validator;
class DatabaseHostFormRequest extends AdminFormRequest
{
public function rules(): array
{
if ($this->method() !== 'POST') {
return DatabaseHost::getRulesForUpdate($this->route()->parameter('host'));
}
return DatabaseHost::getRules();
}
/**
* Modify submitted data before it is passed off to the validator.
*/
protected function getValidatorInstance(): Validator
{
if (!$this->filled('node_id')) {
$this->merge(['node_id' => null]);
}
return parent::getValidatorInstance();
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Egg;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class EggFormRequest extends AdminFormRequest
{
public function rules(): array
{
$rules = [
'name' => 'required|string|max:191',
'description' => 'nullable|string',
'docker_images' => 'required|string',
'force_outgoing_ip' => 'sometimes|boolean',
'file_denylist' => 'array',
'startup' => 'required|string',
'config_from' => 'sometimes|bail|nullable|numeric',
'config_stop' => 'required_without:config_from|nullable|string|max:191',
'config_startup' => 'required_without:config_from|nullable|json',
'config_logs' => 'required_without:config_from|nullable|json',
'config_files' => 'required_without:config_from|nullable|json',
];
if ($this->method() === 'POST') {
$rules['nest_id'] = 'required|numeric|exists:nests,id';
}
return $rules;
}
public function withValidator($validator)
{
$validator->sometimes('config_from', 'exists:eggs,id', function () {
return (int) $this->input('config_from') !== 0;
});
}
public function validated($key = null, $default = null): array
{
$data = parent::validated();
return array_merge($data, [
'force_outgoing_ip' => array_get($data, 'force_outgoing_ip', false),
]);
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Egg;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class EggImportFormRequest extends AdminFormRequest
{
public function rules(): array
{
$rules = [
'import_file' => 'bail|required|file|max:1000|mimetypes:application/json,text/plain',
];
if ($this->method() !== 'PUT') {
$rules['import_to_nest'] = 'bail|required|integer|exists:nests,id';
}
return $rules;
}
}

View File

@ -1,22 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Egg;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class EggScriptFormRequest extends AdminFormRequest
{
/**
* Return the rules to be used when validating the data sent in the request.
*/
public function rules(): array
{
return [
'script_install' => 'sometimes|nullable|string',
'script_is_privileged' => 'sometimes|required|boolean',
'script_entry' => 'sometimes|required|string',
'script_container' => 'sometimes|required|string',
'copy_script_from' => 'sometimes|nullable|numeric',
];
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Egg;
use Pterodactyl\Models\EggVariable;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class EggVariableFormRequest extends AdminFormRequest
{
/**
* Define rules for validation of this request.
*/
public function rules(): array
{
return [
'name' => 'required|string|min:1|max:191',
'description' => 'sometimes|nullable|string',
'env_variable' => 'required|regex:/^[\w]{1,191}$/|notIn:' . EggVariable::RESERVED_ENV_NAMES,
'options' => 'sometimes|required|array',
'rules' => 'bail|required|string',
'default_value' => 'present',
];
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\Location;
class LocationFormRequest extends AdminFormRequest
{
/**
* Set up the validation rules to use for these requests.
*/
public function rules(): array
{
if ($this->method() === 'PATCH') {
/** @var Location $location */
$location = $this->route()->parameter('location');
return Location::getRulesForUpdate($location->id);
}
return Location::getRules();
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\Mount;
class MountFormRequest extends AdminFormRequest
{
/**
* Set up the validation rules to use for these requests.
*/
public function rules(): array
{
if ($this->method() === 'PATCH') {
/** @var Mount $mount */
$mount = $this->route()->parameter('mount');
return Mount::getRulesForUpdate($mount->id);
}
return Mount::getRules();
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Nest;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class StoreNestFormRequest extends AdminFormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|min:1|max:191',
'description' => 'string|nullable',
];
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
class NewUserFormRequest extends AdminFormRequest
{
/**
* Rules to apply to requests for updating or creating a user
* in the Admin CP.
*/
public function rules(): array
{
return Collection::make(
User::getRules()
)->only([
'email',
'username',
'name_first',
'name_last',
'password',
'language',
'root_admin',
])->toArray();
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Node;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class AllocationAliasFormRequest extends AdminFormRequest
{
public function rules(): array
{
return [
'alias' => 'present|nullable|string',
'allocation_id' => 'required|numeric|exists:allocations,id',
];
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Node;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class AllocationFormRequest extends AdminFormRequest
{
public function rules(): array
{
return [
'allocation_ip' => 'required|string',
'allocation_alias' => 'sometimes|nullable|string|max:191',
'allocation_ports' => 'required|array',
];
}
}

View File

@ -1,25 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Node;
use Pterodactyl\Rules\Fqdn;
use Pterodactyl\Models\Node;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class NodeFormRequest extends AdminFormRequest
{
/**
* Get rules to apply to data in this request.
*/
public function rules(): array
{
if ($this->method() === 'PATCH') {
return Node::getRulesForUpdate($this->route()->parameter('node'));
}
$data = Node::getRules();
$data['fqdn'][] = Fqdn::make('scheme');
return $data;
}
}

View File

@ -1,58 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\Server;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class ServerFormRequest extends AdminFormRequest
{
/**
* Rules to be applied to this request.
*/
public function rules(): array
{
$rules = Server::getRules();
$rules['description'][] = 'nullable';
$rules['custom_image'] = 'sometimes|nullable|string';
return $rules;
}
/**
* Run validation after the rules above have been applied.
*/
public function withValidator(Validator $validator): void
{
$validator->after(function ($validator) {
$validator->sometimes('node_id', 'required|numeric|bail|exists:nodes,id', function ($input) {
return !$input->auto_deploy;
});
$validator->sometimes('allocation_id', [
'required',
'numeric',
'bail',
Rule::exists('allocations', 'id')->where(function ($query) {
$query->where('node_id', $this->input('node_id'));
$query->whereNull('server_id');
}),
], function ($input) {
return !$input->auto_deploy;
});
$validator->sometimes('allocation_additional.*', [
'sometimes',
'required',
'numeric',
Rule::exists('allocations', 'id')->where(function ($query) {
$query->where('node_id', $this->input('node_id'));
$query->whereNull('server_id');
}),
], function ($input) {
return !$input->auto_deploy;
});
});
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Servers\Databases;
use Illuminate\Validation\Rule;
use Illuminate\Database\Query\Builder;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class StoreServerDatabaseRequest extends AdminFormRequest
{
/**
* Validation rules for database creation.
*/
public function rules(): array
{
return [
'database' => [
'required',
'string',
'min:1',
'max:24',
Rule::unique('databases')->where(function (Builder $query) {
$query->where('database_host_id', $this->input('database_host_id') ?? 0);
}),
],
'max_connections' => 'nullable',
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
'database_host_id' => 'required|integer|exists:database_hosts,id',
];
}
}

View File

@ -1,50 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Settings;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class AdvancedSettingsFormRequest extends AdminFormRequest
{
/**
* Return all the rules to apply to this request's data.
*/
public function rules(): array
{
return [
'recaptcha:enabled' => 'required|in:true,false',
'recaptcha:secret_key' => 'required|string|max:191',
'recaptcha:website_key' => 'required|string|max:191',
'pterodactyl:guzzle:timeout' => 'required|integer|between:1,60',
'pterodactyl:guzzle:connect_timeout' => 'required|integer|between:1,60',
'pterodactyl:client_features:allocations:enabled' => 'required|in:true,false',
'pterodactyl:client_features:allocations:range_start' => [
'nullable',
'required_if:pterodactyl:client_features:allocations:enabled,true',
'integer',
'between:1024,65535',
],
'pterodactyl:client_features:allocations:range_end' => [
'nullable',
'required_if:pterodactyl:client_features:allocations:enabled,true',
'integer',
'between:1024,65535',
'gt:pterodactyl:client_features:allocations:range_start',
],
];
}
public function attributes(): array
{
return [
'recaptcha:enabled' => 'reCAPTCHA Enabled',
'recaptcha:secret_key' => 'reCAPTCHA Secret Key',
'recaptcha:website_key' => 'reCAPTCHA Website Key',
'pterodactyl:guzzle:timeout' => 'HTTP Request Timeout',
'pterodactyl:guzzle:connect_timeout' => 'HTTP Connection Timeout',
'pterodactyl:client_features:allocations:enabled' => 'Auto Create Allocations Enabled',
'pterodactyl:client_features:allocations:range_start' => 'Starting Port',
'pterodactyl:client_features:allocations:range_end' => 'Ending Port',
];
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Settings;
use Illuminate\Validation\Rule;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class BaseSettingsFormRequest extends AdminFormRequest
{
use AvailableLanguages;
public function rules(): array
{
return [
'app:name' => 'required|string|max:191',
'pterodactyl:auth:2fa_required' => 'required|integer|in:0,1,2',
'app:locale' => ['required', 'string', Rule::in(array_keys($this->getAvailableLanguages()))],
];
}
public function attributes(): array
{
return [
'app:name' => 'Company Name',
'pterodactyl:auth:2fa_required' => 'Require 2-Factor Authentication',
'app:locale' => 'Default Language',
];
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin\Settings;
use Illuminate\Validation\Rule;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class MailSettingsFormRequest extends AdminFormRequest
{
/**
* Return rules to validate mail settings POST data against.
*/
public function rules(): array
{
return [
'mail:mailers:smtp:host' => 'required|string',
'mail:mailers:smtp:port' => 'required|integer|between:1,65535',
'mail:mailers:smtp:encryption' => ['present', Rule::in([null, 'tls', 'ssl'])],
'mail:mailers:smtp:username' => 'nullable|string|max:191',
'mail:mailers:smtp:password' => 'nullable|string|max:191',
'mail:from:address' => 'required|string|email',
'mail:from:name' => 'nullable|string|max:191',
];
}
/**
* Override the default normalization function for this type of request
* as we need to accept empty values on the keys.
*/
public function normalize(array $only = null): array
{
$keys = array_flip(array_keys($this->rules()));
if (empty($this->input('mail:mailers:smtp:password'))) {
unset($keys['mail:mailers:smtp:password']);
}
return $this->only(array_flip($keys));
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace Pterodactyl\Http\Requests\Admin;
use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
class UserFormRequest extends AdminFormRequest
{
/**
* Rules to apply to requests for updating or creating a user
* in the Admin CP.
*/
public function rules(): array
{
return Collection::make(
User::getRulesForUpdate($this->route()->parameter('user'))
)->only([
'email',
'username',
'name_first',
'name_last',
'password',
'language',
'root_admin',
])->toArray();
}
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Jobs\Schedule; namespace Pterodactyl\Jobs\Schedule;
use Exception;
use Pterodactyl\Jobs\Job; use Pterodactyl\Jobs\Job;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Pterodactyl\Models\Task; use Pterodactyl\Models\Task;

View File

@ -10,7 +10,6 @@ use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Pterodactyl\Extensions\Themes\Theme;
use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Eloquent\Relations\Relation;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
@ -61,10 +60,6 @@ class AppServiceProvider extends ServiceProvider
if (!config('pterodactyl.load_environment_only', false) && $this->app->environment() !== 'testing') { if (!config('pterodactyl.load_environment_only', false) && $this->app->environment() !== 'testing') {
$this->app->register(SettingsServiceProvider::class); $this->app->register(SettingsServiceProvider::class);
} }
$this->app->singleton('extensions.themes', function () {
return new Theme();
});
} }
/** /**

View File

@ -224,7 +224,6 @@ return [
'Alert' => Prologue\Alerts\Facades\Alert::class, 'Alert' => Prologue\Alerts\Facades\Alert::class,
'Carbon' => Carbon\Carbon::class, 'Carbon' => Carbon\Carbon::class,
'JavaScript' => Laracasts\Utilities\JavaScript\JavaScriptFacade::class, 'JavaScript' => Laracasts\Utilities\JavaScript\JavaScriptFacade::class,
'Theme' => Pterodactyl\Extensions\Facades\Theme::class,
// Custom Facades // Custom Facades
'Activity' => Pterodactyl\Facades\Activity::class, 'Activity' => Pterodactyl\Facades\Activity::class,

View File

@ -1,6 +0,0 @@
// Hacky fix for browsers ignoring autocomplete="off"
$(document).ready(function() {
$('.form-autocomplete-stop').on('click', function () {
$(this).removeAttr('readonly').blur().focus();
});
});

View File

@ -1,121 +0,0 @@
/* global define, KeyboardEvent, module */
(function () {
var keyboardeventKeyPolyfill = {
polyfill: polyfill,
keys: {
3: 'Cancel',
6: 'Help',
8: 'Backspace',
9: 'Tab',
12: 'Clear',
13: 'Enter',
16: 'Shift',
17: 'Control',
18: 'Alt',
19: 'Pause',
20: 'CapsLock',
27: 'Escape',
28: 'Convert',
29: 'NonConvert',
30: 'Accept',
31: 'ModeChange',
32: ' ',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'ArrowLeft',
38: 'ArrowUp',
39: 'ArrowRight',
40: 'ArrowDown',
41: 'Select',
42: 'Print',
43: 'Execute',
44: 'PrintScreen',
45: 'Insert',
46: 'Delete',
48: ['0', ')'],
49: ['1', '!'],
50: ['2', '@'],
51: ['3', '#'],
52: ['4', '$'],
53: ['5', '%'],
54: ['6', '^'],
55: ['7', '&'],
56: ['8', '*'],
57: ['9', '('],
91: 'OS',
93: 'ContextMenu',
144: 'NumLock',
145: 'ScrollLock',
181: 'VolumeMute',
182: 'VolumeDown',
183: 'VolumeUp',
186: [';', ':'],
187: ['=', '+'],
188: [',', '<'],
189: ['-', '_'],
190: ['.', '>'],
191: ['/', '?'],
192: ['`', '~'],
219: ['[', '{'],
220: ['\\', '|'],
221: [']', '}'],
222: ["'", '"'],
224: 'Meta',
225: 'AltGraph',
246: 'Attn',
247: 'CrSel',
248: 'ExSel',
249: 'EraseEof',
250: 'Play',
251: 'ZoomOut'
}
};
// Function keys (F1-24).
var i;
for (i = 1; i < 25; i++) {
keyboardeventKeyPolyfill.keys[111 + i] = 'F' + i;
}
// Printable ASCII characters.
var letter = '';
for (i = 65; i < 91; i++) {
letter = String.fromCharCode(i);
keyboardeventKeyPolyfill.keys[i] = [letter.toLowerCase(), letter.toUpperCase()];
}
function polyfill () {
if (!('KeyboardEvent' in window) ||
'key' in KeyboardEvent.prototype) {
return false;
}
// Polyfill `key` on `KeyboardEvent`.
var proto = {
get: function (x) {
var key = keyboardeventKeyPolyfill.keys[this.which || this.keyCode];
if (Array.isArray(key)) {
key = key[+this.shiftKey];
}
return key;
}
};
Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
return proto;
}
if (typeof define === 'function' && define.amd) {
define('keyboardevent-key-polyfill', keyboardeventKeyPolyfill);
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
module.exports = keyboardeventKeyPolyfill;
} else if (window) {
window.keyboardeventKeyPolyfill = keyboardeventKeyPolyfill;
}
})();

File diff suppressed because one or more lines are too long

View File

@ -1,232 +0,0 @@
/**
* Bootsnip - "Bootstrap Checkboxes/Radios"
* Bootstrap 3.2.0 Snippet by i-heart-php <http://bootsnipp.com/i-heart-php>
*
* Copyright (c) 2013 Bootsnipp.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.
*/
.checkbox {
padding-left: 20px;
}
.checkbox label {
display: inline-block;
position: relative;
padding-left: 5px;
}
.checkbox label::before {
content: "";
display: inline-block;
position: absolute;
width: 17px;
height: 17px;
left: 0;
top: 2.5px;
margin-left: -20px;
border: 1px solid #cccccc;
border-radius: 3px;
background-color: #fff;
-webkit-transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
-o-transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
}
.checkbox label::after {
display: inline-block;
position: absolute;
width: 16px;
height: 16px;
left: 0;
top: 2.5px;
margin-left: -20px;
padding-left: 3px;
padding-top: 1px;
font-size: 11px;
color: #555555;
}
.checkbox input[type="checkbox"] {
opacity: 0;
}
.checkbox input[type="checkbox"]:focus + label::before {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.checkbox input[type="checkbox"]:checked + label::after {
font-family: 'FontAwesome';
content: "\f00c";
}
.checkbox input[type="checkbox"]:disabled + label {
opacity: 0.65;
}
.checkbox input[type="checkbox"]:disabled + label::before {
background-color: #eeeeee;
cursor: not-allowed;
}
.checkbox.checkbox-circle label::before {
border-radius: 50%;
}
.checkbox.checkbox-inline {
margin-top: 0;
}
.checkbox-primary input[type="checkbox"]:checked + label::before {
background-color: #428bca;
border-color: #428bca;
}
.checkbox-primary input[type="checkbox"]:checked + label::after {
color: #fff;
}
.checkbox-danger input[type="checkbox"]:checked + label::before {
background-color: #d9534f;
border-color: #d9534f;
}
.checkbox-danger input[type="checkbox"]:checked + label::after {
color: #fff;
}
.checkbox-info input[type="checkbox"]:checked + label::before {
background-color: #5bc0de;
border-color: #5bc0de;
}
.checkbox-info input[type="checkbox"]:checked + label::after {
color: #fff;
}
.checkbox-warning input[type="checkbox"]:checked + label::before {
background-color: #f0ad4e;
border-color: #f0ad4e;
}
.checkbox-warning input[type="checkbox"]:checked + label::after {
color: #fff;
}
.checkbox-success input[type="checkbox"]:checked + label::before {
background-color: #5cb85c;
border-color: #5cb85c;
}
.checkbox-success input[type="checkbox"]:checked + label::after {
color: #fff;
}
.radio {
padding-left: 20px;
}
.radio label {
display: inline-block;
position: relative;
padding-left: 5px;
}
.radio label::before {
content: "";
display: inline-block;
position: absolute;
width: 17px;
height: 17px;
left: 0;
margin-left: -20px;
border: 1px solid #cccccc;
border-radius: 50%;
background-color: #fff;
-webkit-transition: border 0.15s ease-in-out;
-o-transition: border 0.15s ease-in-out;
transition: border 0.15s ease-in-out;
}
.radio label::after {
display: inline-block;
position: absolute;
content: " ";
width: 11px;
height: 11px;
left: 3px;
top: 3px;
margin-left: -20px;
border-radius: 50%;
background-color: #555555;
-webkit-transform: scale(0, 0);
-ms-transform: scale(0, 0);
-o-transform: scale(0, 0);
transform: scale(0, 0);
-webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
-moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
-o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
}
.radio input[type="radio"] {
opacity: 0;
}
.radio input[type="radio"]:focus + label::before {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.radio input[type="radio"]:checked + label::after {
-webkit-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
.radio input[type="radio"]:disabled + label {
opacity: 0.65;
}
.radio input[type="radio"]:disabled + label::before {
cursor: not-allowed;
}
.radio.radio-inline {
margin-top: 0;
}
.radio-primary input[type="radio"] + label::after {
background-color: #428bca;
}
.radio-primary input[type="radio"]:checked + label::before {
border-color: #428bca;
}
.radio-primary input[type="radio"]:checked + label::after {
background-color: #428bca;
}
.radio-danger input[type="radio"] + label::after {
background-color: #d9534f;
}
.radio-danger input[type="radio"]:checked + label::before {
border-color: #d9534f;
}
.radio-danger input[type="radio"]:checked + label::after {
background-color: #d9534f;
}
.radio-info input[type="radio"] + label::after {
background-color: #5bc0de;
}
.radio-info input[type="radio"]:checked + label::before {
border-color: #5bc0de;
}
.radio-info input[type="radio"]:checked + label::after {
background-color: #5bc0de;
}
.radio-warning input[type="radio"] + label::after {
background-color: #f0ad4e;
}
.radio-warning input[type="radio"]:checked + label::before {
border-color: #f0ad4e;
}
.radio-warning input[type="radio"]:checked + label::after {
background-color: #f0ad4e;
}
.radio-success input[type="radio"] + label::after {
background-color: #5cb85c;
}
.radio-success input[type="radio"]:checked + label::before {
border-color: #5cb85c;
}
.radio-success input[type="radio"]:checked + label::after {
background-color: #5cb85c;
}

View File

@ -1,835 +0,0 @@
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 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.
*/
@import 'checkbox.css';
.login-page {
background: #10529f;
}
#login-position-elements {
margin: 25% auto;
}
.login-logo {
color: #fff;
font-weight: 400;
}
.login-copyright {
color: rgba(255, 255, 255, 0.3);
}
.login-copyright > a {
color: rgba(255, 255, 255, 0.6);
}
.particles-js-canvas-el {
position: absolute;
width: 100%;
height: 100%;
top: 0;
z-index: -1;
}
.pterodactyl-login-box {
background: rgba(0, 0, 0, 0.25);
border-radius: 3px;
padding: 20px;
}
.pterodactyl-login-input > input {
background: rgba(0, 0, 0, 0.4);
border: 1px solid #000;
border-radius: 2px;
color: #fff;
}
.pterodactyl-login-input > .form-control-feedback {
color: #fff;
}
.pterodactyl-login-button--main {
background: rgba(0, 0, 0, 0.4);
border: 1px solid #000;
border-radius: 2px;
color: #fff;
}
.pterodactyl-login-button--main:hover {
background: rgba(0, 0, 0, 0.7);
border: 1px solid #000;
border-radius: 2px;
color: #fff;
}
.pterodactyl-login-button--left {
background: rgba(255, 255, 255, 0.4);
border: 1px solid rgba(255, 255, 255, 0.6);
border-radius: 2px;
color: #fff;
}
.pterodactyl-login-button--left:hover {
background: rgba(255, 255, 255, 0.6);
border: 1px solid rgba(255, 255, 255, 0.8);
border-radius: 2px;
color: #fff;
}
.weight-100 {
font-weight: 100;
}
.weight-300 {
font-weight: 300;
}
.btn-clear {
background: transparent;
}
.user-panel > .info {
position: relative;
left: 0;
}
code {
background-color: #eef1f6;
color: #596981;
border-radius: 2px;
padding-left: 4px;
padding-right: 4px;
line-height: 1.4;
font-size: 85%;
border: 1px solid rgba(0, 0, 0, .1);
display: inline-block;
}
p {
line-height: 1.6 !important;
}
p.small {
margin-top: 3px !important;
}
.control-sidebar-dark .control-sidebar-menu > li > a.active {
background: #1e282c;
}
.callout-nomargin {
margin: 0;
}
.table {
font-size: 14px !important;
}
.table .min-size {
width:1px;
white-space: nowrap;
}
@media (max-width:767px) {
.box-header > .box-tools {
position: relative !important;
padding: 0px 10px 10px;
}
}
.middle, .align-middle {
vertical-align: middle !important;
}
#fileOptionMenu.dropdown-menu > li > a {
padding:3px 6px;
}
.hasFileHover {
border: 2px dashed #0087F7;
border-top: 0 !important;
border-radius: 5px;
margin: 0;
opacity: 0.5;
}
.hasFileHover * {
pointer-events: none !important;
}
td.has-progress {
padding: 0px !important;
border-top: 0px !important;
}
.progress.progress-table-bottom {
margin: 0 !important;
height:5px !important;
padding:0;
border:0;
}
.muted {
filter: alpha(opacity=20);
opacity: 0.2;
}
.muted-hover:hover {
filter: alpha(opacity=100);
opacity: 1;
}
.use-pointer {
cursor: pointer !important;
}
.input-loader {
display: none;
position:relative;
top: -25px;
float: right;
right: 5px;
color: #cccccc;
height: 0;
}
.box-header > .form-group {
margin-bottom: 0;
}
.box-header > .form-group > div > p.small {
margin: 0;
}
.no-margin {
margin: 0 !important;
}
li.select2-results__option--highlighted[aria-selected="false"] > .user-block > .username > a {
color: #fff;
}
li.select2-results__option--highlighted[aria-selected="false"] > .user-block > .description {
color: #eee;
}
.select2-selection.select2-selection--multiple {
min-height: 36px !important;
}
.select2-search--inline .select2-search__field:focus {
outline: none;
border: 0 !important;
}
.img-bordered-xs {
border: 1px solid #d2d6de;
padding: 1px;
}
span[aria-labelledby="select2-pUserId-container"] {
padding-left: 2px !important;
}
.box {
box-shadow: 0 0 0 1px rgba(89, 105, 128, .1), 0 1px 3px 0 rgba(89, 105, 128, .1), 0 1px 2px 0 rgba(0, 0, 0, .05) !important;
}
.alert-danger {
color: #ffffff !important;
background: #d64242 !important;
border: 1px solid #841d1d;
}
.alert-info {
color: #ffffff !important;
background: #408fec !important;
border: 1px solid #1055a5;
}
.alert-success {
color: #ffffff !important;
background: #51b060 !important;
border: 1px solid #2b5f33;
}
.alert-warning {
color: #ffffff !important;
background: #fa9636 !important;
border: 1px solid #b45b05;
}
.callout-slim a {
color: #555 !important;
}
.bg-purple {
background-color: #79589f !important;
}
.label-default {
background-color: #eef1f6 !important;
}
.callout.callout-info.callout-slim {
border: 1px solid #1055a5 !important;
border-left: 5px solid #1055a5 !important;
border-right: 5px solid #1055a5 !important;
color: #777 !important;
background: transparent !important;
}
.callout.callout-danger.callout-slim {
border: 1px solid #c23321 !important;
border-left: 5px solid #c23321 !important;
border-right: 5px solid #c23321 !important;
color: #777 !important;
background: transparent !important;
}
.callout.callout-warning.callout-slim {
border: 1px solid #c87f0a !important;
border-left: 5px solid #c87f0a !important;
border-right: 5px solid #c87f0a !important;
color: #777 !important;
background: transparent !important;
}
.callout.callout-success.callout-slim {
border: 1px solid #00733e !important;
border-left: 5px solid #00733e !important;
border-right: 5px solid #00733e !important;
color: #777 !important;
background: transparent !important;
}
.callout.callout-default.callout-slim {
border: 1px solid #eee !important;
border-left: 5px solid #eee !important;
border-right: 5px solid #eee !important;
color: #777 !important;
background: transparent !important;
}
.callout code {
background-color: #515f6cbb;
color: #c3c3c3;
border: 1px solid rgba(0, 0, 0, .25);
}
.tab-pane .box-footer {
margin: 0 -10px -10px;
}
.select2-container{ width: 100% !important; }
.nav-tabs-custom > .nav-tabs > li:hover {
border-top-color:#3c8dbc;
}
.nav-tabs-custom > .nav-tabs > li.active.tab-danger, .nav-tabs-custom > .nav-tabs > li.tab-danger:hover {
border-top-color: #c23321;
}
.nav-tabs-custom > .nav-tabs > li.active.tab-success, .nav-tabs-custom > .nav-tabs > li.tab-success:hover {
border-top-color: #00733e;
}
.nav-tabs-custom > .nav-tabs > li.active.tab-info, .nav-tabs-custom > .nav-tabs > li.tab-info:hover {
border-top-color: #0097bc;
}
.nav-tabs-custom > .nav-tabs > li.active.tab-warning, .nav-tabs-custom > .nav-tabs > li.tab-warning:hover {
border-top-color: #c87f0a;
}
.nav-tabs-custom.nav-tabs-floating > .nav-tabs {
border-bottom: 0px !important;
}
.nav-tabs-custom.nav-tabs-floating > .nav-tabs > li {
margin-bottom: 0px !important;
}
.nav-tabs-custom.nav-tabs-floating > .nav-tabs > li:first-child.active,
.nav-tabs-custom.nav-tabs-floating > .nav-tabs > li:first-child:hover {
border-radius: 3px 0 0 0;
}
.nav-tabs-custom.nav-tabs-floating > .nav-tabs > li:first-child.active > a {
border-radius: 0 0 0 3px;
}
.position-relative {
position: relative;
}
.no-pad-bottom {
padding-bottom: 0 !important;
}
.no-margin-bottom {
margin-bottom: 0 !important;
}
.btn-icon > i.fa {
line-height: 1.5;
}
.btn.active, .btn.active.focus {
background-color: #408fec;
}
.strong {
font-weight: bold !important;
}
.server-description > td {
padding-top: 0 !important;
border-top: 0 !important;
}
tr:hover + tr.server-description {
background-color: #f5f5f5 !important;
}
.login-corner-info {
position: absolute;
bottom: 5px;
right: 10px;
color: white;
}
input.form-autocomplete-stop[readonly] {
background: inherit;
cursor: text;
}
/* fix Google Recaptcha badge */
.grecaptcha-badge {
bottom: 54px !important;
background: white;
box-shadow: none !important;
}
.dropdown-massactions {
min-width: 80px;
}
.select-all-files {
position: relative;
bottom: 1px;
margin-right: 7px !important;
}
.select-file {
position: relative;
bottom: 1px;
margin-right: 2px !important;
}
.select-folder {
position: relative;
bottom: 1px;
margin-right: 5px !important;
}
label.control-label > span {
font-size: 80%;
font-weight: 400;
font-style: italic;
color: #dd4b39;
}
label.control-label > span.field-required:before {
content: "required";
color: #dd4b39;
}
label.control-label > span.field-optional:before {
content: "optional";
color: #bbbbbb;
}
.pagination > li > a, .pagination > li > span {
padding: 3px 10px !important;
}
.logo-mini > img {
height: 42px;
width: auto;
}
.search01 {
width: 30%;
}
.number-info-box-content {
padding: 15px 10px 0;
}
/* *******
> Version v1.0
******* */
body {
color: #cad1d8;
}
.fixed .main-header {
box-shadow: 0 4px 8px 0 rgba(0,0,0,.12), 0 2px 4px 0 rgba(0,0,0,.08);
}
.skin-blue .wrapper, .skin-blue .main-sidebar, .skin-blue .left-side {
background-color: #181f27;
box-shadow: 0 4px 8px 0 rgba(0,0,0,.12), 0 2px 4px 0 rgba(0,0,0,.08);
}
.skin-blue .main-header .logo {
background-color: #1f2933;
color: #9aa5b1;
}
.skin-blue .main-header .navbar .sidebar-toggle {
color: #9aa5b1;
}
.skin-blue .main-header .navbar .nav>li>a {
color: #9aa5b1;
}
.skin-blue .sidebar-menu>li.header {
color: #797979;
background: #0e111582;
}
.skin-blue .main-header .navbar {
background-color: #1f2933;
}
.skin-blue .main-header .navbar .sidebar-toggle:hover {
background-color: #1c252e;
}
.skin-blue .main-header .logo:hover {
background-color: #1c252e;
}
.main-footer {
background: #1f2933;
color: #9aa5b1;
border-top: 1px solid #1f2933;
}
.skin-blue .sidebar-menu>li.active>a {
border-left-color: #099aa5;
}
.text-gray {
color: #9aa5b1 !important;
}
.text-green {
color: #00a65a !important;
}
.text-muted {
color: #9aa5b1 !important;
}
.text-danger {
color: #ff1c00;
}
.content-wrapper {
background-color: #33404d;
}
.btn-success {
background-color: #189a1c;
border-color: #0f8513;
}
.btn.btn-green:hover {
background-color: #0f8513;
border-color: #0e7717;
}
.btn-primary {
background-color: #0967d3;
border-color: #0550b3;
}
.btn.btn-primary:hover {
background-color: #0550b3;
border-color: #0345a0;
}
.box {
box-shadow: 0 4px 8px 0 rgba(0,0,0,.12), 0 2px 4px 0 rgba(0,0,0,.08) !important;
background: #3f4d5a;
border-top: 3px solid #1f2933;
}
.box-header {
color: #cad1d8;
background: #1f2933;
}
.box-header.with-border {
border-bottom: 1px solid #1f2933;
}
.box.box-default {
border-top-color: #1f2933;
}
.box-footer {
border-top: 1px solid #4d5b69;
background-color: #3f4d5a;
}
.content-header>.breadcrumb>li>a {
color: #cad1d8;
}
.breadcrumb>.active {
color: #cad1d8;
}
.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small {
color: #cad1d8;
}
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
border-top: 1px solid #4d5b69;
}
.table>thead>tr>th {
border-bottom: 2px solid #4d5b69;
}
.table-hover>tbody>tr:hover {
background-color: #33404d;
}
a {
color: #007eff;
}
.nav-tabs-custom {
background: #1f2933;
}
.nav-tabs-custom>.nav-tabs>li.active {
border-top-color: #099aa5;
}
.nav-tabs-custom>.nav-tabs>li.active>a {
border-top-color: transparent;
border-left-color: #15161c;
border-right-color: #15161c;
background: #13181e;
}
.nav-tabs-custom>.nav-tabs>li>a {
color: #9aa5b1;
}
.nav-tabs-custom>.nav-tabs>li.active>a, .nav-tabs-custom>.nav-tabs>li.active:hover>a {
color: #9aa5b1;
}
input.form-control {
padding: .75rem;
background-color: #515f6cbb;
border-width: 1px;
border-color: #606d7b;
border-radius: .25rem;
color: #cad1d8;
box-shadow: none;
-webkit-transition: border .15s linear,box-shaodw .15s ease-in;
transition: border .15s linear,box-shaodw .15s ease-in;
}
textarea.form-control {
padding: .75rem;
background-color: #515f6cbb;
border-width: 1px;
border-color: #606d7b;
border-radius: .25rem;
color: #cad1d8;
box-shadow: none;
-webkit-transition: border .15s linear,box-shaodw .15s ease-in;
transition: border .15s linear,box-shaodw .15s ease-in;
}
.input-group .input-group-addon {
border-color: #606d7b;
background-color: #515f6cbb;
color: #cad1d8;
}
.select2-container--default .select2-selection--single, .select2-selection .select2-selection--single {
border: 1px solid #606d7b;
}
.select2-container--default .select2-selection--single {
background-color: #515f6cbb;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
color: #cad1d8;
}
.select2-container--default .select2-selection--multiple {
background-color: #515f6cbb;
}
.select2-container--default .select2-selection--multiple {
border: 1px solid #606d7b;
border-radius: 0;
}
code {
background-color: #515f6cbb;
color: #c3c3c3;
border: 1px solid rgba(0, 0, 0, .25);
}
.btn-default {
background-color: #33404d;
color: #cad1d8;
border-color: #606d7b;
}
.select2-results__option {
background-color: #b5bcc1;
color: #444;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #3c8dbc;
}
.modal-body {
background: #3f4d5a;
}
.modal-header {
background: #3f4d5a;
border-bottom-color: #4d5b69;
}
.modal-footer {
background: #3f4d5a;
border-top-color: #4d5b69;
}
@media (max-width: 991px) {
.content-header>.breadcrumb {
background: #1f2933 !important;
}
}
.nav-tabs-custom>.nav-tabs>li.active>a, .nav-tabs-custom>.nav-tabs>li.active:hover>a {
background-color: #101216;
}
.select2-container--default .select2-results__option[aria-selected=true], .select2-container--default .select2-results__option[aria-selected=true]:hover {
color: #fff;
}
.select2-dropdown {
background-color: #515f6cbb;
border: 1px solid #606d7b;
}
.select2-container--default.select2-container--focus .select2-selection--multiple, .select2-container--default .select2-search--dropdown .select2-search__field {
border-color: #d2d6de !important;
background-color: #515f6cbb;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #099aa5;
}
a {
color: #288afb;
}
a:hover {
color: #206ec7;
}
.form-control {
border-color: #606d7b;
background-color: #515f6cbb;
color: #cad1d8;
}
.form-control[disabled], .form-control[readonly],
fieldset[disabled] .form-control {
background-color: #1f2933;
color: #cad1d8;
cursor: not-allowed;
}
.well {
min-height: 20px;
padding: 19px;
margin-bottom: 20px;
background-color: #515f6cbb;
border: 1px solid #606d7b;
}
.well-lg {
padding: 24px;
}
.well-sm {
padding: 9px;
}
.small-box h3, .small-box p {
color: #c3c3c3;
}
.small-box-footer {
color: #288afb;
}
.small-box .icon {
color: #cad1d8;
}
.bg-gray {
background-color: #33404d !important;
}
pre {
color: #cad1d8;
background-color: #515f6cbb;
border-color: #1f2933;
}

View File

@ -1,105 +0,0 @@
/*Design for Terminal*/
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro');
#terminal-body {
background: rgb(26, 26, 26);
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#terminal {
font-family: 'Source Code Pro', monospace;
color: rgb(223, 223, 223);
background: rgb(26, 26, 26);
font-size: 12px;
line-height: 14px;
padding: 10px 10px 0;
box-sizing: border-box;
height: 500px;
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
border-radius: 5px 5px 0 0;
}
#terminal > .cmd {
padding: 1px 0;
word-wrap: break-word;
white-space: pre-wrap;
}
#terminal_input {
width: 100%;
background: rgb(26, 26, 26);
border-radius: 0 0 5px 5px;
padding: 0 0 0 10px !important;
}
.terminal_input--input, .terminal_input--prompt {
font-family: 'Source Code Pro', monospace;
margin-bottom: 0;
border: 0 !important;
background: transparent !important;
color: rgb(223, 223, 223);
font-size: 12px;
padding: 1px 0 4px !important;
}
.terminal_input--input {
margin-left: 6px;
line-height: 1;
outline: none !important;
}
.terminal-notify {
position: absolute;
right: 30px;
bottom: 30px;
padding: 3.5px 7px;
border-radius: 3px;
background: #fff;
color: #000;
opacity: .5;
font-size: 16px;
cursor: pointer;
z-index: 10;
}
.terminal-notify:hover {
opacity: .9;
}
.ansi-black-fg { color: rgb(0, 0, 0); }
.ansi-red-fg { color: rgb(166, 0, 44); }
.ansi-green-fg { color: rgb(55, 106, 27); }
.ansi-yellow-fg { color: rgb(241, 133, 24); }
.ansi-blue-fg { color: rgb(17, 56, 163); }
.ansi-magenta-fg { color: rgb(67, 0, 117); }
.ansi-cyan-fg { color: rgb(18, 95, 105); }
.ansi-white-fg { color: rgb(255, 255, 255); }
.ansi-bright-black-fg { color: rgb(51, 51, 51); }
.ansi-bright-red-fg { color: rgb(223, 45, 39); }
.ansi-bright-green-fg { color: rgb(105, 175, 45); }
.ansi-bright-yellow-fg { color: rgb(254, 232, 57); }
.ansi-bright-blue-fg { color: rgb(68, 145, 240); }
.ansi-bright-magenta-fg { color: rgb(151, 50, 174); }
.ansi-bright-cyan-fg{ color: rgb(37, 173, 98); }
.ansi-bright-white-fg { color: rgb(208, 208, 208); }
.ansi-black-bg { background: rgb(0, 0, 0); }
.ansi-red-bg { background: rgb(166, 0, 44); }
.ansi-green-bg { background: rgb(55, 106, 27); }
.ansi-yellow-bg { background: rgb(241, 133, 24); }
.ansi-blue-bg { background: rgb(17, 56, 163); }
.ansi-magenta-bg { background: rgb(67, 0, 117); }
.ansi-cyan-bg { background: rgb(18, 95, 105); }
.ansi-white-bg { background: rgb(255, 255, 255); }
.ansi-bright-black-bg { background: rgb(51, 51, 51); }
.ansi-bright-red-bg { background: rgb(223, 45, 39); }
.ansi-bright-green-bg { background: rgb(105, 175, 45); }
.ansi-bright-yellow-bg { background: rgb(254, 232, 57); }
.ansi-bright-blue-bg { background: rgb(68, 145, 240); }
.ansi-bright-magenta-bg { background: rgb(151, 50, 174); }
.ansi-bright-cyan-bg { background: rgb(37, 173, 98); }
.ansi-bright-white-bg { background: rgb(208, 208, 208); }

View File

@ -1,23 +0,0 @@
// Copyright (c) 2015 - 2017 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.
$.urlParam=function(name){var results=new RegExp("[\\?&]"+name+"=([^&#]*)").exec(decodeURIComponent(window.location.href));if(results==null){return null}else{return results[1]||0}};function getPageName(url){var index=url.lastIndexOf("/")+1;var filenameWithExtension=url.substr(index);var filename=filenameWithExtension.split(".")[0];return filename}
// Remeber Active Tab and Navigate to it on Reload
for(var queryParameters={},queryString=location.search.substring(1),re=/([^&=]+)=([^&]*)/g,m;m=re.exec(queryString);)queryParameters[decodeURIComponent(m[1])]=decodeURIComponent(m[2]);$("a[data-toggle='tab']").click(function(){queryParameters.tab=$(this).attr("href").substring(1),window.history.pushState(null,null,location.pathname+"?"+$.param(queryParameters))});
if($.urlParam('tab') != null){$('.nav.nav-tabs a[href="#' + $.urlParam('tab') + '"]').tab('show');}

View File

@ -1,216 +0,0 @@
// Copyright (c) 2015 - 2017 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.
$(document).ready(function() {
$('#pNestId').select2({
placeholder: 'Select a Nest',
}).change();
$('#pEggId').select2({
placeholder: 'Select a Nest Egg',
});
$('#pPackId').select2({
placeholder: 'Select a Service Pack',
});
$('#pNodeId').select2({
placeholder: 'Select a Node',
}).change();
$('#pAllocation').select2({
placeholder: 'Select a Default Allocation',
});
$('#pAllocationAdditional').select2({
placeholder: 'Select Additional Allocations',
});
});
let lastActiveBox = null;
$(document).on('click', function (event) {
if (lastActiveBox !== null) {
lastActiveBox.removeClass('box-primary');
}
lastActiveBox = $(event.target).closest('.box');
lastActiveBox.addClass('box-primary');
});
$('#pNodeId').on('change', function () {
currentNode = $(this).val();
$.each(Pterodactyl.nodeData, function (i, v) {
if (v.id == currentNode) {
$('#pAllocation').html('').select2({
data: v.allocations,
placeholder: 'Select a Default Allocation',
});
updateAdditionalAllocations();
}
});
});
$('#pNestId').on('change', function (event) {
$('#pEggId').html('').select2({
data: $.map(_.get(Pterodactyl.nests, $(this).val() + '.eggs', []), function (item) {
return {
id: item.id,
text: item.name,
};
}),
}).change();
});
$('#pEggId').on('change', function (event) {
let parentChain = _.get(Pterodactyl.nests, $('#pNestId').val(), null);
let objectChain = _.get(parentChain, 'eggs.' + $(this).val(), null);
const images = _.get(objectChain, 'docker_images', {})
$('#pDefaultContainer').html('');
const keys = Object.keys(images);
for (let i = 0; i < keys.length; i++) {
let opt = document.createElement('option');
opt.value = images[keys[i]];
opt.innerHTML = keys[i] + " (" + images[keys[i]] + ")";
$('#pDefaultContainer').append(opt);
}
if (!_.get(objectChain, 'startup', false)) {
$('#pStartup').val(_.get(parentChain, 'startup', 'ERROR: Startup Not Defined!'));
} else {
$('#pStartup').val(_.get(objectChain, 'startup'));
}
$('#pPackId').html('').select2({
data: [{ id: 0, text: 'No Service Pack' }].concat(
$.map(_.get(objectChain, 'packs', []), function (item, i) {
return {
id: item.id,
text: item.name + ' (' + item.version + ')',
};
})
),
});
const variableIds = {};
$('#appendVariablesTo').html('');
$.each(_.get(objectChain, 'variables', []), function (i, item) {
variableIds[item.env_variable] = 'var_ref_' + item.id;
let isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
let dataAppend = ' \
<div class="form-group col-sm-6"> \
<label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
<input type="text" id="var_ref_' + item.id + '" autocomplete="off" name="environment[' + item.env_variable + ']" class="form-control" value="' + item.default_value + '" /> \
<p class="text-muted small">' + item.description + '<br /> \
<strong>Access in Startup:</strong> <code>{{' + item.env_variable + '}}</code><br /> \
<strong>Validation Rules:</strong> <code>' + item.rules + '</code></small></p> \
</div> \
';
$('#appendVariablesTo').append(dataAppend);
});
// If you receive a warning on this line, it should be fine to ignore. this function is
// defined in "resources/views/admin/servers/new.blade.php" near the bottom of the file.
serviceVariablesUpdated($('#pEggId').val(), variableIds);
});
$('#pAllocation').on('change', function () {
updateAdditionalAllocations();
});
function updateAdditionalAllocations() {
let currentAllocation = $('#pAllocation').val();
let currentNode = $('#pNodeId').val();
$.each(Pterodactyl.nodeData, function (i, v) {
if (v.id == currentNode) {
let allocations = [];
for (let i = 0; i < v.allocations.length; i++) {
const allocation = v.allocations[i];
if (allocation.id != currentAllocation) {
allocations.push(allocation);
}
}
$('#pAllocationAdditional').html('').select2({
data: allocations,
placeholder: 'Select Additional Allocations',
});
}
});
}
function initUserIdSelect(data) {
function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
$('#pUserId').select2({
ajax: {
url: '/admin/users/accounts.json',
dataType: 'json',
delay: 250,
data: function (params) {
return {
filter: { email: params.term },
page: params.page,
};
},
processResults: function (data, params) {
return { results: data };
},
cache: true,
},
data: data,
escapeMarkup: function (markup) { return markup; },
minimumInputLength: 2,
templateResult: function (data) {
if (data.loading) return escapeHtml(data.text);
return '<div class="user-block"> \
<img class="img-circle img-bordered-xs" src="https://www.gravatar.com/avatar/' + escapeHtml(data.md5) + '?s=120" alt="User Image"> \
<span class="username"> \
<a href="#">' + escapeHtml(data.name_first) + ' ' + escapeHtml(data.name_last) +'</a> \
</span> \
<span class="description"><strong>' + escapeHtml(data.email) + '</strong> - ' + escapeHtml(data.username) + '</span> \
</div>';
},
templateSelection: function (data) {
return '<div> \
<span> \
<img class="img-rounded img-bordered-xs" src="https://www.gravatar.com/avatar/' + escapeHtml(data.md5) + '?s=120" style="height:28px;margin-top:-4px;" alt="User Image"> \
</span> \
<span style="padding-left:5px;"> \
' + escapeHtml(data.name_first) + ' ' + escapeHtml(data.name_last) + ' (<strong>' + escapeHtml(data.email) + '</strong>) \
</span> \
</div>';
}
});
}

View File

@ -1,56 +0,0 @@
$(document).ready(function () {
$('#pNodeId').select2({
placeholder: 'Select a Node',
}).change();
$('#pAllocation').select2({
placeholder: 'Select a Default Allocation',
});
$('#pAllocationAdditional').select2({
placeholder: 'Select Additional Allocations',
});
});
$('#pNodeId').on('change', function () {
let currentNode = $(this).val();
$.each(Pterodactyl.nodeData, function (i, v) {
if (v.id == currentNode) {
$('#pAllocation').html('').select2({
data: v.allocations,
placeholder: 'Select a Default Allocation',
});
updateAdditionalAllocations();
}
});
});
$('#pAllocation').on('change', function () {
updateAdditionalAllocations();
});
function updateAdditionalAllocations() {
let currentAllocation = $('#pAllocation').val();
let currentNode = $('#pNodeId').val();
$.each(Pterodactyl.nodeData, function (i, v) {
if (v.id == currentNode) {
let allocations = [];
for (let i = 0; i < v.allocations.length; i++) {
const allocation = v.allocations[i];
if (allocation.id != currentAllocation) {
allocations.push(allocation);
}
}
$('#pAllocationAdditional').html('').select2({
data: allocations,
placeholder: 'Select Additional Allocations',
});
}
});
}

View File

@ -1,65 +0,0 @@
// Copyright (c) 2015 - 2017 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.
$(document).ready(function () {
Socket.on('console', function (data) {
if (typeof data === 'undefined' || typeof data.line === 'undefined') {
return;
}
if (~data.line.indexOf('You need to agree to the EULA in order to run the server')) {
swal({
title: 'EULA Acceptance',
text: 'By pressing \'I Accept\' below you are indicating your agreement to the <a href="https://account.mojang.com/documents/minecraft_eula" target="_blank">Mojang EULA</a>.',
type: 'info',
html: true,
showCancelButton: true,
showConfirmButton: true,
cancelButtonText: 'I do not Accept',
confirmButtonText: 'I Accept',
closeOnConfirm: false,
showLoaderOnConfirm: true
}, function () {
$.ajax({
type: 'POST',
url: Pterodactyl.meta.saveFile,
headers: { 'X-CSRF-Token': Pterodactyl.meta.csrfToken, },
data: {
file: 'eula.txt',
contents: 'eula=true'
}
}).done(function (data) {
$('[data-attr="power"][data-action="start"]').trigger('click');
swal({
type: 'success',
title: '',
text: 'The EULA for this server has been accepted, restarting server now.',
});
}).fail(function (jqXHR) {
console.error(jqXHR);
swal({
title: 'Whoops!',
text: 'An error occurred while attempting to set the EULA as accepted: ' + jqXHR.responseJSON.error,
type: 'error'
})
});
});
}
});
});

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})});
(function() {
window.require(["ace/ext/elastic_tabstops_lite"], function() {});
})();

View File

@ -1,5 +0,0 @@
;
(function() {
window.require(["ace/ext/error_marker"], function() {});
})();

View File

@ -1,5 +0,0 @@
define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var t=e.editor,n=e.getAccelKey();if(n){var t=e.editor,r=e.getDocumentPosition(),i=t.session,s=i.getTokenAt(r.row,r.column);t._emit("linkHover",{position:r,token:s})}}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("ace/editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}})});
(function() {
window.require(["ace/ext/linking"], function() {});
})();

View File

@ -1,5 +0,0 @@
define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],AsciiDoc:["asciidoc|adoc"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],Bro:["bro"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],CSharp:["cs"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Drools:["drl"],Dummy:["dummy"],DummySyntax:["dummy"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr|fth|4th"],Fortran:["f|f90"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],Haskell_Cabal:["cabal"],haXe:["hx"],Hjson:["hjson"],HTML:["html|htm|xhtml"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Jack:["jack"],Jade:["jade|pug"],Java:["java"],JavaScript:["js|jsm|jsx"],JSON:["json"],JSONiq:["jq"],JSP:["jsp"],JSX:["jsx"],Julia:["jl"],Kotlin:["kt|kts"],LaTeX:["tex|latex|ltx|bib"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],LogiQL:["logic|lql"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MEL:["mel"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nix:["nix"],NSIS:["nsi|nsh"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Python:["py"],R:["r"],Razor:["cshtml|asp"],RDoc:["Rd"],RHTML:["Rhtml"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SASS:["sass"],SCAD:["scad"],Scala:["scala"],Scheme:["scm|sm|rkt|oak|scheme"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Smarty:["smarty|tpl"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],TSX:["tsx"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}});
(function() {
window.require(["ace/ext/modelist"], function() {});
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){console.log(e,a,n.selectionStart,n.selectionEnd);if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})});
(function() {
window.require(["ace/ext/spellcheck"], function() {});
})();

View File

@ -1,5 +0,0 @@
define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){"use strict";function l(e,t){this.$u=e,this.$doc=t}var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();if(n){var r=new l(n,t);t.setUndoManager(r)}return t.$informUndoManager=i.delayedCall(function(){t.$deltas=[]}),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),function(){this.execute=function(e){this.$u.execute(e)},this.undo=function(){var e=this.$u.undo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.redo=function(){var e=this.$u.redo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.reset=function(){this.$u.reset()},this.hasUndo=function(){return this.$u.hasUndo()},this.hasRedo=function(){return this.$u.hasRedo()}}.call(l.prototype),t.Split=f}),define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){"use strict";n.exports=e("../split")});
(function() {
window.require(["ace/ext/split"], function() {});
})();

View File

@ -1,5 +0,0 @@
define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/config","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=".ace_static_highlight {font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;font-size: 12px;white-space: pre-wrap}.ace_static_highlight .ace_gutter {width: 2em;text-align: right;padding: 0 3px 0 0;margin-right: 3px;}.ace_static_highlight.ace_show_gutter .ace_line {padding-left: 2.6em;}.ace_static_highlight .ace_line { position: relative; }.ace_static_highlight .ace_gutter-cell {-moz-user-select: -moz-none;-khtml-user-select: none;-webkit-user-select: none;user-select: none;top: 0;bottom: 0;left: 0;position: absolute;}.ace_static_highlight .ace_gutter-cell:before {content: counter(ace_line, decimal);counter-increment: ace_line;}.ace_static_highlight {counter-reset: ace_line;}",o=e("../config"),u=e("../lib/dom"),a=function(){this.config={}};a.prototype=i.prototype;var f=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",a=[];if(e.firstElementChild){var l=0;for(var c=0;c<e.childNodes.length;c++){var h=e.childNodes[c];h.nodeType==3?(l+=h.data.length,o+=h.data):a.push(l,h)}}else o=u.getInnerText(e),t.trim&&(o=o.trim());f.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<a.length;i+=2){var s=t.session.doc.indexToPosition(a[i]),o=a[i+1],f=r.children[s.row];f&&f.appendChild(o)}n&&n()})};f.render=function(e,t,n,i,s,u){function h(){var r=f.renderSync(e,t,n,i,s);return u?u(r):r}var a=1,l=r.prototype.$modes;typeof n=="string"&&(a++,o.loadModule(["theme",n],function(e){n=e,--a||h()}));var c;return t&&typeof t=="object"&&!t.getTokenizer&&(c=t,t=c.path),typeof t=="string"&&(a++,o.loadModule(["mode",t],function(e){if(!l[t]||c)l[t]=new e.Mode(c);t=l[t],--a||h()})),--a||h()},f.renderSync=function(e,t,n,i,o){i=parseInt(i||1,10);var u=new r("");u.setUseWorker(!1),u.setMode(t);var f=new a;f.setSession(u),u.setValue(e);var l=[],c=u.getLength();for(var h=0;h<c;h++)l.push("<div class='ace_line'>"),o||l.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'></span>"),f.$renderLine(l,h,!0,!1),l.push("\n</div>");var p="<div class='"+n.cssClass+"'>"+"<div class='ace_static_highlight"+(o?"":" ace_show_gutter")+"' style='counter-reset:ace_line "+(i-1)+"'>"+l.join("")+"</div>"+"</div>";return f.destroy(),{css:s+n.cssText,html:p,session:u}},n.exports=f,n.exports.highlight=f});
(function() {
window.require(["ace/ext/static_highlight"], function() {});
})();

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"],function(e,t,n){"use strict";e("ace/lib/fixoldbrowsers");var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Cobalt","cobalt","dark"],["Gruvbox","gruvbox","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})});
(function() {
window.require(["ace/ext/themelist"], function() {});
})();

View File

@ -1,5 +0,0 @@
define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang");t.$detectIndentation=function(e,t){function c(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;if(a[0]==" ")i++,s=-Number.MAX_VALUE;else{var f=a.match(/^ */)[0].length;if(f&&a[f]!=" "){var l=f-s;l>0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(u<o&&a[a.length-1]=="\\")a=e[u++]}var h=r.reduce(function(e,t){return e+t},0),p={score:0,length:0},d=0;for(var u=1;u<12;u++){var v=c(u);u==1?(d=v,v=n[1]?.9:.8,n.length||(v=0)):v/=d,r[u]&&(v+=r[u]/h),v>p.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||d<i/4||p.score<1.8)m=undefined;return{ch:" ",length:m}}if(d>i+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t?-1:0;for(var s=0,o=r.length;s<o;s++){var u=r[s],a=u.search(/\s+$/);a>i&&n.removeInLine(s,a,u.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch=" ":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",exec:function(e){t.trimTrailingSpace(e.session)}},{name:"convertIndentation",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]});
(function() {
window.require(["ace/ext/whitespace"], function() {});
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define("ace/mode/ini_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s="\\\\(?:[\\\\0abtrn;#=:]|x[a-fA-F\\d]{4})",o=function(){this.$rules={start:[{token:"punctuation.definition.comment.ini",regex:"#.*",push_:[{token:"comment.line.number-sign.ini",regex:"$|^",next:"pop"},{defaultToken:"comment.line.number-sign.ini"}]},{token:"punctuation.definition.comment.ini",regex:";.*",push_:[{token:"comment.line.semicolon.ini",regex:"$|^",next:"pop"},{defaultToken:"comment.line.semicolon.ini"}]},{token:["keyword.other.definition.ini","text","punctuation.separator.key-value.ini"],regex:"\\b([a-zA-Z0-9_.-]+)\\b(\\s*)(=)"},{token:["punctuation.definition.entity.ini","constant.section.group-title.ini","punctuation.definition.entity.ini"],regex:"^(\\[)(.*?)(\\])"},{token:"punctuation.definition.string.begin.ini",regex:"'",push:[{token:"punctuation.definition.string.end.ini",regex:"'",next:"pop"},{token:"constant.language.escape",regex:s},{defaultToken:"string.quoted.single.ini"}]},{token:"punctuation.definition.string.begin.ini",regex:'"',push:[{token:"constant.language.escape",regex:s},{token:"punctuation.definition.string.end.ini",regex:'"',next:"pop"},{defaultToken:"string.quoted.double.ini"}]}]},this.normalizeRules()};o.metaData={fileTypes:["ini","conf"],keyEquivalent:"^~I",name:"Ini",scopeName:"source.ini"},r.inherits(o,i),t.IniHighlightRules=o}),define("ace/mode/folding/ini",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/^\s*\[([^\])]*)]\s*(?:$|[;#])/,this.getFoldWidgetRange=function(e,t,n){var r=this.foldingStartMarker,s=e.getLine(n),o=s.match(r);if(!o)return;var u=o[1]+".",a=s.length,f=e.getLength(),l=n,c=n;while(++n<f){s=e.getLine(n);if(/^\s*$/.test(s))continue;o=s.match(r);if(o&&o[1].lastIndexOf(u,0)!==0)break;c=n}if(c>l){var h=e.getLine(c).length;return new i(l,a,c,h)}}}.call(o.prototype)}),define("ace/mode/ini",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/ini_highlight_rules","ace/mode/folding/ini"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./ini_highlight_rules").IniHighlightRules,o=e("./folding/ini").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart=";",this.blockComment=null,this.$id="ace/mode/ini"}.call(u.prototype),t.Mode=u})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./text_highlight_rules").TextHighlightRules,o=e("./behaviour").Behaviour,u=function(){this.HighlightRules=s,this.$behaviour=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){return""},this.$id="ace/mode/plain_text"}.call(u.prototype),t.Mode=u})

Some files were not shown because too many files have changed in this diff Show More