Merge branch 'release/v0.7.16'
This commit is contained in:
commit
29de2085f2
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -3,6 +3,18 @@ This file is a running track of new features and fixes to each version of the pa
|
|||
|
||||
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||
|
||||
## v0.7.16 (Derelict Dermodactylus)
|
||||
### Fixed
|
||||
* Fixed the /api/application/servers endpoint erroring when including subusers or egg
|
||||
* Fixed bug in migration files causing failures when using MySQL 8.
|
||||
* Fixed missing redirect return when an error occurs while modifying database information.
|
||||
* Fixes bug in login attempt tracking.
|
||||
* Fixes a bug where certain URL encoded files would not be editable in the file manager.
|
||||
|
||||
### Added
|
||||
* The application API now includes the egg's name in the egg model's response.
|
||||
* The /api/application/servers endpoint can now include server's databases and subusers.
|
||||
|
||||
## v0.7.15 (Derelict Dermodactylus)
|
||||
### Fixed
|
||||
* Fixes support for PHP 7.3 when running `composer install` commands due to a dependency that needed updating.
|
||||
|
|
|
@ -131,7 +131,7 @@ class DatabaseController extends Controller
|
|||
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
|
||||
)->flash();
|
||||
|
||||
redirect()->route('admin.databases')->withInput($request->validated());
|
||||
return redirect()->route('admin.databases')->withInput($request->validated());
|
||||
} else {
|
||||
throw $exception;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ class DatabaseController extends Controller
|
|||
$this->alert->danger(
|
||||
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
|
||||
)->flash();
|
||||
$redirect->withInput($request->normalize());
|
||||
return $redirect->withInput($request->normalize());
|
||||
} else {
|
||||
throw $exception;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ class LoginController extends Controller
|
|||
{
|
||||
use AuthenticatesUsers;
|
||||
|
||||
const USER_INPUT_FIELD = 'user';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Auth\AuthManager
|
||||
*/
|
||||
|
@ -64,14 +62,14 @@ class LoginController extends Controller
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $lockoutTime;
|
||||
protected $decayMinutes;
|
||||
|
||||
/**
|
||||
* After how many attempts should logins be throttled and locked.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maxLoginAttempts;
|
||||
protected $maxAttempts;
|
||||
|
||||
/**
|
||||
* LoginController constructor.
|
||||
|
@ -98,8 +96,8 @@ class LoginController extends Controller
|
|||
$this->google2FA = $google2FA;
|
||||
$this->repository = $repository;
|
||||
|
||||
$this->lockoutTime = $this->config->get('auth.lockout.time');
|
||||
$this->maxLoginAttempts = $this->config->get('auth.lockout.attempts');
|
||||
$this->decayMinutes = $this->config->get('auth.lockout.time');
|
||||
$this->maxAttempts = $this->config->get('auth.lockout.attempts');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +110,7 @@ class LoginController extends Controller
|
|||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$username = $request->input(self::USER_INPUT_FIELD);
|
||||
$username = $request->input($this->username());
|
||||
$useColumn = $this->getField($username);
|
||||
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
|
@ -209,20 +207,30 @@ class LoginController extends Controller
|
|||
{
|
||||
$this->incrementLoginAttempts($request);
|
||||
$this->fireFailedLoginEvent($user, [
|
||||
$this->getField($request->input(self::USER_INPUT_FIELD)) => $request->input(self::USER_INPUT_FIELD),
|
||||
$this->getField($request->input($this->username())) => $request->input($this->username()),
|
||||
]);
|
||||
|
||||
$errors = [self::USER_INPUT_FIELD => trans('auth.failed')];
|
||||
$errors = [$this->username() => trans('auth.failed')];
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json($errors, 422);
|
||||
}
|
||||
|
||||
return redirect()->route('auth.login')
|
||||
->withInput($request->only(self::USER_INPUT_FIELD))
|
||||
->withInput($request->only($this->username()))
|
||||
->withErrors($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the login username to be used by the controller.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function username()
|
||||
{
|
||||
return 'user';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is logging in using an email or username,.
|
||||
*
|
||||
|
|
|
@ -168,11 +168,11 @@ class Server extends Model implements CleansAttributes, ValidableContract
|
|||
/**
|
||||
* Gets the subusers associated with a server.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function subusers()
|
||||
{
|
||||
return $this->hasManyThrough(User::class, Subuser::class, 'server_id', 'id', 'id', 'user_id');
|
||||
return $this->hasMany(Subuser::class, 'server_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,7 +51,7 @@ class NestDeletionService
|
|||
{
|
||||
$count = $this->serverRepository->findCountWhere([['nest_id', '=', $nest]]);
|
||||
if ($count > 0) {
|
||||
throw new HasActiveServersException(trans('exceptions.service.delete_has_servers'));
|
||||
throw new HasActiveServersException(trans('exceptions.nest.delete_has_servers'));
|
||||
}
|
||||
|
||||
return $this->repository->delete($nest);
|
||||
|
|
|
@ -41,6 +41,7 @@ class EggTransformer extends BaseTransformer
|
|||
return [
|
||||
'id' => $model->id,
|
||||
'uuid' => $model->uuid,
|
||||
'name' => $model->name,
|
||||
'nest' => $model->nest_id,
|
||||
'author' => $model->author,
|
||||
'description' => $model->description,
|
||||
|
|
|
@ -28,6 +28,7 @@ class ServerTransformer extends BaseTransformer
|
|||
'variables',
|
||||
'location',
|
||||
'node',
|
||||
'databases',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -131,7 +132,7 @@ class ServerTransformer extends BaseTransformer
|
|||
|
||||
$server->loadMissing('subusers');
|
||||
|
||||
return $this->collection($server->getRelation('subusers'), $this->makeTransformer(UserTransformer::class), 'user');
|
||||
return $this->collection($server->getRelation('subusers'), $this->makeTransformer(SubuserTransformer::class), 'subuser');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,14 +196,14 @@ class ServerTransformer extends BaseTransformer
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a generic array with service option information for this server.
|
||||
* Return a generic array with egg information for this server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
|
||||
*/
|
||||
public function includeOption(Server $server)
|
||||
public function includeEgg(Server $server)
|
||||
{
|
||||
if (! $this->authorize(AdminAcl::RESOURCE_EGGS)) {
|
||||
return $this->null();
|
||||
|
@ -210,7 +211,7 @@ class ServerTransformer extends BaseTransformer
|
|||
|
||||
$server->loadMissing('egg');
|
||||
|
||||
return $this->item($server->getRelation('egg'), $this->makeTransformer(EggVariableTransformer::class), 'egg');
|
||||
return $this->item($server->getRelation('egg'), $this->makeTransformer(EggTransformer::class), 'egg');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,4 +270,23 @@ class ServerTransformer extends BaseTransformer
|
|||
|
||||
return $this->item($server->getRelation('node'), $this->makeTransformer(NodeTransformer::class), 'node');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a generic array with database information for this server.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \League\Fractal\Resource\Collection|\League\Fractal\Resource\NullResource
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
|
||||
*/
|
||||
public function includeDatabases(Server $server)
|
||||
{
|
||||
if (! $this->authorize(AdminAcl::RESOURCE_SERVER_DATABASES)) {
|
||||
return $this->null();
|
||||
}
|
||||
|
||||
$server->loadMissing('databases');
|
||||
|
||||
return $this->collection($server->getRelation('databases'), $this->makeTransformer(ServerDatabaseTransformer::class), 'databases');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Transformers\Api\Application;
|
||||
|
||||
use Pterodactyl\Models\Subuser;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Services\Acl\Api\AdminAcl;
|
||||
|
||||
class SubuserTransformer extends BaseTransformer
|
||||
{
|
||||
/**
|
||||
* List of resources that can be included.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $availableIncludes = ['user', 'server'];
|
||||
|
||||
/**
|
||||
* Return the resource name for the JSONAPI output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResourceName(): string
|
||||
{
|
||||
return Subuser::RESOURCE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a transformed Subuser model that can be consumed by external services.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $subuser
|
||||
* @return array
|
||||
*/
|
||||
public function transform(Subuser $subuser): array
|
||||
{
|
||||
return [
|
||||
'id' => $subuser->id,
|
||||
'user_id' => $subuser->user_id,
|
||||
'server_id' => $subuser->server_id,
|
||||
'permissions' => $subuser->permissions->map(function (Permission $permission) {
|
||||
return $permission->permission;
|
||||
}),
|
||||
'created_at' => $this->formatTimestamp($subuser->created_at),
|
||||
'updated_at' => $this->formatTimestamp($subuser->updated_at),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a generic item of user for this subuser.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $subuser
|
||||
* @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
|
||||
*/
|
||||
public function includeUser(Subuser $subuser)
|
||||
{
|
||||
if (! $this->authorize(AdminAcl::RESOURCE_USERS)) {
|
||||
return $this->null();
|
||||
}
|
||||
|
||||
$subuser->loadMissing('user');
|
||||
|
||||
return $this->item($subuser->getRelation('user'), $this->makeTransformer(UserTransformer::class), 'user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a generic item of server for this subuser.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Subuser $subuser
|
||||
* @return \League\Fractal\Resource\Item|\League\Fractal\Resource\NullResource
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
|
||||
*/
|
||||
public function includeServer(Subuser $subuser)
|
||||
{
|
||||
if (! $this->authorize(AdminAcl::RESOURCE_SERVERS)) {
|
||||
return $this->null();
|
||||
}
|
||||
|
||||
$subuser->loadMissing('server');
|
||||
|
||||
return $this->item($subuser->getRelation('server'), $this->makeTransformer(ServerTransformer::class), 'server');
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ return [
|
|||
| change this value if you are not maintaining your own internal versions.
|
||||
*/
|
||||
|
||||
'version' => '0.7.15',
|
||||
'version' => '0.7.16',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -12,7 +12,7 @@ return [
|
|||
|
|
||||
*/
|
||||
'lockout' => [
|
||||
'time' => 120,
|
||||
'time' => 2,
|
||||
'attempts' => 3,
|
||||
],
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class AddForeignKeysServers extends Migration
|
|||
MODIFY COLUMN owner INT(10) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN allocation INT(10) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN service INT(10) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN servers.option INT(10) UNSIGNED NOT NULL
|
||||
MODIFY COLUMN `option` INT(10) UNSIGNED NOT NULL
|
||||
');
|
||||
|
||||
Schema::table('servers', function (Blueprint $table) {
|
||||
|
@ -55,7 +55,7 @@ class AddForeignKeysServers extends Migration
|
|||
MODIFY COLUMN owner MEDIUMINT(8) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN allocation MEDIUMINT(8) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN service MEDIUMINT(8) UNSIGNED NOT NULL,
|
||||
MODIFY COLUMN servers.option MEDIUMINT(8) UNSIGNED NOT NULL
|
||||
MODIFY COLUMN `option` MEDIUMINT(8) UNSIGNED NOT NULL
|
||||
');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
@extends('layouts.admin')
|
||||
|
||||
@section('title')
|
||||
Nests → Egg: {{ $egg->name }} → Scripts
|
||||
Nests → Egg: {{ $egg->name }} → Install Script
|
||||
@endsection
|
||||
|
||||
@section('content-header')
|
||||
<h1>{{ $egg->name }}<small>Manage install and upgrade scripts for this Egg.</small></h1>
|
||||
<h1>{{ $egg->name }}<small>Manage the install script for this Egg.</small></h1>
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{{ route('admin.index') }}">Admin</a></li>
|
||||
<li><a href="{{ route('admin.nests') }}">Service</a></li>
|
||||
<li><a href="{{ route('admin.nests') }}">Nests</a></li>
|
||||
<li><a href="{{ route('admin.nests.view', $egg->nest->id) }}">{{ $egg->nest->name }}</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.view', $egg->id) }}">{{ $egg->name }}</a></li>
|
||||
<li class="active">{{ $egg->name }}</li>
|
||||
</ol>
|
||||
@endsection
|
||||
|
@ -26,7 +27,7 @@
|
|||
<ul class="nav nav-tabs">
|
||||
<li><a href="{{ route('admin.nests.egg.view', $egg->id) }}">Configuration</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.variables', $egg->id) }}">Variables</a></li>
|
||||
<li class="active"><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Scripts</a></li>
|
||||
<li class="active"><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Install Script</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<ul class="nav nav-tabs">
|
||||
<li><a href="{{ route('admin.nests.egg.view', $egg->id) }}">Configuration</a></li>
|
||||
<li class="active"><a href="{{ route('admin.nests.egg.variables', $egg->id) }}">Variables</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Scripts</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Install Script</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="{{ route('admin.nests.egg.view', $egg->id) }}">Configuration</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.variables', $egg->id) }}">Variables</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Scripts</a></li>
|
||||
<li><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Install Script</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-xs-12">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="pDaemonBase" class="form-label">Daemon Server File Directory</label>
|
||||
<input type="text" name="daemonBase" id="pDaemonBase" class="form-control" value="/srv/daemon-data" />
|
||||
<p class="text-muted small">Enter the directory where server files should be stored. <strong>If you use OVH you should check your partition scheme. You may need to use <code>/home/daemon-data</code> to have enough space.</strong></p>
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
<td data-identifier="name" data-name="{{ rawurlencode($file['entry']) }}" data-path="@if($file['directory'] !== ''){{ rawurlencode($file['directory']) }}@endif/">
|
||||
@if(in_array($file['mime'], $editableMime))
|
||||
@can('edit-files', $server)
|
||||
<a href="/server/{{ $server->uuidShort }}/files/edit/@if($file['directory'] !== ''){{ rawurlencode($file['directory']) }}/@endif{{ rawurlencode($file['entry']) }}" class="edit_file">{{ $file['entry'] }}</a>
|
||||
<a href="/server/{{ $server->uuidShort }}/files/edit/@if($file['directory'] !== ''){{ $file['directory'] }}/@endif{{ $file['entry'] }}" class="edit_file">{{ $file['entry'] }}</a>
|
||||
@else
|
||||
{{ $file['entry'] }}
|
||||
@endcan
|
||||
|
|
|
@ -60,7 +60,7 @@ class DatabasePasswordServiceTest extends TestCase
|
|||
$this->dynamic->shouldReceive('set')->with('dynamic', $model->database_host_id)->once()->andReturnNull();
|
||||
|
||||
$this->encrypter->expects('encrypt')->with(m::on(function ($string) {
|
||||
preg_match_all('/[!@+=^-]/', $string, $matches, PREG_SET_ORDER);
|
||||
preg_match_all('/[!@+=.^-]/', $string, $matches, PREG_SET_ORDER);
|
||||
$this->assertTrue(count($matches) >= 2 && count($matches) <= 6, "Failed asserting that [{$string}] contains 2 to 6 special characters.");
|
||||
$this->assertTrue(strlen($string) === 24, "Failed asserting that [{$string}] is 24 characters in length.");
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ class NestDeletionServiceTest extends TestCase
|
|||
$this->service->handle(1);
|
||||
} catch (PterodactylException $exception) {
|
||||
$this->assertInstanceOf(HasActiveServersException::class, $exception);
|
||||
$this->assertEquals(trans('exceptions.service.delete_has_servers'), $exception->getMessage());
|
||||
$this->assertEquals(trans('exceptions.nest.delete_has_servers'), $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue