Skip to content

Commit 47235b6

Browse files
committed
Push some basic add server functionality
Doesn’t support adding the server, but adds improved support for handling picking server location, node, and ip+port
1 parent 28594cf commit 47235b6

File tree

9 files changed

+344
-7
lines changed

9 files changed

+344
-7
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Admin;
4+
5+
use Debugbar;
6+
use Pterodactyl\Models\Allocation;
7+
use Pterodactyl\Models\Node;
8+
9+
use Pterodactyl\Http\Controllers\Controller;
10+
use Illuminate\Http\Request;
11+
12+
class AjaxController extends Controller
13+
{
14+
15+
/**
16+
* Controller Constructor
17+
*/
18+
public function __construct()
19+
{
20+
21+
// All routes in this controller are protected by the authentication middleware.
22+
$this->middleware('auth');
23+
$this->middleware('admin');
24+
25+
}
26+
27+
public function postNewServerGetNodes(Request $request)
28+
{
29+
30+
if(!$request->input('location')) {
31+
return response()->json([
32+
'error' => 'Missing location in request.'
33+
], 500);
34+
}
35+
36+
return response(Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get()->toJson());
37+
38+
}
39+
40+
public function postNewServerGetIps(Request $request)
41+
{
42+
43+
if(!$request->input('node')) {
44+
return response()->json([
45+
'error' => 'Missing node in request.'
46+
], 500);
47+
}
48+
49+
$ips = Allocation::where('node', $request->input('node'))->whereNull('assigned_to')->get();
50+
$listing = [];
51+
52+
foreach($ips as &$ip) {
53+
if (array_key_exists($ip->ip, $listing)) {
54+
$listing[$ip->ip] = array_merge($listing[$ip->ip], [$ip->port]);
55+
} else {
56+
$listing[$ip->ip] = [$ip->port];
57+
}
58+
}
59+
return response()->json($listing);
60+
61+
}
62+
63+
}

app/Http/Controllers/Admin/ServersController.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Debugbar;
66
use Pterodactyl\Models\Server;
77
use Pterodactyl\Models\Node;
8+
use Pterodactyl\Models\Location;
89

910
use Pterodactyl\Http\Controllers\Controller;
1011
use Illuminate\Http\Request;
@@ -36,7 +37,9 @@ public function getIndex(Request $request)
3637

3738
public function getNew(Request $request)
3839
{
39-
//
40+
return view('admin.servers.new', [
41+
'locations' => Location::all()
42+
]);
4043
}
4144

4245
public function getView(Request $request, $id)

app/Http/Routes/AdminRoutes.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ public function map(Router $router) {
2424
$router->get('/view/{id}', [ 'as' => 'admin.servers.view', 'uses' => 'Admin\ServersController@getView' ]);
2525
});
2626

27+
// AJAX Routes
28+
$router->group(['prefix' => 'ajax'], function ($server) use ($router) {
29+
$router->post('/new/server/get-nodes', [ 'uses' => 'Admin\AjaxController@postNewServerGetNodes' ]);
30+
$router->post('/new/server/get-ips', [ 'uses' => 'Admin\AjaxController@postNewServerGetIps' ]);
31+
});
32+
2733
});
2834
}
2935

app/Models/Allocation.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Pterodactyl\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
class Allocation extends Model
8+
{
9+
10+
/**
11+
* The table associated with the model.
12+
*
13+
* @var string
14+
*/
15+
protected $table = 'allocations';
16+
17+
}

app/Models/Location.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Pterodactyl\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
class Location extends Model
8+
{
9+
10+
/**
11+
* The table associated with the model.
12+
*
13+
* @var string
14+
*/
15+
protected $table = 'locations';
16+
17+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Schema\Blueprint;
4+
use Illuminate\Database\Migrations\Migration;
5+
6+
class AddAssignedTo extends Migration
7+
{
8+
/**
9+
* Run the migrations.
10+
*
11+
* @return void
12+
*/
13+
public function up()
14+
{
15+
Schema::table('allocations', function (Blueprint $table) {
16+
$table->mediumInteger('assigned_to')->unsigned()->nullable()->after('port');
17+
});
18+
}
19+
20+
/**
21+
* Reverse the migrations.
22+
*
23+
* @return void
24+
*/
25+
public function down()
26+
{
27+
Schema::table('allocations', function (Blueprint $table) {
28+
$table->dropColumn('assigned_to');
29+
});
30+
}
31+
}

public/css/pterodactyl.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ body{font-size:13px}
6363
.centered{text-align:center}
6464
.console{font:85% 'Droid Sans Mono',monospace;color:#333;height:300px!important;text-wrap:normal;overflow-y:scroll;overflow-x:hidden;border:0;resize:none}
6565
.console[readonly=readonly]{background:#fefefe;cursor:default}
66-
.files_loading_box{position:absolute;background:rgba(255,255,255,.8);width:100%;z-index:9999;display:none}
67-
.files_loading_box i{font-size:30px;color:rgba(0,0,0,.6);position:absolute}
66+
.ajax_loading_box{position:absolute;background:rgba(255,255,255,.8);width:100%;z-index:9999;display:none}
67+
.ajax_loading_box i{font-size:30px;color:rgba(0,0,0,.6);position:absolute}
6868
.btn-xxs{padding:2px 6px;font-size:10px;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:2px}
6969
.form-control{height:36px}
7070
.input-group-addon{font-size:12px;}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
@extends('layouts.admin')
2+
3+
@section('title')
4+
Server List
5+
@endsection
6+
7+
@section('content')
8+
<div class="col-md-9">
9+
<ul class="breadcrumb">
10+
<li><a href="/admin">Admin Control</a></li>
11+
<li><a href="/admin/servers">Servers</a></li>
12+
<li class="active">Create New Server</li>
13+
</ul>
14+
<h3>Create New Server</h3><hr />
15+
<form action="#" method="POST">
16+
<div class="well">
17+
<div class="row">
18+
<div class="form-group col-md-6">
19+
<label for="server_name" class="control-label">Server Name</label>
20+
<div>
21+
<input type="text" autocomplete="off" name="server_name" class="form-control" />
22+
<p class="text-muted" style="margin: 0 0 -10.5px;"><small><em>Character limits: <code>a-zA-Z0-9_-</code> and <code>[Space]</code> (max 35 characters)</em></small></p>
23+
</div>
24+
</div>
25+
<div class="form-group col-md-6">
26+
<label for="server_name" class="control-label">Owner Email</label>
27+
<div>
28+
<input type="text" autocomplete="off" name="owner_email" class="form-control" />
29+
</div>
30+
</div>
31+
</div>
32+
</div>
33+
<div id="load_settings">
34+
<div class="well">
35+
<div class="row">
36+
<div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin" id="position_me"></i></div>
37+
<div class="form-group col-md-6">
38+
<label for="location" class="control-label">Server Location</label>
39+
<div>
40+
<select name="location" id="getLocation" class="form-control">
41+
<option></option>
42+
@foreach($locations as $location)
43+
<option value="{{ $location->id }}">{{ $location->long }} ({{ $location->short }})</option>
44+
@endforeach
45+
</select>
46+
</div>
47+
</div>
48+
<div class="form-group col-md-6 hidden">
49+
<label for="location" class="control-label">Server Node</label>
50+
<div>
51+
<select name="node" id="getNode" class="form-control">
52+
<option></option>
53+
</select>
54+
</div>
55+
</div>
56+
</div>
57+
<div class="row">
58+
<div class="form-group col-md-6 hidden">
59+
<label for="location" class="control-label">Server IP</label>
60+
<div>
61+
<select name="node" id="getIP" class="form-control">
62+
<option></option>
63+
</select>
64+
</div>
65+
</div>
66+
<div class="form-group col-md-6 hidden">
67+
<label for="location" class="control-label">Server Port</label>
68+
<div>
69+
<select name="node" id="getPort" class="form-control"></select>
70+
</div>
71+
</div>
72+
</div>
73+
</div>
74+
</div>
75+
</form>
76+
</div>
77+
<script>
78+
$(document).ready(function () {
79+
var nodeData = null;
80+
var currentLocation = null;
81+
var currentNode = null;
82+
$('#getLocation').on('change', function (event) {
83+
84+
if ($('#getLocation').val() === '' || $('#getLocation').val() === currentLocation) {
85+
return;
86+
}
87+
88+
currentLocation = $('#getLocation').val();
89+
currentNode = null;
90+
91+
// Hide Existing, and Reset contents
92+
$('#getNode').html('<option></option>').parent().parent().addClass('hidden');
93+
$('#getIP').html('<option></option>').parent().parent().addClass('hidden');
94+
$('#getPort').html('').parent().parent().addClass('hidden');
95+
96+
handleLoader(true);
97+
98+
$.ajax({
99+
method: 'POST',
100+
url: '/admin/ajax/new/server/get-nodes',
101+
headers: {
102+
'X-CSRF-TOKEN': '{{ csrf_token() }}'
103+
},
104+
data: {
105+
location: $('#getLocation').val()
106+
}
107+
}).done(function (data) {
108+
var data = $.parseJSON(data);
109+
$.each(data, function (i, item) {
110+
var isPublic = (item.public !== 1) ? '(Private Node)' : '';
111+
$('#getNode').append('<option value="' + item.id + '">' + item.name + ' ' + isPublic + '</option>');
112+
});
113+
$('#getNode').parent().parent().removeClass('hidden')
114+
}).fail(function (jqXHR) {
115+
alert('An error occured while attempting to load a list of nodes in this location.');
116+
console.log(jqXHR);
117+
}).always(function () {
118+
handleLoader();
119+
})
120+
});
121+
$('#getNode').on('change', function (event) {
122+
123+
if ($('#getNode').val() === '' || $('#getNode').val() === currentNode) {
124+
return;
125+
}
126+
127+
currentNode = $('#getNode').val();
128+
129+
// Hide Existing, and Reset contents
130+
$('#getIP').html('<option></option>').parent().parent().addClass('hidden');
131+
$('#getPort').html('').parent().parent().addClass('hidden');
132+
133+
handleLoader(true);
134+
135+
$.ajax({
136+
method: 'POST',
137+
url: '/admin/ajax/new/server/get-ips',
138+
headers: {
139+
'X-CSRF-TOKEN': '{{ csrf_token() }}'
140+
},
141+
data: {
142+
node: $('#getNode').val()
143+
}
144+
}).done(function (data) {
145+
nodeData = data;
146+
$.each(data, function (ip, ports) {
147+
$('#getIP').append('<option value="' + ip + '">' + ip + '</option>');
148+
});
149+
$('#getIP').parent().parent().removeClass('hidden');
150+
}).fail(function (jqXHR) {
151+
console.log(jqXHR);
152+
}).always(function () {
153+
handleLoader();
154+
});
155+
156+
});
157+
$('#getIP').on('change', function (event) {
158+
159+
if ($('#getIP').val() === '') {
160+
return;
161+
}
162+
163+
$('#getPort').html('');
164+
165+
$.each(nodeData[$('#getIP').val()], function (i, port) {
166+
$('#getPort').append('<option value="' + port +'">' + port + '</option>');
167+
});
168+
169+
$('#getPort').parent().parent().removeClass('hidden');
170+
171+
});
172+
173+
// Show Loading Animation
174+
function handleLoader (show) {
175+
176+
// Show Animation
177+
if (show === true){
178+
var height = $('#load_settings').height();
179+
var width = $('#load_settings').width();
180+
var center_height = (height / 2) - 16;
181+
var center_width = (width / 2) - 16;
182+
$('#position_me').css({
183+
'top': center_height,
184+
'left': center_width,
185+
'font-size': '32px'
186+
});
187+
$(".ajax_loading_box").css({
188+
'height': height,
189+
'margin': '-20px 0 0 -5px',
190+
'width': width
191+
}).fadeIn();
192+
} else {
193+
$('.ajax_loading_box').fadeOut(100);
194+
}
195+
196+
}
197+
198+
});
199+
</script>
200+
@endsection

0 commit comments

Comments
 (0)