First pass at XML exporter for services

This commit is contained in:
Dane Everitt 2017-10-03 00:01:04 -05:00
parent 12faf80faf
commit 0d739257a9
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
7 changed files with 283 additions and 3 deletions

View File

@ -0,0 +1,45 @@
<?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 Pterodactyl\Http\Controllers\Admin\Services\Options;
use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Services\Exporter\XMLExporterService;
class OptionShareController extends Controller
{
/**
* @var \Pterodactyl\Services\Services\Exporter\XMLExporterService
*/
protected $exporterService;
/**
* OptionShareController constructor.
*
* @param \Pterodactyl\Services\Services\Exporter\XMLExporterService $exporterService
*/
public function __construct(XMLExporterService $exporterService)
{
$this->exporterService = $exporterService;
}
/**
* @param \Pterodactyl\Models\ServiceOption $option
* @return $this
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function export(ServiceOption $option)
{
return response($this->exporterService->handle($option), 200, [
'Content-Type' => 'application/xml',
]);
}
}

View File

@ -0,0 +1,118 @@
<?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 Pterodactyl\Services\Services\Exporter;
use Carbon\Carbon;
use Sabre\Xml\Writer;
use Sabre\Xml\Service;
use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface;
class XMLExporterService
{
const XML_OPTION_NAMESPACE = '{https://pterodactyl.io/exporter/option/}';
/**
* @var \Carbon\Carbon
*/
protected $carbon;
/**
* @var \Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface
*/
protected $repository;
/**
* @var \Sabre\Xml\Service
*/
protected $xml;
/**
* XMLExporterService constructor.
*
* @param \Carbon\Carbon $carbon
* @param \Sabre\Xml\Service $xml
* @param \Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface $repository
*/
public function __construct(
Carbon $carbon,
Service $xml,
ServiceOptionRepositoryInterface $repository
) {
$this->carbon = $carbon;
$this->repository = $repository;
$this->xml = $xml;
$this->xml->namespaceMap = [
str_replace(['{', '}'], '', self::XML_OPTION_NAMESPACE) => 'p',
];
}
/**
* Return an XML structure to represent this service option.
*
* @param int|\Pterodactyl\Models\ServiceOption $option
* @return string
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function handle($option): string
{
if (! $option instanceof ServiceOption) {
$option = $this->repository->find($option);
}
$struct = [
'exported_at' => $this->carbon->now()->toIso8601String(),
'name' => $option->name,
'author' => array_get(explode(':', $option->tag), 0),
'tag' => $option->tag,
'description' => $option->description,
'image' => $option->docker_image,
'config' => [
'files' => $option->config_files,
'startup' => $option->config_startup,
'logs' => $option->config_logs,
'stop' => $option->config_stop,
],
'scripts' => [
'installation' => [
'script' => function (Writer $writer) use ($option) {
return $writer->writeCData($option->copy_script_install);
},
],
],
];
return $this->xml->write(self::XML_OPTION_NAMESPACE . 'root', $this->recursiveArrayKeyPrepend($struct));
}
/**
* @param array $array
* @param string $prepend
*
* @return array
*/
protected function recursiveArrayKeyPrepend(array $array, $prepend = self::XML_OPTION_NAMESPACE): array
{
$parsed = [];
foreach ($array as $k => &$v) {
$k = $prepend . $k;
if (is_array($v)) {
$v = $this->recursiveArrayKeyPrepend($v);
}
$parsed[$k] = $v;
}
return $parsed;
}
}

View File

@ -35,6 +35,7 @@
"prologue/alerts": "^0.4",
"ramsey/uuid": "^3.7",
"s1lentium/iptools": "^1.1",
"sabre/xml": "^2.0",
"sofa/eloquence": "~5.4.1",
"spatie/laravel-fractal": "^4.0",
"watson/validating": "^3.0",

116
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "46a0a06ec8f3af50ed6ec05c2bb3b9a3",
"content-hash": "bc8c88f86ea043406bce2f8fddf704b3",
"packages": [
{
"name": "aws/aws-sdk-php",
@ -2510,6 +2510,120 @@
],
"time": "2016-08-21T15:57:09+00:00"
},
{
"name": "sabre/uri",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-uri.git",
"reference": "a42126042c7dcb53e2978dadb6d22574d1359b4c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-uri/zipball/a42126042c7dcb53e2978dadb6d22574d1359b4c",
"reference": "a42126042c7dcb53e2978dadb6d22574d1359b4c",
"shasum": ""
},
"require": {
"php": ">=7"
},
"require-dev": {
"phpunit/phpunit": "^6.0",
"sabre/cs": "~1.0.0"
},
"type": "library",
"autoload": {
"files": [
"lib/functions.php"
],
"psr-4": {
"Sabre\\Uri\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "Functions for making sense out of URIs.",
"homepage": "http://sabre.io/uri/",
"keywords": [
"rfc3986",
"uri",
"url"
],
"time": "2017-02-20T20:02:35+00:00"
},
{
"name": "sabre/xml",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-xml.git",
"reference": "054292959a1f2b64c10c9c7a03a816ba1872b8a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-xml/zipball/054292959a1f2b64c10c9c7a03a816ba1872b8a3",
"reference": "054292959a1f2b64c10c9c7a03a816ba1872b8a3",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20",
"php": ">=7.0",
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
"phpunit/phpunit": "*",
"sabre/cs": "~1.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Sabre\\Xml\\": "lib/"
},
"files": [
"lib/Deserializer/functions.php",
"lib/Serializer/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Markus Staab",
"email": "markus.staab@redaxo.de",
"role": "Developer"
}
],
"description": "sabre/xml is an XML library that you may not hate.",
"homepage": "https://sabre.io/xml/",
"keywords": [
"XMLReader",
"XMLWriter",
"dom",
"xml"
],
"time": "2016-11-16T00:41:01+00:00"
},
{
"name": "sofa/eloquence",
"version": "5.4.1",

View File

@ -131,7 +131,8 @@
<button id="deleteButton" type="submit" name="_method" value="DELETE" class="btn btn-danger btn-sm muted muted-hover">
<i class="fa fa-trash-o"></i>
</button>
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Edit Service</button>
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Edit Option</button>
<a href="{{ route('admin.services.option.export', ['option' => $option->id]) }}" class="btn btn-sm btn-info pull-right" style="margin-right:10px;">Export Option Configuration</a>
</div>
</div>
</div>

View File

@ -101,7 +101,7 @@
@foreach($service->options as $option)
<tr>
<td><a href="{{ route('admin.services.option.view', $option->id) }}">{{ $option->name }}</a></td>
<td>{!! $option->description !!}</td>
<td class="col-xs-6">{!! $option->description !!}</td>
<td><code>{{ $option->tag }}</code></td>
<td class="text-center">{{ $option->servers->count() }}</td>
</tr>

View File

@ -155,6 +155,7 @@ Route::group(['prefix' => 'services'], function () {
Route::get('/view/{service}/functions', 'ServiceController@viewFunctions')->name('admin.services.view.functions');
Route::get('/option/new', 'OptionController@create')->name('admin.services.option.new');
Route::get('/option/{option}', 'OptionController@viewConfiguration')->name('admin.services.option.view');
Route::get('/option/{option}/export', 'Services\Options\OptionShareController@export')->name('admin.services.option.export');
Route::get('/option/{option}/variables', 'VariableController@view')->name('admin.services.option.variables');
Route::get('/option/{option}/scripts', 'OptionController@viewScripts')->name('admin.services.option.scripts');