Begin moving packs to new service mechanisms, refactor exceptions for services

This commit is contained in:
Dane Everitt 2017-08-18 22:19:06 -05:00
parent 46cb71e69d
commit 9d3dca87f2
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
62 changed files with 492 additions and 303 deletions

View File

@ -13,5 +13,5 @@ Default panel users:
MySQL is accessible using root/pterodactyl or pterodactyl/pterodactyl MySQL is accessible using root/pterodactyl or pterodactyl/pterodactyl
Services for pteroq and mailhog are running Service for pteroq and mailhog are running
##################################################### #####################################################

View File

@ -3,6 +3,7 @@ dist: trusty
php: php:
- '7.0' - '7.0'
- '7.1' - '7.1'
- '7.2'
sudo: false sudo: false
cache: cache:
directories: directories:

View File

@ -245,7 +245,7 @@ spatie/laravel-fractal (4.0.0 => 4.0.1)
* New theme applied to Admin CP. Many graphical changes were made, some data was moved around and some display data changed. Too much was changed to feasibly log it all in here. Major breaking changes or notable new features will be logged. * New theme applied to Admin CP. Many graphical changes were made, some data was moved around and some display data changed. Too much was changed to feasibly log it all in here. Major breaking changes or notable new features will be logged.
* New server creation page now makes significantly less AJAX calls and is much quicker to respond. * New server creation page now makes significantly less AJAX calls and is much quicker to respond.
* Server and Node view pages wee modified to split tabs into individual pages to make re-themeing and modifications significantly easier, and reduce MySQL query loads on page. * Server and Node view pages wee modified to split tabs into individual pages to make re-themeing and modifications significantly easier, and reduce MySQL query loads on page.
* `[pre.4]` — Services and Pack magement overhauled to be faster, cleaner, and more extensible in the future. * `[pre.4]` — Service and Pack magement overhauled to be faster, cleaner, and more extensible in the future.
* Most of the backend `UnhandledException` display errors now include a clearer error that directs admins to the program's logs. * Most of the backend `UnhandledException` display errors now include a clearer error that directs admins to the program's logs.
* Table seeders for services now can be run during upgrades and will attempt to locate and update, or create new if not found in the database. * Table seeders for services now can be run during upgrades and will attempt to locate and update, or create new if not found in the database.
* Many structural changes to the database and `Pterodactyl\Models` classes that would flood this changelog if they were all included. All required migrations included to handle database changes. * Many structural changes to the database and `Pterodactyl\Models` classes that would flood this changelog if they were all included. All required migrations included to handle database changes.

View File

@ -0,0 +1,39 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface;
interface PackRepositoryInterface extends RepositoryInterface, SearchableInterface
{
/**
* Return all of the file archives for a given pack.
*
* @param int $id
* @param bool $collection
* @return object|\Illuminate\Support\Collection
*/
public function getFileArchives($id, $collection = false);
}

View File

@ -22,7 +22,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Exceptions\Services; namespace Pterodactyl\Exceptions\Service;
class HasActiveServersException extends \Exception class HasActiveServersException extends \Exception
{ {

View File

@ -0,0 +1,30 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Exceptions\Service\Pack;
class InvalidFileMimeTypeException extends \Exception
{
//
}

View File

@ -0,0 +1,30 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Exceptions\Service\Pack;
class InvalidFileUploadException extends \Exception
{
//
}

View File

@ -22,7 +22,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Exceptions\Services\Server; namespace Pterodactyl\Exceptions\Service\Server;
use Exception; use Exception;

View File

@ -22,7 +22,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Exceptions\Services\ServiceOption; namespace Pterodactyl\Exceptions\Service\ServiceOption;
class InvalidCopyFromException extends \Exception class InvalidCopyFromException extends \Exception
{ {

View File

@ -22,7 +22,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Exceptions\Services\ServiceOption; namespace Pterodactyl\Exceptions\Service\ServiceOption;
class NoParentConfigurationFoundException extends \Exception class NoParentConfigurationFoundException extends \Exception
{ {

View File

@ -22,7 +22,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Exceptions\Services\ServiceVariable; namespace Pterodactyl\Exceptions\Service\ServiceVariable;
use Exception; use Exception;

View File

@ -30,7 +30,7 @@ use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Http\Requests\Admin\Service\EditOptionScript; use Pterodactyl\Http\Requests\Admin\Service\EditOptionScript;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Services\Services\Options\OptionUpdateService; use Pterodactyl\Services\Services\Options\OptionUpdateService;
use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface;
use Pterodactyl\Services\Services\Options\OptionCreationService; use Pterodactyl\Services\Services\Options\OptionCreationService;
@ -38,8 +38,8 @@ use Pterodactyl\Services\Services\Options\OptionDeletionService;
use Pterodactyl\Http\Requests\Admin\Service\ServiceOptionFormRequest; use Pterodactyl\Http\Requests\Admin\Service\ServiceOptionFormRequest;
use Pterodactyl\Services\Services\Options\InstallScriptUpdateService; use Pterodactyl\Services\Services\Options\InstallScriptUpdateService;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\InvalidCopyFromException; use Pterodactyl\Exceptions\Service\ServiceOption\InvalidCopyFromException;
use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; use Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException;
class OptionController extends Controller class OptionController extends Controller
{ {

View File

@ -30,7 +30,7 @@ use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Services\ServiceUpdateService; use Pterodactyl\Services\Services\ServiceUpdateService;
use Pterodactyl\Services\Services\ServiceCreationService; use Pterodactyl\Services\Services\ServiceCreationService;
use Pterodactyl\Services\Services\ServiceDeletionService; use Pterodactyl\Services\Services\ServiceDeletionService;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Http\Requests\Admin\Service\ServiceFormRequest; use Pterodactyl\Http\Requests\Admin\Service\ServiceFormRequest;
use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface;
use Pterodactyl\Http\Requests\Admin\Service\ServiceFunctionsFormRequest; use Pterodactyl\Http\Requests\Admin\Service\ServiceFunctionsFormRequest;

View File

@ -83,7 +83,7 @@ class VariableController extends Controller
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @throws \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function store(OptionVariableFormRequest $request, ServiceOption $option) public function store(OptionVariableFormRequest $request, ServiceOption $option)
{ {
@ -117,7 +117,7 @@ class VariableController extends Controller
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @throws \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function update(OptionVariableFormRequest $request, ServiceOption $option, ServiceVariable $variable) public function update(OptionVariableFormRequest $request, ServiceOption $option, ServiceVariable $variable)
{ {

View File

@ -26,12 +26,15 @@ namespace Pterodactyl\Models;
use File; use File;
use Storage; use Storage;
use Sofa\Eloquence\Eloquence;
use Sofa\Eloquence\Validable;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Nicolaslopezj\Searchable\SearchableTrait; use Sofa\Eloquence\Contracts\CleansAttributes;
use Sofa\Eloquence\Contracts\Validable as ValidableContract;
class Pack extends Model class Pack extends Model implements CleansAttributes, ValidableContract
{ {
use SearchableTrait; use Eloquence, Validable;
/** /**
* The table associated with the model. * The table associated with the model.
@ -46,7 +49,33 @@ class Pack extends Model
* @var array * @var array
*/ */
protected $fillable = [ protected $fillable = [
'option_id', 'name', 'version', 'description', 'selectable', 'visible', 'locked', 'option_id', 'uuid', 'name', 'version', 'description', 'selectable', 'visible', 'locked',
];
/**
* @var array
*/
protected static $applicationRules = [
'name' => 'required',
'version' => 'required',
'description' => 'sometimes',
'selectable' => 'sometimes|required',
'visible' => 'sometimes|required',
'locked' => 'sometimes|required',
'option_id' => 'required',
];
/**
* @var array
*/
protected static $dataIntegrityRules = [
'name' => 'string',
'version' => 'string',
'description' => 'nullable|string',
'selectable' => 'boolean',
'visible' => 'boolean',
'locked' => 'boolean',
'option_id' => 'exists:service_options,id',
]; ];
/** /**
@ -66,18 +95,13 @@ class Pack extends Model
* *
* @var array * @var array
*/ */
protected $searchable = [ protected $searchableColumns = [
'columns' => [ 'name' => 10,
'packs.name' => 10, 'uuid' => 8,
'packs.uuid' => 8, 'option.name' => 6,
'service_options.name' => 6, 'option.tag' => 5,
'service_options.tag' => 5, 'option.docker_image' => 5,
'service_options.docker_image' => 5, 'version' => 2,
'packs.version' => 2,
],
'joins' => [
'service_options' => ['packs.option_id', 'service_options.id'],
],
]; ];
/** /**
@ -85,6 +109,7 @@ class Pack extends Model
* *
* @param bool $collection * @param bool $collection
* @return \Illuminate\Support\Collection|object * @return \Illuminate\Support\Collection|object
* @deprecated
*/ */
public function files($collection = false) public function files($collection = false)
{ {

View File

@ -22,20 +22,22 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Repositories\Eloquent\Attributes; namespace Pterodactyl\Repositories\Concerns;
use Pterodactyl\Repositories\Eloquent\EloquentRepository; trait Searchable
use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface;
abstract class SearchableRepository extends EloquentRepository implements SearchableInterface
{ {
/** /**
* The term to search.
*
* @var bool|string * @var bool|string
*/ */
protected $searchTerm = false; protected $searchTerm = false;
/** /**
* {@inheritdoc} * Perform a search of the model using the given term.
*
* @param string $term
* @return $this
*/ */
public function search($term) public function search($term)
{ {

View File

@ -28,10 +28,12 @@ use Pterodactyl\Models\Location;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
use Pterodactyl\Repositories\Eloquent\Attributes\SearchableRepository; use Pterodactyl\Repositories\Concerns\Searchable;
class LocationRepository extends SearchableRepository implements LocationRepositoryInterface class LocationRepository extends EloquentRepository implements LocationRepositoryInterface
{ {
use Searchable;
/** /**
* @var string * @var string
*/ */

View File

@ -27,10 +27,12 @@ namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Repositories\Eloquent\Attributes\SearchableRepository; use Pterodactyl\Repositories\Concerns\Searchable;
class NodeRepository extends SearchableRepository implements NodeRepositoryInterface class NodeRepository extends EloquentRepository implements NodeRepositoryInterface
{ {
use Searchable;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -0,0 +1,65 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Pack;
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
use Pterodactyl\Repositories\Concerns\Searchable;
use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
class PackRepository extends EloquentRepository implements PackRepositoryInterface
{
use Searchable;
/**
* {@inheritdoc}
*/
public function model()
{
return Pack::class;
}
/**
* {@inheritdoc}
*/
public function getFileArchives($id, $collection = false)
{
$pack = $this->getBuilder()->find($id, ['id', 'uuid']);
$storage = $this->app->make(FilesystemFactory::class);
$files = collect($storage->disk('default')->files('packs/' . $pack->uuid));
$files = $files->map(function ($file) {
$path = storage_path('app/' . $file);
return (object) [
'name' => basename($file),
'hash' => sha1_file($path),
'size' => human_readable($path),
];
});
return ($collection) ? $files : (object) $files->all();
}
}

View File

@ -25,12 +25,14 @@
namespace Pterodactyl\Repositories\Eloquent; namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Concerns\Searchable;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Repositories\Eloquent\Attributes\SearchableRepository;
class ServerRepository extends SearchableRepository implements ServerRepositoryInterface class ServerRepository extends EloquentRepository implements ServerRepositoryInterface
{ {
use Searchable;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -26,12 +26,14 @@ namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Pterodactyl\Repositories\Concerns\Searchable;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Repositories\Eloquent\Attributes\SearchableRepository;
class UserRepository extends SearchableRepository implements UserRepositoryInterface class UserRepository extends EloquentRepository implements UserRepositoryInterface
{ {
use Searchable;
/** /**
* @var \Illuminate\Contracts\Config\Repository * @var \Illuminate\Contracts\Config\Repository
*/ */

View File

@ -1,163 +0,0 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Repositories;
use Cron;
use Validator;
use Pterodactyl\Models\Task;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\DisplayValidationException;
class TaskRepository
{
/**
* The default values to use for new tasks.
*
* @var array
*/
protected $defaults = [
'year' => '*',
'day_of_week' => '*',
'month' => '*',
'day_of_month' => '*',
'hour' => '*',
'minute' => '*/30',
];
/**
* Task action types.
*
* @var array
*/
protected $actions = [
'command',
'power',
];
/**
* Deletes a given task.
*
* @param int $id
* @return bool
*/
public function delete($id)
{
$task = Task::findOrFail($id);
$task->delete();
}
/**
* Toggles a task active or inactive.
*
* @param int $id
* @return bool
*/
public function toggle($id)
{
$task = Task::findOrFail($id);
$task->active = ! $task->active;
$task->queued = false;
$task->save();
return $task->active;
}
/**
* Create a new scheduled task for a given server.
*
* @param int $server
* @param int $user
* @param array $data
* @return \Pterodactyl\Models\Task
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create($server, $user, $data)
{
$server = Server::findOrFail($server);
$user = User::findOrFail($user);
$validator = Validator::make($data, [
'action' => 'string|required',
'data' => 'string|required',
'year' => 'string|sometimes',
'day_of_week' => 'string|sometimes',
'month' => 'string|sometimes',
'day_of_month' => 'string|sometimes',
'hour' => 'string|sometimes',
'minute' => 'string|sometimes',
]);
if ($validator->fails()) {
throw new DisplayValidationException(json_encode($validator->errors()));
}
if (! in_array($data['action'], $this->actions)) {
throw new DisplayException('The action provided is not valid.');
}
$cron = $this->defaults;
foreach ($this->defaults as $setting => $value) {
if (array_key_exists($setting, $data) && ! is_null($data[$setting]) && $data[$setting] !== '') {
$cron[$setting] = $data[$setting];
}
}
// Check that is this a valid Cron Entry
try {
$buildCron = Cron::factory(sprintf('%s %s %s %s %s %s',
$cron['minute'],
$cron['hour'],
$cron['day_of_month'],
$cron['month'],
$cron['day_of_week'],
$cron['year']
));
} catch (\Exception $ex) {
throw $ex;
}
return Task::create([
'user_id' => $user->id,
'server_id' => $server->id,
'active' => 1,
'action' => $data['action'],
'data' => $data['data'],
'queued' => 0,
'year' => $cron['year'],
'day_of_week' => $cron['day_of_week'],
'month' => $cron['month'],
'day_of_month' => $cron['day_of_month'],
'hour' => $cron['hour'],
'minute' => $cron['minute'],
'last_run' => null,
'next_run' => $buildCron->getNextRunDate(),
]);
}
}

View File

@ -0,0 +1,119 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Services\Packs;
use Ramsey\Uuid\Uuid;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
use Pterodactyl\Exceptions\Service\Pack\InvalidFileUploadException;
use Pterodactyl\Exceptions\Service\Pack\InvalidFileMimeTypeException;
class PackCreationService
{
/**
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* @var \Illuminate\Database\ConnectionInterface
*/
protected $connection;
/**
* @var \Pterodactyl\Contracts\Repository\PackRepositoryInterface
*/
protected $repository;
/**
* @var \Illuminate\Contracts\Filesystem\Factory
*/
protected $storage;
/**
* PackCreationService constructor.
*
* @param \Illuminate\Contracts\Config\Repository $config
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Illuminate\Contracts\Filesystem\Factory $storage
* @param \Pterodactyl\Contracts\Repository\PackRepositoryInterface $repository
*/
public function __construct(
ConfigRepository $config,
ConnectionInterface $connection,
FilesystemFactory $storage,
PackRepositoryInterface $repository
) {
$this->config = $config;
$this->connection = $connection;
$this->repository = $repository;
$this->storage = $storage;
}
/**
* Add a new service pack to the system.
*
* @param array $data
* @param \Illuminate\Http\UploadedFile|null $file
* @return \Pterodactyl\Models\Pack
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Service\Pack\InvalidFileMimeTypeException
* @throws \Pterodactyl\Exceptions\Service\Pack\InvalidFileUploadException
*/
public function handle(array $data, $file = null)
{
if (! is_null($file)) {
if (! $file->isValid()) {
throw new InvalidFileUploadException;
}
if (! in_array($file->getMimeType(), $this->config->get('pterodactyl.files.pack_types'))) {
throw new InvalidFileMimeTypeException;
}
}
// Transform values to boolean
$data['selectable'] = isset($data['selectable']);
$data['visible'] = isset($data['visible']);
$data['locked'] = isset($data['locked']);
$this->connection->beginTransaction();
$pack = $this->repository->create(array_merge(
['uuid' => Uuid::uuid4()], $data
));
$this->storage->disk('default')->makeDirectory('packs/' . $pack->uuid);
if (! is_null($file)) {
$file->storeAs('packs/' . $pack->uuid, 'archive.tar.gz');
}
$this->connection->commit();
return $pack;
}
}

View File

@ -26,7 +26,7 @@ namespace Pterodactyl\Services\Services\Options;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\InvalidCopyFromException; use Pterodactyl\Exceptions\Service\ServiceOption\InvalidCopyFromException;
class InstallScriptUpdateService class InstallScriptUpdateService
{ {
@ -53,7 +53,7 @@ class InstallScriptUpdateService
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Services\ServiceOption\InvalidCopyFromException * @throws \Pterodactyl\Exceptions\Service\ServiceOption\InvalidCopyFromException
*/ */
public function handle($option, array $data) public function handle($option, array $data)
{ {

View File

@ -25,7 +25,7 @@
namespace Pterodactyl\Services\Services\Options; namespace Pterodactyl\Services\Services\Options;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; use Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException;
class OptionCreationService class OptionCreationService
{ {
@ -51,7 +51,7 @@ class OptionCreationService
* @return \Pterodactyl\Models\ServiceOption * @return \Pterodactyl\Models\ServiceOption
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException * @throws \Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException
*/ */
public function handle(array $data) public function handle(array $data)
{ {

View File

@ -24,7 +24,7 @@
namespace Pterodactyl\Services\Services\Options; namespace Pterodactyl\Services\Services\Options;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
@ -60,7 +60,7 @@ class OptionDeletionService
* @param int $option * @param int $option
* @return int * @return int
* *
* @throws \Pterodactyl\Exceptions\Services\HasActiveServersException * @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/ */
public function handle($option) public function handle($option)
{ {

View File

@ -26,7 +26,7 @@ namespace Pterodactyl\Services\Services\Options;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; use Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException;
class OptionUpdateService class OptionUpdateService
{ {
@ -53,7 +53,7 @@ class OptionUpdateService
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException * @throws \Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException
*/ */
public function handle($option, array $data) public function handle($option, array $data)
{ {

View File

@ -24,7 +24,7 @@
namespace Pterodactyl\Services\Services; namespace Pterodactyl\Services\Services;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface;
@ -60,7 +60,7 @@ class ServiceDeletionService
* @param int $service * @param int $service
* @return int * @return int
* *
* @throws \Pterodactyl\Exceptions\Services\HasActiveServersException * @throws \Pterodactyl\Exceptions\Service\HasActiveServersException
*/ */
public function handle($service) public function handle($service)
{ {

View File

@ -28,7 +28,7 @@ use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Models\ServiceVariable; use Pterodactyl\Models\ServiceVariable;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServiceVariableRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceVariableRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException; use Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException;
class VariableCreationService class VariableCreationService
{ {
@ -58,7 +58,7 @@ class VariableCreationService
* @return \Pterodactyl\Models\ServiceVariable * @return \Pterodactyl\Models\ServiceVariable
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @throws \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function handle($option, array $data) public function handle($option, array $data)
{ {

View File

@ -27,7 +27,7 @@ namespace Pterodactyl\Services\Services\Variables;
use Pterodactyl\Models\ServiceVariable; use Pterodactyl\Models\ServiceVariable;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Contracts\Repository\ServiceVariableRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceVariableRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException; use Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException;
class VariableUpdateService class VariableUpdateService
{ {
@ -56,7 +56,7 @@ class VariableUpdateService
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @throws \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function handle($variable, array $data) public function handle($variable, array $data)
{ {

View File

@ -1,5 +1,5 @@
<?php <?php
/** /*
* Pterodactyl - Panel * Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>. * Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
* *
@ -22,52 +22,16 @@
* SOFTWARE. * SOFTWARE.
*/ */
namespace Pterodactyl\Repositories; if (! function_exists('human_readable')) {
class HelperRepository
{
/** /**
* Listing of editable files in the control panel. * Generate a human-readable filesize for a given file path.
* *
* @var array * @param string $path
*/ * @param int $precision
protected static $editable = [
'application/json',
'application/javascript',
'application/xml',
'application/xhtml+xml',
'text/xml',
'text/css',
'text/html',
'text/plain',
'text/x-perl',
'text/x-shellscript',
'inode/x-empty',
];
/**
* Converts from bytes to the largest possible size that is still readable.
*
* @param int $bytes
* @param int $decimals
* @return string * @return string
* @deprecated
*/ */
public static function bytesToHuman($bytes, $decimals = 2) function human_readable($path, $precision = 2)
{ {
$sz = explode(',', 'B,KB,MB,GB'); return app('file')->humanReadableSize($path, $precision);
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . $sz[$factor];
}
/**
* Returns array of editable files.
*
* @return array
*/
public static function editableFiles()
{
return self::$editable;
} }
} }

View File

@ -54,6 +54,9 @@
"classmap": [ "classmap": [
"database" "database"
], ],
"files": [
"app/helpers.php"
],
"psr-4": { "psr-4": {
"Pterodactyl\\": "app/" "Pterodactyl\\": "app/"
} }

View File

@ -135,6 +135,33 @@ return [
'in_context' => env('PHRASE_IN_CONTEXT', false), 'in_context' => env('PHRASE_IN_CONTEXT', false),
], ],
/*
|--------------------------------------------------------------------------
| File Editor
|--------------------------------------------------------------------------
|
| This array includes the MIME filetypes that can be edited via the web.
*/
'files' => [
'editable' => [
'application/json',
'application/javascript',
'application/xml',
'application/xhtml+xml',
'inode/x-empty',
'text/xml',
'text/css',
'text/html',
'text/plain',
'text/x-perl',
'text/x-shellscript',
],
'pack_types' => [
'application/gzip',
'application/x-gzip',
],
],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| JSON Response Routes | JSON Response Routes

View File

@ -4,7 +4,7 @@ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Third Party Services | Third Party Service
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This file is for storing the credentials for third party services such | This file is for storing the credentials for third party services such

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemovePackWhenParentServiceOptionIsDeleted extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('packs', function (Blueprint $table) {
$table->dropForeign(['option_id']);
$table->foreign('option_id')->references('id')->on('service_options')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('packs', function (Blueprint $table) {
$table->dropForeign(['option_id']);
$table->foreign('option_id')->references('id')->on('service_options');
});
}
}

File diff suppressed because one or more lines are too long

View File

@ -173,7 +173,7 @@ return [
'service_header' => 'Service Control', 'service_header' => 'Service Control',
'service' => [ 'service' => [
'list' => [ 'list' => [
'title' => 'List Services', 'title' => 'List Service',
'desc' => 'Allows listing of all services configured on the system.', 'desc' => 'Allows listing of all services configured on the system.',
], ],
'view' => [ 'view' => [

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services &rarr; {{ $service->name }} &rarr; Functions Service &rarr; {{ $service->name }} &rarr; Functions
@endsection @endsection
@section('content-header') @section('content-header')
<h1>{{ $service->name }}<small>Extend the default daemon functions using this service file.</small></h1> <h1>{{ $service->name }}<small>Extend the default daemon functions using this service file.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.services.view', $service->id) }}">{{ $service->name }}</a></li> <li><a href="{{ route('admin.services.view', $service->id) }}">{{ $service->name }}</a></li>
<li class="active">Functions</li> <li class="active">Functions</li>
</ol> </ol>

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services Service
@endsection @endsection
@section('content-header') @section('content-header')
<h1>Services<small>All services currently available on this system.</small></h1> <h1>Service<small>All services currently available on this system.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li class="active">Services</li> <li class="active">Service</li>
</ol> </ol>
@endsection @endsection
@ -36,7 +36,7 @@
<div class="col-xs-12"> <div class="col-xs-12">
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">Configured Services</h3> <h3 class="box-title">Configured Service</h3>
<div class="box-tools"> <div class="box-tools">
<a href="{{ route('admin.services.new') }}"><button class="btn btn-primary btn-sm">Create New</button></a> <a href="{{ route('admin.services.new') }}"><button class="btn btn-primary btn-sm">Create New</button></a>
</div> </div>

View File

@ -27,7 +27,7 @@
<h1>New Service<small>Configure a new service to deploy to all nodes.</small></h1> <h1>New Service<small>Configure a new service to deploy to all nodes.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li class="active">New</li> <li class="active">New</li>
</ol> </ol>
@endsection @endsection
@ -64,7 +64,7 @@
<label class="control-label">Folder Name</label> <label class="control-label">Folder Name</label>
<div> <div>
<input type="text" name="folder" class="form-control" value="{{ old('folder') }}" /> <input type="text" name="folder" class="form-control" value="{{ old('folder') }}" />
<p class="text-muted"><small>Services are downloaded by the daemon and stored in a folder using this name. The storage location is <code>/srv/daemon/services/{NAME}</code> by default.</small></p> <p class="text-muted"><small>Service are downloaded by the daemon and stored in a folder using this name. The storage location is <code>/srv/daemon/services/{NAME}</code> by default.</small></p>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services &rarr; New Option Service &rarr; New Option
@endsection @endsection
@section('content-header') @section('content-header')
<h1>New Option<small>Create a new service option to assign to servers.</small></h1> <h1>New Option<small>Create a new service option to assign to servers.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li class="active">New Service Option</li> <li class="active">New Service Option</li>
</ol> </ol>
@endsection @endsection

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services &rarr; Option: {{ $option->name }} &rarr; Scripts Service &rarr; Option: {{ $option->name }} &rarr; Scripts
@endsection @endsection
@section('content-header') @section('content-header')
<h1>{{ $option->name }}<small>Manage install and upgrade scripts for this service option.</small></h1> <h1>{{ $option->name }}<small>Manage install and upgrade scripts for this service option.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li> <li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li>
<li class="active">{{ $option->name }}</li> <li class="active">{{ $option->name }}</li>
</ol> </ol>

View File

@ -27,7 +27,7 @@
<h1>{{ $option->name }}<small>Managing variables for this service option.</small></h1> <h1>{{ $option->name }}<small>Managing variables for this service option.</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li> <li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li>
<li><a href="{{ route('admin.services.option.view', $option->id) }}">{{ $option->name }}</a></li> <li><a href="{{ route('admin.services.option.view', $option->id) }}">{{ $option->name }}</a></li>
<li class="active">Variables</li> <li class="active">Variables</li>

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services &rarr; Option: {{ $option->name }} Service &rarr; Option: {{ $option->name }}
@endsection @endsection
@section('content-header') @section('content-header')
<h1>{{ $option->name }}<small>{{ str_limit($option->description, 50) }}</small></h1> <h1>{{ $option->name }}<small>{{ str_limit($option->description, 50) }}</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li> <li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li>
<li class="active">{{ $option->name }}</li> <li class="active">{{ $option->name }}</li>
</ol> </ol>

View File

@ -20,14 +20,14 @@
@extends('layouts.admin') @extends('layouts.admin')
@section('title') @section('title')
Services &rarr; {{ $service->name }} Service &rarr; {{ $service->name }}
@endsection @endsection
@section('content-header') @section('content-header')
<h1>{{ $service->name }}<small>{{ str_limit($service->description, 50) }}</small></h1> <h1>{{ $service->name }}<small>{{ str_limit($service->description, 50) }}</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li> <li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Services</a></li> <li><a href="{{ route('admin.services') }}">Service</a></li>
<li class="active">{{ $service->name }}</li> <li class="active">{{ $service->name }}</li>
</ol> </ol>
@endsection @endsection
@ -71,7 +71,7 @@
<label class="control-label">Folder Name</label> <label class="control-label">Folder Name</label>
<div> <div>
<input type="text" name="folder" class="form-control" value="{{ $service->folder }}" /> <input type="text" name="folder" class="form-control" value="{{ $service->folder }}" />
<p class="text-muted"><small>Services are downloaded by the daemon and stored in a folder using this name. The storage location is <code>/srv/daemon/services/{NAME}</code> by default.</small></p> <p class="text-muted"><small>Service are downloaded by the daemon and stored in a folder using this name. The storage location is <code>/srv/daemon/services/{NAME}</code> by default.</small></p>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -128,7 +128,7 @@
<li class="header">SERVICE MANAGEMENT</li> <li class="header">SERVICE MANAGEMENT</li>
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.services') ?: 'active' }}"> <li class="{{ ! starts_with(Route::currentRouteName(), 'admin.services') ?: 'active' }}">
<a href="{{ route('admin.services') }}"> <a href="{{ route('admin.services') }}">
<i class="fa fa-th-large"></i> <span>Services</span> <i class="fa fa-th-large"></i> <span>Service</span>
</a> </a>
</li> </li>
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.packs') ?: 'active' }}"> <li class="{{ ! starts_with(Route::currentRouteName(), 'admin.packs') ?: 'active' }}">

View File

@ -99,6 +99,9 @@ class DatabaseControllerTest extends TestCase
$this->assertViewKeyEquals('hosts', 'getWithViewDetails', $view); $this->assertViewKeyEquals('hosts', 'getWithViewDetails', $view);
} }
/**
* Test the view controller for displaying a specific database host.
*/
public function testViewController() public function testViewController()
{ {
$this->locationRepository->shouldReceive('getAllWithNodes')->withNoArgs()->once()->andReturn('getAllWithNodes'); $this->locationRepository->shouldReceive('getAllWithNodes')->withNoArgs()->once()->andReturn('getAllWithNodes');

View File

@ -71,7 +71,7 @@ class AssignmentServiceTest extends TestCase
// //
// This can also be avoided if tests were run in isolated processes, or if that test // This can also be avoided if tests were run in isolated processes, or if that test
// came first, but neither of those are good solutions, so this is the next best option. // came first, but neither of those are good solutions, so this is the next best option.
PHPMock::defineFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname'); PHPMock::defineFunctionMock('\\Pterodactyl\\Service\\Allocations', 'gethostbyname');
$this->node = factory(Node::class)->make(); $this->node = factory(Node::class)->make();
$this->connection = m::mock(ConnectionInterface::class); $this->connection = m::mock(ConnectionInterface::class);
@ -180,7 +180,7 @@ class AssignmentServiceTest extends TestCase
'allocation_ports' => ['1024'], 'allocation_ports' => ['1024'],
]; ];
$this->getFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname') $this->getFunctionMock('\\Pterodactyl\\Service\\Allocations', 'gethostbyname')
->expects($this->once())->willReturn('192.168.1.1'); ->expects($this->once())->willReturn('192.168.1.1');
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();

View File

@ -81,7 +81,7 @@ class KeyServiceTest extends TestCase
*/ */
public function test_create_function() public function test_create_function()
{ {
$this->getFunctionMock('\\Pterodactyl\\Services\\Api', 'random_bytes') $this->getFunctionMock('\\Pterodactyl\\Service\\Api', 'random_bytes')
->expects($this->exactly(2)) ->expects($this->exactly(2))
->willReturnCallback(function ($bytes) { ->willReturnCallback(function ($bytes) {
return hex2bin(str_pad('', $bytes * 2, '0')); return hex2bin(str_pad('', $bytes * 2, '0'));

View File

@ -84,7 +84,7 @@ class DatabaseManagementServiceTest extends TestCase
$this->encrypter = m::mock(Encrypter::class); $this->encrypter = m::mock(Encrypter::class);
$this->repository = m::mock(DatabaseRepositoryInterface::class); $this->repository = m::mock(DatabaseRepositoryInterface::class);
$this->getFunctionMock('\\Pterodactyl\\Services\\Database', 'str_random') $this->getFunctionMock('\\Pterodactyl\\Service\\Database', 'str_random')
->expects($this->any())->willReturn('str_random'); ->expects($this->any())->willReturn('str_random');
$this->service = new DatabaseManagementService( $this->service = new DatabaseManagementService(

View File

@ -61,7 +61,7 @@ class CreationServiceTest extends TestCase
*/ */
public function testNodeIsCreatedAndDaemonSecretIsGenerated() public function testNodeIsCreatedAndDaemonSecretIsGenerated()
{ {
$this->getFunctionMock('\\Pterodactyl\\Services\\Nodes', 'bin2hex') $this->getFunctionMock('\\Pterodactyl\\Service\\Nodes', 'bin2hex')
->expects($this->once())->willReturn('hexResult'); ->expects($this->once())->willReturn('hexResult');
$this->repository->shouldReceive('create')->with([ $this->repository->shouldReceive('create')->with([

View File

@ -97,14 +97,14 @@ class UpdateServiceTest extends TestCase
*/ */
public function testNodeIsUpdatedAndDaemonSecretIsReset() public function testNodeIsUpdatedAndDaemonSecretIsReset()
{ {
$this->getFunctionMock('\\Pterodactyl\\Services\\Nodes', 'random_bytes') $this->getFunctionMock('\\Pterodactyl\\Service\\Nodes', 'random_bytes')
->expects($this->once())->willReturnCallback(function ($bytes) { ->expects($this->once())->willReturnCallback(function ($bytes) {
$this->assertEquals(CreationService::DAEMON_SECRET_LENGTH, $bytes); $this->assertEquals(CreationService::DAEMON_SECRET_LENGTH, $bytes);
return '\00'; return '\00';
}); });
$this->getFunctionMock('\\Pterodactyl\\Services\\Nodes', 'bin2hex') $this->getFunctionMock('\\Pterodactyl\\Service\\Nodes', 'bin2hex')
->expects($this->once())->willReturn('hexResponse'); ->expects($this->once())->willReturn('hexResponse');
$this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf() $this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf()

View File

@ -155,7 +155,7 @@ class CreationServiceTest extends TestCase
$this->uuid = m::mock('overload:Ramsey\Uuid\Uuid'); $this->uuid = m::mock('overload:Ramsey\Uuid\Uuid');
$this->writer = m::mock(Writer::class); $this->writer = m::mock(Writer::class);
$this->getFunctionMock('\\Pterodactyl\\Services\\Servers', 'bin2hex') $this->getFunctionMock('\\Pterodactyl\\Service\\Servers', 'bin2hex')
->expects($this->any())->willReturn('randomstring'); ->expects($this->any())->willReturn('randomstring');
$this->getFunctionMock('\\Ramsey\\Uuid\\Uuid', 'uuid4') $this->getFunctionMock('\\Ramsey\\Uuid\\Uuid', 'uuid4')

View File

@ -84,7 +84,7 @@ class DetailsModificationServiceTest extends TestCase
$this->repository = m::mock(ServerRepository::class); $this->repository = m::mock(ServerRepository::class);
$this->writer = m::mock(Writer::class); $this->writer = m::mock(Writer::class);
$this->getFunctionMock('\\Pterodactyl\\Services\\Servers', 'bin2hex') $this->getFunctionMock('\\Pterodactyl\\Service\\Servers', 'bin2hex')
->expects($this->any())->willReturn('randomString'); ->expects($this->any())->willReturn('randomString');
$this->service = new DetailsModificationService( $this->service = new DetailsModificationService(

View File

@ -46,10 +46,10 @@ class UsernameGenerationServiceTest extends TestCase
$this->service = new UsernameGenerationService(); $this->service = new UsernameGenerationService();
$this->getFunctionMock('\\Pterodactyl\\Services\\Servers', 'bin2hex') $this->getFunctionMock('\\Pterodactyl\\Service\\Servers', 'bin2hex')
->expects($this->any())->willReturn('dddddddd'); ->expects($this->any())->willReturn('dddddddd');
$this->getFunctionMock('\\Pterodactyl\\Services\\Servers', 'str_random') $this->getFunctionMock('\\Pterodactyl\\Service\\Servers', 'str_random')
->expects($this->any())->willReturnCallback(function ($count) { ->expects($this->any())->willReturnCallback(function ($count) {
return str_pad('', $count, 'a'); return str_pad('', $count, 'a');
}); });

View File

@ -30,7 +30,7 @@ use Tests\TestCase;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Services\Services\Options\InstallScriptUpdateService; use Pterodactyl\Services\Services\Options\InstallScriptUpdateService;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\InvalidCopyFromException; use Pterodactyl\Exceptions\Service\ServiceOption\InvalidCopyFromException;
class InstallScriptUpdateServiceTest extends TestCase class InstallScriptUpdateServiceTest extends TestCase
{ {

View File

@ -30,7 +30,7 @@ use Tests\TestCase;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Services\Services\Options\OptionCreationService; use Pterodactyl\Services\Services\Options\OptionCreationService;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; use Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException;
class OptionCreationServiceTest extends TestCase class OptionCreationServiceTest extends TestCase
{ {

View File

@ -26,7 +26,7 @@ namespace Tests\Unit\Services\Services\Options;
use Mockery as m; use Mockery as m;
use Tests\TestCase; use Tests\TestCase;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Services\Services\Options\OptionDeletionService; use Pterodactyl\Services\Services\Options\OptionDeletionService;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;

View File

@ -30,7 +30,7 @@ use Tests\TestCase;
use Pterodactyl\Models\ServiceOption; use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Services\Services\Options\OptionUpdateService; use Pterodactyl\Services\Services\Options\OptionUpdateService;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; use Pterodactyl\Exceptions\Service\ServiceOption\NoParentConfigurationFoundException;
class OptionUpdateServiceTest extends TestCase class OptionUpdateServiceTest extends TestCase
{ {

View File

@ -28,7 +28,7 @@ use Exception;
use Mockery as m; use Mockery as m;
use Tests\TestCase; use Tests\TestCase;
use Pterodactyl\Services\Services\ServiceDeletionService; use Pterodactyl\Services\Services\ServiceDeletionService;
use Pterodactyl\Exceptions\Services\HasActiveServersException; use Pterodactyl\Exceptions\Service\HasActiveServersException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface;

View File

@ -99,7 +99,7 @@ class VariableCreationServiceTest extends TestCase
* Test that all of the reserved variables defined in the model trigger an exception. * Test that all of the reserved variables defined in the model trigger an exception.
* *
* @dataProvider reservedNamesProvider * @dataProvider reservedNamesProvider
* @expectedException \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @expectedException \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames($variable) public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames($variable)
{ {

View File

@ -126,7 +126,7 @@ class VariableUpdateServiceTest extends TestCase
* Test that all of the reserved variables defined in the model trigger an exception. * Test that all of the reserved variables defined in the model trigger an exception.
* *
* @dataProvider reservedNamesProvider * @dataProvider reservedNamesProvider
* @expectedException \Pterodactyl\Exceptions\Services\ServiceVariable\ReservedVariableNameException * @expectedException \Pterodactyl\Exceptions\Service\ServiceVariable\ReservedVariableNameException
*/ */
public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames($variable) public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames($variable)
{ {