diff --git a/app/Http/Controllers/Admin/LocationController.php b/app/Http/Controllers/Admin/LocationController.php index 4e602f7ca..8325405f6 100644 --- a/app/Http/Controllers/Admin/LocationController.php +++ b/app/Http/Controllers/Admin/LocationController.php @@ -24,96 +24,127 @@ namespace Pterodactyl\Http\Controllers\Admin; -use Log; -use Alert; -use Illuminate\Http\Request; use Pterodactyl\Models\Location; -use Pterodactyl\Exceptions\DisplayException; +use Prologue\Alerts\AlertsMessageBag; +use Pterodactyl\Services\LocationService; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Repositories\LocationRepository; -use Pterodactyl\Exceptions\DisplayValidationException; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Requests\Admin\LocationRequest; class LocationController extends Controller { + /** + * @var \Prologue\Alerts\AlertsMessageBag + */ + protected $alert; + + /** + * @var \Pterodactyl\Models\Location + */ + protected $location; + + /** + * @var \Pterodactyl\Services\LocationService + */ + protected $service; + + /** + * LocationController constructor. + * + * @param \Prologue\Alerts\AlertsMessageBag $alert + * @param \Pterodactyl\Models\Location $location + * @param \Pterodactyl\Services\LocationService $service + */ + public function __construct(AlertsMessageBag $alert, Location $location, LocationService $service) + { + $this->alert = $alert; + $this->location = $location; + $this->service = $service; + } + /** * Return the location overview page. * - * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function index(Request $request) + public function index() { return view('admin.locations.index', [ - 'locations' => Location::withCount('nodes', 'servers')->get(), + 'locations' => $this->location->withCount('nodes', 'servers')->get(), ]); } /** * Return the location view page. * - * @param \Illuminate\Http\Request $request - * @param int $id + * @param \Pterodactyl\Models\Location $location * @return \Illuminate\View\View */ - public function view(Request $request, $id) + public function view(Location $location) { - return view('admin.locations.view', ['location' => Location::with('nodes.servers')->findOrFail($id)]); + $location->load('nodes.servers'); + + return view('admin.locations.view', ['location' => $location]); } /** * Handle request to create new location. * - * @param \Illuminate\Http\Request $request + * @param \Pterodactyl\Http\Requests\Admin\LocationRequest $request * @return \Illuminate\Http\RedirectResponse + * + * @throws \Throwable + * @throws \Watson\Validating\ValidationException */ - public function create(Request $request) + public function create(LocationRequest $request) { - $repo = new LocationRepository; + $location = $this->service->create($request->normalize()); + $this->alert->success('Location was created successfully.')->flash(); - try { - $location = $repo->create($request->intersect(['short', 'long'])); - Alert::success('Location was created successfully.')->flash(); - - return redirect()->route('admin.locations.view', $location->id); - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.locations')->withErrors(json_decode($ex->getMessage())); - } catch (\Exception $ex) { - Log::error($ex); - Alert::error('An unhandled exception occurred while processing this request. This error has been logged.')->flash(); - } - - return redirect()->route('admin.locations'); + return redirect()->route('admin.locations.view', $location->id); } /** * Handle request to update or delete location. * - * @param \Illuminate\Http\Request $request - * @param int $id + * @param \Pterodactyl\Http\Requests\Admin\LocationRequest $request + * @param \Pterodactyl\Models\Location $location * @return \Illuminate\Http\RedirectResponse + * + * @throws \Throwable + * @throws \Watson\Validating\ValidationException */ - public function update(Request $request, $id) + public function update(LocationRequest $request, Location $location) { - $repo = new LocationRepository; - - try { - if ($request->input('action') !== 'delete') { - $location = $repo->update($id, $request->intersect(['short', 'long'])); - Alert::success('Location was updated successfully.')->flash(); - } else { - $repo->delete($id); - - return redirect()->route('admin.locations'); - } - } catch (DisplayValidationException $ex) { - return redirect()->route('admin.locations.view', $id)->withErrors(json_decode($ex->getMessage())); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); - } catch (\Exception $ex) { - Log::error($ex); - Alert::error('An unhandled exception occurred while processing this request. This error has been logged.')->flash(); + if ($request->input('action') === 'delete') { + return $this->delete($location); } - return redirect()->route('admin.locations.view', $id); + $this->service->update($location, $request->normalize()); + $this->alert->success('Location was updated successfully.')->flash(); + + return redirect()->route('admin.locations.view', $location->id); + } + + /** + * Delete a location from the system. + * + * @param \Pterodactyl\Models\Location $location + * @return \Illuminate\Http\RedirectResponse + * + * @throws \Exception + * @throws \Pterodactyl\Exceptions\DisplayException + */ + public function delete(Location $location) + { + try { + $this->service->delete($location); + + return redirect()->route('admin.locations'); + } catch (DisplayException $ex) { + $this->alert->danger($ex->getMessage())->flash(); + } + + return redirect()->route('admin.locations.view', $location->id); } } diff --git a/app/Http/Requests/Admin/LocationRequest.php b/app/Http/Requests/Admin/LocationRequest.php new file mode 100644 index 000000000..c2f80d546 --- /dev/null +++ b/app/Http/Requests/Admin/LocationRequest.php @@ -0,0 +1,40 @@ +. + * + * 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; + +use Pterodactyl\Models\Location; + +class LocationRequest extends AdminFormRequest +{ + /** + * Setup the validation rules to use for these requests. + * + * @return array + */ + public function rules() + { + return app()->make(Location::class)->getRules(); + } +} diff --git a/app/Models/Location.php b/app/Models/Location.php index f9ceec767..bb1529403 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -25,9 +25,12 @@ namespace Pterodactyl\Models; use Illuminate\Database\Eloquent\Model; +use Watson\Validating\ValidatingTrait; class Location extends Model { + use ValidatingTrait; + /** * The table associated with the model. * @@ -42,6 +45,16 @@ class Location extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; + /** + * Validation rules to apply when attempting to save a model to the DB. + * + * @var array + */ + protected $rules = [ + 'short' => 'required|string|between:1,60|unique:locations,short', + 'long' => 'required|string|between:1,255', + ]; + /** * Gets the nodes in a specificed location. * diff --git a/app/Services/LocationService.php b/app/Services/LocationService.php new file mode 100644 index 000000000..8db67592e --- /dev/null +++ b/app/Services/LocationService.php @@ -0,0 +1,98 @@ +. + * + * 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; + +use Pterodactyl\Models\Location; +use Pterodactyl\Exceptions\DisplayException; + +class LocationService +{ + /** + * @var \Pterodactyl\Models\Location + */ + protected $model; + + /** + * LocationService constructor. + * + * @param \Pterodactyl\Models\Location $location + */ + public function __construct(Location $location) + { + $this->model = $location; + } + + /** + * Create the location in the database and return it. + * + * @param array $data + * @return \Pterodactyl\Models\Location + * + * @throws \Throwable + * @throws \Watson\Validating\ValidationException + */ + public function create(array $data) + { + $location = $this->model->fill($data); + $location->saveOrFail(); + + return $location; + } + + /** + * Update location model in the DB. + * + * @param \Pterodactyl\Models\Location $location + * @param array $data + * @return \Pterodactyl\Models\Location + * + * @throws \Throwable + * @throws \Watson\Validating\ValidationException + */ + public function update(Location $location, array $data) + { + $location->fill($data)->saveOrFail(); + + return $location; + } + + /** + * Delete a model from the DB. + * + * @param \Pterodactyl\Models\Location $location + * @return bool + * + * @throws \Exception + * @throws \Pterodactyl\Exceptions\DisplayException + */ + public function delete(Location $location) + { + if ($location->nodes()->count() > 0) { + throw new DisplayException('Cannot delete a location that has nodes assigned to it.'); + } + + return $location->delete(); + } +} diff --git a/composer.json b/composer.json index c1fea93a1..861b11d49 100644 --- a/composer.json +++ b/composer.json @@ -12,14 +12,14 @@ ], "require": { "php": ">=7.0.0", + "ext-mbstring": "*", + "ext-pdo_mysql": "*", + "ext-zip": "*", "aws/aws-sdk-php": "3.26.5", "barryvdh/laravel-debugbar": "2.3.2", "daneeveritt/login-notifications": "1.0.0", "doctrine/dbal": "2.5.12", "edvinaskrucas/settings": "2.0.0", - "ext-mbstring": "*", - "ext-zip": "*", - "ext-pdo_mysql": "*", "fideloper/proxy": "3.3.0", "guzzlehttp/guzzle": "6.2.3", "igaster/laravel-theme": "1.14.0", @@ -35,6 +35,7 @@ "prologue/alerts": "0.4.1", "s1lentium/iptools": "1.1.0", "spatie/laravel-fractal": "4.0.0", + "watson/validating": "3.0.s1", "webpatser/laravel-uuid": "2.0.1" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 03b4a0671..a8466d76a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "84c501086eb1d2505bf6ce8bb4d06f61", - "content-hash": "5d52bbe44333fc6d4a0d922958510fde", + "hash": "3a539370a2c653dbe460cad3d03c3db5", + "content-hash": "ad3015e0fe97ab992635581a6c72fddd", "packages": [ { "name": "aws/aws-sdk-php", @@ -3640,6 +3640,56 @@ ], "time": "2016-09-01 10:05:43" }, + { + "name": "watson/validating", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/dwightwatson/validating.git", + "reference": "3cef5b4cd0af2dc26d2c7ca668bd12f4d4ab421b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dwightwatson/validating/zipball/3cef5b4cd0af2dc26d2c7ca668bd12f4d4ab421b", + "reference": "3cef5b4cd0af2dc26d2c7ca668bd12f4d4ab421b", + "shasum": "" + }, + "require": { + "illuminate/contracts": ">=5.3", + "illuminate/database": ">=5.3", + "illuminate/events": ">=5.3", + "illuminate/support": ">=5.3", + "illuminate/validation": ">=5.3", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Watson\\Validating\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dwight Watson", + "email": "dwight@studiousapp.com" + } + ], + "description": "Eloquent model validating trait.", + "keywords": [ + "eloquent", + "laravel", + "validation" + ], + "time": "2016-10-31 21:53:17" + }, { "name": "webpatser/laravel-uuid", "version": "2.0.1", @@ -5938,8 +5988,8 @@ "platform": { "php": ">=7.0.0", "ext-mbstring": "*", - "ext-zip": "*", - "ext-pdo_mysql": "*" + "ext-pdo_mysql": "*", + "ext-zip": "*" }, "platform-dev": [] } diff --git a/routes/admin.php b/routes/admin.php index 2fe4a0b2a..6d2730ce1 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -33,10 +33,10 @@ Route::get('/', 'BaseController@getIndex')->name('admin.index'); */ Route::group(['prefix' => 'locations'], function () { Route::get('/', 'LocationController@index')->name('admin.locations'); - Route::get('/view/{id}', 'LocationController@view')->name('admin.locations.view'); + Route::get('/view/{location}', 'LocationController@view')->name('admin.locations.view'); Route::post('/', 'LocationController@create'); - Route::post('/view/{id}', 'LocationController@update'); + Route::post('/view/{location}', 'LocationController@update'); }); /*