Skip to content

Commit cef3e4c

Browse files
committed
Add base routes for managing servers as a client
1 parent 9a32b9f commit cef3e4c

18 files changed

+262
-270
lines changed

app/Http/Controllers/Api/Application/ApplicationApiController.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
namespace Pterodactyl\Http\Controllers\Api\Application;
44

55
use Illuminate\Http\Request;
6+
use Webmozart\Assert\Assert;
67
use Illuminate\Http\Response;
78
use Illuminate\Container\Container;
89
use Pterodactyl\Http\Controllers\Controller;
910
use Pterodactyl\Extensions\Spatie\Fractalistic\Fractal;
1011
use Pterodactyl\Transformers\Api\Application\BaseTransformer;
11-
use Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException;
1212

1313
abstract class ApplicationApiController extends Controller
1414
{
@@ -56,18 +56,14 @@ public function loadDependencies(Fractal $fractal, Request $request)
5656
*
5757
* @param string $abstract
5858
* @return \Pterodactyl\Transformers\Api\Application\BaseTransformer
59-
*
60-
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
6159
*/
6260
public function getTransformer(string $abstract)
6361
{
6462
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
6563
$transformer = Container::getInstance()->make($abstract);
6664
$transformer->setKey($this->request->attributes->get('api_key'));
6765

68-
if (! $transformer instanceof BaseTransformer) {
69-
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
70-
}
66+
Assert::isInstanceOf($transformer, BaseTransformer::class);
7167

7268
return $transformer;
7369
}

app/Http/Controllers/Api/Client/ClientApiController.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<?php
22

3-
namespace Pterodactyl\Http\Controllers\Api\Application;
3+
namespace Pterodactyl\Http\Controllers\Api\Client;
44

5+
use Webmozart\Assert\Assert;
56
use Illuminate\Container\Container;
6-
use Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException;
7+
use Pterodactyl\Transformers\Api\Client\BaseClientTransformer;
8+
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
79

810
abstract class ClientApiController extends ApplicationApiController
911
{
@@ -12,18 +14,15 @@ abstract class ClientApiController extends ApplicationApiController
1214
*
1315
* @param string $abstract
1416
* @return \Pterodactyl\Transformers\Api\Client\BaseClientTransformer
15-
*
16-
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
1717
*/
1818
public function getTransformer(string $abstract)
1919
{
2020
/** @var \Pterodactyl\Transformers\Api\Client\BaseClientTransformer $transformer */
2121
$transformer = Container::getInstance()->make($abstract);
22-
$transformer->setKey($this->request->attributes->get('api_key'));
22+
Assert::isInstanceOf($transformer, BaseClientTransformer::class);
2323

24-
if (! $transformer instanceof self) {
25-
throw new InvalidTransformerLevelException('Calls to ' . __METHOD__ . ' must return a transformer that is an instance of ' . __CLASS__);
26-
}
24+
$transformer->setKey($this->request->attributes->get('api_key'));
25+
$transformer->setUser($this->request->user());
2726

2827
return $transformer;
2928
}

app/Http/Controllers/Api/Client/ClientController.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,43 @@
22

33
namespace Pterodactyl\Http\Controllers\Api\Client;
44

5-
use Pterodactyl\Http\Controllers\Api\Application\ClientApiController;
5+
use Pterodactyl\Models\User;
6+
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
7+
use Pterodactyl\Http\Requests\Api\Client\GetServersRequest;
8+
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
69

710
class ClientController extends ClientApiController
811
{
12+
/**
13+
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
14+
*/
15+
private $repository;
16+
17+
/**
18+
* ClientController constructor.
19+
*
20+
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
21+
*/
22+
public function __construct(ServerRepositoryInterface $repository)
23+
{
24+
parent::__construct();
25+
26+
$this->repository = $repository;
27+
}
28+
29+
/**
30+
* Return all of the servers available to the client making the API
31+
* request, including servers the user has access to as a subuser.
32+
*
33+
* @param \Pterodactyl\Http\Requests\Api\Client\GetServersRequest $request
34+
* @return array
35+
*/
36+
public function index(GetServersRequest $request): array
37+
{
38+
$servers = $this->repository->filterUserAccessServers($request->user(), User::FILTER_LEVEL_SUBUSER);
39+
40+
return $this->fractal->collection($servers)
41+
->transformWith($this->getTransformer(ServerTransformer::class))
42+
->toArray();
43+
}
944
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
4+
5+
use Pterodactyl\Models\Server;
6+
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
7+
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
8+
use Pterodactyl\Http\Requests\Api\Client\Servers\GetServerRequest;
9+
10+
class ServerController extends ClientApiController
11+
{
12+
/**
13+
* Transform an individual server into a response that can be consumed by a
14+
* client using the API.
15+
*
16+
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\GetServerRequest $request
17+
* @return array
18+
*/
19+
public function index(GetServerRequest $request): array
20+
{
21+
return $this->fractal->item($request->getModel(Server::class))
22+
->transformWith($this->getTransformer(ServerTransformer::class))
23+
->toArray();
24+
}
25+
}

app/Http/Kernel.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Pterodactyl\Http\Middleware\Server\ScheduleBelongsToServer;
3535
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
3636
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
37+
use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings;
3738
use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser;
3839
use Pterodactyl\Http\Middleware\DaemonAuthenticate as OldDaemonAuthenticate;
3940

@@ -78,7 +79,7 @@ class Kernel extends HttpKernel
7879
],
7980
'client-api' => [
8081
'throttle:60,1',
81-
ApiSubstituteBindings::class,
82+
SubstituteClientApiBindings::class,
8283
SetSessionDriver::class,
8384
'api..key:' . ApiKey::TYPE_ACCOUNT,
8485
AuthenticateIPAccess::class,

app/Http/Middleware/Api/ApiSubstituteBindings.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class ApiSubstituteBindings extends SubstituteBindings
3232
'user' => User::class,
3333
];
3434

35+
/**
36+
* @var \Illuminate\Routing\Router
37+
*/
38+
protected $router;
39+
3540
/**
3641
* Perform substitution of route parameters without triggering
3742
* a 404 error if a model is not found.
@@ -45,6 +50,10 @@ public function handle($request, Closure $next)
4550
$route = $request->route();
4651

4752
foreach (self::$mappings as $key => $model) {
53+
if (! is_null($this->router->getBindingCallback($key))) {
54+
continue;
55+
}
56+
4857
$this->router->model($key, $model, function () use ($request) {
4958
$request->attributes->set('is_missing_model', true);
5059
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Middleware\Api\Client;
4+
5+
use Closure;
6+
use Illuminate\Container\Container;
7+
use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings;
8+
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
9+
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
10+
11+
class SubstituteClientApiBindings extends ApiSubstituteBindings
12+
{
13+
/**
14+
* Perform substitution of route parameters without triggering
15+
* a 404 error if a model is not found.
16+
*
17+
* @param \Illuminate\Http\Request $request
18+
* @param \Closure $next
19+
* @return mixed
20+
*/
21+
public function handle($request, Closure $next)
22+
{
23+
// Override default behavior of the model binding to use a specific table
24+
// column rather than the default 'id'.
25+
$this->router->bind('server', function ($value) use ($request) {
26+
try {
27+
return Container::getInstance()->make(ServerRepositoryInterface::class)->findFirstWhere([
28+
['uuidShort', '=', $value],
29+
]);
30+
} catch (RecordNotFoundException $ex) {
31+
$request->attributes->set('is_missing_model', true);
32+
33+
return null;
34+
}
35+
});
36+
37+
return parent::handle($request, $next);
38+
}
39+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Client;
4+
5+
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
6+
7+
abstract class ClientApiRequest extends ApplicationApiRequest
8+
{
9+
/**
10+
* Determine if the current user is authorized to perform
11+
* the requested action aganist the API.
12+
*
13+
* @return bool
14+
*/
15+
public function authorize(): bool
16+
{
17+
return true;
18+
}
19+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Client;
4+
5+
class GetServersRequest extends ClientApiRequest
6+
{
7+
/**
8+
* @return bool
9+
*/
10+
public function authorize(): bool
11+
{
12+
return true;
13+
}
14+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Client\Servers;
4+
5+
use Pterodactyl\Models\Server;
6+
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
7+
8+
class GetServerRequest extends ClientApiRequest
9+
{
10+
/**
11+
* Determine if a client has permission to view this server on the API. This
12+
* should never be false since this would be checking the same permission as
13+
* resourceExists().
14+
*
15+
* @return bool
16+
*/
17+
public function authorize(): bool
18+
{
19+
return true;
20+
}
21+
22+
/**
23+
* Determine if the user should even know that this server exists.
24+
*
25+
* @return bool
26+
*/
27+
public function resourceExists(): bool
28+
{
29+
return $this->user()->can('view-server', $this->getModel(Server::class));
30+
}
31+
}

0 commit comments

Comments
 (0)