Merge branch 'develop' into develop
This commit is contained in:
commit
665a4dd8a4
115 changed files with 3434 additions and 1970 deletions
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Nest;
|
||||
use Pterodactyl\Models\Mount;
|
||||
|
@ -101,7 +102,6 @@ class MountController extends Controller
|
|||
*/
|
||||
public function create(MountFormRequest $request)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\Mount $mount */
|
||||
$model = (new Mount())->fill($request->validated());
|
||||
$model->forceFill(['uuid' => Uuid::uuid4()->toString()]);
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@ use Illuminate\Http\Request;
|
|||
use Pterodactyl\Models\Server;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Models\Filters\AdminServerFilter;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
|
||||
class ServerController extends Controller
|
||||
|
@ -45,8 +47,10 @@ class ServerController extends Controller
|
|||
public function index(Request $request)
|
||||
{
|
||||
$servers = QueryBuilder::for(Server::query()->with('node', 'user', 'allocation'))
|
||||
->allowedFilters(['uuid', 'name', 'image'])
|
||||
->allowedSorts(['id', 'uuid'])
|
||||
->allowedFilters([
|
||||
AllowedFilter::exact('owner_id'),
|
||||
AllowedFilter::custom('*', new AdminServerFilter),
|
||||
])
|
||||
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
|
||||
|
||||
return $this->view->make('admin.servers.index', ['servers' => $servers]);
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace Pterodactyl\Http\Controllers\Api\Client;
|
|||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Pterodactyl\Models\Filters\MultiFieldServerFilter;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
|
||||
use Pterodactyl\Http\Requests\Api\Client\GetServersRequest;
|
||||
|
@ -43,21 +45,32 @@ class ClientController extends ClientApiController
|
|||
// Start the query builder and ensure we eager load any requested relationships from the request.
|
||||
$builder = QueryBuilder::for(
|
||||
Server::query()->with($this->getIncludesForTransformer($transformer, ['node']))
|
||||
)->allowedFilters('uuid', 'name', 'external_id');
|
||||
)->allowedFilters([
|
||||
'uuid',
|
||||
'name',
|
||||
'external_id',
|
||||
AllowedFilter::custom('*', new MultiFieldServerFilter),
|
||||
]);
|
||||
|
||||
$type = $request->input('type');
|
||||
// Either return all of the servers the user has access to because they are an admin `?type=admin` or
|
||||
// just return all of the servers the user has access to because they are the owner or a subuser of the
|
||||
// server.
|
||||
if ($request->input('type') === 'admin') {
|
||||
$builder = $user->root_admin
|
||||
? $builder->whereNotIn('id', $user->accessibleServers()->pluck('id')->all())
|
||||
// If they aren't an admin but want all the admin servers don't fail the request, just
|
||||
// make it a query that will never return any results back.
|
||||
: $builder->whereRaw('1 = 2');
|
||||
} elseif ($request->input('type') === 'owner') {
|
||||
$builder = $builder->where('owner_id', $user->id);
|
||||
// server. If ?type=admin-all is passed all servers on the system will be returned to the user, rather
|
||||
// than only servers they can see because they are an admin.
|
||||
if (in_array($type, ['admin', 'admin-all'])) {
|
||||
// If they aren't an admin but want all the admin servers don't fail the request, just
|
||||
// make it a query that will never return any results back.
|
||||
if (! $user->root_admin) {
|
||||
$builder->whereRaw('1 = 2');
|
||||
} else {
|
||||
$builder = $type === 'admin-all'
|
||||
? $builder
|
||||
: $builder->whereNotIn('servers.id', $user->accessibleServers()->pluck('id')->all());
|
||||
}
|
||||
} else if ($type === 'owner') {
|
||||
$builder = $builder->where('servers.owner_id', $user->id);
|
||||
} else {
|
||||
$builder = $builder->whereIn('id', $user->accessibleServers()->pluck('id')->all());
|
||||
$builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all());
|
||||
}
|
||||
|
||||
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
|
||||
|
|
|
@ -10,15 +10,19 @@ use Pterodactyl\Models\Server;
|
|||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Helpers\Utilities;
|
||||
use Pterodactyl\Jobs\Schedule\RunTaskJob;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
|
||||
use Pterodactyl\Services\Schedules\ProcessScheduleService;
|
||||
use Pterodactyl\Transformers\Api\Client\ScheduleTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\ViewScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\DeleteScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\UpdateScheduleRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest;
|
||||
|
||||
class ScheduleController extends ClientApiController
|
||||
{
|
||||
|
@ -27,16 +31,23 @@ class ScheduleController extends ClientApiController
|
|||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
|
||||
*/
|
||||
private $service;
|
||||
|
||||
/**
|
||||
* ScheduleController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ScheduleRepository $repository
|
||||
* @param \Pterodactyl\Services\Schedules\ProcessScheduleService $service
|
||||
*/
|
||||
public function __construct(ScheduleRepository $repository)
|
||||
public function __construct(ScheduleRepository $repository, ProcessScheduleService $service)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,6 +158,30 @@ class ScheduleController extends ClientApiController
|
|||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given schedule immediately rather than waiting on it's normally scheduled time
|
||||
* to pass. This does not care about the schedule state.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function execute(TriggerScheduleRequest $request, Server $server, Schedule $schedule)
|
||||
{
|
||||
if (!$schedule->is_active) {
|
||||
throw new BadRequestHttpException(
|
||||
'Cannot trigger schedule exection for a schedule that is not currently active.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->service->handle($schedule, true);
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a schedule and it's associated tasks.
|
||||
*
|
||||
|
|
|
@ -56,7 +56,8 @@ class ScheduleTaskController extends ClientApiController
|
|||
);
|
||||
}
|
||||
|
||||
$lastTask = $schedule->tasks->last();
|
||||
/** @var \Pterodactyl\Models\Task|null $lastTask */
|
||||
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
|
||||
|
||||
/** @var \Pterodactyl\Models\Task $task */
|
||||
$task = $this->repository->create([
|
||||
|
@ -102,13 +103,16 @@ class ScheduleTaskController extends ClientApiController
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if a user can delete the task for a given server.
|
||||
* Delete a given task for a schedule. If there are subsequent tasks stored in the database
|
||||
* for this schedule their sequence IDs are decremented properly.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\ClientApiRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @param \Pterodactyl\Models\Schedule $schedule
|
||||
* @param \Pterodactyl\Models\Task $task
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(ClientApiRequest $request, Server $server, Schedule $schedule, Task $task)
|
||||
{
|
||||
|
@ -120,8 +124,12 @@ class ScheduleTaskController extends ClientApiController
|
|||
throw new HttpForbiddenException('You do not have permission to perform this action.');
|
||||
}
|
||||
|
||||
$this->repository->delete($task->id);
|
||||
$schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([
|
||||
'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'),
|
||||
]);
|
||||
|
||||
return JsonResponse::create(null, Response::HTTP_NO_CONTENT);
|
||||
$task->delete();
|
||||
|
||||
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
use Pterodactyl\Services\Eggs\EggConfigurationService;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Http\Resources\Wings\ServerConfigurationCollection;
|
||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||
|
||||
class ServerDetailsController extends Controller
|
||||
|
@ -27,11 +30,6 @@ class ServerDetailsController extends Controller
|
|||
*/
|
||||
private $configurationStructureService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
|
||||
*/
|
||||
private $nodeRepository;
|
||||
|
||||
/**
|
||||
* ServerConfigurationController constructor.
|
||||
*
|
||||
|
@ -49,7 +47,6 @@ class ServerDetailsController extends Controller
|
|||
$this->eggConfigurationService = $eggConfigurationService;
|
||||
$this->repository = $repository;
|
||||
$this->configurationStructureService = $configurationStructureService;
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +63,7 @@ class ServerDetailsController extends Controller
|
|||
{
|
||||
$server = $this->repository->getByUuid($uuid);
|
||||
|
||||
return JsonResponse::create([
|
||||
return new JsonResponse([
|
||||
'settings' => $this->configurationStructureService->handle($server),
|
||||
'process_configuration' => $this->eggConfigurationService->handle($server),
|
||||
]);
|
||||
|
@ -76,25 +73,19 @@ class ServerDetailsController extends Controller
|
|||
* Lists all servers with their configurations that are assigned to the requesting node.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @return \Pterodactyl\Http\Resources\Wings\ServerConfigurationCollection
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\Node $node */
|
||||
$node = $request->attributes->get('node');
|
||||
$servers = $this->repository->loadEveryServerForNode($node->id);
|
||||
|
||||
$configurations = [];
|
||||
// Avoid run-away N+1 SQL queries by pre-loading the relationships that are used
|
||||
// within each of the services called below.
|
||||
$servers = Server::query()->with('allocations', 'egg', 'mounts', 'variables', 'location')
|
||||
->where('node_id', $node->id)
|
||||
->paginate($request->input('per_page', 50));
|
||||
|
||||
foreach ($servers as $server) {
|
||||
$configurations[$server->uuid] = [
|
||||
'settings' => $this->configurationStructureService->handle($server),
|
||||
'process_configuration' => $this->eggConfigurationService->handle($server),
|
||||
];
|
||||
}
|
||||
|
||||
return JsonResponse::create($configurations);
|
||||
return new ServerConfigurationCollection($servers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
namespace Pterodactyl\Http\Controllers\Auth;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Auth\AuthManager;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Pterodactyl\Http\Requests\Auth\LoginCheckpointRequest;
|
||||
use Illuminate\Contracts\Cache\Repository as CacheRepository;
|
||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||
|
@ -80,29 +82,31 @@ class LoginCheckpointController extends AbstractLoginController
|
|||
* @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException
|
||||
* @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Exception
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function __invoke(LoginCheckpointRequest $request): JsonResponse
|
||||
{
|
||||
$token = $request->input('confirmation_token');
|
||||
$recoveryToken = $request->input('recovery_token');
|
||||
|
||||
try {
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = $this->repository->find($this->cache->get($token, 0));
|
||||
} catch (RecordNotFoundException $exception) {
|
||||
return $this->sendFailedLoginResponse($request, null, 'The authentication token provided has expired, please refresh the page and try again.');
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
$this->sendLockoutResponse($request);
|
||||
}
|
||||
|
||||
// If we got a recovery token try to find one that matches for the user and then continue
|
||||
// through the process (and delete the token).
|
||||
if (! is_null($recoveryToken)) {
|
||||
foreach ($user->recoveryTokens as $token) {
|
||||
if (password_verify($recoveryToken, $token->token)) {
|
||||
$this->recoveryTokenRepository->delete($token->id);
|
||||
$token = $request->input('confirmation_token');
|
||||
try {
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = User::query()->findOrFail($this->cache->get($token, 0));
|
||||
} catch (ModelNotFoundException $exception) {
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
return $this->sendLoginResponse($user, $request);
|
||||
}
|
||||
return $this->sendFailedLoginResponse(
|
||||
$request, null, 'The authentication token provided has expired, please refresh the page and try again.'
|
||||
);
|
||||
}
|
||||
|
||||
// Recovery tokens go through a slightly different pathway for usage.
|
||||
if (! is_null($recoveryToken = $request->input('recovery_token'))) {
|
||||
if ($this->isValidRecoveryToken($user, $recoveryToken)) {
|
||||
return $this->sendLoginResponse($user, $request);
|
||||
}
|
||||
} else {
|
||||
$decrypted = $this->encrypter->decrypt($user->totp_secret);
|
||||
|
@ -114,6 +118,31 @@ class LoginCheckpointController extends AbstractLoginController
|
|||
}
|
||||
}
|
||||
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
return $this->sendFailedLoginResponse($request, $user, ! empty($recoveryToken) ? 'The recovery token provided is not valid.' : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given recovery token is valid for the user account. If we find a matching token
|
||||
* it will be deleted from the database.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function isValidRecoveryToken(User $user, string $value)
|
||||
{
|
||||
foreach ($user->recoveryTokens as $token) {
|
||||
if (password_verify($value, $token->token)) {
|
||||
$token->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class DaemonAuthenticate
|
|||
// Ensure that all of the correct parts are provided in the header.
|
||||
if (count($parts) !== 2 || empty($parts[0]) || empty($parts[1])) {
|
||||
throw new BadRequestHttpException(
|
||||
'The Authorization headed provided was not in a valid format.'
|
||||
'The Authorization header provided was not in a valid format.'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ class StoreServerRequest extends ApplicationApiRequest
|
|||
'feature_limits' => 'required|array',
|
||||
'feature_limits.databases' => $rules['database_limit'],
|
||||
'feature_limits.allocations' => $rules['allocation_limit'],
|
||||
'feature_limits.backups' => $rules['backup_limit'],
|
||||
|
||||
// Placeholders for rules added in withValidator() function.
|
||||
'allocation.default' => '',
|
||||
|
@ -102,6 +103,7 @@ class StoreServerRequest extends ApplicationApiRequest
|
|||
'start_on_completion' => array_get($data, 'start_on_completion', false),
|
||||
'database_limit' => array_get($data, 'feature_limits.databases'),
|
||||
'allocation_limit' => array_get($data, 'feature_limits.allocations'),
|
||||
'backup_limit' => array_get($data, 'feature_limits.backups'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
|
|||
'feature_limits' => 'required|array',
|
||||
'feature_limits.databases' => $rules['database_limit'],
|
||||
'feature_limits.allocations' => $rules['allocation_limit'],
|
||||
'feature_limits.backups' => $rules['backup_limit'],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -60,8 +61,9 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
|
|||
$data = parent::validated();
|
||||
|
||||
$data['allocation_id'] = $data['allocation'];
|
||||
$data['database_limit'] = $data['feature_limits']['databases'];
|
||||
$data['allocation_limit'] = $data['feature_limits']['allocations'];
|
||||
$data['database_limit'] = $data['feature_limits']['databases'] ?? null;
|
||||
$data['allocation_limit'] = $data['feature_limits']['allocations'] ?? null;
|
||||
$data['backup_limit'] = $data['feature_limits']['backups'] ?? null;
|
||||
unset($data['allocation'], $data['feature_limits']);
|
||||
|
||||
// Adjust the limits field to match what is expected by the model.
|
||||
|
@ -90,6 +92,7 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
|
|||
'remove_allocations.*' => 'allocation to remove',
|
||||
'feature_limits.databases' => 'Database Limit',
|
||||
'feature_limits.allocations' => 'Allocation Limit',
|
||||
'feature_limits.backups' => 'Backup Limit',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Schedules;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class TriggerScheduleRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return Permission::ACTION_SCHEDULE_UPDATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
35
app/Http/Resources/Wings/ServerConfigurationCollection.php
Normal file
35
app/Http/Resources/Wings/ServerConfigurationCollection.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Resources\Wings;
|
||||
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
use Pterodactyl\Services\Eggs\EggConfigurationService;
|
||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||
|
||||
class ServerConfigurationCollection extends ResourceCollection
|
||||
{
|
||||
/**
|
||||
* Converts a collection of Server models into an array of configuration responses
|
||||
* that can be understood by Wings. Make sure you've properly loaded the required
|
||||
* relationships on the Server models before calling this function, otherwise you'll
|
||||
* have some serious performance issues from all of the N+1 queries.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$egg = Container::getInstance()->make(EggConfigurationService::class);
|
||||
$configuration = Container::getInstance()->make(ServerConfigurationStructureService::class);
|
||||
|
||||
return $this->collection->map(function (Server $server) use ($configuration, $egg) {
|
||||
return [
|
||||
'uuid' => $server->uuid,
|
||||
'settings' => $configuration->handle($server),
|
||||
'process_configuration' => $egg->handle($server),
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue