From 65630bdcce801125cb15884ed649f2b280df2432 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 16:51:56 -0400 Subject: [PATCH] Move API to use JSON:API standards and fractal serializer Makes the data slightly more complex, but forces a standard and can always be changed down the road simply by changing the default serializer. --- .../API/Admin/ServerController.php | 77 +++++++++++++++++ .../Controllers/API/User/CoreController.php | 7 +- .../Controllers/API/User/ServerController.php | 8 +- .../Admin/AllocationTransformer.php} | 16 ++-- app/Transformers/Admin/ServerTransformer.php | 82 +++++++++++++++++++ app/Transformers/Admin/SubuserTransformer.php | 50 +++++++++++ app/Transformers/Admin/UserTransformer.php | 41 ++++++++++ .../User/AllocationTransformer.php | 1 + app/Transformers/User/OverviewTransformer.php | 2 +- app/Transformers/User/ServerTransformer.php | 8 +- app/Transformers/User/StatsTransformer.php | 1 + app/Transformers/User/SubuserTransformer.php | 1 + config/laravel-fractal.php | 2 +- ..._163232_DropDeletedAtColumnFromServers.php | 32 ++++++++ routes/api-admin.php | 9 +- 15 files changed, 315 insertions(+), 22 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/ServerController.php rename app/{Extensions/NoDataSerializer.php => Transformers/Admin/AllocationTransformer.php} (78%) create mode 100644 app/Transformers/Admin/ServerTransformer.php create mode 100644 app/Transformers/Admin/SubuserTransformer.php create mode 100644 app/Transformers/Admin/UserTransformer.php create mode 100644 database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php new file mode 100644 index 000000000..651f70787 --- /dev/null +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -0,0 +1,77 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Controllers\API\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\Server; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\Admin\ServerTransformer; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; + +class ServerController extends Controller +{ + /** + * Controller to handle returning all servers on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $servers = Server::paginate(20); + + return Fractal::create() + ->collection($servers) + ->transformWith(new ServerTransformer) + ->paginateWith(new IlluminatePaginatorAdapter($servers)) + ->withResourceName('server') + ->toArray(); + } + + /** + * Controller to handle returning information on a single server. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function view(Request $request, $id) + { + $server = Server::findOrFail($id); + + $fractal = Fractal::create()->item($server); + + if ($request->input('include')) { + $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ + 'allocations', 'subusers', 'user', + 'pack', 'service', 'option', + ])->toArray()); + } + + return $fractal->transformWith(new ServerTransformer) + ->withResourceName('server') + ->toArray(); + } +} diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index dfc119d50..b036c0db7 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -27,7 +27,7 @@ namespace Pterodactyl\Http\Controllers\API\User; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Transformers\User\ServerTransformer; +use Pterodactyl\Transformers\User\OverviewTransformer; class CoreController extends Controller { @@ -41,6 +41,9 @@ class CoreController extends Controller { $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); - return Fractal::collection($servers)->transformWith(new ServerTransformer)->toArray(); + return Fractal::collection($servers) + ->transformWith(new OverviewTransformer) + ->withResourceName('server') + ->toArray(); } } diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 15f455ce1..6db58cb4b 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -46,13 +46,15 @@ class ServerController extends Controller $server = Server::byUuid($uuid); $fractal = Fractal::create()->item($server); - if ($request->input('with')) { - $fractal->parseIncludes(collect(explode(',', $request->input('with')))->intersect([ + if ($request->input('include')) { + $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ 'allocations', 'subusers', 'stats', ])->toArray()); } - return $fractal->transformWith(new ServerTransformer)->toArray(); + return $fractal->transformWith(new ServerTransformer) + ->withResourceName('server') + ->toArray(); } /** diff --git a/app/Extensions/NoDataSerializer.php b/app/Transformers/Admin/AllocationTransformer.php similarity index 78% rename from app/Extensions/NoDataSerializer.php rename to app/Transformers/Admin/AllocationTransformer.php index 6db8e633c..d59d29a25 100644 --- a/app/Extensions/NoDataSerializer.php +++ b/app/Transformers/Admin/AllocationTransformer.php @@ -22,22 +22,20 @@ * SOFTWARE. */ -namespace Pterodactyl\Extensions; +namespace Pterodactyl\Transformers\Admin; -use League\Fractal\Serializer\ArraySerializer; +use Pterodactyl\Models\Allocation; +use League\Fractal\TransformerAbstract; -class NoDataSerializer extends ArraySerializer +class AllocationTransformer extends TransformerAbstract { /** - * Serialize a collection and don't insert as a member of `data` - * - * @param string $resourceKey - * @param array $data + * Return a generic transformed server array. * * @return array */ - public function collection($resourceKey, array $data) + public function transform(Allocation $allocation) { - return $data; + return $allocation->toArray(); } } diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php new file mode 100644 index 000000000..875e2261c --- /dev/null +++ b/app/Transformers/Admin/ServerTransformer.php @@ -0,0 +1,82 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Transformers\Admin; + +use Pterodactyl\Models\Server; +use League\Fractal\TransformerAbstract; + +class ServerTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'allocations', + 'user', + 'subusers', + ]; + + /** + * Return a generic transformed server array. + * + * @return array + */ + public function transform(Server $server) + { + return $server->toArray(); + } + + /** + * Return a generic array of allocations for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeAllocations(Server $server) + { + return $this->collection($server->allocations, new AllocationTransformer, 'allocation'); + } + + /** + * Return a generic array of data about subusers for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeSubusers(Server $server) + { + return $this->collection($server->subusers, new SubuserTransformer, 'subuser'); + } + + /** + * Return a generic array of data about subusers for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeUser(Server $server) + { + return $this->item($server->user, new UserTransformer, 'user'); + } +} diff --git a/app/Transformers/Admin/SubuserTransformer.php b/app/Transformers/Admin/SubuserTransformer.php new file mode 100644 index 000000000..1c76dcc99 --- /dev/null +++ b/app/Transformers/Admin/SubuserTransformer.php @@ -0,0 +1,50 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Transformers\Admin; + +use Pterodactyl\Models\Subuser; +use Pterodactyl\Models\Permission; +use League\Fractal\TransformerAbstract; + +class SubuserTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed subuser array. + * + * @return array + */ + public function transform(Subuser $subuser) + { + return [ + 'id' => $subuser->id, + 'username' => $subuser->user->username, + 'email' => $subuser->user->email, + '2fa' => (bool) $subuser->user->use_totp, + 'permissions' => $subuser->permissions->pluck('permission'), + 'created_at' => $subuser->created_at, + 'updated_at' => $subuser->updated_at, + ]; + } +} diff --git a/app/Transformers/Admin/UserTransformer.php b/app/Transformers/Admin/UserTransformer.php new file mode 100644 index 000000000..75dd950a3 --- /dev/null +++ b/app/Transformers/Admin/UserTransformer.php @@ -0,0 +1,41 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Transformers\Admin; + +use Pterodactyl\Models\User; +use League\Fractal\TransformerAbstract; + +class UserTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed subuser array. + * + * @return array + */ + public function transform(User $user) + { + return $user->toArray(); + } +} diff --git a/app/Transformers/User/AllocationTransformer.php b/app/Transformers/User/AllocationTransformer.php index 2e58574e6..0fd0be453 100644 --- a/app/Transformers/User/AllocationTransformer.php +++ b/app/Transformers/User/AllocationTransformer.php @@ -55,6 +55,7 @@ class AllocationTransformer extends TransformerAbstract public function transform(Allocation $allocation) { return [ + 'id' => $allocation->id, 'ip' => $allocation->alias, 'port' => $allocation->port, 'default' => ($allocation->id === $this->server->allocation_id), diff --git a/app/Transformers/User/OverviewTransformer.php b/app/Transformers/User/OverviewTransformer.php index 57c5b8d6c..c8e1db9ed 100644 --- a/app/Transformers/User/OverviewTransformer.php +++ b/app/Transformers/User/OverviewTransformer.php @@ -37,7 +37,7 @@ class OverviewTransformer extends TransformerAbstract public function transform(Server $server) { return [ - 'uuidShort' => $server->uuidShort, + 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, 'node' => $server->node->name, diff --git a/app/Transformers/User/ServerTransformer.php b/app/Transformers/User/ServerTransformer.php index 063718863..4e5aacb56 100644 --- a/app/Transformers/User/ServerTransformer.php +++ b/app/Transformers/User/ServerTransformer.php @@ -48,7 +48,7 @@ class ServerTransformer extends TransformerAbstract public function transform(Server $server) { return [ - 'uuidShort' => $server->uuidShort, + 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, 'description' => $server->description, @@ -73,7 +73,7 @@ class ServerTransformer extends TransformerAbstract { $allocations = $server->allocations; - return $this->collection($allocations, new AllocationTransformer($server)); + return $this->collection($allocations, new AllocationTransformer($server), 'allocation'); } /** @@ -85,7 +85,7 @@ class ServerTransformer extends TransformerAbstract { $server->load('subusers.permissions', 'subusers.user'); - return $this->collection($server->subusers, new SubuserTransformer); + return $this->collection($server->subusers, new SubuserTransformer, 'subuser'); } /** @@ -95,6 +95,6 @@ class ServerTransformer extends TransformerAbstract */ public function includeStats(Server $server) { - return $this->item($server->guzzleClient(), new StatsTransformer); + return $this->item($server->guzzleClient(), new StatsTransformer, 'stat'); } } diff --git a/app/Transformers/User/StatsTransformer.php b/app/Transformers/User/StatsTransformer.php index 15bfa699c..6b08ea8a5 100644 --- a/app/Transformers/User/StatsTransformer.php +++ b/app/Transformers/User/StatsTransformer.php @@ -49,6 +49,7 @@ class StatsTransformer extends TransformerAbstract $json = json_decode($res->getBody()); return [ + 'id' => 1, 'status' => $json->status, 'resources' => $json->proc, ]; diff --git a/app/Transformers/User/SubuserTransformer.php b/app/Transformers/User/SubuserTransformer.php index 0793eed3b..e1a122f1f 100644 --- a/app/Transformers/User/SubuserTransformer.php +++ b/app/Transformers/User/SubuserTransformer.php @@ -38,6 +38,7 @@ class SubuserTransformer extends TransformerAbstract public function transform(Subuser $subuser) { return [ + 'id' => $subuser->id, 'username' => $subuser->user->username, 'email' => $subuser->user->email, '2fa' => (bool) $subuser->user->use_totp, diff --git a/config/laravel-fractal.php b/config/laravel-fractal.php index 9406421d8..32ced203e 100644 --- a/config/laravel-fractal.php +++ b/config/laravel-fractal.php @@ -13,6 +13,6 @@ return [ | */ - 'default_serializer' => Pterodactyl\Extensions\NoDataSerializer::class, + 'default_serializer' => League\Fractal\Serializer\JsonApiSerializer::class, ]; diff --git a/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php b/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php new file mode 100644 index 000000000..ccd318654 --- /dev/null +++ b/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php @@ -0,0 +1,32 @@ +dropColumn('deleted_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('servers', function (Blueprint $table) { + $table->timestamp('deleted_at')->nullable(); + }); + } +} diff --git a/routes/api-admin.php b/routes/api-admin.php index 649828046..7a0992fc1 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -24,11 +24,16 @@ Route::get('/', 'CoreController@index')->name('api.admin'); + /* |-------------------------------------------------------------------------- -| Location Controller Routes +| Server Controller Routes |-------------------------------------------------------------------------- | -| Endpoint: /api/admin +| Endpoint: /api/admin/servers | */ +Route::group(['prefix' => '/servers'], function () { + Route::get('/', 'ServerController@index')->name('api.admin.servers.list'); + Route::get('/{id}', 'ServerController@view')->name('api.admin.servers.view'); +});