Skip to content

Commit d087beb

Browse files
committed
Add some additional test coverage and clean up modification service and suspension service
1 parent 83efb2d commit d087beb

File tree

12 files changed

+218
-507
lines changed

12 files changed

+218
-507
lines changed

app/Models/Model.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Container\Container;
88
use Illuminate\Contracts\Validation\Factory;
99
use Illuminate\Database\Eloquent\Model as IlluminateModel;
10+
use Pterodactyl\Exceptions\Model\DataValidationException;
1011

1112
abstract class Model extends IlluminateModel
1213
{
@@ -55,7 +56,11 @@ protected static function boot()
5556
static::$validatorFactory = Container::getInstance()->make(Factory::class);
5657

5758
static::saving(function (Model $model) {
58-
return $model->validate();
59+
if (! $model->validate()) {
60+
throw new DataValidationException($model->getValidator());
61+
}
62+
63+
return true;
5964
});
6065
}
6166

@@ -147,9 +152,9 @@ public function validate()
147152
}
148153

149154
return $this->getValidator()->setData(
150-
// Trying to do self::toArray() here will leave out keys based on the whitelist/blacklist
151-
// for that model. Doing this will return all of the attributes in a format that can
152-
// properly be validated.
155+
// Trying to do self::toArray() here will leave out keys based on the whitelist/blacklist
156+
// for that model. Doing this will return all of the attributes in a format that can
157+
// properly be validated.
153158
$this->addCastAttributesToArray(
154159
$this->getAttributes(), $this->getMutatedAttributes()
155160
)

app/Models/Server.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* @property string $name
1616
* @property string $description
1717
* @property bool $skip_scripts
18-
* @property int $suspended
18+
* @property bool $suspended
1919
* @property int $owner_id
2020
* @property int $memory
2121
* @property int $swap
@@ -133,7 +133,7 @@ class Server extends Model
133133
protected $casts = [
134134
'node_id' => 'integer',
135135
'skip_scripts' => 'boolean',
136-
'suspended' => 'integer',
136+
'suspended' => 'boolean',
137137
'owner_id' => 'integer',
138138
'memory' => 'integer',
139139
'swap' => 'integer',

app/Services/Servers/ServerConfigurationStructureService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ protected function returnCurrentFormat(Server $server)
5555
{
5656
return [
5757
'uuid' => $server->uuid,
58-
'suspended' => (bool) $server->suspended,
58+
'suspended' => $server->suspended,
5959
'environment' => $this->environment->handle($server),
6060
'invocation' => $server->startup,
6161
'skip_egg_scripts' => $server->skip_scripts,

app/Services/Servers/StartupModificationService.php

Lines changed: 51 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
namespace Pterodactyl\Services\Servers;
44

5+
use Illuminate\Support\Arr;
6+
use Pterodactyl\Models\Egg;
57
use Pterodactyl\Models\User;
68
use Pterodactyl\Models\Server;
9+
use Pterodactyl\Models\ServerVariable;
710
use Illuminate\Database\ConnectionInterface;
811
use Pterodactyl\Traits\Services\HasUserLevels;
9-
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
10-
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
11-
use Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface;
1212

1313
class StartupModificationService
1414
{
@@ -19,63 +19,21 @@ class StartupModificationService
1919
*/
2020
private $connection;
2121

22-
/**
23-
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface
24-
*/
25-
private $eggRepository;
26-
27-
/**
28-
* @var \Pterodactyl\Services\Servers\EnvironmentService
29-
*/
30-
private $environmentService;
31-
32-
/**
33-
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
34-
*/
35-
private $repository;
36-
37-
/**
38-
* @var \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface
39-
*/
40-
private $serverVariableRepository;
41-
4222
/**
4323
* @var \Pterodactyl\Services\Servers\VariableValidatorService
4424
*/
4525
private $validatorService;
4626

47-
/**
48-
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
49-
*/
50-
private $structureService;
51-
5227
/**
5328
* StartupModificationService constructor.
5429
*
5530
* @param \Illuminate\Database\ConnectionInterface $connection
56-
* @param \Pterodactyl\Contracts\Repository\EggRepositoryInterface $eggRepository
57-
* @param \Pterodactyl\Services\Servers\EnvironmentService $environmentService
58-
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
59-
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
60-
* @param \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface $serverVariableRepository
6131
* @param \Pterodactyl\Services\Servers\VariableValidatorService $validatorService
6232
*/
63-
public function __construct(
64-
ConnectionInterface $connection,
65-
EggRepositoryInterface $eggRepository,
66-
EnvironmentService $environmentService,
67-
ServerRepositoryInterface $repository,
68-
ServerConfigurationStructureService $structureService,
69-
ServerVariableRepositoryInterface $serverVariableRepository,
70-
VariableValidatorService $validatorService
71-
) {
33+
public function __construct(ConnectionInterface $connection, VariableValidatorService $validatorService)
34+
{
7235
$this->connection = $connection;
73-
$this->eggRepository = $eggRepository;
74-
$this->environmentService = $environmentService;
75-
$this->repository = $repository;
76-
$this->serverVariableRepository = $serverVariableRepository;
7736
$this->validatorService = $validatorService;
78-
$this->structureService = $structureService;
7937
}
8038

8139
/**
@@ -85,63 +43,70 @@ public function __construct(
8543
* @param array $data
8644
* @return \Pterodactyl\Models\Server
8745
*
88-
* @throws \Illuminate\Validation\ValidationException
89-
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
90-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
46+
* @throws \Throwable
9147
*/
9248
public function handle(Server $server, array $data): Server
9349
{
94-
$this->connection->beginTransaction();
95-
if (! is_null(array_get($data, 'environment'))) {
96-
$this->validatorService->setUserLevel($this->getUserLevel());
97-
$results = $this->validatorService->handle(array_get($data, 'egg_id', $server->egg_id), array_get($data, 'environment', []));
98-
99-
$results->each(function ($result) use ($server) {
100-
$this->serverVariableRepository->withoutFreshModel()->updateOrCreate([
101-
'server_id' => $server->id,
102-
'variable_id' => $result->id,
103-
], [
104-
'variable_value' => $result->value ?? '',
105-
]);
106-
});
107-
}
108-
109-
if ($this->isUserLevel(User::USER_LEVEL_ADMIN)) {
110-
$this->updateAdministrativeSettings($data, $server);
111-
}
112-
113-
$this->connection->commit();
114-
115-
return $server;
50+
return $this->connection->transaction(function () use ($server, $data) {
51+
if (! empty($data['environment'])) {
52+
$egg = $this->isUserLevel(User::USER_LEVEL_ADMIN) ? ($data['egg_id'] ?? $server->egg_id) : $server->egg_id;
53+
54+
$results = $this->validatorService
55+
->setUserLevel($this->getUserLevel())
56+
->handle($egg, $data['environment']);
57+
58+
foreach ($results as $result) {
59+
ServerVariable::query()->updateOrCreate(
60+
[
61+
'server_id' => $server->id,
62+
'variable_id' => $result->id,
63+
],
64+
['variable_value' => $result->value ?? '']
65+
);
66+
}
67+
}
68+
69+
if ($this->isUserLevel(User::USER_LEVEL_ADMIN)) {
70+
$this->updateAdministrativeSettings($data, $server);
71+
}
72+
73+
// Calling ->refresh() rather than ->fresh() here causes it to return the
74+
// variables as triplicates for some reason? Not entirely sure, should dig
75+
// in more to figure it out, but luckily we have a test case covering this
76+
// specific call so we can be assured we're not breaking it _here_ at least.
77+
//
78+
// TODO(dane): this seems like a red-flag for the code powering the relationship
79+
// that should be looked into more.
80+
return $server->fresh();
81+
});
11682
}
11783

11884
/**
11985
* Update certain administrative settings for a server in the DB.
12086
*
12187
* @param array $data
12288
* @param \Pterodactyl\Models\Server $server
123-
*
124-
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
125-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
12689
*/
127-
private function updateAdministrativeSettings(array $data, Server &$server)
90+
protected function updateAdministrativeSettings(array $data, Server &$server)
12891
{
12992
if (
130-
is_digit(array_get($data, 'egg_id'))
93+
is_digit(Arr::get($data, 'egg_id'))
13194
&& $data['egg_id'] != $server->egg_id
132-
&& is_null(array_get($data, 'nest_id'))
95+
&& is_null(Arr::get($data, 'nest_id'))
13396
) {
134-
$egg = $this->eggRepository->setColumns(['id', 'nest_id'])->find($data['egg_id']);
97+
/** @var \Pterodactyl\Models\Egg $egg */
98+
$egg = Egg::query()->select(['nest_id'])->findOrFail($data['egg_id']);
99+
135100
$data['nest_id'] = $egg->nest_id;
136101
}
137102

138-
$server = $this->repository->update($server->id, [
103+
$server->forceFill([
139104
'installed' => 0,
140-
'startup' => array_get($data, 'startup', $server->startup),
141-
'nest_id' => array_get($data, 'nest_id', $server->nest_id),
142-
'egg_id' => array_get($data, 'egg_id', $server->egg_id),
143-
'skip_scripts' => array_get($data, 'skip_scripts') ?? isset($data['skip_scripts']),
144-
'image' => array_get($data, 'docker_image', $server->image),
145-
]);
105+
'startup' => $data['startup'] ?? $server->startup,
106+
'nest_id' => $data['nest_id'] ?? $server->nest_id,
107+
'egg_id' => $data['egg_id'] ?? $server->egg_id,
108+
'skip_scripts' => $data['skip_scripts'] ?? isset($data['skip_scripts']),
109+
'image' => $data['docker_image'] ?? $server->image,
110+
])->save();
146111
}
147112
}

app/Services/Servers/SuspensionService.php

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
namespace Pterodactyl\Services\Servers;
44

5-
use Psr\Log\LoggerInterface;
65
use Webmozart\Assert\Assert;
76
use Pterodactyl\Models\Server;
87
use Illuminate\Database\ConnectionInterface;
98
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
10-
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
119

1210
class SuspensionService
1311
{
@@ -19,16 +17,6 @@ class SuspensionService
1917
*/
2018
private $connection;
2119

22-
/**
23-
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
24-
*/
25-
private $repository;
26-
27-
/**
28-
* @var \Psr\Log\LoggerInterface
29-
*/
30-
private $writer;
31-
3220
/**
3321
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
3422
*/
@@ -39,25 +27,19 @@ class SuspensionService
3927
*
4028
* @param \Illuminate\Database\ConnectionInterface $connection
4129
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
42-
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
43-
* @param \Psr\Log\LoggerInterface $writer
4430
*/
4531
public function __construct(
4632
ConnectionInterface $connection,
47-
DaemonServerRepository $daemonServerRepository,
48-
ServerRepositoryInterface $repository,
49-
LoggerInterface $writer
33+
DaemonServerRepository $daemonServerRepository
5034
) {
5135
$this->connection = $connection;
52-
$this->repository = $repository;
53-
$this->writer = $writer;
5436
$this->daemonServerRepository = $daemonServerRepository;
5537
}
5638

5739
/**
5840
* Suspends a server on the system.
5941
*
60-
* @param int|\Pterodactyl\Models\Server $server
42+
* @param \Pterodactyl\Models\Server $server
6143
* @param string $action
6244
*
6345
* @throws \Throwable
@@ -66,15 +48,16 @@ public function toggle(Server $server, $action = self::ACTION_SUSPEND)
6648
{
6749
Assert::oneOf($action, [self::ACTION_SUSPEND, self::ACTION_UNSUSPEND]);
6850

69-
if (
70-
$action === self::ACTION_SUSPEND && $server->suspended ||
71-
$action === self::ACTION_UNSUSPEND && ! $server->suspended
72-
) {
51+
$isSuspending = $action === self::ACTION_SUSPEND;
52+
// Nothing needs to happen if we're suspending the server and it is already
53+
// suspended in the database. Additionally, nothing needs to happen if the server
54+
// is not suspended and we try to un-suspend the instance.
55+
if ($isSuspending === $server->suspended) {
7356
return;
7457
}
7558

7659
$this->connection->transaction(function () use ($action, $server) {
77-
$this->repository->withoutFreshModel()->update($server->id, [
60+
$server->update([
7861
'suspended' => $action === self::ACTION_SUSPEND,
7962
]);
8063

app/Transformers/Api/Client/ServerTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function transform(Server $server): array
6767
'allocations' => $server->allocation_limit,
6868
'backups' => $server->backup_limit,
6969
],
70-
'is_suspended' => $server->suspended !== 0,
70+
'is_suspended' => $server->suspended,
7171
'is_installing' => $server->installed !== 1,
7272
];
7373
}

tests/Integration/Api/Client/ClientApiIntegrationTestCase.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Pterodactyl\Models\Task;
1010
use Pterodactyl\Models\User;
1111
use Webmozart\Assert\Assert;
12-
use Pterodactyl\Models\Model;
1312
use Pterodactyl\Models\Server;
1413
use Pterodactyl\Models\Subuser;
1514
use Pterodactyl\Models\Location;

0 commit comments

Comments
 (0)