Fix issues with validation in admin CP for server variables, closes #780

This commit is contained in:
Dane Everitt 2017-11-25 13:15:46 -06:00
parent 0bb44a4972
commit 20c1c74116
6 changed files with 42 additions and 88 deletions

View file

@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
### Fixed
* `[beta.2]` — Fixes a bug that would cause an endless exception message stream in the console when attemping to setup environment settings in certain instances.
* `[beta.2]` — Fixes a bug causing the dropdown menu for a server's egg to display the wrong selected value.
* `[beta.2]` — Fixes a bug that would throw a red page of death when submitting an invalid egg variable value for a server in the Admin CP.
## v0.7.0-beta.2 (Derelict Dermodactylus)
### Fixed

View file

@ -9,6 +9,6 @@
namespace Pterodactyl\Exceptions;
class DisplayValidationException extends PterodactylException
class DisplayValidationException extends DisplayException
{
}

View file

@ -78,9 +78,10 @@ class StartupModificationService
* @param \Pterodactyl\Models\Server $server
* @param array $data
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Illuminate\Validation\ValidationException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
*/
public function handle(Server $server, array $data)
{

View file

@ -11,8 +11,8 @@ namespace Pterodactyl\Services\Servers;
use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Validation\ValidationException;
use Pterodactyl\Traits\Services\HasUserLevels;
use Pterodactyl\Exceptions\DisplayValidationException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
@ -25,22 +25,22 @@ class VariableValidatorService
/**
* @var \Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface
*/
protected $optionVariableRepository;
private $optionVariableRepository;
/**
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
*/
protected $serverRepository;
private $serverRepository;
/**
* @var \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface
*/
protected $serverVariableRepository;
private $serverVariableRepository;
/**
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $validator;
private $validator;
/**
* VariableValidatorService constructor.
@ -68,32 +68,32 @@ class VariableValidatorService
* @param int $egg
* @param array $fields
* @return \Illuminate\Support\Collection
* @throws \Illuminate\Validation\ValidationException
*/
public function handle(int $egg, array $fields = []): Collection
{
$variables = $this->optionVariableRepository->findWhere([['egg_id', '=', $egg]]);
$messages = $this->validator->make([], []);
return $variables->map(function ($item) use ($fields) {
$response = $variables->map(function ($item) use ($fields, $messages) {
// Skip doing anything if user is not an admin and
// variable is not user viewable or editable.
if (! $this->isUserLevel(User::USER_LEVEL_ADMIN) && (! $item->user_editable || ! $item->user_viewable)) {
return false;
}
$validator = $this->validator->make([
$v = $this->validator->make([
'variable_value' => array_get($fields, $item->env_variable),
], [
'variable_value' => $item->rules,
], [], [
'variable_value' => trans('validation.internal.variable_value', ['env' => $item->name]),
]);
if ($validator->fails()) {
throw new DisplayValidationException(json_encode(
collect([
'notice' => [
trans('admin/server.exceptions.bad_variable', ['name' => $item->name]),
],
])->merge($validator->errors()->toArray())
));
if ($v->fails()) {
foreach ($v->getMessageBag()->all() as $message) {
$messages->getMessageBag()->add($item->env_variable, $message);
}
}
return (object) [
@ -104,5 +104,11 @@ class VariableValidatorService
})->filter(function ($item) {
return is_object($item);
});
if (! empty($messages->getMessageBag()->all())) {
throw new ValidationException($messages);
}
return $response;
}
}

View file

@ -85,23 +85,6 @@ return [
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute format is invalid.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
@ -114,4 +97,9 @@ return [
*/
'attributes' => [],
// Internal validation logic for Pterodactyl
'internal' => [
'variable_value' => ':env variable',
],
];

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Tests\Unit\Services\Servers;
@ -15,8 +8,7 @@ use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
use Pterodactyl\Models\EggVariable;
use Illuminate\Contracts\Validation\Factory;
use Pterodactyl\Exceptions\PterodactylException;
use Pterodactyl\Exceptions\DisplayValidationException;
use Illuminate\Validation\ValidationException;
use Pterodactyl\Services\Servers\VariableValidatorService;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
@ -27,22 +19,17 @@ class VariableValidatorServiceTest extends TestCase
/**
* @var \Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface|\Mockery\Mock
*/
protected $optionVariableRepository;
private $optionVariableRepository;
/**
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface|\Mockery\Mock
*/
protected $serverRepository;
private $serverRepository;
/**
* @var \Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface|\Mockery\Mock
*/
protected $serverVariableRepository;
/**
* @var \Illuminate\Contracts\Validation\Factory|\Mockery\Mock
*/
protected $validator;
private $serverVariableRepository;
/**
* Setup tests.
@ -54,7 +41,6 @@ class VariableValidatorServiceTest extends TestCase
$this->optionVariableRepository = m::mock(EggVariableRepositoryInterface::class);
$this->serverRepository = m::mock(ServerRepositoryInterface::class);
$this->serverVariableRepository = m::mock(ServerVariableRepositoryInterface::class);
$this->validator = m::mock(Factory::class);
}
/**
@ -77,13 +63,6 @@ class VariableValidatorServiceTest extends TestCase
$variables = $this->getVariableCollection();
$this->optionVariableRepository->shouldReceive('findWhere')->with([['egg_id', '=', 1]])->andReturn($variables);
$this->validator->shouldReceive('make')->with([
'variable_value' => 'Test_SomeValue_0',
], [
'variable_value' => $variables[0]->rules,
])->once()->andReturnSelf();
$this->validator->shouldReceive('fails')->withNoArgs()->once()->andReturn(false);
$response = $this->getService()->handle(1, [
$variables[0]->env_variable => 'Test_SomeValue_0',
$variables[1]->env_variable => 'Test_SomeValue_1',
@ -112,15 +91,6 @@ class VariableValidatorServiceTest extends TestCase
$variables = $this->getVariableCollection();
$this->optionVariableRepository->shouldReceive('findWhere')->with([['egg_id', '=', 1]])->andReturn($variables);
foreach ($variables as $key => $variable) {
$this->validator->shouldReceive('make')->with([
'variable_value' => 'Test_SomeValue_' . $key,
], [
'variable_value' => $variables[$key]->rules,
])->once()->andReturnSelf();
$this->validator->shouldReceive('fails')->withNoArgs()->once()->andReturn(false);
}
$service = $this->getService();
$service->setUserLevel(User::USER_LEVEL_ADMIN);
$response = $service->handle(1, [
@ -152,28 +122,16 @@ class VariableValidatorServiceTest extends TestCase
$variables = $this->getVariableCollection();
$this->optionVariableRepository->shouldReceive('findWhere')->with([['egg_id', '=', 1]])->andReturn($variables);
$this->validator->shouldReceive('make')->with([
'variable_value' => null,
], [
'variable_value' => $variables[0]->rules,
])->once()->andReturnSelf();
$this->validator->shouldReceive('fails')->withNoArgs()->once()->andReturn(true);
$this->validator->shouldReceive('errors')->withNoArgs()->once()->andReturnSelf();
$this->validator->shouldReceive('toArray')->withNoArgs()->once()->andReturn([]);
try {
$this->getService()->handle(1, [$variables[0]->env_variable => null]);
} catch (PterodactylException $exception) {
$this->assertInstanceOf(DisplayValidationException::class, $exception);
} catch (ValidationException $exception) {
$messages = $exception->validator->getMessageBag()->all();
$decoded = json_decode($exception->getMessage());
$this->assertEquals(0, json_last_error(), 'Assert that response is decodable JSON.');
$this->assertObjectHasAttribute('notice', $decoded);
$this->assertEquals(
trans('admin/server.exceptions.bad_variable', ['name' => $variables[0]->name]),
$decoded->notice[0]
);
$this->assertNotEmpty($messages);
$this->assertSame(1, count($messages));
$this->assertSame(trans('validation.required', [
'attribute' => trans('validation.internal.variable_value', ['env' => $variables[0]->name]),
]), $messages[0]);
}
}
@ -205,7 +163,7 @@ class VariableValidatorServiceTest extends TestCase
$this->optionVariableRepository,
$this->serverRepository,
$this->serverVariableRepository,
$this->validator
$this->app->make(Factory::class)
);
}
}