diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php new file mode 100644 index 000000000..415300ebb --- /dev/null +++ b/app/Http/Controllers/Admin/NodesController.php @@ -0,0 +1,75 @@ + Models\Node::select( + 'nodes.*', + 'locations.long as a_locationName', + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node = nodes.id) as a_serverCount') + )->join('locations', 'nodes.location', '=', 'locations.id')->paginate(20), + ]); + } + + public function getNew(Request $request) + { + return view('admin.nodes.new', [ + 'locations' => Models\Location::all() + ]); + } + + public function postNew(Request $request) + { + try { + $node = new NodeRepository; + $new = $node->create($request->except([ + '_token' + ])); + Alert::success('Successfully created new node. You should allocate some IP addresses to it now.')->flash(); + return redirect()->route('admin.nodes.view', [ + 'id' => $new + ]); + } catch (\Pterodactyl\Exceptions\DisplayValidationException $e) { + return redirect()->route('admin.nodes.new')->withErrors(json_decode($e->getMessage()))->withInput(); + } catch (\Pterodactyl\Exceptions\DisplayException $e) { + Alert::danger($e->getMessage())->flash(); + } catch (\Exception $e) { + Log::error($e); + Alert::danger('An unhandled exception occured while attempting to add this node. Please try again.')->flash(); + } + return redirect()->route('admin.nodes.new')->withInput(); + } + + public function getView(Request $request, $id) + { + $node = Models\Node::findOrFail($id); + return view('admin.nodes.view', [ + 'node' => $node + ]); + } + +} diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index e02ca4ebe..c00da60b9 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -137,6 +137,39 @@ class AdminRoutes { }); + // Node Routes + $router->group([ + 'prefix' => 'admin/nodes', + 'middleware' => [ + 'auth', + 'admin' + ] + ], function () use ($router) { + + // View All Nodes + $router->get('/', [ + 'as' => 'admin.nodes', + 'uses' => 'Admin\NodesController@getIndex' + ]); + + // Add New Node + $router->get('/new', [ + 'as' => 'admin.nodes.new', + 'uses' => 'Admin\NodesController@getNew' + ]); + + $router->post('/new', [ + 'uses' => 'Admin\NodesController@postNew' + ]); + + // View Node + $router->get('/view/{id}', [ + 'as' => 'admin.nodes.view', + 'uses' => 'Admin\NodesController@getView' + ]); + + }); + } } diff --git a/app/Models/Node.php b/app/Models/Node.php index 1f605070f..68f1283d0 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -22,6 +22,13 @@ class Node extends Model */ protected $hidden = ['daemonSecret']; + /** + * Fields that are not mass assignable. + * + * @var array + */ + protected $guarded = ['id', 'created_at', 'updated_at']; + /** * @var array */ diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php new file mode 100644 index 000000000..c4316d910 --- /dev/null +++ b/app/Repositories/NodeRepository.php @@ -0,0 +1,66 @@ + 'required|regex:/^([\w .-]{1,100})$/', + 'location' => 'required|numeric|min:1|exists:locations,id', + 'public' => 'required|numeric|between:0,1', + 'fqdn' => 'required|string|unique:nodes,fqdn', + 'scheme' => 'required|regex:/^(http(s)?)$/', + 'memory' => 'required|numeric|min:1', + 'memory_overallocate' => 'required|numeric|min:-1', + 'disk' => 'required|numeric|min:1', + 'disk_overallocate' => 'required|numeric|min:-1', + 'daemonBase' => 'required|regex:/^([\/][\d\w.\-\/]+)$/', + 'daemonSFTP' => 'required|numeric|between:1,65535', + 'daemonListen' => 'required|numeric|between:1,65535' + ]); + + // Run validator, throw catchable and displayable exception if it fails. + // Exception includes a JSON result of failed validation rules. + if ($validator->fails()) { + throw new DisplayValidationException($validator->errors()); + } + + // Verify the FQDN + if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { + throw new DisplayException('The FQDN provided does not resolve to a valid IP address.'); + } + + // Should we be nulling the overallocations? + $data['memory_overallocate'] = ($data['memory_overallocate'] < 0) ? null : $data['memory_overallocate']; + $data['disk_overallocate'] = ($data['disk_overallocate'] < 0) ? null : $data['disk_overallocate']; + + // Set the Secret + $uuid = new UuidService; + $data['daemonSecret'] = (string) $uuid->generate('nodes', 'daemonSecret'); + + // Store the Data + $node = new Models\Node; + $node->fill($data); + $node->save(); + + return $node->id; + + } + +} diff --git a/database/migrations/2016_01_04_232911_remove_node_ip.php b/database/migrations/2016_01_04_232911_remove_node_ip.php new file mode 100644 index 000000000..b8f9072a8 --- /dev/null +++ b/database/migrations/2016_01_04_232911_remove_node_ip.php @@ -0,0 +1,31 @@ +dropColumn('ip'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('nodes', function (Blueprint $table) { + $table->string('ip')->after('fqdn'); + }); + } +} diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php new file mode 100644 index 000000000..7c8c0f818 --- /dev/null +++ b/resources/views/admin/nodes/index.blade.php @@ -0,0 +1,51 @@ +@extends('layouts.admin') + +@section('title') + Node List +@endsection + +@section('content') +
Name | +Location | +FQDN | +Memory | +Disk | +Servers | +HTTPS | +Public | +
---|---|---|---|---|---|---|---|
{{ $node->name }} | +{{ $node->a_locationName }} | +{{ $node->fqdn }} |
+ {{ $node->memory }} MB | +{{ $node->disk }} MB | +{{ $node->a_serverCount }} | ++ | + |