Skip to content

Commit 15289b7

Browse files
committed
Finish first round of User/Node API additions
Will still need some tweaking and improvements to allow everything to be used.
1 parent d21f70c commit 15289b7

File tree

10 files changed

+220
-68
lines changed

10 files changed

+220
-68
lines changed

app/Exceptions/DisplayException.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use Log;
1313
use Throwable;
14+
use Illuminate\Http\Response;
1415
use Prologue\Alerts\AlertsMessageBag;
1516

1617
class DisplayException extends PterodactylException
@@ -65,7 +66,7 @@ public function render($request)
6566
if ($request->expectsJson()) {
6667
return response()->json(Handler::convertToArray($this, [
6768
'detail' => $this->getMessage(),
68-
]), method_exists($this, 'getStatusCode') ? $this->getStatusCode() : 500);
69+
]), method_exists($this, 'getStatusCode') ? $this->getStatusCode() : Response::HTTP_INTERNAL_SERVER_ERROR);
6970
}
7071

7172
app()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash();
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
<?php
2-
/**
3-
* Pterodactyl - Panel
4-
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5-
*
6-
* This software is licensed under the terms of the MIT license.
7-
* https://opensource.org/licenses/MIT
8-
*/
92

103
namespace Pterodactyl\Exceptions\Service;
114

5+
use Illuminate\Http\Response;
126
use Pterodactyl\Exceptions\DisplayException;
137

148
class HasActiveServersException extends DisplayException
159
{
10+
/**
11+
* @return int
12+
*/
13+
public function getStatusCode()
14+
{
15+
return Response::HTTP_BAD_REQUEST;
16+
}
1617
}
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
<?php
2-
/**
3-
* Pterodactyl - Panel
4-
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5-
*
6-
* This software is licensed under the terms of the MIT license.
7-
* https://opensource.org/licenses/MIT
8-
*/
92

103
namespace Pterodactyl\Exceptions\Service\Location;
114

5+
use Illuminate\Http\Response;
126
use Pterodactyl\Exceptions\DisplayException;
137

148
class HasActiveNodesException extends DisplayException
159
{
10+
/**
11+
* @return int
12+
*/
13+
public function getStatusCode()
14+
{
15+
return Response::HTTP_BAD_REQUEST;
16+
}
1617
}

app/Http/Controllers/API/Admin/Nodes/NodeController.php

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,29 @@
55
use Spatie\Fractal\Fractal;
66
use Illuminate\Http\Request;
77
use Pterodactyl\Models\Node;
8+
use Illuminate\Http\Response;
9+
use Illuminate\Http\JsonResponse;
810
use Pterodactyl\Http\Controllers\Controller;
11+
use Pterodactyl\Services\Nodes\NodeUpdateService;
12+
use Pterodactyl\Services\Nodes\NodeCreationService;
13+
use Pterodactyl\Services\Nodes\NodeDeletionService;
914
use Pterodactyl\Transformers\Api\Admin\NodeTransformer;
1015
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
16+
use Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest;
1117
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
1218

1319
class NodeController extends Controller
1420
{
21+
/**
22+
* @var \Pterodactyl\Services\Nodes\NodeCreationService
23+
*/
24+
private $creationService;
25+
26+
/**
27+
* @var \Pterodactyl\Services\Nodes\NodeDeletionService
28+
*/
29+
private $deletionService;
30+
1531
/**
1632
* @var \Spatie\Fractal\Fractal
1733
*/
@@ -22,16 +38,32 @@ class NodeController extends Controller
2238
*/
2339
private $repository;
2440

41+
/**
42+
* @var \Pterodactyl\Services\Nodes\NodeUpdateService
43+
*/
44+
private $updateService;
45+
2546
/**
2647
* NodeController constructor.
2748
*
2849
* @param \Spatie\Fractal\Fractal $fractal
50+
* @param \Pterodactyl\Services\Nodes\NodeCreationService $creationService
51+
* @param \Pterodactyl\Services\Nodes\NodeDeletionService $deletionService
52+
* @param \Pterodactyl\Services\Nodes\NodeUpdateService $updateService
2953
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
3054
*/
31-
public function __construct(Fractal $fractal, NodeRepositoryInterface $repository)
32-
{
55+
public function __construct(
56+
Fractal $fractal,
57+
NodeCreationService $creationService,
58+
NodeDeletionService $deletionService,
59+
NodeUpdateService $updateService,
60+
NodeRepositoryInterface $repository
61+
) {
3362
$this->fractal = $fractal;
3463
$this->repository = $repository;
64+
$this->creationService = $creationService;
65+
$this->deletionService = $deletionService;
66+
$this->updateService = $updateService;
3567
}
3668

3769
/**
@@ -67,4 +99,63 @@ public function view(Request $request, Node $node): array
6799

68100
return $fractal->toArray();
69101
}
102+
103+
/**
104+
* Create a new node on the Panel. Returns the created node and a HTTP/201
105+
* status response on success.
106+
*
107+
* @param \Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest $request
108+
* @return \Illuminate\Http\JsonResponse
109+
*
110+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
111+
*/
112+
public function store(NodeFormRequest $request): JsonResponse
113+
{
114+
$node = $this->creationService->handle($request->normalize());
115+
116+
return $this->fractal->item($node)
117+
->transformWith(new NodeTransformer($request))
118+
->withResourceName('node')
119+
->addMeta([
120+
'link' => route('api.admin.node.view', ['node' => $node->id]),
121+
])
122+
->respond(201);
123+
}
124+
125+
/**
126+
* Update an existing node on the Panel.
127+
*
128+
* @param \Pterodactyl\Http\Requests\Admin\Node\NodeFormRequest $request
129+
* @param \Pterodactyl\Models\Node $node
130+
* @return array
131+
*
132+
* @throws \Pterodactyl\Exceptions\DisplayException
133+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
134+
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
135+
*/
136+
public function update(NodeFormRequest $request, Node $node): array
137+
{
138+
$node = $this->updateService->returnUpdatedModel()->handle($node, $request->normalize());
139+
140+
return $this->fractal->item($node)
141+
->transformWith(new NodeTransformer($request))
142+
->withResourceName('node')
143+
->toArray();
144+
}
145+
146+
/**
147+
* Deletes a given node from the Panel as long as there are no servers
148+
* currently attached to it.
149+
*
150+
* @param \Pterodactyl\Models\Node $node
151+
* @return \Illuminate\Http\Response
152+
*
153+
* @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
154+
*/
155+
public function delete(Node $node): Response
156+
{
157+
$this->deletionService->handle($node);
158+
159+
return response('', 201);
160+
}
70161
}

app/Http/Controllers/API/Admin/Users/UserController.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,17 @@ public function update(UserFormRequest $request, User $user): array
146146
}
147147
}
148148

149-
return $this->fractal->item($collection->get('user'))
149+
$response = $this->fractal->item($collection->get('model'))
150150
->transformWith(new UserTransformer($request))
151-
->withResourceName('user')
152-
->addMeta([
151+
->withResourceName('user');
152+
153+
if (count($errors) > 0) {
154+
$response->addMeta([
153155
'revocation_errors' => $errors,
154-
])
155-
->toArray();
156+
]);
157+
}
158+
159+
return $response->toArray();
156160
}
157161

158162
/**

app/Models/User.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
use Sofa\Eloquence\Eloquence;
66
use Sofa\Eloquence\Validable;
7+
use Illuminate\Validation\Rules\In;
78
use Illuminate\Auth\Authenticatable;
89
use Illuminate\Database\Eloquent\Model;
910
use Illuminate\Notifications\Notifiable;
1011
use Sofa\Eloquence\Contracts\CleansAttributes;
1112
use Illuminate\Auth\Passwords\CanResetPassword;
13+
use Pterodactyl\Traits\Helpers\AvailableLanguages;
1214
use Illuminate\Foundation\Auth\Access\Authorizable;
1315
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
1416
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
@@ -23,7 +25,9 @@ class User extends Model implements
2325
CleansAttributes,
2426
ValidableContract
2527
{
26-
use Authenticatable, Authorizable, CanResetPassword, Eloquence, Notifiable, Validable;
28+
use Authenticatable, Authorizable, AvailableLanguages, CanResetPassword, Eloquence, Notifiable, Validable {
29+
gatherRules as eloquenceGatherRules;
30+
}
2731

2832
const USER_LEVEL_USER = 0;
2933
const USER_LEVEL_ADMIN = 1;
@@ -138,11 +142,23 @@ class User extends Model implements
138142
'name_last' => 'string|between:1,255',
139143
'password' => 'nullable|string',
140144
'root_admin' => 'boolean',
141-
'language' => 'string|between:2,5',
145+
'language' => 'string',
142146
'use_totp' => 'boolean',
143147
'totp_secret' => 'nullable|string',
144148
];
145149

150+
/**
151+
* Implement language verification by overriding Eloquence's gather
152+
* rules function.
153+
*/
154+
protected static function gatherRules()
155+
{
156+
$rules = self::eloquenceGatherRules();
157+
$rules['language'][] = new In(array_keys((new self)->getAvailableLanguages()));
158+
159+
return $rules;
160+
}
161+
146162
/**
147163
* Send the password reset notification.
148164
*

app/Services/Nodes/NodeUpdateService.php

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,82 +9,71 @@
99

1010
namespace Pterodactyl\Services\Nodes;
1111

12-
use Illuminate\Log\Writer;
1312
use Pterodactyl\Models\Node;
1413
use GuzzleHttp\Exception\RequestException;
15-
use Pterodactyl\Exceptions\DisplayException;
14+
use Pterodactyl\Traits\Services\ReturnsUpdatedModels;
1615
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
16+
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
1717
use Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface;
1818

1919
class NodeUpdateService
2020
{
21+
use ReturnsUpdatedModels;
22+
2123
/**
2224
* @var \Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface
2325
*/
24-
protected $configRepository;
26+
private $configRepository;
2527

2628
/**
2729
* @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface
2830
*/
29-
protected $repository;
30-
31-
/**
32-
* @var \Illuminate\Log\Writer
33-
*/
34-
protected $writer;
31+
private $repository;
3532

3633
/**
3734
* UpdateService constructor.
3835
*
3936
* @param \Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface $configurationRepository
4037
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
41-
* @param \Illuminate\Log\Writer $writer
4238
*/
4339
public function __construct(
4440
ConfigurationRepositoryInterface $configurationRepository,
45-
NodeRepositoryInterface $repository,
46-
Writer $writer
41+
NodeRepositoryInterface $repository
4742
) {
4843
$this->configRepository = $configurationRepository;
4944
$this->repository = $repository;
50-
$this->writer = $writer;
5145
}
5246

5347
/**
5448
* Update the configuration values for a given node on the machine.
5549
*
56-
* @param int|\Pterodactyl\Models\Node $node
57-
* @param array $data
58-
* @return mixed
50+
* @param \Pterodactyl\Models\Node $node
51+
* @param array $data
52+
* @return \Pterodactyl\Models\Node|mixed
5953
*
6054
* @throws \Pterodactyl\Exceptions\DisplayException
6155
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
6256
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
6357
*/
64-
public function handle($node, array $data)
58+
public function handle(Node $node, array $data)
6559
{
66-
if (! $node instanceof Node) {
67-
$node = $this->repository->find($node);
68-
}
69-
7060
if (! is_null(array_get($data, 'reset_secret'))) {
71-
$data['daemonSecret'] = str_random(NodeCreationService::DAEMON_SECRET_LENGTH);
61+
$data['daemonSecret'] = str_random(Node::DAEMON_SECRET_LENGTH);
7262
unset($data['reset_secret']);
7363
}
7464

75-
$updateResponse = $this->repository->withoutFresh()->update($node->id, $data);
65+
if ($this->getUpdatedModel()) {
66+
$response = $this->repository->update($node->id, $data);
67+
} else {
68+
$response = $this->repository->withoutFresh()->update($node->id, $data);
69+
}
7670

7771
try {
7872
$this->configRepository->setNode($node->id)->update();
7973
} catch (RequestException $exception) {
80-
$response = $exception->getResponse();
81-
$this->writer->warning($exception);
82-
83-
throw new DisplayException(trans('exceptions.node.daemon_off_config_updated', [
84-
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
85-
]));
74+
throw new DaemonConnectionException($exception);
8675
}
8776

88-
return $updateResponse;
77+
return $response;
8978
}
9079
}

0 commit comments

Comments
 (0)