Merge branch 'release/v0.7.13'

This commit is contained in:
Dane Everitt 2019-03-03 14:02:11 -08:00
commit aae67a8a11
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
39 changed files with 511 additions and 216 deletions

View file

@ -1,9 +1,17 @@
--- ---
name: "\U0001F41B Bug Report" name: "\U0001F41B Bug Report"
about: Create a report to help us resolve a bug or error about: For reporting code or design bugs with the software. DO NOT REPORT APACHE/NGINX/PHP CONFIGURATION ISSUES.
--- ---
DO NOT REPORT ISSUES CONFIGURING: SSL, PHP, APACHE, NGINX, YOUR MACHINE, SSH, SFTP, ETC. ON THIS GITHUB TRACKER.
For assistance installating this software, as well as debugging issues with dependencies, please use our discord server: https://discord.gg/pterodactyl
You MUST complete all of the below information when reporting a bug, failure to do so will result in closure of your issue. PLEASE stop spamming our tracker with "bugs" that are not related to this project.
**STOP: READ FIRST, AND THEN DELETE THE ABOVE LINES**
**Background (please complete the following information):** **Background (please complete the following information):**
* Panel or Daemon: * Panel or Daemon:
* Version of Panel/Daemon: * Version of Panel/Daemon:

View file

@ -6,3 +6,9 @@ about: 'Visit our Discord for installation help: https://pterodactyl.io/discord'
We use GitHub issues only to discuss about Pterodactyl bugs and new features. For We use GitHub issues only to discuss about Pterodactyl bugs and new features. For
this kind of questions about using Pterodactyl, please visit our Discord for assistance: https://pterodactyl.io/discord this kind of questions about using Pterodactyl, please visit our Discord for assistance: https://pterodactyl.io/discord
DO NOT REPORT ISSUES CONFIGURING: SSL, PHP, APACHE, NGINX, YOUR MACHINE, SSH, SFTP, ETC. ON THIS GITHUB TRACKER.
For assistance installating this software, as well as debugging issues with dependencies, please use our discord server: https://discord.gg/pterodactyl
PLEASE stop spamming our tracker with "bugs" that are not related to this project.

View file

@ -3,6 +3,27 @@ This file is a running track of new features and fixes to each version of the pa
This project follows [Semantic Versioning](http://semver.org) guidelines. This project follows [Semantic Versioning](http://semver.org) guidelines.
## v0.7.13 (Derelict Dermodactylus)
### Fixed
* Fixes a bug with the location update API endpoint throwing an error due to an unexected response value.
* Fixes bug where node creation API endpoint was not correctly requiring the `disk_overallocate` key.
* Prevents an exception from being thrown when a database with the same name is created on two different hosts.
* Fixes the redis password not saving correctly when setting up the environment from the command line.
* Fixes a bug with transaction handling in many areas of the application that would cause validation error messages
and other session data to not be persisted properly when using the database as the session driver.
* Fix a bug introduced at some point in the past that causes internal data integrity exceptions to not bubble up to
the user correctly, leading to extraneous and confusing exception messages.
* Fixes a bug causing servers to not be marked as having failed installation in some cases.
### Changed
* `allocation_limit` for servers now defaults to a null value, and is not required in PATCH/POST requests when adding
a server through the API.
* The `PATCH` endpoint for `/api/applications/servers/{server}/build` now accepts an array called `limits` to match
the response from the server `GET` endpoint.
### Added
* The server listing for a node is now paginated to 25 servers per page to improve performance on large nodes.
## v0.7.12 (Derelict Dermodactylus) ## v0.7.12 (Derelict Dermodactylus)
### Fixed ### Fixed
* Fixes an issue with the locations API endpoint referencing an invalid namespace. * Fixes an issue with the locations API endpoint referencing an invalid namespace.

View file

@ -178,9 +178,7 @@ class AppSettingsCommand extends Command
if ($askForRedisPassword) { if ($askForRedisPassword) {
$this->output->comment(trans('command/messages.environment.app.redis_pass_help')); $this->output->comment(trans('command/messages.environment.app.redis_pass_help'));
$this->variables['REDIS_PASSWORD'] = $this->option('redis-pass') ?? $this->output->askHidden( $this->variables['REDIS_PASSWORD'] = $this->option('redis-pass') ?? $this->output->askHidden(
trans('command/messages.environment.app.redis_password'), function () { trans('command/messages.environment.app.redis_password')
return '';
}
); );
} }

View file

@ -55,16 +55,6 @@ interface NodeRepositoryInterface extends RepositoryInterface, SearchableInterfa
*/ */
public function loadNodeAllocations(Node $node, bool $refresh = false): Node; public function loadNodeAllocations(Node $node, bool $refresh = false): Node;
/**
* Return a node with all of the servers attached to that node.
*
* @param int $id
* @return \Pterodactyl\Models\Node
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getNodeServers(int $id): Node;
/** /**
* Return a collection of nodes for all locations to use in server creation UI. * Return a collection of nodes for all locations to use in server creation UI.
* *

View file

@ -152,4 +152,14 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter
* @return int * @return int
*/ */
public function getSuspendedServersCount(): int; public function getSuspendedServersCount(): int;
/**
* Returns all of the servers that exist for a given node in a paginated response.
*
* @param int $node
* @param int $limit
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function loadAllServersForNode(int $node, int $limit): LengthAwarePaginator;
} }

View file

@ -6,6 +6,7 @@ use Exception;
use PDOException; use PDOException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Illuminate\Database\Connection;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Session\TokenMismatchException; use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@ -14,6 +15,7 @@ use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
@ -137,6 +139,41 @@ class Handler extends ExceptionHandler
*/ */
public function render($request, Exception $exception) public function render($request, Exception $exception)
{ {
$connections = Container::getInstance()->make(Connection::class);
// If we are currently wrapped up inside a transaction, we will roll all the way
// back to the beginning. This needs to happen, otherwise session data does not
// get properly persisted.
//
// This is kind of a hack, and ideally things like this should be handled as
// much as possible at the code level, but there are a lot of spots that do a
// ton of actions and were written before this bug discovery was made.
//
// @see https://github.com/pterodactyl/panel/pull/1468
if ($connections->transactionLevel()) {
$connections->rollBack(0);
}
// Because of some breaking change snuck into a Laravel update that didn't get caught
// by any of the tests, exceptions implementing the HttpExceptionInterface get marked
// as being HttpExceptions, but aren't actually implementing the HttpException abstract.
//
// This is incredibly annoying because we can't just temporarily override the handler to
// allow these (at least without taking on a high maintenance cost). Laravel 5.8 fixes this,
// so when we update (or have updated) this code can be removed.
//
// @see https://github.com/laravel/framework/pull/25975
// @todo remove this code when upgrading to Laravel 5.8
if ($exception instanceof HttpExceptionInterface && ! $exception instanceof HttpException) {
$exception = new HttpException(
$exception->getStatusCode(),
$exception->getMessage(),
$exception,
$exception->getHeaders(),
$exception->getCode()
);
}
return parent::render($request, $exception); return parent::render($request, $exception);
} }

View file

@ -2,19 +2,28 @@
namespace Pterodactyl\Exceptions\Repository; namespace Pterodactyl\Exceptions\Repository;
class RecordNotFoundException extends RepositoryException use Illuminate\Http\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class RecordNotFoundException extends RepositoryException implements HttpExceptionInterface
{ {
/** /**
* Handle request to render this exception to a user. Returns the default * Returns the status code.
* 404 page view.
* *
* @param \Illuminate\Http\Request $request * @return int
* @return \Illuminate\Http\Response
*/ */
public function render($request) public function getStatusCode()
{ {
if (! config('app.debug')) { return Response::HTTP_NOT_FOUND;
return response()->view('errors.404', [], 404); }
}
/**
* Returns response headers.
*
* @return array
*/
public function getHeaders()
{
return [];
} }
} }

View file

@ -24,6 +24,7 @@ use Pterodactyl\Services\Allocations\AssignmentService;
use Pterodactyl\Services\Helpers\SoftwareVersionService; use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest; use Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Node\AllocationFormRequest; use Pterodactyl\Http\Requests\Admin\Node\AllocationFormRequest;
use Pterodactyl\Services\Allocations\AllocationDeletionService; use Pterodactyl\Services\Allocations\AllocationDeletionService;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
@ -32,6 +33,11 @@ use Pterodactyl\Http\Requests\Admin\Node\AllocationAliasFormRequest;
class NodesController extends Controller class NodesController extends Controller
{ {
/**
* @var \Pterodactyl\Services\Allocations\AllocationDeletionService
*/
protected $allocationDeletionService;
/** /**
* @var \Prologue\Alerts\AlertsMessageBag * @var \Prologue\Alerts\AlertsMessageBag
*/ */
@ -72,6 +78,11 @@ class NodesController extends Controller
*/ */
protected $repository; protected $repository;
/**
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
*/
protected $serverRepository;
/** /**
* @var \Pterodactyl\Services\Nodes\NodeUpdateService * @var \Pterodactyl\Services\Nodes\NodeUpdateService
*/ */
@ -81,10 +92,6 @@ class NodesController extends Controller
* @var \Pterodactyl\Services\Helpers\SoftwareVersionService * @var \Pterodactyl\Services\Helpers\SoftwareVersionService
*/ */
protected $versionService; protected $versionService;
/**
* @var \Pterodactyl\Services\Allocations\AllocationDeletionService
*/
private $allocationDeletionService;
/** /**
* NodesController constructor. * NodesController constructor.
@ -98,6 +105,7 @@ class NodesController extends Controller
* @param \Pterodactyl\Services\Nodes\NodeDeletionService $deletionService * @param \Pterodactyl\Services\Nodes\NodeDeletionService $deletionService
* @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $locationRepository * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $locationRepository
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository * @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $serverRepository
* @param \Pterodactyl\Services\Nodes\NodeUpdateService $updateService * @param \Pterodactyl\Services\Nodes\NodeUpdateService $updateService
* @param \Pterodactyl\Services\Helpers\SoftwareVersionService $versionService * @param \Pterodactyl\Services\Helpers\SoftwareVersionService $versionService
*/ */
@ -111,6 +119,7 @@ class NodesController extends Controller
NodeDeletionService $deletionService, NodeDeletionService $deletionService,
LocationRepositoryInterface $locationRepository, LocationRepositoryInterface $locationRepository,
NodeRepositoryInterface $repository, NodeRepositoryInterface $repository,
ServerRepositoryInterface $serverRepository,
NodeUpdateService $updateService, NodeUpdateService $updateService,
SoftwareVersionService $versionService SoftwareVersionService $versionService
) { ) {
@ -123,6 +132,7 @@ class NodesController extends Controller
$this->deletionService = $deletionService; $this->deletionService = $deletionService;
$this->locationRepository = $locationRepository; $this->locationRepository = $locationRepository;
$this->repository = $repository; $this->repository = $repository;
$this->serverRepository = $serverRepository;
$this->updateService = $updateService; $this->updateService = $updateService;
$this->versionService = $versionService; $this->versionService = $versionService;
} }
@ -178,8 +188,6 @@ class NodesController extends Controller
* *
* @param \Pterodactyl\Models\Node $node * @param \Pterodactyl\Models\Node $node
* @return \Illuminate\View\View * @return \Illuminate\View\View
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function viewIndex(Node $node) public function viewIndex(Node $node)
{ {
@ -235,19 +243,17 @@ class NodesController extends Controller
/** /**
* Shows the server listing page for a specific node. * Shows the server listing page for a specific node.
* *
* @param int $node * @param \Pterodactyl\Models\Node $node
* @return \Illuminate\View\View * @return \Illuminate\View\View
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function viewServers($node) public function viewServers(Node $node)
{ {
$node = $this->repository->getNodeServers($node); $servers = $this->serverRepository->loadAllServersForNode($node->id, 25);
Javascript::put([ Javascript::put([
'node' => collect($node->makeVisible('daemonSecret'))->only(['scheme', 'fqdn', 'daemonListen', 'daemonSecret']), 'node' => collect($node->makeVisible('daemonSecret'))->only(['scheme', 'fqdn', 'daemonListen', 'daemonSecret']),
]); ]);
return view('admin.nodes.view.servers', ['node' => $node]); return view('admin.nodes.view.servers', ['node' => $node, 'servers' => $servers]);
} }
/** /**

View file

@ -5,10 +5,14 @@ namespace Pterodactyl\Http\Controllers\Daemon;
use Cache; use Cache;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Illuminate\Http\Response;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Events\Server\Installed as ServerInstalled; use Pterodactyl\Events\Server\Installed as ServerInstalled;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher; use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
class ActionController extends Controller class ActionController extends Controller
{ {
@ -16,15 +20,21 @@ class ActionController extends Controller
* @var \Illuminate\Contracts\Events\Dispatcher * @var \Illuminate\Contracts\Events\Dispatcher
*/ */
private $eventDispatcher; private $eventDispatcher;
/**
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
*/
private $repository;
/** /**
* ActionController constructor. * ActionController constructor.
* *
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
* @param \Illuminate\Contracts\Events\Dispatcher $eventDispatcher * @param \Illuminate\Contracts\Events\Dispatcher $eventDispatcher
*/ */
public function __construct(EventDispatcher $eventDispatcher) public function __construct(ServerRepository $repository, EventDispatcher $eventDispatcher)
{ {
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->repository = $repository;
} }
/** /**
@ -32,34 +42,47 @@ class ActionController extends Controller
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function markInstall(Request $request) public function markInstall(Request $request): JsonResponse
{ {
$server = Server::where('uuid', $request->input('server'))->with('node')->first(); try {
if (! $server) { /** @var \Pterodactyl\Models\Server $server */
return response()->json([ $server = $this->repository->findFirstWhere([
'uuid' => $request->input('server'),
]);
} catch (RecordNotFoundException $exception) {
return JsonResponse::create([
'error' => 'No server by that ID was found on the system.', 'error' => 'No server by that ID was found on the system.',
], 422); ], Response::HTTP_UNPROCESSABLE_ENTITY);
}
if (! $server->relationLoaded('node')) {
$server->load('node');
} }
$hmac = $request->input('signed'); $hmac = $request->input('signed');
$status = $request->input('installed'); $status = $request->input('installed');
if (! hash_equals(base64_decode($hmac), hash_hmac('sha256', $server->uuid, $server->node->daemonSecret, true))) { if (! hash_equals(base64_decode($hmac), hash_hmac('sha256', $server->uuid, $server->getRelation('node')->daemonSecret, true))) {
return response()->json([ return JsonResponse::create([
'error' => 'Signed HMAC was invalid.', 'error' => 'Signed HMAC was invalid.',
], 403); ], Response::HTTP_FORBIDDEN);
} }
$server->installed = ($status === 'installed') ? 1 : 2; $this->repository->update($server->id, [
$server->save(); 'installed' => ($status === 'installed') ? 1 : 2,
], true, true);
// Only fire event if server installed successfully. // Only fire event if server installed successfully.
if ($server->installed === 1) { if ($status === 'installed') {
$this->eventDispatcher->dispatch(new ServerInstalled($server)); $this->eventDispatcher->dispatch(new ServerInstalled($server));
} }
return response()->json([]); // Don't use a 204 here, the daemon is hard-checking for a 200 code.
return JsonResponse::create([]);
} }
/** /**

View file

@ -2,6 +2,8 @@
namespace Pterodactyl\Http\Requests\Admin\Servers\Databases; namespace Pterodactyl\Http\Requests\Admin\Servers\Databases;
use Illuminate\Validation\Rule;
use Illuminate\Database\Query\Builder;
use Pterodactyl\Http\Requests\Admin\AdminFormRequest; use Pterodactyl\Http\Requests\Admin\AdminFormRequest;
class StoreServerDatabaseRequest extends AdminFormRequest class StoreServerDatabaseRequest extends AdminFormRequest
@ -14,7 +16,15 @@ class StoreServerDatabaseRequest extends AdminFormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'database' => 'required|string|min:1|max:24', '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);
}),
],
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/', 'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
'database_host_id' => 'required|integer|exists:database_hosts,id', 'database_host_id' => 'required|integer|exists:database_hosts,id',
]; ];

View file

@ -30,6 +30,6 @@ class UpdateLocationRequest extends StoreLocationRequest
return collect(Location::getUpdateRulesForId($locationId))->only([ return collect(Location::getUpdateRulesForId($locationId))->only([
'short', 'short',
'long', 'long',
]); ])->toArray();
} }
} }

View file

@ -36,7 +36,7 @@ class StoreNodeRequest extends ApplicationApiRequest
'memory', 'memory',
'memory_overallocate', 'memory_overallocate',
'disk', 'disk',
'disk_overallocation', 'disk_overallocate',
'upload_size', 'upload_size',
'daemonListen', 'daemonListen',
'daemonSFTP', 'daemonSFTP',

View file

@ -2,6 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases;
use Illuminate\Validation\Rule;
use Illuminate\Database\Query\Builder;
use Pterodactyl\Services\Acl\Api\AdminAcl; use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
@ -25,7 +27,15 @@ class StoreServerDatabaseRequest extends ApplicationApiRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'database' => 'required|string|min:1|max:24', 'database' => [
'required',
'string',
'min:1',
'max:24',
Rule::unique('databases')->where(function (Builder $query) {
$query->where('database_host_id', $this->input('host') ?? 0);
}),
],
'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/', 'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/',
'host' => 'required|integer|exists:database_hosts,id', 'host' => 'required|integer|exists:database_hosts,id',
]; ];

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers; namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Support\Collection;
class UpdateServerBuildConfigurationRequest extends ServerWriteRequest class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
{ {
@ -17,15 +18,29 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
return [ return [
'allocation' => $rules['allocation_id'], 'allocation' => $rules['allocation_id'],
'memory' => $rules['memory'],
'swap' => $rules['swap'], 'limits' => 'sometimes|array',
'io' => $rules['io'], 'limits.memory' => $this->requiredToOptional('memory', $rules['memory'], true),
'cpu' => $rules['cpu'], 'limits.swap' => $this->requiredToOptional('swap', $rules['swap'], true),
'disk' => $rules['disk'], 'limits.io' => $this->requiredToOptional('io', $rules['io'], true),
'limits.cpu' => $this->requiredToOptional('cpu', $rules['cpu'], true),
'limits.disk' => $this->requiredToOptional('disk', $rules['disk'], true),
// Legacy rules to maintain backwards compatable API support without requiring
// a major version bump.
//
// @see https://github.com/pterodactyl/panel/issues/1500
'memory' => $this->requiredToOptional('memory', $rules['memory']),
'swap' => $this->requiredToOptional('swap', $rules['swap']),
'io' => $this->requiredToOptional('io', $rules['io']),
'cpu' => $this->requiredToOptional('cpu', $rules['cpu']),
'disk' => $this->requiredToOptional('disk', $rules['disk']),
'add_allocations' => 'bail|array', 'add_allocations' => 'bail|array',
'add_allocations.*' => 'integer', 'add_allocations.*' => 'integer',
'remove_allocations' => 'bail|array', 'remove_allocations' => 'bail|array',
'remove_allocations.*' => 'integer', 'remove_allocations.*' => 'integer',
'feature_limits' => 'required|array', 'feature_limits' => 'required|array',
'feature_limits.databases' => $rules['database_limit'], 'feature_limits.databases' => $rules['database_limit'],
'feature_limits.allocations' => $rules['allocation_limit'], 'feature_limits.allocations' => $rules['allocation_limit'],
@ -46,6 +61,15 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
$data['allocation_limit'] = $data['feature_limits']['allocations']; $data['allocation_limit'] = $data['feature_limits']['allocations'];
unset($data['allocation'], $data['feature_limits']); unset($data['allocation'], $data['feature_limits']);
// Adjust the limits field to match what is expected by the model.
if (! empty($data['limits'])) {
foreach ($data['limits'] as $key => $value) {
$data[$key] = $value;
}
unset($data['limits']);
}
return $data; return $data;
} }
@ -65,4 +89,30 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
'feature_limits.allocations' => 'Allocation Limit', 'feature_limits.allocations' => 'Allocation Limit',
]; ];
} }
/**
* Converts existing rules for certain limits into a format that maintains backwards
* compatability with the old API endpoint while also supporting a more correct API
* call.
*
* @param string $field
* @param array $rules
* @param bool $limits
* @return array
*
* @see https://github.com/pterodactyl/panel/issues/1500
*/
protected function requiredToOptional(string $field, array $rules, bool $limits = false)
{
if (! in_array('required', $rules)) {
return $rules;
}
return (new Collection($rules))
->filter(function ($value) {
return $value !== 'required';
})
->prepend($limits ? 'required_with:limits' : 'required_without:limits')
->toArray();
}
} }

View file

@ -63,7 +63,7 @@ class Server extends Model implements CleansAttributes, ValidableContract
'image' => 'required', 'image' => 'required',
'startup' => 'required', 'startup' => 'required',
'database_limit' => 'present', 'database_limit' => 'present',
'allocation_limit' => 'present', 'allocation_limit' => 'sometimes',
]; ];
/** /**
@ -87,7 +87,7 @@ class Server extends Model implements CleansAttributes, ValidableContract
'startup' => 'string', 'startup' => 'string',
'skip_scripts' => 'boolean', 'skip_scripts' => 'boolean',
'image' => 'string|max:255', 'image' => 'string|max:255',
'installed' => 'boolean', 'installed' => 'in:0,1,2',
'database_limit' => 'nullable|integer|min:0', 'database_limit' => 'nullable|integer|min:0',
'allocation_limit' => 'nullable|integer|min:0', 'allocation_limit' => 'nullable|integer|min:0',
]; ];

View file

@ -6,10 +6,8 @@ use Generator;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Concerns\Searchable; use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
class NodeRepository extends EloquentRepository implements NodeRepositoryInterface class NodeRepository extends EloquentRepository implements NodeRepositoryInterface
{ {
@ -140,25 +138,6 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
return $node; return $node;
} }
/**
* Return a node with all of the servers attached to that node.
*
* @param int $id
* @return \Pterodactyl\Models\Node
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getNodeServers(int $id): Node
{
try {
return $this->getBuilder()->with([
'servers.user', 'servers.nest', 'servers.egg',
])->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
}
/** /**
* Return a collection of nodes for all locations to use in server creation UI. * Return a collection of nodes for all locations to use in server creation UI.
* *

View file

@ -2,6 +2,7 @@
namespace Pterodactyl\Repositories\Eloquent; namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
@ -338,4 +339,20 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
{ {
return $this->getBuilder()->where('suspended', true)->count(); return $this->getBuilder()->where('suspended', true)->count();
} }
/**
* Returns all of the servers that exist for a given node in a paginated response.
*
* @param int $node
* @param int $limit
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function loadAllServersForNode(int $node, int $limit): LengthAwarePaginator
{
return $this->getBuilder()
->with(['user', 'nest', 'egg'])
->where('node_id', '=', $node)
->paginate($limit);
}
} }

View file

@ -2,5 +2,4 @@ coverage:
status: status:
project: off project: off
patch: off patch: off
comment: comment: false
layout: "diff"

View file

@ -21,7 +21,7 @@
"doctrine/dbal": "^2.5", "doctrine/dbal": "^2.5",
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"guzzlehttp/guzzle": "^6.3", "guzzlehttp/guzzle": "^6.3",
"hashids/hashids": "^2.0", "hashids/hashids": "^3.0",
"igaster/laravel-theme": "^2.0.6", "igaster/laravel-theme": "^2.0.6",
"laracasts/utilities": "^3.0", "laracasts/utilities": "^3.0",
"laravel/framework": "~5.7.14", "laravel/framework": "~5.7.14",
@ -37,8 +37,8 @@
"sofa/eloquence-base": "v5.6.2", "sofa/eloquence-base": "v5.6.2",
"sofa/eloquence-validable": "v5.6", "sofa/eloquence-validable": "v5.6",
"spatie/laravel-fractal": "^5.4", "spatie/laravel-fractal": "^5.4",
"webmozart/assert": "^1.2", "staudenmeir/belongs-to-through": "~2.3.0",
"znck/belongs-to-through": "^2.3" "webmozart/assert": "^1.2"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.2", "barryvdh/laravel-debugbar": "^3.2",

106
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "17de367358e9573d913860f1b446e9a7", "content-hash": "2079d9e659d2f26492c9931277bd1f25",
"packages": [ "packages": [
{ {
"name": "appstract/laravel-blade-directives", "name": "appstract/laravel-blade-directives",
@ -2958,6 +2958,58 @@
], ],
"time": "2018-09-28T16:17:34+00:00" "time": "2018-09-28T16:17:34+00:00"
}, },
{
"name": "staudenmeir/belongs-to-through",
"version": "v2.3.2",
"source": {
"type": "git",
"url": "https://github.com/staudenmeir/belongs-to-through.git",
"reference": "2ba1ff76353058d2b4d395e725617d97fd103ab0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/staudenmeir/belongs-to-through/zipball/2ba1ff76353058d2b4d395e725617d97fd103ab0",
"reference": "2ba1ff76353058d2b4d395e725617d97fd103ab0",
"shasum": ""
},
"require": {
"illuminate/database": "~5.0"
},
"require-dev": {
"fabpot/php-cs-fixer": "^1.11",
"orchestra/testbench": "~3.0",
"phpunit/php-code-coverage": "^3.3",
"phpunit/phpunit": "~5.0",
"satooshi/php-coveralls": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Znck\\Eloquent\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rahul Kadyan",
"email": "hi@znck.me"
}
],
"description": "Adds belongsToThrough relation to laravel models",
"homepage": "https://github.com/staudenmeir/belongs-to-through",
"keywords": [
"belongsToThrough",
"eloquent",
"laravel",
"model",
"models",
"znck"
],
"time": "2019-02-01T14:33:18+00:00"
},
{ {
"name": "swiftmailer/swiftmailer", "name": "swiftmailer/swiftmailer",
"version": "v6.1.3", "version": "v6.1.3",
@ -4143,58 +4195,6 @@
"validate" "validate"
], ],
"time": "2018-01-29T19:49:41+00:00" "time": "2018-01-29T19:49:41+00:00"
},
{
"name": "znck/belongs-to-through",
"version": "v2.3.1",
"source": {
"type": "git",
"url": "https://github.com/znck/belongs-to-through.git",
"reference": "8ac53e9134072902a8d3f3e18c327d4a8fd70d3d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/znck/belongs-to-through/zipball/8ac53e9134072902a8d3f3e18c327d4a8fd70d3d",
"reference": "8ac53e9134072902a8d3f3e18c327d4a8fd70d3d",
"shasum": ""
},
"require": {
"illuminate/database": "~5.0"
},
"require-dev": {
"fabpot/php-cs-fixer": "^1.11",
"orchestra/testbench": "~3.0",
"phpunit/php-code-coverage": "^3.3",
"phpunit/phpunit": "~5.0",
"satooshi/php-coveralls": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Znck\\Eloquent\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rahul Kadyan",
"email": "hi@znck.me"
}
],
"description": "Adds belongsToThrough relation to laravel models",
"homepage": "https://github.com/znck/belongs-to-through",
"keywords": [
"belongsToThrough",
"eloquent",
"laravel",
"model",
"models",
"znck"
],
"time": "2017-07-23T13:11:16+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [

View file

@ -9,7 +9,7 @@ return [
| change this value if you are not maintaining your own internal versions. | change this value if you are not maintaining your own internal versions.
*/ */
'version' => '0.7.12', 'version' => '0.7.13',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class SetAllocationLimitDefaultNull extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('servers', function (Blueprint $table) {
$table->unsignedInteger('allocation_limit')->nullable()->default(null)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('servers', function (Blueprint $table) {
$table->unsignedInteger('allocation_limit')->nullable()->default(0)->change();
});
}
}

View file

@ -0,0 +1,40 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class FixUniqueIndexToAccountForHost extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('databases', function (Blueprint $table) {
$table->dropUnique(['database']);
$table->dropUnique(['username']);
$table->unique(['database_host_id', 'database']);
$table->unique(['database_host_id', 'username']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('databases', function (Blueprint $table) {
$table->dropUnique(['database_host_id', 'database']);
$table->dropUnique(['database_host_id', 'username']);
$table->unique(['database']);
$table->unique(['username']);
});
}
}

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\n# Bungeecord Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\ncd \/mnt\/server\n\nif [ -z \"${BUNGEE_VERSION}\" ] || [ \"${BUNGEE_VERSION}\" == \"latest\" ]; then\n BUNGEE_VERSION=\"lastStableBuild\"\nfi\n\ncurl -o ${SERVER_JARFILE} https:\/\/ci.md-5.net\/job\/BungeeCord\/${BUNGEE_VERSION}\/artifact\/bootstrap\/target\/BungeeCord.jar", "script": "#!\/bin\/ash\n# Bungeecord Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\ncd \/mnt\/server\n\nif [ -z \"${BUNGEE_VERSION}\" ] || [ \"${BUNGEE_VERSION}\" == \"latest\" ]; then\n BUNGEE_VERSION=\"lastStableBuild\"\nfi\n\ncurl -o ${SERVER_JARFILE} https:\/\/ci.md-5.net\/job\/BungeeCord\/${BUNGEE_VERSION}\/artifact\/bootstrap\/target\/BungeeCord.jar",
"container": "alpine:3.4", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -3,7 +3,7 @@
"meta": { "meta": {
"version": "PTDL_v1" "version": "PTDL_v1"
}, },
"exported_at": "2018-06-25T15:47:07-04:00", "exported_at": "2019-02-07T07:47:35-05:00",
"name": "Forge Minecraft", "name": "Forge Minecraft",
"author": "support@pterodactyl.io", "author": "support@pterodactyl.io",
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.", "description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
@ -17,7 +17,7 @@
}, },
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl\r\n\r\nif [ -z \"$MC_VERSION\" ] || [ \"$MC_VERSION\" == \"latest\" ]; then\r\n FORGE_VERSION=$(curl -sl https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9]\\?\\.\\?[0-9]\\?[0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\?[0-9]\\.[0-9][0-9][0-9][0-9]' | sed 's\/ \/\/g')\r\nelse\r\n FORGE_VERSION=$(curl -sl https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/index_$MC_VERSION.html | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9]\\?\\.\\?[0-9]\\?[0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\?[0-9]\\.[0-9][0-9][0-9][0-9]' | sed 's\/ \/\/g')\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"\\nDownloading Forge Version $FORGE_VERSION\\n\"\r\ncurl -sS https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$FORGE_VERSION\/forge-$FORGE_VERSION-installer.jar -o installer.jar\r\ncurl -sS https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$FORGE_VERSION\/forge-$FORGE_VERSION-universal.jar -o $SERVER_JARFILE\r\n\r\necho -e \"\\nInstalling forge server usint the installer jar file.\\n\"\r\njava -jar installer.jar --installServer\r\n\r\necho -e \"\\nDeleting installer jar file and cleaning up.\\n\"\r\nrm -rf installer.jar", "script": "#!\/bin\/ash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl\r\n\r\nif [ -z \"$MC_VERSION\" ] || [ \"$MC_VERSION\" == \"latest\" ]; then\r\n FORGE_VERSION=$(echo $(curl -sSl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A2 Latest | grep small) | grep -o -e '[1].[0-9]*.[0-9]* - [0-9]*.[0-9]*.[0-9]*.[0-9]*' | sed 's\/ \/\/g')\r\nelse\r\n FORGE_VERSION=$(echo $(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/index_$MC_VERSION.html | grep -A2 Latest | grep small) | grep -o -e '[1].[0-9]*.[0-9]* - [0-9]*.[0-9]*.[0-9]*.[0-9]*' | sed 's\/ \/\/g')\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"\\nDownloading Forge Version $FORGE_VERSION\\n\"\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$FORGE_VERSION\/forge-$FORGE_VERSION-installer.jar -o installer.jar\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$FORGE_VERSION\/forge-$FORGE_VERSION-universal.jar -o $SERVER_JARFILE\r\n\r\necho -e \"\\nInstalling forge server usint the installer jar file.\\n\"\r\njava -jar installer.jar --installServer\r\n\r\necho -e \"\\nDeleting installer jar file and cleaning up.\\n\"\r\nrm -rf installer.jar",
"container": "openjdk:8-alpine", "container": "openjdk:8-alpine",
"entrypoint": "ash" "entrypoint": "ash"
} }

View file

@ -0,0 +1,63 @@
{
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
"meta": {
"version": "PTDL_v1"
},
"exported_at": "2019-02-27T22:23:55-05:00",
"name": "Paper",
"author": "parker@pterodactyl.io",
"description": "High performance Spigot fork that aims to fix gameplay and mechanics inconsistencies.",
"image": "quay.io\/pterodactyl\/core:java",
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \",\r\n \"userInteraction\": [\r\n \"Go to eula.txt for more info.\"\r\n ]\r\n}",
"logs": "{}",
"stop": "stop"
},
"scripts": {
"installation": {
"script": "#!\/bin\/ash\r\n# Paper Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk add --no-cache --update curl jq\r\n\r\nif [ -n \"${DL_PATH}\" ]; then\r\n echo -e \"using supplied download url\"\r\n DOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's\/{{\/${\/g' -e 's\/}}\/}\/g')`\r\nelse\r\n VER_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r --arg VERSION $MINECRAFT_VERSION '.versions[] | IN($VERSION)' | grep true`\r\n LATEST_PAPER_VERSION=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r '.versions' | jq -r '.[0]'`\r\n \r\n if [ \"${VER_EXISTS}\" == \"true\" ]; then\r\n echo -e \"Version is valid. Using version ${MINECRAFT_VERSION}\"\r\n else\r\n echo -e \"Using the latest paper version\"\r\n MINECRAFT_VERSION=${LATEST_PAPER_VERSION}\r\n fi\r\n \r\n BUILD_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds.all[] | IN($BUILD)' | grep true`\r\n LATEST_PAPER_BUILD=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r '.builds.latest'`\r\n \r\n if [ \"${BUILD_EXISTS}\" == \"true\" ] || [ ${BUILD_NUMBER} == \"latest\" ]; then\r\n echo -e \"Build is valid. Using version ${BUILD_NUMBER}\"\r\n else\r\n echo -e \"Using the latest paper build\"\r\n BUILD_NUMBER=${LATEST_PAPER_BUILD}\r\n fi\r\n \r\n echo \"Version being downloaded\"\r\n echo -e \"MC Version: ${MINECRAFT_VERSION}\"\r\n echo -e \"Build: ${BUILD_NUMBER}\"\r\n DOWNLOAD_URL=https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION}\/${BUILD_NUMBER}\/download \r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\r\n\r\ncurl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\r\n\r\necho -e \"Downloading MC server.properties\"\r\ncurl -o server.properties https:\/\/raw.githubusercontent.com\/parkervcp\/eggs\/master\/minecraft_java\/server.properties",
"container": "alpine:3.9",
"entrypoint": "ash"
}
},
"variables": [
{
"name": "Minecraft Version",
"description": "The version of minecraft to download. \r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.",
"env_variable": "MINECRAFT_VERSION",
"default_value": "latest",
"user_viewable": 1,
"user_editable": 0,
"rules": "nullable|string|max:20"
},
{
"name": "Server Jar File",
"description": "The name of the server jarfile to run the server with.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|string|max:20"
},
{
"name": "Download Path",
"description": "A URL to use to download a server.jar rather than the ones in the install script. This is not user viewable.",
"env_variable": "DL_PATH",
"default_value": "",
"user_viewable": 0,
"user_editable": 0,
"rules": "nullable|string"
},
{
"name": "Build Number",
"description": "The build number for the paper release.\r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.",
"env_variable": "BUILD_NUMBER",
"default_value": "latest",
"user_viewable": 1,
"user_editable": 0,
"rules": "required|string|max:20"
}
]
}

View file

@ -1,54 +0,0 @@
{
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
"meta": {
"version": "PTDL_v1"
},
"exported_at": "2018-11-16T02:14:51-05:00",
"name": "Spigot",
"author": "support@pterodactyl.io",
"description": "Spigot is the most widely-used modded Minecraft server software in the world. It powers many of the top Minecraft server networks around to ensure they can cope with their huge player base and ensure the satisfaction of their players. Spigot works by reducing and eliminating many causes of lag, as well as adding in handy features and settings that help make your job of server administration easier.",
"image": "quay.io\/pterodactyl\/core:java-glibc",
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"enable-query\": \"true\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \",\r\n \"userInteraction\": [\r\n \"Go to eula.txt for more info.\"\r\n ]\r\n}",
"logs": "{\r\n \"custom\": false,\r\n \"location\": \"logs\/latest.log\"\r\n}",
"stop": "stop"
},
"scripts": {
"installation": {
"script": "#!\/bin\/ash\r\n# Spigot Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\n## Only download if a path is provided, otherwise continue.\r\nif [ ! -z \"${DL_PATH}\" ]; then\r\n apk update\r\n apk add curl\r\n\r\n cd \/mnt\/server\r\n\r\n MODIFIED_DOWNLOAD=`eval echo $(echo ${DL_PATH} | sed -e 's\/{{\/${\/g' -e 's\/}}\/}\/g')`\r\n curl -sSL -o ${SERVER_JARFILE} ${MODIFIED_DOWNLOAD}\r\nelse\r\n apk add --no-cache curl git openjdk8 openssl bash\r\n \r\n cd \/srv\/\r\n \r\n wget https:\/\/hub.spigotmc.org\/jenkins\/job\/BuildTools\/lastSuccessfulBuild\/artifact\/target\/BuildTools.jar\r\n \r\n mv BuildTools.jar \/srv\/\r\n\r\n java -jar BuildTools.jar --rev ${DL_VERSION}\r\n\r\n mv spigot-*.jar \/mnt\/server\/${SERVER_JARFILE}\r\nfi",
"container": "alpine:3.7",
"entrypoint": "ash"
}
},
"variables": [
{
"name": "Server Jar File",
"description": "The name of the server jarfile to run the server with.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
},
{
"name": "Spigot Version",
"description": "The version of Spigot to download (using the --rev tag). Use \"latest\" for latest.",
"env_variable": "DL_VERSION",
"default_value": "latest",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|string|between:3,7"
},
{
"name": "Download Path",
"description": "A URL to use to download Spigot rather than building it on the server. This is not user viewable. Use <code>{{DL_VERSION}}<\/code> in the URL to automatically insert the assigned version into the URL. If you do not enter a URL Spigot will build directly in the container (this will fail on low memory containers).",
"env_variable": "DL_PATH",
"default_value": "",
"user_viewable": 0,
"user_editable": 0,
"rules": "nullable|string"
}
]
}

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\n# Sponge Installation Script\n#\n# Server Files: \/mnt\/server\n\napk update\napk add curl\n\ncd \/mnt\/server\n\ncurl -sSL \"https:\/\/repo.spongepowered.org\/maven\/org\/spongepowered\/spongevanilla\/${SPONGE_VERSION}\/spongevanilla-${SPONGE_VERSION}.jar\" -o ${SERVER_JARFILE}", "script": "#!\/bin\/ash\n# Sponge Installation Script\n#\n# Server Files: \/mnt\/server\n\napk update\napk add curl\n\ncd \/mnt\/server\n\ncurl -sSL \"https:\/\/repo.spongepowered.org\/maven\/org\/spongepowered\/spongevanilla\/${SPONGE_VERSION}\/spongevanilla-${SPONGE_VERSION}.jar\" -o ${SERVER_JARFILE}",
"container": "alpine:3.4", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\r\n# Vanilla MC Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl jq\r\n\r\ncd \/mnt\/server\r\n\r\nLATEST_VERSION=`curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq -r '.latest.release'`\r\n\r\nif [ -z \"$VANILLA_VERSION\" ] || [ \"$VANILLA_VERSION\" == \"latest\" ]; then\r\n MANIFEST_URL=$(curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq .versions | jq -r '.[] | select(.id == \"'$LATEST_VERSION'\") | .url')\r\nelse\r\n MANIFEST_URL=$(curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq .versions | jq -r '.[] | select(.id == \"'$VANILLA_VERSION'\") | .url')\r\nfi\r\n\r\nDOWNLOAD_URL=`curl $MANIFEST_URL | jq .downloads.server | jq -r '. | .url'`\r\n\r\ncurl -o ${SERVER_JARFILE} $DOWNLOAD_URL", "script": "#!\/bin\/ash\r\n# Vanilla MC Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl jq\r\n\r\ncd \/mnt\/server\r\n\r\nLATEST_VERSION=`curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq -r '.latest.release'`\r\n\r\nif [ -z \"$VANILLA_VERSION\" ] || [ \"$VANILLA_VERSION\" == \"latest\" ]; then\r\n MANIFEST_URL=$(curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq .versions | jq -r '.[] | select(.id == \"'$LATEST_VERSION'\") | .url')\r\nelse\r\n MANIFEST_URL=$(curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq .versions | jq -r '.[] | select(.id == \"'$VANILLA_VERSION'\") | .url')\r\nfi\r\n\r\nDOWNLOAD_URL=`curl $MANIFEST_URL | jq .downloads.server | jq -r '. | .url'`\r\n\r\ncurl -o ${SERVER_JARFILE} $DOWNLOAD_URL",
"container": "alpine:3.7", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -3,7 +3,7 @@
"meta": { "meta": {
"version": "PTDL_v1" "version": "PTDL_v1"
}, },
"exported_at": "2018-07-06T11:27:32+02:00", "exported_at": "2019-02-13T12:30:54-05:00",
"name": "Ark: Survival Evolved", "name": "Ark: Survival Evolved",
"author": "support@pterodactyl.io", "author": "support@pterodactyl.io",
"description": "As a man or woman stranded, naked, freezing, and starving on the unforgiving shores of a mysterious island called ARK, use your skill and cunning to kill or tame and ride the plethora of leviathan dinosaurs and other primeval creatures roaming the land. Hunt, harvest resources, craft items, grow crops, research technologies, and build shelters to withstand the elements and store valuables, all while teaming up with (or preying upon) hundreds of other players to survive, dominate... and escape! \u2014 Gamepedia: ARK", "description": "As a man or woman stranded, naked, freezing, and starving on the unforgiving shores of a mysterious island called ARK, use your skill and cunning to kill or tame and ride the plethora of leviathan dinosaurs and other primeval creatures roaming the land. Hunt, harvest resources, craft items, grow crops, research technologies, and build shelters to withstand the elements and store valuables, all while teaming up with (or preying upon) hundreds of other players to survive, dominate... and escape! \u2014 Gamepedia: ARK",
@ -11,7 +11,7 @@
"startup": ".\/ShooterGame\/Binaries\/Linux\/ShooterGameServer {{SERVER_MAP}}?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}", "startup": ".\/ShooterGame\/Binaries\/Linux\/ShooterGameServer {{SERVER_MAP}}?listen?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}",
"config": { "config": {
"files": "{}", "files": "{}",
"startup": "{\r\n \"done\": \"gameserver Steam ID\",\r\n \"userInteraction\": []\r\n}", "startup": "{\r\n \"done\": \"Setting breakpad minidump AppID = 346110\",\r\n \"userInteraction\": []\r\n}",
"logs": "{\r\n \"custom\": true,\r\n \"location\": \"logs\/latest.log\"\r\n}", "logs": "{\r\n \"custom\": true,\r\n \"location\": \"logs\/latest.log\"\r\n}",
"stop": "quit" "stop": "quit"
}, },

View file

@ -3,12 +3,12 @@
"meta": { "meta": {
"version": "PTDL_v1" "version": "PTDL_v1"
}, },
"exported_at": "2018-06-19T07:46:27-04:00", "exported_at": "2019-02-16T14:20:52-05:00",
"name": "Garrys Mod", "name": "Garrys Mod",
"author": "support@pterodactyl.io", "author": "support@pterodactyl.io",
"description": "Garrys Mod, is a sandbox physics game created by Garry Newman, and developed by his company, Facepunch Studios.", "description": "Garrys Mod, is a sandbox physics game created by Garry Newman, and developed by his company, Facepunch Studios.",
"image": "quay.io\/pterodactyl\/core:source", "image": "quay.io\/pterodactyl\/core:source",
"startup": ".\/srcds_run -game garrysmod -console -port {{SERVER_PORT}} +ip 0.0.0.0 +map {{SRCDS_MAP}} -strictportbind -norestart +sv_setsteamaccount {{STEAM_ACC}}", "startup": ".\/srcds_run -game garrysmod -console -port {{SERVER_PORT}} +ip 0.0.0.0 +map {{SRCDS_MAP}} +gamemode {{GAMEMODE}} -strictportbind -norestart +sv_setsteamaccount {{STEAM_ACC}} +host_workshop_collection {{WORKSHOP_ID}} +maxplayers {{MAX_PLAYERS}} -tickrate {{TICKRATE}}",
"config": { "config": {
"files": "{}", "files": "{}",
"startup": "{\r\n \"done\": \"gameserver Steam ID\",\r\n \"userInteraction\": []\r\n}", "startup": "{\r\n \"done\": \"gameserver Steam ID\",\r\n \"userInteraction\": []\r\n}",
@ -17,7 +17,7 @@
}, },
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/bash\n# Garry's Mod Installation Script\n#\n# Server Files: \/mnt\/server\napt -y update\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\n\ncd \/tmp\ncurl -sSL -o steamcmd.tar.gz http:\/\/media.steampowered.com\/installer\/steamcmd_linux.tar.gz\n\nmkdir -p \/mnt\/server\/steamcmd\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\ncd \/mnt\/server\/steamcmd\n\n# SteamCMD fails otherwise for some reason, even running as root.\n# This is changed at the end of the install process anyways.\nchown -R root:root \/mnt\n\nexport HOME=\/mnt\/server\n.\/steamcmd.sh +login anonymous +force_install_dir \/mnt\/server +app_update 4020 +quit\n\nmkdir -p \/mnt\/server\/.steam\/sdk32\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so", "script": "#!\/bin\/bash\r\n# Garry's Mod Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\ncd \/tmp\r\ncurl -sSL -o steamcmd.tar.gz http:\/\/media.steampowered.com\/installer\/steamcmd_linux.tar.gz\r\n\r\nmkdir -p \/mnt\/server\/steamcmd\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\n\r\nexport HOME=\/mnt\/server\r\n.\/steamcmd.sh +login anonymous +force_install_dir \/mnt\/server +app_update 4020 +quit\r\n\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n# Creating needed default files for the game\r\ncd \/mnt\/server\/garrysmod\/lua\/autorun\/server\r\necho '\r\n-- Docs: https:\/\/wiki.garrysmod.com\/page\/resource\/AddWorkshop\r\n-- Place the ID of the workshop addon you want to be downloaded to people who join your server, not the collection ID\r\n-- Use https:\/\/beta.configcreator.com\/create\/gmod\/resources.lua to easily create a list based on your collection ID\r\n\r\nresource.AddWorkshop( \"\" )\r\n' > workshop.lua\r\n\r\ncd \/mnt\/server\/garrysmod\/cfg\r\necho '\r\n\/\/ Please do not set RCon in here, use the startup parameters.\r\n\r\nhostname\t\t\"New Gmod Server\"\r\nsv_password\t\t\"\"\r\nsv_loadingurl \"\"\r\n\r\n\/\/ Steam Server List Settings\r\nsv_region \"255\"\r\nsv_lan \"0\"\r\nsv_max_queries_sec_global \"30000\"\r\nsv_max_queries_window \"45\"\r\nsv_max_queries_sec \"5\"\r\n\r\n\/\/ Server Limits\r\nsbox_maxprops\t\t100\r\nsbox_maxragdolls\t5\r\nsbox_maxnpcs\t\t10\r\nsbox_maxballoons\t10\r\nsbox_maxeffects\t\t10\r\nsbox_maxdynamite\t10\r\nsbox_maxlamps\t\t10\r\nsbox_maxthrusters\t10\r\nsbox_maxwheels\t\t10\r\nsbox_maxhoverballs\t10\r\nsbox_maxvehicles\t20\r\nsbox_maxbuttons\t\t10\r\nsbox_maxsents\t\t20\r\nsbox_maxemitters\t5\r\nsbox_godmode\t\t0\r\nsbox_noclip\t\t 0\r\n\r\n\/\/ Network Settings - Please keep these set to default.\r\n\r\nsv_minrate\t\t75000\r\nsv_maxrate\t\t0\r\ngmod_physiterations\t2\r\nnet_splitpacket_maxrate\t45000\r\ndecalfrequency\t\t12 \r\n\r\n\/\/ Execute Ban Files - Please do not edit\r\nexec banned_ip.cfg \r\nexec banned_user.cfg \r\n\r\n\/\/ Add custom lines under here\r\n' > server.cfg",
"container": "ubuntu:16.04", "container": "ubuntu:16.04",
"entrypoint": "bash" "entrypoint": "bash"
} }
@ -39,7 +39,7 @@
"default_value": "", "default_value": "",
"user_viewable": 1, "user_viewable": 1,
"user_editable": 1, "user_editable": 1,
"rules": "required|string|alpha_num|size:32" "rules": "nullable|string|alpha_num|size:32"
}, },
{ {
"name": "Source AppID", "name": "Source AppID",
@ -49,6 +49,42 @@
"user_viewable": 0, "user_viewable": 0,
"user_editable": 0, "user_editable": 0,
"rules": "required|string|max:20" "rules": "required|string|max:20"
},
{
"name": "Workshop ID",
"description": "The ID of your workshop collection (the numbers at the end of the URL)",
"env_variable": "WORKSHOP_ID",
"default_value": "",
"user_viewable": 1,
"user_editable": 1,
"rules": "nullable|integer"
},
{
"name": "Gamemode",
"description": "The gamemode of your server.",
"env_variable": "GAMEMODE",
"default_value": "sandbox",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|string"
},
{
"name": "Max Players",
"description": "The maximum amount of players allowed on your game server.",
"env_variable": "MAX_PLAYERS",
"default_value": "32",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|integer|max:128"
},
{
"name": "Tickrate",
"description": "The tickrate defines how fast the server will update each entities location.",
"env_variable": "TICKRATE",
"default_value": "22",
"user_viewable": 1,
"user_editable": 1,
"rules": "required|integer|max:100"
} }
] ]
} }

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\n# TShock Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl unzip\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/NyxStudios\/TShock\/releases\/download\/v${T_VERSION}\/tshock_${T_VERSION}.zip\n\nunzip -o tshock_${T_VERSION}.zip -d \/mnt\/server", "script": "#!\/bin\/ash\n# TShock Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl unzip\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/NyxStudios\/TShock\/releases\/download\/v${T_VERSION}\/tshock_${T_VERSION}.zip\n\nunzip -o tshock_${T_VERSION}.zip -d \/mnt\/server",
"container": "alpine:3.4", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\n# Mumble Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/mumble-voip\/mumble\/releases\/download\/${MUMBLE_VERSION}\/murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\n\ntar -xjvf murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\ncp -r murmur-static_x86-${MUMBLE_VERSION}\/* \/mnt\/server", "script": "#!\/bin\/ash\n# Mumble Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/mumble-voip\/mumble\/releases\/download\/${MUMBLE_VERSION}\/murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\n\ntar -xjvf murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\ncp -r murmur-static_x86-${MUMBLE_VERSION}\/* \/mnt\/server",
"container": "alpine:3.4", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -18,7 +18,7 @@
"scripts": { "scripts": {
"installation": { "installation": {
"script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/mnt\/server\n\ncurl http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar xj --strip-components=1", "script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/mnt\/server\n\ncurl http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar xj --strip-components=1",
"container": "alpine:3.4", "container": "alpine:3.9",
"entrypoint": "ash" "entrypoint": "ash"
} }
}, },

View file

@ -51,7 +51,7 @@
<th class="text-center">CPU</th> <th class="text-center">CPU</th>
<th class="text-center">Status</th> <th class="text-center">Status</th>
</tr> </tr>
@foreach($node->servers as $server) @foreach($servers as $server)
<tr data-server="{{ $server->uuid }}"> <tr data-server="{{ $server->uuid }}">
<td><code>{{ $server->uuidShort }}</code></td> <td><code>{{ $server->uuidShort }}</code></td>
<td><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></td> <td><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></td>
@ -64,6 +64,11 @@
</tr> </tr>
@endforeach @endforeach
</table> </table>
@if($servers->hasPages())
<div class="box-footer with-border">
<div class="col-md-12 text-center">{!! $servers->render() !!}</div>
</div>
@endif
</div> </div>
</div> </div>
</div> </div>

View file

@ -108,7 +108,7 @@
</div> </div>
<div class="box-footer"> <div class="box-footer">
{!! csrf_field() !!} {!! csrf_field() !!}
<p class="text-muted small">You are currently using <strong>{{ count($databases) }}</strong> of <strong>{{ $server->database_limit ?? '&infin;' }}</strong> databases. A username and password for this database will be randomly generated after form submission.</p> <p class="text-muted small">You are currently using <strong>{{ count($databases) }}</strong> of <strong>{{ $server->database_limit ?? '' }}</strong> databases. A username and password for this database will be randomly generated after form submission.</p>
<input type="submit" class="btn btn-sm btn-success pull-right" value="Create Database" /> <input type="submit" class="btn btn-sm btn-success pull-right" value="Create Database" />
</div> </div>
</form> </form>

0
storage/app/packs/.githold Normal file → Executable file
View file

0
storage/framework/cache/data/.gitignore vendored Normal file → Executable file
View file