diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php new file mode 100644 index 00000000..9d247439 --- /dev/null +++ b/app/Http/Controllers/Admin/PackController.php @@ -0,0 +1,108 @@ + + * + * 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\Http\Controllers\Admin; + +use Alert; +use Log; +use Storage; + +use Pterodactyl\Models; +use Pterodactyl\Repositories\ServiceRepository\Pack; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayValidationException; +use Pterodactyl\Exceptions\DisplayException; + +use Illuminate\Http\Request; + +class PackController extends Controller +{ + public function __construct() + { + // + } + + public function list(Request $request, $id) + { + $option = Models\ServiceOptions::findOrFail($id); + return view('admin.services.packs.index', [ + 'packs' => Models\ServicePack::where('option', $option->id)->get(), + 'service' => Models\Service::findOrFail($option->parent_service), + 'option' => $option + ]); + } + + public function new(Request $request, $opt = null) + { + $options = Models\ServiceOptions::select( + 'services.name AS p_service', + 'service_options.id', + 'service_options.name' + )->join('services', 'services.id', '=', 'service_options.parent_service')->get(); + + $array = []; + foreach($options as &$option) { + if (!array_key_exists($option->p_service, $array)) { + $array[$option->p_service] = []; + } + + $array[$option->p_service] = array_merge($array[$option->p_service], [[ + 'id' => $option->id, + 'name' => $option->name + ]]); + } + + return view('admin.services.packs.new', [ + 'services' => $array, + 'packFor' => $opt, + ]); + } + + public function create(Request $request) + { + // dd($request->all()); + try { + $repo = new Pack; + $id = $repo->create($request->except([ + '_token' + ])); + Alert::success('Successfully created new service!')->flash(); + return redirect()->route('admin.services.packs.edit', $id)->withInput(); + } catch (DisplayValidationException $ex) { + return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); + } catch (DisplayException $ex) { + Alert::danger($ex->getMessage())->flash(); + } catch (\Exception $ex) { + Log::error($ex); + Alert::danger('An error occured while attempting to add a new service pack.')->flash(); + } + return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput(); + + } + + public function edit(Request $request, $id) + { + $pack = Models\ServicePack::findOrFail($id); + dd($pack, Storage::url('packs/' . $pack->uuid)); + } +} diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index 726fccc2..73679de6 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -430,6 +430,32 @@ class AdminRoutes { ]); }); + // Service Packs + $router->group([ + 'prefix' => 'admin/services/packs', + 'middleware' => [ + 'auth', + 'admin', + 'csrf' + ] + ], function () use ($router) { + $router->get('/new/{option?}', [ + 'as' => 'admin.services.packs.new', + 'uses' => 'Admin\PackController@new' + ]); + $router->post('/new', [ + 'uses' => 'Admin\PackController@create' + ]); + $router->get('/for/{option}', [ + 'as' => 'admin.services.packs.for', + 'uses' => 'Admin\PackController@list' + ]); + $router->get('/edit/{pack}', [ + 'as' => 'admin.services.packs.edit', + 'uses' => 'Admin\PackController@edit' + ]); + }); + } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php new file mode 100644 index 00000000..f43be94b --- /dev/null +++ b/app/Models/ServicePack.php @@ -0,0 +1,60 @@ + + * + * 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\Models; + +use Illuminate\Database\Eloquent\Model; + +class ServicePack extends Model +{ + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'service_packs'; + + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'option' => 'integer', + 'build_memory' => 'integer', + 'build_swap' => 'integer', + 'build_cpu' => 'integer', + 'build_io' => 'integer', + 'selectable' => 'boolean', + 'visible' => 'boolean' + ]; + +} diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php new file mode 100644 index 00000000..b644dae5 --- /dev/null +++ b/app/Repositories/ServiceRepository/Pack.php @@ -0,0 +1,105 @@ + + * + * 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\ServiceRepository; + +use DB; +use Storage; +use Uuid; +use Validator; + +use Pterodactyl\Models; +use Pterodactyl\Services\UuidService; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Exceptions\DisplayValidationException; + +class Pack +{ + + public function __construct() + { + // + } + + public function create(array $data) + { + $validator = Validator::make($data, [ + 'name' => 'required|string', + 'version' => 'required|string', + 'description' => 'string', + 'option' => 'required|exists:service_options,id', + 'selectable' => 'sometimes|boolean', + 'visible' => 'sometimes|boolean', + 'build_memory' => 'required|integer|min:0', + 'build_swap' => 'required|integer|min:0', + 'build_cpu' => 'required|integer|min:0', + 'build_io' => 'required|integer|min:10|max:1000', + 'build_container' => 'required|string', + 'build_script' => 'sometimes|string' + ]); + + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + if (isset($data['file_upload'])) { + if (!$data['file_upload']->isValid()) { + throw new DisplayException('The file provided does not appear to be valid.'); + } + + if (!in_array($data['file_upload']->getMimeType(), [ + 'application/zip', + 'application/gzip' + ])) { + throw new DisplayException('The file provided does not meet the required filetypes of application/zip or application/gzip.'); + } + } + + DB::transaction(function () use ($data) { + $uuid = new UuidService; + $pack = Models\ServicePack::create([ + 'option' => $data['option'], + 'uuid' => $uuid->generate('servers', 'uuid'), + 'build_memory' => $data['build_memory'], + 'build_swap' => $data['build_swap'], + 'build_cpu' => $data['build_swap'], + 'build_io' => $data['build_io'], + 'build_script' => (empty($data['build_script'])) ? null : $data['build_script'], + 'build_container' => $data['build_container'], + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']) + ]); + + $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; + $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + + $pack->save(); + + return $pack->id; + }); + } + +} diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 4dc1755b..91062dcb 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -101,6 +101,8 @@ class Service DB::beginTransaction(); try { + Storage::deleteDirectory('services/' . $service->file); + Models\ServiceVariables::whereIn('option_id', $options->get()->toArray())->delete(); $options->delete(); $service->delete(); @@ -128,23 +130,10 @@ class Service $filepath = 'services/' . $service->file . '/' . $filename; $backup = 'services/.bak/' . str_random(12) . '.bak'; - DB::beginTransaction(); - try { Storage::move($filepath, $backup); Storage::put($filepath, $data['contents']); - - $checksum = Models\Checksum::firstOrNew([ - 'service' => $service->id, - 'filename' => $filename - ]); - - $checksum->checksum = sha1_file(storage_path('app/' . $filepath)); - $checksum->save(); - - DB::commit(); } catch(\Exception $ex) { - DB::rollback(); Storage::move($backup, $filepath); throw $ex; } diff --git a/database/migrations/2016_11_09_163911_add_checksums_table.php b/database/migrations/2016_11_09_163911_add_checksums_table.php deleted file mode 100644 index 4935faaf..00000000 --- a/database/migrations/2016_11_09_163911_add_checksums_table.php +++ /dev/null @@ -1,36 +0,0 @@ -increments('id'); - $table->integer('service')->unsigned(); - $table->string('filename'); - $table->char('checksum', 40); - $table->timestamps(); - - $table->foreign('service')->references('id')->on('services'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::drop('checksums'); - } -} diff --git a/database/migrations/2016_11_11_220649_add_pack_support.php b/database/migrations/2016_11_11_220649_add_pack_support.php new file mode 100644 index 00000000..87a66b40 --- /dev/null +++ b/database/migrations/2016_11_11_220649_add_pack_support.php @@ -0,0 +1,46 @@ +increments('id'); + $table->unsignedInteger('option'); + $table->char('uuid', 36)->unique(); + $table->unsignedInteger('build_memory')->nullable(); + $table->unsignedInteger('build_swap')->nullable(); + $table->unsignedInteger('build_cpu')->nullable(); + $table->unsignedInteger('build_io')->nullable(); + $table->text('build_script')->nullable(); + $table->string('build_container')->default('alpine:latest'); + $table->string('name'); + $table->string('version'); + $table->text('description')->nullable(); + $table->boolean('selectable')->default(true); + $table->boolean('visible')->default(true); + $table->timestamps(); + + $table->foreign('option')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('service_packs'); + } +} diff --git a/database/migrations/2016_11_11_231731_set_service_name_unique.php b/database/migrations/2016_11_11_231731_set_service_name_unique.php new file mode 100644 index 00000000..4db76f8e --- /dev/null +++ b/database/migrations/2016_11_11_231731_set_service_name_unique.php @@ -0,0 +1,32 @@ +unique('name'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('services', function (Blueprint $table) { + $table->dropUnique('services_name_unique'); + }); + } +} diff --git a/public/themes/default/css/pterodactyl.css b/public/themes/default/css/pterodactyl.css index 607da8d1..fb24beda 100755 --- a/public/themes/default/css/pterodactyl.css +++ b/public/themes/default/css/pterodactyl.css @@ -307,3 +307,14 @@ td.has-progress { padding:0; border:0; } + +.fuelux .checkbox-formheight.checkbox-custom.checkbox-inline.highlight { + height: 36px; + padding: 10px 8px 4px 28px; + width: 100%; +} + +.fuelux .checkbox-formheight.checkbox-custom.checkbox-inline.highlight:before { + left: 8px; + top: 11px; +} diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index d5de1a91..414f8974 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -30,6 +30,7 @@
Name | +Version | +UUID | +Selectable | +Visible | +
---|---|---|---|---|
{{ $pack->name }} | +{{ $pack->version }} | +{{ $pack->uuid }} |
+ @if($pack->selectable)@else@endif | +@if($pack->visible)@else@endif | +
+ + + + + + + | +