Move services onto new services system, includes tests
This commit is contained in:
		
							parent
							
								
									e91079d128
								
							
						
					
					
						commit
						90bbe57148
					
				| @ -12,7 +12,6 @@ services: | ||||
| before_install: | ||||
|   - mysql -e 'CREATE DATABASE IF NOT EXISTS travis;' | ||||
| before_script: | ||||
| #  - phpenv config-rm xdebug.ini | ||||
|   - cp .env.travis .env | ||||
|   - composer install --no-interaction --prefer-dist --no-suggest --verbose | ||||
|   - php artisan migrate --seed -v | ||||
|  | ||||
| @ -33,4 +33,12 @@ interface ServiceRepositoryInterface extends RepositoryInterface | ||||
|      * @return \Illuminate\Support\Collection | ||||
|      */ | ||||
|     public function getWithOptions($id = null); | ||||
| 
 | ||||
|     /** | ||||
|      * Return a service along with its associated options and the servers relation on those options. | ||||
|      * | ||||
|      * @param  int $id | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getWithOptionServers($id); | ||||
| } | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| namespace Pterodactyl\Exceptions\Services\ServiceOption; | ||||
| namespace Pterodactyl\Exceptions\Services; | ||||
| 
 | ||||
| class HasActiveServersException extends \Exception | ||||
| { | ||||
| @ -38,7 +38,7 @@ use Pterodactyl\Http\Requests\Admin\Service\ServiceOptionFormRequest; | ||||
| use Pterodactyl\Services\Services\Options\InstallScriptUpdateService; | ||||
| use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; | ||||
| use Pterodactyl\Exceptions\Services\ServiceOption\InvalidCopyFromException; | ||||
| use Pterodactyl\Exceptions\Services\ServiceOption\HasActiveServersException; | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| use Pterodactyl\Exceptions\Services\ServiceOption\NoParentConfigurationFoundException; | ||||
| 
 | ||||
| class OptionController extends Controller | ||||
| @ -145,14 +145,14 @@ class OptionController extends Controller | ||||
|     /** | ||||
|      * Delete a given option from the database. | ||||
|      * | ||||
|      * @param \Pterodactyl\Models\ServiceOption $option | ||||
|      * @param  \Pterodactyl\Models\ServiceOption $option | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      */ | ||||
|     public function delete(ServiceOption $option) | ||||
|     public function destroy(ServiceOption $option) | ||||
|     { | ||||
|         try { | ||||
|             $this->optionDeletionService->handle($option->id); | ||||
|             $this->alert->success()->flash(); | ||||
|             $this->alert->success(trans('admin/services.options.notices.option_deleted'))->flash(); | ||||
|         } catch (HasActiveServersException $exception) { | ||||
|             $this->alert->danger($exception->getMessage())->flash(); | ||||
| 
 | ||||
| @ -229,6 +229,7 @@ class OptionController extends Controller | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException | ||||
|      */ | ||||
|     public function updateScripts(EditOptionScript $request, ServiceOption $option) | ||||
|     { | ||||
|  | ||||
| @ -24,37 +24,76 @@ | ||||
| 
 | ||||
| namespace Pterodactyl\Http\Controllers\Admin; | ||||
| 
 | ||||
| use Log; | ||||
| use Alert; | ||||
| use Pterodactyl\Models; | ||||
| use Illuminate\Http\Request; | ||||
| use Pterodactyl\Exceptions\DisplayException; | ||||
| use Pterodactyl\Models\Service; | ||||
| use Prologue\Alerts\AlertsMessageBag; | ||||
| use Pterodactyl\Http\Controllers\Controller; | ||||
| use Pterodactyl\Repositories\ServiceRepository; | ||||
| use Pterodactyl\Exceptions\DisplayValidationException; | ||||
| use Pterodactyl\Services\Services\ServiceUpdateService; | ||||
| use Pterodactyl\Services\Services\ServiceCreationService; | ||||
| use Pterodactyl\Services\Services\ServiceDeletionService; | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| use Pterodactyl\Http\Requests\Admin\Service\ServiceFormRequest; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| use Pterodactyl\Http\Requests\Admin\Service\ServiceFunctionsFormRequest; | ||||
| 
 | ||||
| class ServiceController extends Controller | ||||
| { | ||||
|     /** | ||||
|      * @var \Prologue\Alerts\AlertsMessageBag | ||||
|      */ | ||||
|     protected $alert; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceCreationService | ||||
|      */ | ||||
|     protected $creationService; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceDeletionService | ||||
|      */ | ||||
|     protected $deletionService; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceUpdateService | ||||
|      */ | ||||
|     protected $updateService; | ||||
| 
 | ||||
|     public function __construct( | ||||
|         AlertsMessageBag $alert, | ||||
|         ServiceCreationService $creationService, | ||||
|         ServiceDeletionService $deletionService, | ||||
|         ServiceRepositoryInterface $repository, | ||||
|         ServiceUpdateService $updateService | ||||
|     ) { | ||||
|         $this->alert = $alert; | ||||
|         $this->creationService = $creationService; | ||||
|         $this->deletionService = $deletionService; | ||||
|         $this->repository = $repository; | ||||
|         $this->updateService = $updateService; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Display service overview page. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function index(Request $request) | ||||
|     public function index() | ||||
|     { | ||||
|         return view('admin.services.index', [ | ||||
|             'services' => Models\Service::withCount('servers', 'options', 'packs')->get(), | ||||
|             'services' => $this->repository->getWithOptions(), | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Display create service page. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function create(Request $request) | ||||
|     public function create() | ||||
|     { | ||||
|         return view('admin.services.new'); | ||||
|     } | ||||
| @ -62,91 +101,96 @@ class ServiceController extends Controller | ||||
|     /** | ||||
|      * Return base view for a service. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @param  int                       $id | ||||
|      * @param  int $service | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function view(Request $request, $id) | ||||
|     public function view($service) | ||||
|     { | ||||
|         return view('admin.services.view', [ | ||||
|             'service' => Models\Service::with('options', 'options.servers')->findOrFail($id), | ||||
|             'service' => $this->repository->getWithOptionServers($service), | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Return function editing view for a service. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @param  int                       $id | ||||
|      * @param  \Pterodactyl\Models\Service $service | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function viewFunctions(Request $request, $id) | ||||
|     public function viewFunctions(Service $service) | ||||
|     { | ||||
|         return view('admin.services.functions', ['service' => Models\Service::findOrFail($id)]); | ||||
|         return view('admin.services.functions', ['service' => $service]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle post action for new service. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @param  \Pterodactyl\Http\Requests\Admin\Service\ServiceFormRequest $request | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      */ | ||||
|     public function store(Request $request) | ||||
|     public function store(ServiceFormRequest $request) | ||||
|     { | ||||
|         $repo = new ServiceRepository; | ||||
|         $service = $this->creationService->handle($request->normalize()); | ||||
|         $this->alert->success(trans('admin/services.notices.service_created', ['name' => $service->name]))->flash(); | ||||
| 
 | ||||
|         try { | ||||
|             $service = $repo->create($request->intersect([ | ||||
|                 'name', 'description', 'folder', 'startup', | ||||
|             ])); | ||||
|             Alert::success('Successfully created new service!')->flash(); | ||||
| 
 | ||||
|             return redirect()->route('admin.services.view', $service->id); | ||||
|         } catch (DisplayValidationException $ex) { | ||||
|             return redirect()->route('admin.services.new')->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. This error has been logged.')->flash(); | ||||
|         } | ||||
| 
 | ||||
|         return redirect()->route('admin.services.new')->withInput(); | ||||
|         return redirect()->route('admin.services.view', $service->id); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Edits configuration for a specific service. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @param  int                       $id | ||||
|      * @param  \Pterodactyl\Http\Requests\Admin\Service\ServiceFormRequest $request | ||||
|      * @param  \Pterodactyl\Models\Service                                 $service | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException | ||||
|      */ | ||||
|     public function update(ServiceFormRequest $request, Service $service) | ||||
|     { | ||||
|         $this->updateService->handle($service->id, $request->normalize()); | ||||
|         $this->alert->success(trans('admin/services.notices.service_updated'))->flash(); | ||||
| 
 | ||||
|         return redirect()->route('admin.services.view', $service); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Update the functions file for a service. | ||||
|      * | ||||
|      * @param  \Pterodactyl\Http\Requests\Admin\Service\ServiceFunctionsFormRequest $request | ||||
|      * @param  \Pterodactyl\Models\Service                                           $service | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException | ||||
|      */ | ||||
|     public function updateFunctions(ServiceFunctionsFormRequest $request, Service $service) | ||||
|     { | ||||
|         $this->updateService->handle($service->id, $request->normalize()); | ||||
|         $this->alert->success(trans('admin/services.notices.functions_updated'))->flash(); | ||||
| 
 | ||||
|         return redirect()->route('admin.services.view.functions', $service->id); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete a service from the panel. | ||||
|      * | ||||
|      * @param  \Pterodactyl\Models\Service $service | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      */ | ||||
|     public function edit(Request $request, $id) | ||||
|     public function destroy(Service $service) | ||||
|     { | ||||
|         $repo = new ServiceRepository; | ||||
|         $redirectTo = ($request->input('redirect_to')) ? 'admin.services.view.functions' : 'admin.services.view'; | ||||
| 
 | ||||
|         try { | ||||
|             if ($request->input('action') !== 'delete') { | ||||
|                 $repo->update($id, $request->intersect([ | ||||
|                     'name', 'description', 'folder', 'startup', 'index_file', | ||||
|                 ])); | ||||
|                 Alert::success('Service has been updated successfully.')->flash(); | ||||
|             } else { | ||||
|                 $repo->delete($id); | ||||
|                 Alert::success('Successfully deleted service from the system.')->flash(); | ||||
|             $this->deletionService->handle($service->id); | ||||
|             $this->alert->success(trans('admin/services.notices.service_deleted'))->flash(); | ||||
|         } catch (HasActiveServersException $exception) { | ||||
|             $this->alert->danger($exception->getMessage())->flash(); | ||||
| 
 | ||||
|                 return redirect()->route('admin.services'); | ||||
|             } | ||||
|         } catch (DisplayValidationException $ex) { | ||||
|             return redirect()->route($redirectTo, $id)->withErrors(json_decode($ex->getMessage()))->withInput(); | ||||
|         } catch (DisplayException $ex) { | ||||
|             Alert::danger($ex->getMessage())->flash(); | ||||
|         } catch (\Exception $ex) { | ||||
|             Log::error($ex); | ||||
|             Alert::danger('An error occurred while attempting to update this service. This error has been logged.')->flash(); | ||||
|             return redirect()->back(); | ||||
|         } | ||||
| 
 | ||||
|         return redirect()->route($redirectTo, $id); | ||||
|         return redirect()->route('admin.services'); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										52
									
								
								app/Http/Requests/Admin/Service/ServiceFormRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								app/Http/Requests/Admin/Service/ServiceFormRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| <?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\Http\Requests\Admin\Service; | ||||
| 
 | ||||
| use Pterodactyl\Http\Requests\Admin\AdminFormRequest; | ||||
| 
 | ||||
| class ServiceFormRequest extends AdminFormRequest | ||||
| { | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public function rules() | ||||
|     { | ||||
|         $rules = [ | ||||
|             'name' => 'required|string|min:1|max:255', | ||||
|             'description' => 'required|nullable|string', | ||||
|             'folder' => 'required|regex:/^[\w.-]{1,50}$/|unique:services,folder', | ||||
|             'startup' => 'required|nullable|string', | ||||
|         ]; | ||||
| 
 | ||||
|         if ($this->method() === 'PATCH') { | ||||
|             $service = $this->route()->parameter('service'); | ||||
|             $rules['folder'] = $rules['folder'] . ',' . $service->id; | ||||
| 
 | ||||
|             return $rules; | ||||
|         } | ||||
| 
 | ||||
|         return $rules; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| <?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\Http\Requests\Admin\Service; | ||||
| 
 | ||||
| use Pterodactyl\Http\Requests\Admin\AdminFormRequest; | ||||
| 
 | ||||
| class ServiceFunctionsFormRequest extends AdminFormRequest | ||||
| { | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public function rules() | ||||
|     { | ||||
|         return [ | ||||
|             'index_file' => 'required|nullable|string', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @ -24,10 +24,16 @@ | ||||
| 
 | ||||
| namespace Pterodactyl\Models; | ||||
| 
 | ||||
| use Sofa\Eloquence\Eloquence; | ||||
| use Sofa\Eloquence\Validable; | ||||
| use Illuminate\Database\Eloquent\Model; | ||||
| use Sofa\Eloquence\Contracts\CleansAttributes; | ||||
| use Sofa\Eloquence\Contracts\Validable as ValidableContract; | ||||
| 
 | ||||
| class Service extends Model | ||||
| class Service extends Model implements CleansAttributes, ValidableContract | ||||
| { | ||||
|     use Eloquence, Validable; | ||||
| 
 | ||||
|     /** | ||||
|      * The table associated with the model. | ||||
|      * | ||||
| @ -40,52 +46,31 @@ class Service extends Model | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $fillable = [ | ||||
|         'name', 'description', 'folder', 'startup', 'index_file', | ||||
|     protected $fillable = ['name', 'author', 'description', 'folder', 'startup', 'index_file']; | ||||
| 
 | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     protected static $applicationRules = [ | ||||
|         'author' => 'required', | ||||
|         'name' => 'required', | ||||
|         'description' => 'sometimes', | ||||
|         'folder' => 'required', | ||||
|         'startup' => 'sometimes', | ||||
|         'index_file' => 'required', | ||||
|     ]; | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the default contents of the index.js file for a service. | ||||
|      * | ||||
|      * @return string | ||||
|      * @var array | ||||
|      */ | ||||
|     public static function defaultIndexFile() | ||||
|     { | ||||
|         return <<<'EOF' | ||||
| 'use strict'; | ||||
| 
 | ||||
| /** | ||||
|  * Pterodactyl - Daemon | ||||
|  * 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. | ||||
|  */ | ||||
| const rfr = require('rfr'); | ||||
| const _ = require('lodash'); | ||||
| 
 | ||||
| const Core = rfr('src/services/index.js'); | ||||
| 
 | ||||
| class Service extends Core {} | ||||
| 
 | ||||
| module.exports = Service; | ||||
| EOF; | ||||
|     } | ||||
|     protected static $dataIntegrityRules = [ | ||||
|         'author' => 'string|size:36', | ||||
|         'name' => 'string|max:255', | ||||
|         'description' => 'nullable|string', | ||||
|         'folder' => 'string|max:255|regex:/^[\w.-]{1,50}$/|unique:services,folder', | ||||
|         'startup' => 'nullable|string', | ||||
|         'index_file' => 'string', | ||||
|     ]; | ||||
| 
 | ||||
|     /** | ||||
|      * Gets all service options associated with this service. | ||||
|  | ||||
| @ -49,8 +49,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function create(array $fields, $validate = true, $force = false) | ||||
|     { | ||||
|         Assert::boolean($validate, 'Second argument passed to create should be boolean, recieved %s.'); | ||||
|         Assert::boolean($force, 'Third argument passed to create should be boolean, received %s.'); | ||||
|         Assert::boolean($validate, 'Second argument passed to create must be boolean, recieved %s.'); | ||||
|         Assert::boolean($force, 'Third argument passed to create must be boolean, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->newModelInstance(); | ||||
| 
 | ||||
| @ -77,7 +77,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function find($id) | ||||
|     { | ||||
|         Assert::integer($id, 'First argument passed to find should be integer, received %s.'); | ||||
|         Assert::numeric($id, 'First argument passed to find must be numeric, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->find($id, $this->getColumns()); | ||||
| 
 | ||||
| @ -125,8 +125,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function delete($id, $destroy = false) | ||||
|     { | ||||
|         Assert::integer($id, 'First argument passed to delete should be integer, received %s.'); | ||||
|         Assert::boolean($destroy, 'Second argument passed to delete should be boolean, received %s.'); | ||||
|         Assert::numeric($id, 'First argument passed to delete must be numeric, received %s.'); | ||||
|         Assert::boolean($destroy, 'Second argument passed to delete must be boolean, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->where($this->getModel()->getKeyName(), $id); | ||||
| 
 | ||||
| @ -138,7 +138,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function deleteWhere(array $attributes, $force = false) | ||||
|     { | ||||
|         Assert::boolean($force, 'Second argument passed to deleteWhere should be boolean, received %s.'); | ||||
|         Assert::boolean($force, 'Second argument passed to deleteWhere must be boolean, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->where($attributes); | ||||
| 
 | ||||
| @ -150,9 +150,9 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function update($id, array $fields, $validate = true, $force = false) | ||||
|     { | ||||
|         Assert::integer($id, 'First argument passed to update expected to be integer, received %s.'); | ||||
|         Assert::boolean($validate, 'Third argument passed to update should be boolean, received %s.'); | ||||
|         Assert::boolean($force, 'Fourth argument passed to update should be boolean, received %s.'); | ||||
|         Assert::numeric($id, 'First argument passed to update must be numeric, received %s.'); | ||||
|         Assert::boolean($validate, 'Third argument passed to update must be boolean, received %s.'); | ||||
|         Assert::boolean($force, 'Fourth argument passed to update must be boolean, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->where('id', $id)->first(); | ||||
| 
 | ||||
| @ -182,7 +182,7 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function updateWhereIn($column, array $values, array $fields) | ||||
|     { | ||||
|         Assert::stringNotEmpty($column, 'First argument passed to updateWhereIn expected to be a string, received %s.'); | ||||
|         Assert::stringNotEmpty($column, 'First argument passed to updateWhereIn must be a non-empty string, received %s.'); | ||||
| 
 | ||||
|         return $this->getBuilder()->whereIn($column, $values)->update($fields); | ||||
|     } | ||||
| @ -255,8 +255,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf | ||||
|      */ | ||||
|     public function updateOrCreate(array $where, array $fields, $validate = true, $force = false) | ||||
|     { | ||||
|         Assert::boolean($validate, 'Third argument passed to updateOrCreate should be boolean, received %s.'); | ||||
|         Assert::boolean($force, 'Fourth argument passed to updateOrCreate should be boolean, received %s.'); | ||||
|         Assert::boolean($validate, 'Third argument passed to updateOrCreate must be boolean, received %s.'); | ||||
|         Assert::boolean($force, 'Fourth argument passed to updateOrCreate must be boolean, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->withColumns('id')->findWhere($where)->first(); | ||||
| 
 | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| 
 | ||||
| namespace Pterodactyl\Repositories\Eloquent; | ||||
| 
 | ||||
| use Webmozart\Assert\Assert; | ||||
| use Pterodactyl\Models\Service; | ||||
| use Pterodactyl\Exceptions\Repository\RecordNotFoundException; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| @ -43,11 +44,12 @@ class ServiceRepository extends EloquentRepository implements ServiceRepositoryI | ||||
|      */ | ||||
|     public function getWithOptions($id = null) | ||||
|     { | ||||
|         Assert::nullOrNumeric($id, 'First argument passed to getWithOptions must be null or numeric, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->with('options.packs', 'options.variables'); | ||||
| 
 | ||||
|         if (! is_null($id)) { | ||||
|             $instance = $instance->find($id, $this->getColumns()); | ||||
| 
 | ||||
|             if (! $instance) { | ||||
|                 throw new RecordNotFoundException(); | ||||
|             } | ||||
| @ -57,4 +59,19 @@ class ServiceRepository extends EloquentRepository implements ServiceRepositoryI | ||||
| 
 | ||||
|         return $instance->get($this->getColumns()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function getWithOptionServers($id) | ||||
|     { | ||||
|         Assert::numeric($id, 'First argument passed to getWithOptionServers must be numeric, received %s.'); | ||||
| 
 | ||||
|         $instance = $this->getBuilder()->with('options.servers')->find($id, $this->getColumns()); | ||||
|         if (! $instance) { | ||||
|             throw new RecordNotFoundException(); | ||||
|         } | ||||
| 
 | ||||
|         return $instance; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,135 +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 DB; | ||||
| use Validator; | ||||
| use Pterodactyl\Models\Service; | ||||
| use Pterodactyl\Exceptions\DisplayException; | ||||
| use Pterodactyl\Exceptions\DisplayValidationException; | ||||
| 
 | ||||
| class ServiceRepository | ||||
| { | ||||
|     /** | ||||
|      * Creates a new service on the system. | ||||
|      * | ||||
|      * @param  array  $data | ||||
|      * @return \Pterodactyl\Models\Service | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\DisplayValidationException | ||||
|      */ | ||||
|     public function create(array $data) | ||||
|     { | ||||
|         $validator = Validator::make($data, [ | ||||
|             'name' => 'required|string|min:1|max:255', | ||||
|             'description' => 'required|nullable|string', | ||||
|             'folder' => 'required|unique:services,folder|regex:/^[\w.-]{1,50}$/', | ||||
|             'startup' => 'required|nullable|string', | ||||
|         ]); | ||||
| 
 | ||||
|         if ($validator->fails()) { | ||||
|             throw new DisplayValidationException(json_encode($validator->errors())); | ||||
|         } | ||||
| 
 | ||||
|         return DB::transaction(function () use ($data) { | ||||
|             $service = new Service; | ||||
|             $service->author = config('pterodactyl.service.author'); | ||||
|             $service->fill([ | ||||
|                 'name' => $data['name'], | ||||
|                 'description' => (isset($data['description'])) ? $data['description'] : null, | ||||
|                 'folder' => $data['folder'], | ||||
|                 'startup' => (isset($data['startup'])) ? $data['startup'] : null, | ||||
|                 'index_file' => Service::defaultIndexFile(), | ||||
|             ])->save(); | ||||
| 
 | ||||
|             // It is possible for an event to return false or throw an exception
 | ||||
|             // which won't necessarily be detected by this transaction.
 | ||||
|             //
 | ||||
|             // This check ensures the model was actually saved.
 | ||||
|             if (! $service->exists) { | ||||
|                 throw new \Exception('Service model was created however the response appears to be invalid. Did an event fire wrongly?'); | ||||
|             } | ||||
| 
 | ||||
|             return $service; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Updates a service. | ||||
|      * | ||||
|      * @param  int    $id | ||||
|      * @param  array  $data | ||||
|      * @return \Pterodactyl\Models\Service | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\DisplayValidationException | ||||
|      */ | ||||
|     public function update($id, array $data) | ||||
|     { | ||||
|         $service = Service::findOrFail($id); | ||||
| 
 | ||||
|         $validator = Validator::make($data, [ | ||||
|             'name' => 'sometimes|required|string|min:1|max:255', | ||||
|             'description' => 'sometimes|required|nullable|string', | ||||
|             'folder' => 'sometimes|required|regex:/^[\w.-]{1,50}$/', | ||||
|             'startup' => 'sometimes|required|nullable|string', | ||||
|             'index_file' => 'sometimes|required|string', | ||||
|         ]); | ||||
| 
 | ||||
|         if ($validator->fails()) { | ||||
|             throw new DisplayValidationException(json_encode($validator->errors())); | ||||
|         } | ||||
| 
 | ||||
|         return DB::transaction(function () use ($data, $service) { | ||||
|             $service->fill($data)->save(); | ||||
| 
 | ||||
|             return $service; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Deletes a service and associated files and options. | ||||
|      * | ||||
|      * @param  int   $id | ||||
|      * @return void | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\DisplayException | ||||
|      */ | ||||
|     public function delete($id) | ||||
|     { | ||||
|         $service = Service::withCount('servers')->with('options')->findOrFail($id); | ||||
| 
 | ||||
|         if ($service->servers_count > 0) { | ||||
|             throw new DisplayException('You cannot delete a service that has servers associated with it.'); | ||||
|         } | ||||
| 
 | ||||
|         DB::transaction(function () use ($service) { | ||||
|             foreach ($service->options as $option) { | ||||
|                 (new OptionRepository)->delete($option->id); | ||||
|             } | ||||
| 
 | ||||
|             $service->delete(); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @ -26,7 +26,7 @@ namespace Pterodactyl\Services\Services\Options; | ||||
| 
 | ||||
| use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; | ||||
| use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; | ||||
| use Pterodactyl\Exceptions\Services\ServiceOption\HasActiveServersException; | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| 
 | ||||
| class OptionDeletionService | ||||
| { | ||||
| @ -60,7 +60,7 @@ class OptionDeletionService | ||||
|      * @param  int $option | ||||
|      * @return int | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Services\ServiceOption\HasActiveServersException | ||||
|      * @throws \Pterodactyl\Exceptions\Services\HasActiveServersException | ||||
|      */ | ||||
|     public function handle($option) | ||||
|     { | ||||
|  | ||||
							
								
								
									
										79
									
								
								app/Services/Services/ServiceCreationService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								app/Services/Services/ServiceCreationService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| <?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\Services; | ||||
| 
 | ||||
| use Pterodactyl\Traits\Services\CreatesServiceIndex; | ||||
| use Illuminate\Contracts\Config\Repository as ConfigRepository; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| 
 | ||||
| class ServiceCreationService | ||||
| { | ||||
|     use CreatesServiceIndex; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Illuminate\Contracts\Config\Repository | ||||
|      */ | ||||
|     protected $config; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * ServiceCreationService constructor. | ||||
|      * | ||||
|      * @param \Illuminate\Contracts\Config\Repository                      $config | ||||
|      * @param \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface $repository | ||||
|      */ | ||||
|     public function __construct( | ||||
|         ConfigRepository $config, | ||||
|         ServiceRepositoryInterface $repository | ||||
|     ) { | ||||
|         $this->config = $config; | ||||
|         $this->repository = $repository; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new service on the system. | ||||
|      * | ||||
|      * @param  array $data | ||||
|      * @return \Pterodactyl\Models\Service | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      */ | ||||
|     public function handle(array $data) | ||||
|     { | ||||
|         return $this->repository->create(array_merge([ | ||||
|             'author' => $this->config->get('pterodactyl.service.author'), | ||||
|         ], [ | ||||
|             'name' => array_get($data, 'name'), | ||||
|             'description' => array_get($data, 'description'), | ||||
|             'folder' => array_get($data, 'folder'), | ||||
|             'startup' => array_get($data, 'startup'), | ||||
|             'index_file' => $this->getIndexScript(), | ||||
|         ])); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										74
									
								
								app/Services/Services/ServiceDeletionService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/Services/Services/ServiceDeletionService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| <?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\Services; | ||||
| 
 | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| 
 | ||||
| class ServiceDeletionService | ||||
| { | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface | ||||
|      */ | ||||
|     protected $serverRepository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * ServiceDeletionService constructor. | ||||
|      * | ||||
|      * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface  $serverRepository | ||||
|      * @param \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface $repository | ||||
|      */ | ||||
|     public function __construct( | ||||
|         ServerRepositoryInterface $serverRepository, | ||||
|         ServiceRepositoryInterface $repository | ||||
|     ) { | ||||
|         $this->serverRepository = $serverRepository; | ||||
|         $this->repository = $repository; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete a service from the system only if there are no servers attached to it. | ||||
|      * | ||||
|      * @param  int $service | ||||
|      * @return int | ||||
|      * | ||||
|      * @throws \Pterodactyl\Exceptions\Services\HasActiveServersException | ||||
|      */ | ||||
|     public function handle($service) | ||||
|     { | ||||
|         $count = $this->serverRepository->findCountWhere([['service_id', '=', $service]]); | ||||
|         if ($count > 0) { | ||||
|             throw new HasActiveServersException(trans('admin/exceptions.service.delete_has_servers')); | ||||
|         } | ||||
| 
 | ||||
|         return $this->repository->delete($service); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										62
									
								
								app/Services/Services/ServiceUpdateService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/Services/Services/ServiceUpdateService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| <?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\Services; | ||||
| 
 | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| 
 | ||||
| class ServiceUpdateService | ||||
| { | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * ServiceUpdateService constructor. | ||||
|      * | ||||
|      * @param \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface $repository | ||||
|      */ | ||||
|     public function __construct(ServiceRepositoryInterface $repository) | ||||
|     { | ||||
|         $this->repository = $repository; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Update a service and prevent changing the author once it is set. | ||||
|      * | ||||
|      * @param  int   $service | ||||
|      * @param  array $data | ||||
|      * @throws \Pterodactyl\Exceptions\Model\DataValidationException | ||||
|      * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException | ||||
|      */ | ||||
|     public function handle($service, array $data) | ||||
|     { | ||||
|         if (! is_null(array_get($data, 'author'))) { | ||||
|             unset($data['author']); | ||||
|         } | ||||
| 
 | ||||
|         $this->repository->withoutFresh()->update($service, $data); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										71
									
								
								app/Traits/Services/CreatesServiceIndex.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Traits/Services/CreatesServiceIndex.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| <?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\Traits\Services; | ||||
| 
 | ||||
| trait CreatesServiceIndex | ||||
| { | ||||
|     /** | ||||
|      * Returns the default index.js file that is used for services on the daemon. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getIndexScript() | ||||
|     { | ||||
|         return <<<'EOF' | ||||
| 'use strict'; | ||||
| 
 | ||||
| /** | ||||
|  * Pterodactyl - Daemon | ||||
|  * 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. | ||||
|  */ | ||||
| const rfr = require('rfr'); | ||||
| const _ = require('lodash'); | ||||
| 
 | ||||
| const Core = rfr('src/services/index.js'); | ||||
| 
 | ||||
| class Service extends Core {} | ||||
| 
 | ||||
| module.exports = Service; | ||||
| EOF; | ||||
|     } | ||||
| } | ||||
| @ -88,6 +88,17 @@ $factory->define(Pterodactyl\Models\Node::class, function (Faker\Generator $fake | ||||
|     ]; | ||||
| }); | ||||
| 
 | ||||
| $factory->define(Pterodactyl\Models\Service::class, function (Faker\Generator $faker) { | ||||
|     return [ | ||||
|         'author' => $faker->unique()->uuid, | ||||
|         'name' => $faker->word, | ||||
|         'description' => null, | ||||
|         'folder' => strtolower($faker->unique()->word), | ||||
|         'startup' => 'java -jar test.jar', | ||||
|         'index_file' => 'indexjs', | ||||
|     ]; | ||||
| }); | ||||
| 
 | ||||
| $factory->define(Pterodactyl\Models\ServiceOption::class, function (Faker\Generator $faker) { | ||||
|     return [ | ||||
|         'id' => $faker->unique()->randomNumber(), | ||||
|  | ||||
| @ -0,0 +1,36 @@ | ||||
| <?php | ||||
| 
 | ||||
| use Illuminate\Support\Facades\Schema; | ||||
| use Illuminate\Database\Schema\Blueprint; | ||||
| use Illuminate\Database\Migrations\Migration; | ||||
| 
 | ||||
| class CascadeDeletionWhenAParentServiceIsDeleted extends Migration | ||||
| { | ||||
|     /** | ||||
|      * Run the migrations. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function up() | ||||
|     { | ||||
|         Schema::table('service_options', function (Blueprint $table) { | ||||
|             $table->dropForeign(['service_id']); | ||||
| 
 | ||||
|             $table->foreign('service_id')->references('id')->on('services')->onDelete('cascade'); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reverse the migrations. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function down() | ||||
|     { | ||||
|         Schema::table('service_options', function (Blueprint $table) { | ||||
|             $table->dropForeign(['service_id']); | ||||
| 
 | ||||
|             $table->foreign('service_id')->references('id')->on('services'); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @ -34,6 +34,7 @@ return [ | ||||
|         'cidr_out_of_range' => 'CIDR notation only allows masks between /25 and /32.', | ||||
|     ], | ||||
|     'service' => [ | ||||
|         'delete_has_servers' => 'A service with active servers attached to it cannot be deleted from the Panel.', | ||||
|         'options' => [ | ||||
|             'delete_has_servers' => 'A service option with active servers attached to it cannot be deleted from the Panel.', | ||||
|             'invalid_copy_id' => 'The service option selected for copying a script from either does not exist, or is copying a script itself.', | ||||
|  | ||||
| @ -23,8 +23,15 @@ | ||||
|  */ | ||||
| 
 | ||||
| return [ | ||||
|     'notices' => [ | ||||
|         'service_created' => 'A new service, :name, has been successfully created.', | ||||
|         'service_deleted' => 'Successfully deleted the requested service from the Panel.', | ||||
|         'service_updated' => 'Successfully updated the service configuration options.', | ||||
|         'functions_updated' => 'The service functions file has been updated. You will need to reboot your Nodes in order for these changes to be applied.', | ||||
|     ], | ||||
|     'options' => [ | ||||
|         'notices' => [ | ||||
|             'option_deleted' => 'Successfully deleted the requested service option from the Panel.', | ||||
|             'option_updated' => 'Service option configuration has been updated successfully.', | ||||
|             'script_updated' => 'Service option install script has been updated and will run whenever servers are installed.', | ||||
|             'option_created' => 'New service option was created successfully. You will need to restart any running daemons to apply this new service.', | ||||
|  | ||||
| @ -50,15 +50,14 @@ | ||||
|             <div class="box-header with-border"> | ||||
|                 <h3 class="box-title">Functions Control</h3> | ||||
|             </div> | ||||
|             <form action="{{ route('admin.services.view', $service->id) }}" method="POST"> | ||||
|             <form action="{{ route('admin.services.view.functions', $service->id) }}" method="POST"> | ||||
|                 <div class="box-body no-padding"> | ||||
|                     <div id="editor_index"style="height:500px">{{ $service->index_file }}</div> | ||||
|                     <textarea name="index_file" class="hidden"></textarea> | ||||
|                 </div> | ||||
|                 <div class="box-footer"> | ||||
|                     {!! csrf_field() !!} | ||||
|                     <input type="hidden" name="redirect_to" value="functions" /> | ||||
|                     <button type="submit" name="action" value="edit" class="btn btn-sm btn-success pull-right">Save File</button> | ||||
|                     <button type="submit" name="_method" value="PATCH" class="btn btn-sm btn-success pull-right">Save File</button> | ||||
|                 </div> | ||||
|             </form> | ||||
|         </div> | ||||
|  | ||||
| @ -166,8 +166,8 @@ Route::group(['prefix' => 'nodes'], function () { | ||||
| Route::group(['prefix' => 'services'], function () { | ||||
|     Route::get('/', 'ServiceController@index')->name('admin.services'); | ||||
|     Route::get('/new', 'ServiceController@create')->name('admin.services.new'); | ||||
|     Route::get('/view/{id}', 'ServiceController@view')->name('admin.services.view'); | ||||
|     Route::get('/view/{id}/functions', 'ServiceController@viewFunctions')->name('admin.services.view.functions'); | ||||
|     Route::get('/view/{service}', 'ServiceController@view')->name('admin.services.view'); | ||||
|     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}/variables', 'VariableController@view')->name('admin.services.option.variables'); | ||||
| @ -177,13 +177,14 @@ Route::group(['prefix' => 'services'], function () { | ||||
|     Route::post('/option/new', 'OptionController@store'); | ||||
|     Route::post('/option/{option}/variables', 'VariableController@store'); | ||||
| 
 | ||||
|     Route::patch('/view/{option}', 'ServiceController@edit'); | ||||
|     Route::patch('/view/{service}', 'ServiceController@update'); | ||||
|     Route::patch('/view/{service}/functions', 'ServiceController@updateFunctions'); | ||||
|     Route::patch('/option/{option}', 'OptionController@editConfiguration'); | ||||
|     Route::patch('/option/{option}/scripts', 'OptionController@updateScripts'); | ||||
|     Route::patch('/option/{option}/variables/{variable}', 'VariableController@update')->name('admin.services.option.variables.edit'); | ||||
| 
 | ||||
|     Route::delete('/view/{id}', 'ServiceController@delete'); | ||||
|     Route::delete('/option/{option}', 'OptionController@delete'); | ||||
|     Route::delete('/view/{service}', 'ServiceController@destroy'); | ||||
|     Route::delete('/option/{option}', 'OptionController@destroy'); | ||||
|     Route::delete('/option/{option}/variables/{variable}', 'VariableController@delete'); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -27,7 +27,7 @@ namespace Tests\Unit\Services\Services\Options; | ||||
| use Mockery as m; | ||||
| use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; | ||||
| use Pterodactyl\Contracts\Repository\ServiceOptionRepositoryInterface; | ||||
| use Pterodactyl\Exceptions\Services\ServiceOption\HasActiveServersException; | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| use Pterodactyl\Services\Services\Options\OptionDeletionService; | ||||
| use Tests\TestCase; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										94
									
								
								tests/Unit/Services/Services/ServiceCreationServiceTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								tests/Unit/Services/Services/ServiceCreationServiceTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| <?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 Tests\Unit\Services\Services; | ||||
| 
 | ||||
| use Mockery as m; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| use Pterodactyl\Models\Service; | ||||
| use Pterodactyl\Services\Services\ServiceCreationService; | ||||
| use Pterodactyl\Traits\Services\CreatesServiceIndex; | ||||
| use Tests\TestCase; | ||||
| use Illuminate\Contracts\Config\Repository; | ||||
| 
 | ||||
| class ServiceCreationServiceTest extends TestCase | ||||
| { | ||||
|     use CreatesServiceIndex; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Illuminate\Contracts\Config\Repository | ||||
|      */ | ||||
|     protected $config; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceCreationService | ||||
|      */ | ||||
|     protected $service; | ||||
| 
 | ||||
|     /** | ||||
|      * Setup tests. | ||||
|      */ | ||||
|     public function setUp() | ||||
|     { | ||||
|         parent::setUp(); | ||||
| 
 | ||||
|         $this->config = m::mock(Repository::class); | ||||
|         $this->repository = m::mock(ServiceRepositoryInterface::class); | ||||
| 
 | ||||
|         $this->service = new ServiceCreationService($this->config, $this->repository); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test that a new service can be created using the correct data. | ||||
|      */ | ||||
|     public function testCreateNewService() | ||||
|     { | ||||
|         $model = factory(Service::class)->make(); | ||||
|         $data = [ | ||||
|             'name' => $model->name, | ||||
|             'description' => $model->description, | ||||
|             'folder' => $model->folder, | ||||
|             'startup' => $model->startup, | ||||
|         ]; | ||||
| 
 | ||||
|         $this->config->shouldReceive('get')->with('pterodactyl.service.author')->once()->andReturn('0000-author'); | ||||
|         $this->repository->shouldReceive('create')->with([ | ||||
|             'author' => '0000-author', | ||||
|             'name' => $data['name'], | ||||
|             'description' => $data['description'], | ||||
|             'folder' => $data['folder'], | ||||
|             'startup' => $data['startup'], | ||||
|             'index_file' => $this->getIndexScript(), | ||||
|         ])->once()->andReturn($model); | ||||
| 
 | ||||
|         $response = $this->service->handle($data); | ||||
|         $this->assertInstanceOf(Service::class, $response); | ||||
|         $this->assertEquals($model, $response); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										104
									
								
								tests/Unit/Services/Services/ServiceDeletionServiceTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								tests/Unit/Services/Services/ServiceDeletionServiceTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| <?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 Tests\Unit\Services\Services; | ||||
| 
 | ||||
| use Exception; | ||||
| use Mockery as m; | ||||
| use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| use Pterodactyl\Exceptions\Services\HasActiveServersException; | ||||
| use Pterodactyl\Services\Services\ServiceDeletionService; | ||||
| use Tests\TestCase; | ||||
| 
 | ||||
| class ServiceDeletionServiceTest extends TestCase | ||||
| { | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface | ||||
|      */ | ||||
|     protected $serverRepository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceDeletionService | ||||
|      */ | ||||
|     protected $service; | ||||
| 
 | ||||
|     /** | ||||
|      * Setup tests. | ||||
|      */ | ||||
|     public function setUp() | ||||
|     { | ||||
|         parent::setUp(); | ||||
| 
 | ||||
|         $this->serverRepository = m::mock(ServerRepositoryInterface::class); | ||||
|         $this->repository = m::mock(ServiceRepositoryInterface::class); | ||||
| 
 | ||||
|         $this->service = new ServiceDeletionService($this->serverRepository, $this->repository); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test that a service is deleted when there are no servers attached to a service. | ||||
|      */ | ||||
|     public function testServiceIsDeleted() | ||||
|     { | ||||
|         $this->serverRepository->shouldReceive('findCountWhere')->with([['service_id', '=', 1]])->once()->andReturn(0); | ||||
|         $this->repository->shouldReceive('delete')->with(1)->once()->andReturn(1); | ||||
| 
 | ||||
|         $this->assertEquals(1, $this->service->handle(1)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test that an exception is thrown when there are servers attached to a service. | ||||
|      * | ||||
|      * @dataProvider serverCountProvider | ||||
|      */ | ||||
|     public function testExceptionIsThrownIfServersAreAttached($count) | ||||
|     { | ||||
|         $this->serverRepository->shouldReceive('findCountWhere')->with([['service_id', '=', 1]])->once()->andReturn($count); | ||||
| 
 | ||||
|         try { | ||||
|             $this->service->handle(1); | ||||
|         } catch (Exception $exception) { | ||||
|             $this->assertInstanceOf(HasActiveServersException::class, $exception); | ||||
|             $this->assertEquals(trans('admin/exceptions.service.delete_has_servers'), $exception->getMessage()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Provide assorted server counts to ensure that an exception is always thrown when more than 0 servers are found. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function serverCountProvider() | ||||
|     { | ||||
|         return [ | ||||
|             [1], [2], [5], [10], | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										77
									
								
								tests/Unit/Services/Services/ServiceUpdateServiceTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								tests/Unit/Services/Services/ServiceUpdateServiceTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | ||||
| <?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 Tests\Unit\Services\Services; | ||||
| 
 | ||||
| use Mockery as m; | ||||
| use Pterodactyl\Contracts\Repository\ServiceRepositoryInterface; | ||||
| use Pterodactyl\Services\Services\ServiceUpdateService; | ||||
| use Tests\TestCase; | ||||
| 
 | ||||
| class ServiceUpdateServiceTest extends TestCase | ||||
| { | ||||
|     /** | ||||
|      * @var \Pterodactyl\Contracts\Repository\ServiceRepositoryInterface | ||||
|      */ | ||||
|     protected $repository; | ||||
| 
 | ||||
|     /** | ||||
|      * @var \Pterodactyl\Services\Services\ServiceUpdateService | ||||
|      */ | ||||
|     protected $service; | ||||
| 
 | ||||
|     /** | ||||
|      * Setup tests. | ||||
|      */ | ||||
|     public function setUp() | ||||
|     { | ||||
|         parent::setUp(); | ||||
| 
 | ||||
|         $this->repository = m::mock(ServiceRepositoryInterface::class); | ||||
| 
 | ||||
|         $this->service = new ServiceUpdateService($this->repository); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test that the author key is removed from the data array before updating the record. | ||||
|      */ | ||||
|     public function testAuthorArrayKeyIsRemovedIfPassed() | ||||
|     { | ||||
|         $this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf() | ||||
|             ->shouldReceive('update')->with(1, ['otherfield' => 'value'])->once()->andReturnNull(); | ||||
| 
 | ||||
|         $this->service->handle(1, ['author' => 'author1', 'otherfield' => 'value']); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test that the function continues to work when no author key is passed. | ||||
|      */ | ||||
|     public function testServiceIsUpdatedWhenNoAuthorKeyIsPassed() | ||||
|     { | ||||
|         $this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf() | ||||
|             ->shouldReceive('update')->with(1, ['otherfield' => 'value'])->once()->andReturnNull(); | ||||
| 
 | ||||
|         $this->service->handle(1, ['otherfield' => 'value']); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dane Everitt
						Dane Everitt