From 8afced34108395317b83b3ac1b6f5189b28375bb Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 27 Jan 2018 12:38:56 -0600 Subject: [PATCH] Add nests & eggs Cleanup middleware handling and parameters on controllers... --- .../Serializers/PterodactylSerializer.php | 72 +++++++++ .../Spatie/Fractalistic/Fractal.php | 4 +- .../Locations/LocationController.php | 49 +++--- .../Api/Application/Nests/EggController.php | 61 +++++++ .../Api/Application/Nests/NestController.php | 57 +++++++ .../Nodes/AllocationController.php | 62 +++++--- .../Api/Application/Nodes/NodeController.php | 52 +++--- .../Servers/DatabaseController.php | 36 ++--- .../Application/Servers/ServerController.php | 5 +- .../Servers/ServerDetailsController.php | 18 ++- .../Servers/ServerManagementController.php | 27 ++-- .../Api/Application/Users/UserController.php | 49 ++---- .../Middleware/Api/ApiSubstituteBindings.php | 36 +++++ ...pplication => DeleteAllocationRequest.php} | 0 .../Allocations/StoreAllocationRequest.php | 46 ++++++ .../Api/Application/ApplicationApiRequest.php | 21 +++ .../Application/Nests/Eggs/GetEggRequest.php | 29 ++++ .../Application/Nests/Eggs/GetEggsRequest.php | 19 +++ .../Api/Application/Nests/GetNestsRequest.php | 19 +++ .../Api/Application/EggTransformer.php | 150 ++++++++++++++++++ .../Api/Application/NestTransformer.php | 63 ++++++++ .../Api/Application/OptionTransformer.php | 116 -------------- .../Application/ServerDatabaseTransformer.php | 1 - .../Api/Application/ServiceTransformer.php | 101 ------------ .../ServiceVariableTransformer.php | 69 -------- routes/api-application.php | 21 +++ 26 files changed, 737 insertions(+), 446 deletions(-) create mode 100644 app/Extensions/League/Fractal/Serializers/PterodactylSerializer.php create mode 100644 app/Http/Controllers/Api/Application/Nests/EggController.php create mode 100644 app/Http/Controllers/Api/Application/Nests/NestController.php rename app/Http/Requests/Api/Application/Allocations/{DeleteAllocationRequest.phpApplication => DeleteAllocationRequest.php} (100%) create mode 100644 app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php create mode 100644 app/Http/Requests/Api/Application/Nests/Eggs/GetEggRequest.php create mode 100644 app/Http/Requests/Api/Application/Nests/Eggs/GetEggsRequest.php create mode 100644 app/Http/Requests/Api/Application/Nests/GetNestsRequest.php create mode 100644 app/Transformers/Api/Application/EggTransformer.php create mode 100644 app/Transformers/Api/Application/NestTransformer.php delete mode 100644 app/Transformers/Api/Application/OptionTransformer.php delete mode 100644 app/Transformers/Api/Application/ServiceTransformer.php delete mode 100644 app/Transformers/Api/Application/ServiceVariableTransformer.php diff --git a/app/Extensions/League/Fractal/Serializers/PterodactylSerializer.php b/app/Extensions/League/Fractal/Serializers/PterodactylSerializer.php new file mode 100644 index 000000000..9599ca2c9 --- /dev/null +++ b/app/Extensions/League/Fractal/Serializers/PterodactylSerializer.php @@ -0,0 +1,72 @@ + $resourceKey, + 'attributes' => $data, + ]; + } + + /** + * Serialize a collection. + * + * @param string $resourceKey + * @param array $data + * @return array + */ + public function collection($resourceKey, array $data) + { + $response = []; + foreach ($data as $datum) { + $response[] = $this->item($resourceKey, $datum); + } + + return [ + 'object' => 'list', + 'data' => $response, + ]; + } + + /** + * Serialize a null resource. + * + * @return array + */ + public function null() + { + return [ + 'object' => 'null_resource', + 'attributes' => null, + ]; + } + + /** + * Merge the included resources with the parent resource being serialized. + * + * @param array $transformedData + * @param array $includedData + * @return array + */ + public function mergeIncludes($transformedData, $includedData) + { + foreach ($includedData as $key => $datum) { + $transformedData['relationships'][$key] = $datum; + } + + return $transformedData; + } +} diff --git a/app/Extensions/Spatie/Fractalistic/Fractal.php b/app/Extensions/Spatie/Fractalistic/Fractal.php index 35a8b8f3b..5bb0dd52b 100644 --- a/app/Extensions/Spatie/Fractalistic/Fractal.php +++ b/app/Extensions/Spatie/Fractalistic/Fractal.php @@ -4,9 +4,9 @@ namespace Pterodactyl\Extensions\Spatie\Fractalistic; use League\Fractal\TransformerAbstract; use Spatie\Fractal\Fractal as SpatieFractal; -use League\Fractal\Serializer\JsonApiSerializer; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use League\Fractal\Pagination\IlluminatePaginatorAdapter; +use Pterodactyl\Extensions\League\Fractal\Serializers\PterodactylSerializer; class Fractal extends SpatieFractal { @@ -22,7 +22,7 @@ class Fractal extends SpatieFractal { // Set the serializer by default. if (is_null($this->serializer)) { - $this->serializer = new JsonApiSerializer; + $this->serializer = new PterodactylSerializer; } // Automatically set the paginator on the response object if the diff --git a/app/Http/Controllers/Api/Application/Locations/LocationController.php b/app/Http/Controllers/Api/Application/Locations/LocationController.php index 5af4c0782..42bb2a08c 100644 --- a/app/Http/Controllers/Api/Application/Locations/LocationController.php +++ b/app/Http/Controllers/Api/Application/Locations/LocationController.php @@ -2,22 +2,20 @@ namespace Pterodactyl\Http\Controllers\Api\Application\Locations; -use Spatie\Fractal\Fractal; use Illuminate\Http\Response; use Pterodactyl\Models\Location; use Illuminate\Http\JsonResponse; -use Pterodactyl\Http\Controllers\Controller; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; use Pterodactyl\Services\Locations\LocationUpdateService; use Pterodactyl\Services\Locations\LocationCreationService; use Pterodactyl\Services\Locations\LocationDeletionService; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Transformers\Api\Application\LocationTransformer; +use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; use Pterodactyl\Http\Requests\Api\Application\Locations\GetLocationsRequest; use Pterodactyl\Http\Requests\Api\Application\Locations\DeleteLocationRequest; use Pterodactyl\Http\Requests\Api\Application\Locations\UpdateLocationRequest; -class LocationController extends Controller +class LocationController extends ApplicationApiController { /** * @var \Pterodactyl\Services\Locations\LocationCreationService @@ -29,11 +27,6 @@ class LocationController extends Controller */ private $deletionService; - /** - * @var \Spatie\Fractal\Fractal - */ - private $fractal; - /** * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface */ @@ -47,22 +40,21 @@ class LocationController extends Controller /** * LocationController constructor. * - * @param \Spatie\Fractal\Fractal $fractal * @param \Pterodactyl\Services\Locations\LocationCreationService $creationService * @param \Pterodactyl\Services\Locations\LocationDeletionService $deletionService * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository * @param \Pterodactyl\Services\Locations\LocationUpdateService $updateService */ public function __construct( - Fractal $fractal, LocationCreationService $creationService, LocationDeletionService $deletionService, LocationRepositoryInterface $repository, LocationUpdateService $updateService ) { + parent::__construct(); + $this->creationService = $creationService; $this->deletionService = $deletionService; - $this->fractal = $fractal; $this->repository = $repository; $this->updateService = $updateService; } @@ -78,9 +70,7 @@ class LocationController extends Controller $locations = $this->repository->paginated(100); return $this->fractal->collection($locations) - ->transformWith((new LocationTransformer)->setKey($request->key())) - ->withResourceName('location') - ->paginateWith(new IlluminatePaginatorAdapter($locations)) + ->transformWith($this->getTransformer(LocationTransformer::class)) ->toArray(); } @@ -88,14 +78,12 @@ class LocationController extends Controller * Return a single location. * * @param \Pterodactyl\Http\Controllers\Api\Application\Locations\GetLocationRequest $request - * @param \Pterodactyl\Models\Location $location * @return array */ - public function view(GetLocationRequest $request, Location $location): array + public function view(GetLocationRequest $request): array { - return $this->fractal->item($location) - ->transformWith((new LocationTransformer)->setKey($request->key())) - ->withResourceName('location') + return $this->fractal->item($request->getModel(Location::class)) + ->transformWith($this->getTransformer(LocationTransformer::class)) ->toArray(); } @@ -113,8 +101,12 @@ class LocationController extends Controller $location = $this->creationService->handle($request->validated()); return $this->fractal->item($location) - ->transformWith((new LocationTransformer)->setKey($request->key())) - ->withResourceName('location') + ->transformWith($this->getTransformer(LocationTransformer::class)) + ->addMeta([ + 'resource' => route('api.application.locations.view', [ + 'location' => $location->id, + ]), + ]) ->respond(201); } @@ -122,19 +114,17 @@ class LocationController extends Controller * Update a location on the Panel and return the updated record to the user. * * @param \Pterodactyl\Http\Requests\Api\Application\Locations\UpdateLocationRequest $request - * @param \Pterodactyl\Models\Location $location * @return array * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function update(UpdateLocationRequest $request, Location $location): array + public function update(UpdateLocationRequest $request): array { - $location = $this->updateService->handle($location, $request->validated()); + $location = $this->updateService->handle($request->getModel(Location::class), $request->validated()); return $this->fractal->item($location) - ->transformWith((new LocationTransformer)->setKey($request->key())) - ->withResourceName('location') + ->transformWith($this->getTransformer(LocationTransformer::class)) ->toArray(); } @@ -142,14 +132,13 @@ class LocationController extends Controller * Delete a location from the Panel. * * @param \Pterodactyl\Http\Requests\Api\Application\Locations\DeleteLocationRequest $request - * @param \Pterodactyl\Models\Location $location * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Service\Location\HasActiveNodesException */ - public function delete(DeleteLocationRequest $request, Location $location): Response + public function delete(DeleteLocationRequest $request): Response { - $this->deletionService->handle($location); + $this->deletionService->handle($request->getModel(Location::class)); return response('', 204); } diff --git a/app/Http/Controllers/Api/Application/Nests/EggController.php b/app/Http/Controllers/Api/Application/Nests/EggController.php new file mode 100644 index 000000000..21ce4ec9f --- /dev/null +++ b/app/Http/Controllers/Api/Application/Nests/EggController.php @@ -0,0 +1,61 @@ +repository = $repository; + } + + /** + * Return all eggs that exist for a given nest. + * + * @param \Pterodactyl\Http\Requests\Api\Application\Nests\Eggs\GetEggsRequest $request + * @return array + */ + public function index(GetEggsRequest $request): array + { + $eggs = $this->repository->findWhere([ + ['nest_id', '=', $request->getModel(Nest::class)->id], + ]); + + return $this->fractal->collection($eggs) + ->transformWith($this->getTransformer(EggTransformer::class)) + ->toArray(); + } + + /** + * Return a single egg that exists on the specified nest. + * + * @param \Pterodactyl\Http\Requests\Api\Application\Nests\Eggs\GetEggRequest $request + * @return array + */ + public function view(GetEggRequest $request): array + { + return $this->fractal->item($request->getModel(Egg::class)) + ->transformWith($this->getTransformer(EggTransformer::class)) + ->toArray(); + } +} diff --git a/app/Http/Controllers/Api/Application/Nests/NestController.php b/app/Http/Controllers/Api/Application/Nests/NestController.php new file mode 100644 index 000000000..adeacc56c --- /dev/null +++ b/app/Http/Controllers/Api/Application/Nests/NestController.php @@ -0,0 +1,57 @@ +repository = $repository; + } + + /** + * Return all Nests that exist on the Panel. + * + * @param \Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest $request + * @return array + */ + public function index(GetNestsRequest $request): array + { + $nests = $this->repository->paginated(50); + + return $this->fractal->collection($nests) + ->transformWith($this->getTransformer(NestTransformer::class)) + ->toArray(); + } + + /** + * Return information about a single Nest model. + * + * @param \Pterodactyl\Http\Requests\Api\Application\Nests\GetNestsRequest $request + * @return array + */ + public function view(GetNestsRequest $request): array + { + return $this->fractal->item($request->getModel(Nest::class)) + ->transformWith($this->getTransformer(NestTransformer::class)) + ->toArray(); + } +} diff --git a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php index 969d4b55d..ef35e91c5 100644 --- a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php +++ b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php @@ -2,20 +2,25 @@ namespace Pterodactyl\Http\Controllers\Api\Application\Nodes; -use Spatie\Fractal\Fractal; use Pterodactyl\Models\Node; use Illuminate\Http\Response; use Pterodactyl\Models\Allocation; -use Pterodactyl\Http\Controllers\Controller; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; +use Pterodactyl\Services\Allocations\AssignmentService; use Pterodactyl\Services\Allocations\AllocationDeletionService; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; use Pterodactyl\Transformers\Api\Application\AllocationTransformer; +use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; use Pterodactyl\Http\Requests\Api\Application\Allocations\GetAllocationsRequest; -use Pterodactyl\Http\Requests\Api\Application\Allocations\DeleteAllocationRequestApplication; +use Pterodactyl\Http\Requests\Api\Application\Allocations\StoreAllocationRequest; +use Pterodactyl\Http\Requests\Api\Application\Allocations\DeleteAllocationRequest; -class AllocationController extends Controller +class AllocationController extends ApplicationApiController { + /** + * @var \Pterodactyl\Services\Allocations\AssignmentService + */ + private $assignmentService; + /** * @var \Pterodactyl\Services\Allocations\AllocationDeletionService */ @@ -34,14 +39,19 @@ class AllocationController extends Controller /** * AllocationController constructor. * + * @param \Pterodactyl\Services\Allocations\AssignmentService $assignmentService * @param \Pterodactyl\Services\Allocations\AllocationDeletionService $deletionService * @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $repository - * @param \Spatie\Fractal\Fractal $fractal */ - public function __construct(AllocationDeletionService $deletionService, AllocationRepositoryInterface $repository, Fractal $fractal) - { + public function __construct( + AssignmentService $assignmentService, + AllocationDeletionService $deletionService, + AllocationRepositoryInterface $repository + ) { + parent::__construct(); + + $this->assignmentService = $assignmentService; $this->deletionService = $deletionService; - $this->fractal = $fractal; $this->repository = $repository; } @@ -49,33 +59,45 @@ class AllocationController extends Controller * Return all of the allocations that exist for a given node. * * @param \Pterodactyl\Http\Requests\Api\Application\Allocations\GetAllocationsRequest $request - * @param \Pterodactyl\Models\Node $node * @return array */ - public function index(GetAllocationsRequest $request, Node $node): array + public function index(GetAllocationsRequest $request): array { - $allocations = $this->repository->getPaginatedAllocationsForNode($node->id, 100); + $allocations = $this->repository->getPaginatedAllocationsForNode( + $request->getModel(Node::class)->id, 50 + ); return $this->fractal->collection($allocations) - ->transformWith((new AllocationTransformer)->setKey($request->key())) - ->withResourceName('allocation') - ->paginateWith(new IlluminatePaginatorAdapter($allocations)) + ->transformWith($this->getTransformer(AllocationTransformer::class)) ->toArray(); } + /** + * Store new allocations for a given node. + * + * @param \Pterodactyl\Http\Requests\Api\Application\Allocations\StoreAllocationRequest $request + * @return array + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ + public function store(StoreAllocationRequest $request): array + { + $this->assignmentService->handle($request->getModel(Node::class), $request->validated()); + + return response('', 204); + } + /** * Delete a specific allocation from the Panel. * - * @param \Pterodactyl\Http\Requests\Api\Application\Allocations\DeleteAllocationRequestApplication $request - * @param \Pterodactyl\Models\Node $node - * @param \Pterodactyl\Models\Allocation $allocation + * @param \Pterodactyl\Http\Requests\Api\Application\Allocations\DeleteAllocationRequest $request * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Service\Allocation\ServerUsingAllocationException */ - public function delete(DeleteAllocationRequestApplication $request, Node $node, Allocation $allocation): Response + public function delete(DeleteAllocationRequest $request): Response { - $this->deletionService->handle($allocation); + $this->deletionService->handle($request->getModel(Allocation::class)); return response('', 204); } diff --git a/app/Http/Controllers/Api/Application/Nodes/NodeController.php b/app/Http/Controllers/Api/Application/Nodes/NodeController.php index cf115db96..2e1c76a5c 100644 --- a/app/Http/Controllers/Api/Application/Nodes/NodeController.php +++ b/app/Http/Controllers/Api/Application/Nodes/NodeController.php @@ -2,15 +2,12 @@ namespace Pterodactyl\Http\Controllers\Api\Application\Nodes; -use Spatie\Fractal\Fractal; use Pterodactyl\Models\Node; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; -use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Services\Nodes\NodeUpdateService; use Pterodactyl\Services\Nodes\NodeCreationService; use Pterodactyl\Services\Nodes\NodeDeletionService; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Transformers\Api\Application\NodeTransformer; use Pterodactyl\Http\Requests\Api\Application\Nodes\GetNodeRequest; @@ -18,8 +15,9 @@ use Pterodactyl\Http\Requests\Api\Application\Nodes\GetNodesRequest; use Pterodactyl\Http\Requests\Api\Application\Nodes\StoreNodeRequest; use Pterodactyl\Http\Requests\Api\Application\Nodes\DeleteNodeRequest; use Pterodactyl\Http\Requests\Api\Application\Nodes\UpdateNodeRequest; +use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; -class NodeController extends Controller +class NodeController extends ApplicationApiController { /** * @var \Pterodactyl\Services\Nodes\NodeCreationService @@ -31,11 +29,6 @@ class NodeController extends Controller */ private $deletionService; - /** - * @var \Spatie\Fractal\Fractal - */ - private $fractal; - /** * @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface */ @@ -49,20 +42,19 @@ class NodeController extends Controller /** * NodeController constructor. * - * @param \Spatie\Fractal\Fractal $fractal * @param \Pterodactyl\Services\Nodes\NodeCreationService $creationService * @param \Pterodactyl\Services\Nodes\NodeDeletionService $deletionService * @param \Pterodactyl\Services\Nodes\NodeUpdateService $updateService * @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository */ public function __construct( - Fractal $fractal, NodeCreationService $creationService, NodeDeletionService $deletionService, NodeUpdateService $updateService, NodeRepositoryInterface $repository ) { - $this->fractal = $fractal; + parent::__construct(); + $this->repository = $repository; $this->creationService = $creationService; $this->deletionService = $deletionService; @@ -77,12 +69,10 @@ class NodeController extends Controller */ public function index(GetNodesRequest $request): array { - $nodes = $this->repository->paginated(100); + $nodes = $this->repository->paginated(50); return $this->fractal->collection($nodes) - ->transformWith((new NodeTransformer)->setKey($request->key())) - ->withResourceName('node') - ->paginateWith(new IlluminatePaginatorAdapter($nodes)) + ->transformWith($this->getTransformer(NodeTransformer::class)) ->toArray(); } @@ -90,14 +80,12 @@ class NodeController extends Controller * Return data for a single instance of a node. * * @param \Pterodactyl\Http\Requests\Api\Application\Nodes\GetNodeRequest $request - * @param \Pterodactyl\Models\Node $node * @return array */ - public function view(GetNodeRequest $request, Node $node): array + public function view(GetNodeRequest $request): array { - return $this->fractal->item($node) - ->transformWith((new NodeTransformer)->setKey($request->key())) - ->withResourceName('node') + return $this->fractal->item($request->getModel(Node::class)) + ->transformWith($this->getTransformer(NodeTransformer::class)) ->toArray(); } @@ -115,10 +103,11 @@ class NodeController extends Controller $node = $this->creationService->handle($request->validated()); return $this->fractal->item($node) - ->transformWith((new NodeTransformer)->setKey($request->key())) - ->withResourceName('node') + ->transformWith($this->getTransformer(NodeTransformer::class)) ->addMeta([ - 'link' => route('api.admin.node.view', ['node' => $node->id]), + 'resource' => route('api.application.nodes.view', [ + 'node' => $node->id, + ]), ]) ->respond(201); } @@ -127,20 +116,20 @@ class NodeController extends Controller * Update an existing node on the Panel. * * @param \Pterodactyl\Http\Requests\Api\Application\Nodes\UpdateNodeRequest $request - * @param \Pterodactyl\Models\Node $node * @return array * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function update(UpdateNodeRequest $request, Node $node): array + public function update(UpdateNodeRequest $request): array { - $node = $this->updateService->returnUpdatedModel()->handle($node, $request->validated()); + $node = $this->updateService->returnUpdatedModel()->handle( + $request->getModel(Node::class), $request->validated() + ); return $this->fractal->item($node) - ->transformWith((new NodeTransformer)->setKey($request->key())) - ->withResourceName('node') + ->transformWith($this->getTransformer(NodeTransformer::class)) ->toArray(); } @@ -149,14 +138,13 @@ class NodeController extends Controller * currently attached to it. * * @param \Pterodactyl\Http\Requests\Api\Application\Nodes\DeleteNodeRequest $request - * @param \Pterodactyl\Models\Node $node * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Service\HasActiveServersException */ - public function delete(DeleteNodeRequest $request, Node $node): Response + public function delete(DeleteNodeRequest $request): Response { - $this->deletionService->handle($node); + $this->deletionService->handle($request->getModel(Node::class)); return response('', 204); } diff --git a/app/Http/Controllers/Api/Application/Servers/DatabaseController.php b/app/Http/Controllers/Api/Application/Servers/DatabaseController.php index 41d637489..05512a4ee 100644 --- a/app/Http/Controllers/Api/Application/Servers/DatabaseController.php +++ b/app/Http/Controllers/Api/Application/Servers/DatabaseController.php @@ -57,12 +57,11 @@ class DatabaseController extends ApplicationApiController * server. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\Databases\GetServerDatabasesRequest $request - * @param \Pterodactyl\Models\Server $server * @return array */ - public function index(GetServerDatabasesRequest $request, Server $server): array + public function index(GetServerDatabasesRequest $request): array { - $databases = $this->repository->getDatabasesForServer($server->id); + $databases = $this->repository->getDatabasesForServer($request->getModel(Server::class)->id); return $this->fractal->collection($databases) ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) @@ -73,13 +72,11 @@ class DatabaseController extends ApplicationApiController * Return a single server database. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\Databases\GetServerDatabaseRequest $request - * @param \Pterodactyl\Models\Server $server - * @param \Pterodactyl\Models\Database $database * @return array */ - public function view(GetServerDatabaseRequest $request, Server $server, Database $database): array + public function view(GetServerDatabaseRequest $request): array { - return $this->fractal->item($database) + return $this->fractal->item($request->getModel(Database::class)) ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) ->toArray(); } @@ -87,16 +84,15 @@ class DatabaseController extends ApplicationApiController /** * Reset the password for a specific server database. * - * @param \Pterodactyl\Models\Server $server - * @param \Pterodactyl\Models\Database $database + * @param \Pterodactyl\Http\Requests\Api\Application\Servers\Databases\ServerDatabaseWriteRequest $request * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function resetPassword(ServerDatabaseWriteRequest $request, Server $server, Database $database): Response + public function resetPassword(ServerDatabaseWriteRequest $request): Response { - $this->databasePasswordService->handle($database, str_random(24)); + $this->databasePasswordService->handle($request->getModel(Database::class), str_random(24)); return response('', 204); } @@ -105,35 +101,39 @@ class DatabaseController extends ApplicationApiController * Create a new database on the Panel for a given server. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\Databases\StoreServerDatabaseRequest $request - * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\JsonResponse * * @throws \Exception * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException */ - public function store(StoreServerDatabaseRequest $request, Server $server): JsonResponse + public function store(StoreServerDatabaseRequest $request): JsonResponse { + $server = $request->getModel(Server::class); $database = $this->databaseManagementService->create($server->id, $request->validated()); return $this->fractal->item($database) ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) + ->addMeta([ + 'resource' => route('api.application.servers.databases.view', [ + 'server' => $server->id, + 'database' => $database->id, + ]), + ]) ->respond(201); } /** - * Delete a specific database from the Panel. + * Handle a request to delete a specific server database from the Panel. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\Databases\ServerDatabaseWriteRequest $request - * @param \Pterodactyl\Models\Server $server - * @param \Pterodactyl\Models\Database $database * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function delete(ServerDatabaseWriteRequest $request, Server $server, Database $database): Response + public function delete(ServerDatabaseWriteRequest $request): Response { - $this->databaseManagementService->delete($database->id); + $this->databaseManagementService->delete($request->getModel(Database::class)->id); return response('', 204); } diff --git a/app/Http/Controllers/Api/Application/Servers/ServerController.php b/app/Http/Controllers/Api/Application/Servers/ServerController.php index 98d90f284..9d9a7474f 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerController.php @@ -56,12 +56,11 @@ class ServerController extends ApplicationApiController * Show a single server transformed for the application API. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request - * @param \Pterodactyl\Models\Server $server * @return array */ - public function view(ServerWriteRequest $request, Server $server): array + public function view(ServerWriteRequest $request): array { - return $this->fractal->item($server) + return $this->fractal->item($request->getModel(Server::class)) ->transformWith($this->getTransformer(ServerTransformer::class)) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php index 1a9cb889e..e544c138a 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php @@ -28,8 +28,10 @@ class ServerDetailsController extends ApplicationApiController * @param \Pterodactyl\Services\Servers\BuildModificationService $buildModificationService * @param \Pterodactyl\Services\Servers\DetailsModificationService $detailsModificationService */ - public function __construct(BuildModificationService $buildModificationService, DetailsModificationService $detailsModificationService) - { + public function __construct( + BuildModificationService $buildModificationService, + DetailsModificationService $detailsModificationService + ) { parent::__construct(); $this->buildModificationService = $buildModificationService; @@ -40,16 +42,17 @@ class ServerDetailsController extends ApplicationApiController * Update the details for a specific server. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\UpdateServerDetailsRequest $request - * @param \Pterodactyl\Models\Server $server * @return array * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function details(UpdateServerDetailsRequest $request, Server $server): array + public function details(UpdateServerDetailsRequest $request): array { - $server = $this->detailsModificationService->returnUpdatedModel()->handle($server, $request->validated()); + $server = $this->detailsModificationService->returnUpdatedModel()->handle( + $request->getModel(Server::class), $request->validated() + ); return $this->fractal->item($server) ->transformWith($this->getTransformer(ServerTransformer::class)) @@ -60,16 +63,15 @@ class ServerDetailsController extends ApplicationApiController * Update the build details for a specific server. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\UpdateServerBuildConfigurationRequest $request - * @param \Pterodactyl\Models\Server $server * @return array * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function build(UpdateServerBuildConfigurationRequest $request, Server $server): array + public function build(UpdateServerBuildConfigurationRequest $request): array { - $server = $this->buildModificationService->handle($server, $request->validated()); + $server = $this->buildModificationService->handle($request->getModel(Server::class), $request->validated()); return $this->fractal->item($server) ->transformWith($this->getTransformer(ServerTransformer::class)) diff --git a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php index 4379616fa..9ab324d7e 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php @@ -34,8 +34,11 @@ class ServerManagementController extends ApplicationApiController * @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallServerService * @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService */ - public function __construct(ContainerRebuildService $rebuildService, ReinstallServerService $reinstallServerService, SuspensionService $suspensionService) - { + public function __construct( + ContainerRebuildService $rebuildService, + ReinstallServerService $reinstallServerService, + SuspensionService $suspensionService + ) { parent::__construct(); $this->rebuildService = $rebuildService; @@ -47,16 +50,15 @@ class ServerManagementController extends ApplicationApiController * Suspend a server on the Panel. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request - * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function suspend(ServerWriteRequest $request, Server $server): Response + public function suspend(ServerWriteRequest $request): Response { - $this->suspensionService->toggle($server, SuspensionService::ACTION_SUSPEND); + $this->suspensionService->toggle($request->getModel(Server::class), SuspensionService::ACTION_SUSPEND); return $this->returnNoContent(); } @@ -65,16 +67,15 @@ class ServerManagementController extends ApplicationApiController * Unsuspend a server on the Panel. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request - * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function unsuspend(ServerWriteRequest $request, Server $server): Response + public function unsuspend(ServerWriteRequest $request): Response { - $this->suspensionService->toggle($server, SuspensionService::ACTION_UNSUSPEND); + $this->suspensionService->toggle($request->getModel(Server::class), SuspensionService::ACTION_UNSUSPEND); return $this->returnNoContent(); } @@ -83,16 +84,15 @@ class ServerManagementController extends ApplicationApiController * Mark a server as needing to be reinstalled. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request - * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function reinstall(ServerWriteRequest $request, Server $server): Response + public function reinstall(ServerWriteRequest $request): Response { - $this->reinstallServerService->reinstall($server); + $this->reinstallServerService->reinstall($request->getModel(Server::class)); return $this->returnNoContent(); } @@ -101,14 +101,13 @@ class ServerManagementController extends ApplicationApiController * Mark a server as needing its container rebuilt the next time it is started. * * @param \Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest $request - * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException */ - public function rebuild(ServerWriteRequest $request, Server $server): Response + public function rebuild(ServerWriteRequest $request): Response { - $this->rebuildService->handle($server); + $this->rebuildService->handle($request->getModel(Server::class)); return $this->returnNoContent(); } diff --git a/app/Http/Controllers/Api/Application/Users/UserController.php b/app/Http/Controllers/Api/Application/Users/UserController.php index 35c534536..96d8c986f 100644 --- a/app/Http/Controllers/Api/Application/Users/UserController.php +++ b/app/Http/Controllers/Api/Application/Users/UserController.php @@ -2,16 +2,12 @@ namespace Pterodactyl\Http\Controllers\Api\Application\Users; -use Spatie\Fractal\Fractal; -use Illuminate\Http\Request; use Pterodactyl\Models\User; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; -use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Services\Users\UserUpdateService; use Pterodactyl\Services\Users\UserCreationService; use Pterodactyl\Services\Users\UserDeletionService; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Transformers\Api\Application\UserTransformer; use Pterodactyl\Http\Requests\Api\Application\Users\GetUserRequest; @@ -19,8 +15,9 @@ use Pterodactyl\Http\Requests\Api\Application\Users\GetUsersRequest; use Pterodactyl\Http\Requests\Api\Application\Users\StoreUserRequest; use Pterodactyl\Http\Requests\Api\Application\Users\DeleteUserRequest; use Pterodactyl\Http\Requests\Api\Application\Users\UpdateUserRequest; +use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; -class UserController extends Controller +class UserController extends ApplicationApiController { /** * @var \Pterodactyl\Services\Users\UserCreationService @@ -32,11 +29,6 @@ class UserController extends Controller */ private $deletionService; - /** - * @var \Spatie\Fractal\Fractal - */ - private $fractal; - /** * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface */ @@ -50,22 +42,21 @@ class UserController extends Controller /** * UserController constructor. * - * @param \Spatie\Fractal\Fractal $fractal * @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository * @param \Pterodactyl\Services\Users\UserCreationService $creationService * @param \Pterodactyl\Services\Users\UserDeletionService $deletionService * @param \Pterodactyl\Services\Users\UserUpdateService $updateService */ public function __construct( - Fractal $fractal, UserRepositoryInterface $repository, UserCreationService $creationService, UserDeletionService $deletionService, UserUpdateService $updateService ) { + parent::__construct(); + $this->creationService = $creationService; $this->deletionService = $deletionService; - $this->fractal = $fractal; $this->repository = $repository; $this->updateService = $updateService; } @@ -83,9 +74,7 @@ class UserController extends Controller $users = $this->repository->paginated(100); return $this->fractal->collection($users) - ->transformWith((new UserTransformer)->setKey($request->key())) - ->withResourceName('user') - ->paginateWith(new IlluminatePaginatorAdapter($users)) + ->transformWith($this->getTransformer(UserTransformer::class)) ->toArray(); } @@ -94,14 +83,12 @@ class UserController extends Controller * were defined in the request. * * @param \Pterodactyl\Http\Requests\Api\Application\Users\GetUserRequest $request - * @param \Pterodactyl\Models\User $user * @return array */ - public function view(GetUserRequest $request, User $user): array + public function view(GetUserRequest $request): array { - return $this->fractal->item($user) - ->transformWith((new UserTransformer)->setKey($request->key())) - ->withResourceName('user') + return $this->fractal->item($request->getModel(User::class)) + ->transformWith($this->getTransformer(UserTransformer::class)) ->toArray(); } @@ -114,16 +101,15 @@ class UserController extends Controller * meta. If there are no errors this is an empty array. * * @param \Pterodactyl\Http\Requests\Api\Application\Users\UpdateUserRequest $request - * @param \Pterodactyl\Models\User $user * @return array * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ - public function update(UpdateUserRequest $request, User $user): array + public function update(UpdateUserRequest $request): array { $this->updateService->setUserLevel(User::USER_LEVEL_ADMIN); - $collection = $this->updateService->handle($user, $request->validated()); + $collection = $this->updateService->handle($request->getModel(User::class), $request->validated()); $errors = []; if (! empty($collection->get('exceptions'))) { @@ -140,8 +126,7 @@ class UserController extends Controller } $response = $this->fractal->item($collection->get('model')) - ->transformWith((new UserTransformer)->setKey($request->key())) - ->withResourceName('user'); + ->transformWith($this->getTransformer(UserTransformer::class)); if (count($errors) > 0) { $response->addMeta([ @@ -167,10 +152,11 @@ class UserController extends Controller $user = $this->creationService->handle($request->validated()); return $this->fractal->item($user) - ->transformWith((new UserTransformer)->setKey($request->key())) - ->withResourceName('user') + ->transformWith($this->getTransformer(UserTransformer::class)) ->addMeta([ - 'link' => route('api.admin.user.view', ['user' => $user->id]), + 'resource' => route('api.application.users.view', [ + 'user' => $user->id, + ]), ]) ->respond(201); } @@ -180,14 +166,13 @@ class UserController extends Controller * on successful deletion. * * @param \Pterodactyl\Http\Requests\Api\Application\Users\DeleteUserRequest $request - * @param \Pterodactyl\Models\User $user * @return \Illuminate\Http\Response * * @throws \Pterodactyl\Exceptions\DisplayException */ - public function delete(DeleteUserRequest $request, User $user): Response + public function delete(DeleteUserRequest $request): Response { - $this->deletionService->handle($user); + $this->deletionService->handle($request->getModel(User::class)); return response('', 204); } diff --git a/app/Http/Middleware/Api/ApiSubstituteBindings.php b/app/Http/Middleware/Api/ApiSubstituteBindings.php index f12cc91a1..41ca8ee70 100644 --- a/app/Http/Middleware/Api/ApiSubstituteBindings.php +++ b/app/Http/Middleware/Api/ApiSubstituteBindings.php @@ -3,11 +3,33 @@ namespace Pterodactyl\Http\Middleware\Api; use Closure; +use Pterodactyl\Models\Egg; +use Pterodactyl\Models\Nest; +use Pterodactyl\Models\Node; +use Pterodactyl\Models\Server; +use Pterodactyl\Models\Database; +use Pterodactyl\Models\Location; +use Pterodactyl\Models\Allocation; use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Database\Eloquent\ModelNotFoundException; class ApiSubstituteBindings extends SubstituteBindings { + /** + * Mappings to automatically assign route parameters to a model. + * + * @var array + */ + protected static $mappings = [ + 'allocation' => Allocation::class, + 'database' => Database::class, + 'egg' => Egg::class, + 'location' => Location::class, + 'nest' => Nest::class, + 'node' => Node::class, + 'server' => Server::class, + ]; + /** * Perform substitution of route parameters without triggering * a 404 error if a model is not found. @@ -20,6 +42,10 @@ class ApiSubstituteBindings extends SubstituteBindings { $route = $request->route(); + foreach (self::$mappings as $key => $model) { + $this->router->model($key, $model); + } + $this->router->substituteBindings($route); // Attempt to resolve bindings for this route. If one of the models @@ -35,4 +61,14 @@ class ApiSubstituteBindings extends SubstituteBindings return $next($request); } + + /** + * Return the registered mappings. + * + * @return array + */ + public static function getMappings() + { + return self::$mappings; + } } diff --git a/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.phpApplication b/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php similarity index 100% rename from app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.phpApplication rename to app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php diff --git a/app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php b/app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php new file mode 100644 index 000000000..2cf2ae004 --- /dev/null +++ b/app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php @@ -0,0 +1,46 @@ + 'required|string', + 'alias' => 'sometimes|nullable|string|max:255', + 'ports' => 'required|array', + 'ports.*' => 'string', + ]; + } + + /** + * @return array + */ + public function validated() + { + $data = parent::validated(); + + return [ + 'allocation_ip' => $data['ip'], + 'allocation_ports' => $data['ports'], + 'allocation_alias' => $data['alias'], + ]; + } +} diff --git a/app/Http/Requests/Api/Application/ApplicationApiRequest.php b/app/Http/Requests/Api/Application/ApplicationApiRequest.php index 3d110d52c..aeb03dfbe 100644 --- a/app/Http/Requests/Api/Application/ApplicationApiRequest.php +++ b/app/Http/Requests/Api/Application/ApplicationApiRequest.php @@ -3,9 +3,11 @@ namespace Pterodactyl\Http\Requests\Api\Application; use Pterodactyl\Models\ApiKey; +use Illuminate\Database\Eloquent\Model; use Pterodactyl\Services\Acl\Api\AdminAcl; use Illuminate\Foundation\Http\FormRequest; use Pterodactyl\Exceptions\PterodactylException; +use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; abstract class ApplicationApiRequest extends FormRequest @@ -73,6 +75,25 @@ abstract class ApplicationApiRequest extends FormRequest return $this->attributes->get('api_key'); } + /** + * Grab a model from the route parameters. If no model exists under + * the specified key a default response is returned. + * + * @param string $model + * @param mixed $default + * @return mixed + */ + public function getModel(string $model, $default = null) + { + $parameterKey = array_get(array_flip(ApiSubstituteBindings::getMappings()), $model); + + if (! is_null($parameterKey)) { + $model = $this->route()->parameter($parameterKey); + } + + return $model ?? $default; + } + /* * Determine if the request passes the authorization check as well * as the exists check. diff --git a/app/Http/Requests/Api/Application/Nests/Eggs/GetEggRequest.php b/app/Http/Requests/Api/Application/Nests/Eggs/GetEggRequest.php new file mode 100644 index 000000000..b3f1a08a0 --- /dev/null +++ b/app/Http/Requests/Api/Application/Nests/Eggs/GetEggRequest.php @@ -0,0 +1,29 @@ +getModel('nest')->id === $this->getModel('egg')->nest_id; + } +} diff --git a/app/Http/Requests/Api/Application/Nests/Eggs/GetEggsRequest.php b/app/Http/Requests/Api/Application/Nests/Eggs/GetEggsRequest.php new file mode 100644 index 000000000..a6aadf904 --- /dev/null +++ b/app/Http/Requests/Api/Application/Nests/Eggs/GetEggsRequest.php @@ -0,0 +1,19 @@ + $model->id, + 'uuid' => $model->uuid, + 'nest' => $model->nest_id, + 'author' => $model->author, + 'description' => $model->description, + 'docker_image' => $model->docker_image, + 'config' => [ + 'files' => json_decode($model->config_files), + 'startup' => json_decode($model->config_startup), + 'stop' => $model->config_stop, + 'logs' => json_decode($model->config_logs), + 'extends' => $model->config_from, + ], + 'startup' => $model->startup, + 'script' => [ + 'privileged' => $model->script_is_privileged, + 'install' => $model->script_install, + 'entry' => $model->script_entry, + 'container' => $model->script_container, + 'extends' => $model->copy_script_from, + ], + $model->getCreatedAtColumn() => $this->formatTimestamp($model->created_at), + $model->getUpdatedAtColumn() => $this->formatTimestamp($model->updated_at), + ]; + } + + /** + * Include the Nest relationship for the given Egg in the transformation. + * + * @param \Pterodactyl\Models\Egg $model + * @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource + */ + public function includeNest(Egg $model) + { + if (! $this->authorize(AdminAcl::RESOURCE_NESTS)) { + return $this->null(); + } + + $model->loadMissing('nest'); + + return $this->item($model->getRelation('nest'), $this->makeTransformer(NestTransformer::class), Nest::RESOURCE_NAME); + } + + /** + * Include the Servers relationship for the given Egg in the transformation. + * + * @param \Pterodactyl\Models\Egg $model + * @return \League\Fractal\Resource\Collection|\League\Fractal\Resource\NullResource + */ + public function includeServers(Egg $model) + { + if (! $this->authorize(AdminAcl::RESOURCE_SERVERS)) { + return $this->null(); + } + + $model->loadMissing('servers'); + + return $this->collection($model->getRelation('servers'), $this->makeTransformer(ServerTransformer::class), Server::RESOURCE_NAME); + } + + /** + * Include more detailed information about the configuration if this Egg is + * extending another. + * + * @param \Pterodactyl\Models\Egg $model + * @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource + */ + public function includeConfig(Egg $model) + { + if (is_null($model->config_from)) { + return $this->null(); + } + + $model->loadMissing('configFrom'); + + return $this->item($model, function (Egg $model) { + return [ + 'files' => json_decode($model->inherit_config_files), + 'startup' => json_decode($model->inherit_config_startup), + 'stop' => $model->inherit_config_stop, + 'logs' => json_decode($model->inherit_config_logs), + ]; + }); + } + + /** + * Include more detailed information about the script configuration if the + * Egg is extending another. + * + * @param \Pterodactyl\Models\Egg $model + * @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource + */ + public function includeScript(Egg $model) + { + if (is_null($model->copy_script_from)) { + return $this->null(); + } + + $model->loadMissing('scriptFrom'); + + return $this->item($model, function (Egg $model) { + return [ + 'privileged' => $model->script_is_privileged, + 'install' => $model->copy_script_install, + 'entry' => $model->copy_script_entry, + 'container' => $model->copy_script_container, + ]; + }); + } +} diff --git a/app/Transformers/Api/Application/NestTransformer.php b/app/Transformers/Api/Application/NestTransformer.php new file mode 100644 index 000000000..9517af61d --- /dev/null +++ b/app/Transformers/Api/Application/NestTransformer.php @@ -0,0 +1,63 @@ +toArray(); + + $response[$model->getUpdatedAtColumn()] = $this->formatTimestamp($model->updated_at); + $response[$model->getCreatedAtColumn()] = $this->formatTimestamp($model->created_at); + + return $response; + } + + /** + * Include the Eggs relationship on the given Nest model transformation. + * + * @param \Pterodactyl\Models\Nest $model + * @return \League\Fractal\Resource\Collection|\League\Fractal\Resource\NullResource + */ + public function includeEggs(Nest $model) + { + if (! $this->authorize(AdminAcl::RESOURCE_EGGS)) { + return $this->null(); + } + + $model->loadMissing('eggs'); + + return $this->collection($model->getRelation('eggs'), $this->makeTransformer(EggTransformer::class), Egg::RESOURCE_NAME); + } +} diff --git a/app/Transformers/Api/Application/OptionTransformer.php b/app/Transformers/Api/Application/OptionTransformer.php deleted file mode 100644 index 089f880ec..000000000 --- a/app/Transformers/Api/Application/OptionTransformer.php +++ /dev/null @@ -1,116 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Transformers\Admin; - -use Pterodactyl\Models\Egg; -use Illuminate\Http\Request; -use League\Fractal\TransformerAbstract; - -class OptionTransformer extends TransformerAbstract -{ - /** - * List of resources that can be included. - * - * @var array - */ - protected $availableIncludes = [ - 'service', - 'packs', - 'servers', - 'variables', - ]; - - /** - * The Illuminate Request object if provided. - * - * @var \Illuminate\Http\Request|bool - */ - protected $request; - - /** - * Setup request object for transformer. - * - * @param \Illuminate\Http\Request|bool $request - */ - public function __construct($request = false) - { - if (! $request instanceof Request && $request !== false) { - throw new DisplayException('Request passed to constructor must be of type Request or false.'); - } - - $this->request = $request; - } - - /** - * Return a generic transformed service option array. - * - * @return array - */ - public function transform(Egg $option) - { - return $option->toArray(); - } - - /** - * Return the parent service for this service option. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeService(Egg $option) - { - if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { - return; - } - - return $this->item($option->service, new ServiceTransformer($this->request), 'service'); - } - - /** - * Return the packs associated with this service option. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includePacks(Egg $option) - { - if ($this->request && ! $this->request->apiKeyHasPermission('pack-list')) { - return; - } - - return $this->collection($option->packs, new PackTransformer($this->request), 'pack'); - } - - /** - * Return the servers associated with this service option. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeServers(Egg $option) - { - if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { - return; - } - - return $this->collection($option->servers, new ServerTransformer($this->request), 'server'); - } - - /** - * Return the variables for this service option. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeVariables(Egg $option) - { - if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { - return; - } - - return $this->collection($option->variables, new ServiceVariableTransformer($this->request), 'variable'); - } -} diff --git a/app/Transformers/Api/Application/ServerDatabaseTransformer.php b/app/Transformers/Api/Application/ServerDatabaseTransformer.php index c374798eb..c71627296 100644 --- a/app/Transformers/Api/Application/ServerDatabaseTransformer.php +++ b/app/Transformers/Api/Application/ServerDatabaseTransformer.php @@ -75,7 +75,6 @@ class ServerDatabaseTransformer extends BaseTransformer { return $this->item($model, function (Database $model) { return [ - 'id' => $model->id, 'password' => $this->encrypter->decrypt($model->password), ]; }, 'database_password'); diff --git a/app/Transformers/Api/Application/ServiceTransformer.php b/app/Transformers/Api/Application/ServiceTransformer.php deleted file mode 100644 index 5f8497cf7..000000000 --- a/app/Transformers/Api/Application/ServiceTransformer.php +++ /dev/null @@ -1,101 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Transformers\Admin; - -use Illuminate\Http\Request; -use Pterodactyl\Models\Nest; -use League\Fractal\TransformerAbstract; - -class ServiceTransformer extends TransformerAbstract -{ - /** - * List of resources that can be included. - * - * @var array - */ - protected $availableIncludes = [ - 'options', - 'servers', - 'packs', - ]; - - /** - * The Illuminate Request object if provided. - * - * @var \Illuminate\Http\Request|bool - */ - protected $request; - - /** - * Setup request object for transformer. - * - * @param \Illuminate\Http\Request|bool $request - */ - public function __construct($request = false) - { - if (! $request instanceof Request && $request !== false) { - throw new DisplayException('Request passed to constructor must be of type Request or false.'); - } - - $this->request = $request; - } - - /** - * Return a generic transformed service array. - * - * @return array - */ - public function transform(Nest $service) - { - return $service->toArray(); - } - - /** - * Return the the service options. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeOptions(Nest $service) - { - if ($this->request && ! $this->request->apiKeyHasPermission('option-list')) { - return; - } - - return $this->collection($service->options, new OptionTransformer($this->request), 'option'); - } - - /** - * Return the servers associated with this service. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeServers(Nest $service) - { - if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { - return; - } - - return $this->collection($service->servers, new ServerTransformer($this->request), 'server'); - } - - /** - * Return the packs associated with this service. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includePacks(Nest $service) - { - if ($this->request && ! $this->request->apiKeyHasPermission('pack-list')) { - return; - } - - return $this->collection($service->packs, new PackTransformer($this->request), 'pack'); - } -} diff --git a/app/Transformers/Api/Application/ServiceVariableTransformer.php b/app/Transformers/Api/Application/ServiceVariableTransformer.php deleted file mode 100644 index 49f5e449a..000000000 --- a/app/Transformers/Api/Application/ServiceVariableTransformer.php +++ /dev/null @@ -1,69 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Pterodactyl\Transformers\Admin; - -use Illuminate\Http\Request; -use Pterodactyl\Models\EggVariable; -use League\Fractal\TransformerAbstract; - -class ServiceVariableTransformer extends TransformerAbstract -{ - /** - * List of resources that can be included. - * - * @var array - */ - protected $availableIncludes = ['variables']; - - /** - * The Illuminate Request object if provided. - * - * @var \Illuminate\Http\Request|bool - */ - protected $request; - - /** - * Setup request object for transformer. - * - * @param \Illuminate\Http\Request|bool $request - */ - public function __construct($request = false) - { - if (! $request instanceof Request && $request !== false) { - throw new DisplayException('Request passed to constructor must be of type Request or false.'); - } - - $this->request = $request; - } - - /** - * Return a generic transformed server variable array. - * - * @return array - */ - public function transform(EggVariable $variable) - { - return $variable->toArray(); - } - - /** - * Return the server variables associated with this variable. - * - * @return \Leauge\Fractal\Resource\Collection - */ - public function includeVariables(EggVariable $variable) - { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { - return; - } - - return $this->collection($variable->serverVariable, new ServerVariableTransformer($this->request), 'server_variable'); - } -} diff --git a/routes/api-application.php b/routes/api-application.php index 85566a68e..9649a4306 100644 --- a/routes/api-application.php +++ b/routes/api-application.php @@ -38,6 +38,8 @@ Route::group(['prefix' => '/nodes'], function () { Route::group(['prefix' => '/{node}/allocations'], function () { Route::get('/', 'Nodes\AllocationController@index')->name('api.application.allocations'); + Route::post('/', 'Nodes\AllocationController@store'); + Route::delete('/{allocation}', 'Nodes\AllocationController@delete')->name('api.application.allocations.view'); }); }); @@ -94,3 +96,22 @@ Route::group(['prefix' => '/servers'], function () { Route::delete('/{database}', 'Servers\DatabaseController@delete'); }); }); + +/* +|-------------------------------------------------------------------------- +| Nest Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/application/nests +| +*/ +Route::group(['prefix' => '/nests'], function () { + Route::get('/', 'Nests\NestController@index')->name('api.application.nests'); + Route::get('/{nest}', 'Nests\NestController@view')->name('api.application.nests.view'); + + // Egg Management Endpoint + Route::group(['prefix' => '/{nest}/eggs'], function () { + Route::get('/', 'Nests\EggController@index')->name('api.application.nests.eggs'); + Route::get('/{egg}', 'Nests\EggController@view')->name('api.application.nests.eggs.view'); + }); +});