Skip to content

Commit

Permalink
Complete new service, option, and variable management interface in Ad…
Browse files Browse the repository at this point in the history
…min CP
  • Loading branch information
DaneEveritt committed Mar 12, 2017
1 parent bccbb30 commit d7682bb
Show file tree
Hide file tree
Showing 16 changed files with 699 additions and 926 deletions.
126 changes: 118 additions & 8 deletions app/Http/Controllers/Admin/OptionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,63 @@
use Log;
use Alert;
use Storage;
use Pterodactyl\Models;
use Javascript;
use Illuminate\Http\Request;
use Pterodactyl\Models\Service;
use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\OptionRepository;
use Pterodactyl\Repositories\VariableRepository;
use Pterodactyl\Exceptions\DisplayValidationException;

class OptionController extends Controller
{
/**
* Handles request to view page for adding new option.
*
* @param Request $request
* @return \Illuminate\View\View
*/
public function new(Request $request)
{
$services = Service::with('options')->get();
Javascript::put(['services' => $services->keyBy('id')]);

return view('admin.services.options.new', ['services' => $services]);
}

/**
* Handles POST request to create a new option.
* @param Request $request
* @return \Illuminate\Response\RedirectResponse
*/
public function create(Request $request)
{
$repo = new OptionRepository;

try {
$option = $repo->create($request->intersect([
'service_id', 'name', 'description', 'tag',
'docker_image', 'startup', 'config_from', 'config_startup',
'config_logs', 'config_files', 'config_stop'
]));
Alert::success('Successfully created new service option.')->flash();

return redirect()->route('admin.services.option.view', $option->id);
} catch (DisplayValidationException $ex) {
return redirect()->route('admin.services.option.new')->withErrors(json_decode($ex->getMessage()))->withInput();
} catch (DisplayException $ex) {
Alert::danger($ex->getMessage())->flash();
} catch (\Exception $ex) {
Log::error($ex);
Alert::danger('An unhandled exception occurred while attempting to create this service. This error has been logged.')->flash();
}

return redirect()->route('admin.services.option.new')->withInput();
}

/**
* Display option overview page.
*
Expand All @@ -45,27 +93,89 @@ class OptionController extends Controller
*/
public function viewConfiguration(Request $request, $id)
{
return view('admin.services.options.view', ['option' => Models\ServiceOption::findOrFail($id)]);
return view('admin.services.options.view', ['option' => ServiceOption::findOrFail($id)]);
}

/**
* Display variable overview page for a service option.
*
* @param Request $request
* @param int $id
* @return \Illuminate\View\View
*/
public function viewVariables(Request $request, $id)
{
return view('admin.services.options.variables', ['option' => ServiceOption::with('variables')->findOrFail($id)]);
}

/**
* Handles POST when editing a configration for a service option.
*
* @param Request $request
* @return \Illuminate\Response\RedirectResponse
*/
public function editConfiguration(Request $request, $id)
{
$repo = new OptionRepository;

try {
$repo->update($id, $request->intersect([
'name', 'description', 'tag', 'docker_image', 'startup',
'config_from', 'config_stop', 'config_logs', 'config_files', 'config_startup',
]));
if ($request->input('action') !== 'delete') {
$repo->update($id, $request->intersect([
'name', 'description', 'tag', 'docker_image', 'startup',
'config_from', 'config_stop', 'config_logs', 'config_files', 'config_startup',
]));
Alert::success('Service option configuration has been successfully updated.')->flash();
} else {
$option = ServiceOption::with('service')->where('id', $id)->first();
$repo->delete($id);
Alert::success('Successfully deleted service option from the system.')->flash();

Alert::success('Service option configuration has been successfully updated.')->flash();
return redirect()->route('admin.services.view', $option->service_id);
}
} catch (DisplayValidationException $ex) {
return redirect()->route('admin.services.option.view', $id)->withErrors(json_decode($ex->getMessage()));
} catch (DisplayException $ex) {
Alert::danger($ex->getMessage())->flash();
} catch (\Exception $ex) {
Log::error($ex);
Alert::danger('An unhandled exception occurred while attempting to update this service option. This error has been logged.')->flash();
Alert::danger('An unhandled exception occurred while attempting to perform that action. This error has been logged.')->flash();
}

return redirect()->route('admin.services.option.view', $id);
}

/**
* Handles POST when editing a configration for a service option.
*
* @param Request $request
* @param int $option
* @param int $variable
* @return \Illuminate\Response\RedirectResponse
*/
public function editVariable(Request $request, $option, $variable)
{
$repo = new VariableRepository;

try {
if ($request->input('action') !== 'delete') {
$variable = $repo->update($variable, $request->only([
'name', 'description', 'env_variable',
'default_value', 'options', 'rules',
]));
Alert::success("The service variable '{$variable->name}' has been updated.")->flash();
} else {
$repo->delete($variable);
Alert::success("That service variable has been deleted.")->flash();
}
} catch (DisplayValidationException $ex) {
return redirect()->route('admin.services.option.variables', $option)->withErrors(json_decode($ex->getMessage()));
} catch (DisplayException $ex) {
Alert::danger($ex->getMessage())->flash();
} catch (\Exception $ex) {
Log::error($ex);
Alert::danger('An unhandled exception was encountered while attempting to process that request. This error has been logged.')->flash();
}

return redirect()->route('admin.services.option.variables', $option);
}
}
41 changes: 11 additions & 30 deletions app/Http/Controllers/Admin/ServiceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,32 +103,6 @@ public function create(Request $request)
return redirect()->route('admin.services.new')->withInput();
}

/**
* Delete a service from the system.
*
* @param Request $request
* @param int $id
* @return \Illuminate\Response\RedirectResponse
*/
public function delete(Request $request, $id)
{
$repo = new ServiceRepository;

try {
$repo->delete($id);
Alert::success('Successfully deleted service.')->flash();

return redirect()->route('admin.services');
} catch (DisplayException $ex) {
Alert::danger($ex->getMessage())->flash();
} catch (\Exception $ex) {
Log::error($ex);
Alert::danger('An error was encountered while attempting to delete that service. This error has been logged')->flash();
}

return redirect()->route('admin.services.view', $id);
}

/**
* Edits configuration for a specific service.
*
Expand All @@ -141,10 +115,17 @@ public function edit(Request $request, $id)
$repo = new ServiceRepository;

try {
$repo->update($id, $request->intersect([
'name', 'description', 'folder', 'startup',
]));
Alert::success('Service has been updated successfully.')->flash();
if ($request->input('action') !== 'delete') {
$repo->update($id, $request->intersect([
'name', 'description', 'folder', 'startup',
]));
Alert::success('Service has been updated successfully.')->flash();
} else {
$repo->delete($id);
Alert::success('Successfully deleted service from the system.')->flash();

return redirect()->route('admin.services');
}
} catch (DisplayValidationException $ex) {
return redirect()->route('admin.services.view', $id)->withErrors(json_decode($ex->getMessage()))->withInput();
} catch (DisplayException $ex) {
Expand Down
11 changes: 8 additions & 3 deletions app/Http/Routes/AdminRoutes.php
Original file line number Diff line number Diff line change
Expand Up @@ -419,20 +419,25 @@ public function map(Router $router)
'uses' => 'Admin\OptionController@new',
]);

$router->post('/option/new', 'Admin\OptionController@create');

$router->get('/option/{id}', [
'as' => 'admin.services.option.view',
'uses' => 'Admin\OptionController@viewConfiguration',
]);

$router->get('/option/{id}/variables', [
'as' => 'admin.services.option.view.variables',
'as' => 'admin.services.option.variables',
'uses' => 'Admin\OptionController@viewVariables',
]);

$router->post('/option/{id}', [
'uses' => 'Admin\OptionController@editConfiguration',
$router->post('/option/{id}/variables/{variable}', [
'as' => 'admin.services.option.variables.edit',
'uses' => 'Admin\OptionController@editVariable',
]);

$router->post('/option/{id}', 'Admin\OptionController@editConfiguration');

});

// Service Packs
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Service extends Model
* @var array
*/
protected $fillable = [
'name', 'description', 'file', 'executable', 'startup',
'name', 'description', 'folder', 'startup',
];

/**
Expand Down
84 changes: 84 additions & 0 deletions app/Repositories/OptionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,100 @@
use Validator;
use Pterodactyl\Models\ServiceOption;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Repositories\VariableRepository;
use Pterodactyl\Exceptions\DisplayValidationException;

class OptionRepository
{
/**
* Creates a new service option on the system.
*
* @param array $data
* @return \Pterodactyl\Models\ServiceOption
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function create(array $data)
{
$validator = Validator::make($data, [
'service_id' => 'required|numeric|exists:services,id',
'name' => 'required|string|max:255',
'description' => 'required|string',
'tag' => 'required|string|max:255|unique:service_options,tag',
'docker_image' => 'required|string|max:255',
'startup' => 'required|string',
'config_from' => 'sometimes|required|numeric|exists:service_options,id',
'config_startup' => 'required_without:config_from|json',
'config_stop' => 'required_without:config_from|string|max:255',
'config_logs' => 'required_without:config_from|json',
'config_files' => 'required_without:config_from|json',
]);

if ($validator->fails()) {
throw new DisplayValidationException($validator->errors());
}

if (isset($data['config_from'])) {
if (! ServiceOption::where('service_id', $data['service_id'])->where('id', $data['config_from'])->first()) {
throw new DisplayException('The `configuration from` directive must be a child of the assigned service.');
}
}

return ServiceOption::create($data);
}

/**
* Deletes a service option from the system.
*
* @param int $id
* @return void
*
* @throws \Pterodactyl\Exceptions\DisplayException
*/
public function delete($id)
{
$option = ServiceOption::with('variables')->withCount('servers')->findOrFail($id);

if ($option->servers_count > 0) {
throw new DisplayException('You cannot delete a service option that has servers associated with it.');
}

DB::transaction(function () use ($option) {
foreach($option->variables as $variable) {
(new VariableRepository)->delete($variable->id);
}

$option->delete();
});
}

/**
* Updates a service option in the database which can then be used
* on nodes.
*
* @param int $id
* @param array $data
* @return \Pterodactyl\Models\ServiceOption
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\DisplayValidationException
*/
public function update($id, array $data)
{
$option = ServiceOption::findOrFail($id);

// Due to code limitations (at least when I am writing this currently)
// we have to make an assumption that if config_from is not passed
// that we should be telling it that no config is wanted anymore.
//
// This really is only an issue if we open API access to this function,
// in which case users will always need to pass `config_from` in order
// to keep it assigned.
if (! isset($data['config_from']) && ! is_null($option->config_from)) {
$option->config_from = null;
}

$validator = Validator::make($data, [
'name' => 'sometimes|required|string|max:255',
'description' => 'sometimes|required|string',
Expand Down Expand Up @@ -73,6 +151,12 @@ public function update($id, array $data)
throw new DisplayValidationException($validator->errors());
}

if (isset($data['config_from'])) {
if (! ServiceOption::where('service_id', $option->service_id)->where('id', $data['config_from'])->first()) {
throw new DisplayException('The `configuration from` directive must be a child of the assigned service.');
}
}

$option->fill($data)->save();

return $option;
Expand Down
Loading

0 comments on commit d7682bb

Please sign in to comment.