Merge branch 'develop' into feature/service-changes
This commit is contained in:
		
						commit
						9eb14614c2
					
				
							
								
								
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -3,6 +3,27 @@ This file is a running track of new features and fixes to each version of the pa | |||||||
| 
 | 
 | ||||||
| This project follows [Semantic Versioning](http://semver.org) guidelines. | This project follows [Semantic Versioning](http://semver.org) guidelines. | ||||||
| 
 | 
 | ||||||
|  | ## v0.5.2 (Bodacious Boreopterus) | ||||||
|  | ### Fixed | ||||||
|  | * Time axis on server graphs is corrected to show the minutes rather than the current month. | ||||||
|  | * Node deletion now works correctly and deletes allocations as well. | ||||||
|  | * Fixes a bug that would leave orphaned databases on the system if there was an error during creation. | ||||||
|  | * Fixes an issue that could occur if a UUID contained `#e#` formatting within it when it comes to creating databases. | ||||||
|  | * Fixed node status display to account for updated daemon security changes. | ||||||
|  | * Fixes default language being selected as German (defaults to English now). | ||||||
|  | * Fixes bug preventing the deletion of database servers. | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | * Using `node:<name>` when filtering servers now properly filters the servers by node name, rather than looking for the node ID. | ||||||
|  | * Using `owner:<email>` when filtering servers now properly filters by the owner's email rather than ID. | ||||||
|  | * Added some quick help buttons to the admin index page for getting support or checking the documentation. | ||||||
|  | * Panel now displays `Pterodactyl Panel` as the company name if one is not set. | ||||||
|  | 
 | ||||||
|  | ### Added | ||||||
|  | * Added basic information about the daemon when viewing a node, including the host OS and version, CPU count, and the daemon version. | ||||||
|  | * Added version checking for the daemon and panel that alerts admins when daemons or the panel is out of date. | ||||||
|  | * Added multiplicator support to certain memory and disk fields that allow users to enter `10g` and have it converted to MB automatically. | ||||||
|  | 
 | ||||||
| ## v0.5.1 (Bodacious Boreopterus) | ## v0.5.1 (Bodacious Boreopterus) | ||||||
| ### Fixed | ### Fixed | ||||||
| * Fixes a bug that allowed a user to bypass 2FA authentication if using the correct username and password for an account. | * Fixes a bug that allowed a user to bypass 2FA authentication if using the correct username and password for an account. | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
| namespace Pterodactyl\Console\Commands; | namespace Pterodactyl\Console\Commands; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
|  | use Version; | ||||||
| 
 | 
 | ||||||
| class ShowVersion extends Command | class ShowVersion extends Command | ||||||
| { | { | ||||||
| @ -58,6 +59,6 @@ class ShowVersion extends Command | |||||||
|      */ |      */ | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         $this->info('You are running Pterodactyl Panel ' . config('app.version')); |         $this->info('You are running Pterodactyl Panel v' . Version::getCurrentPanel() . ' (' . ((Version::isLatestPanel()) ? 'Up to Date' : 'Latest: ' . Version::getDaemon()) . ')'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								app/Facades/Version.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/Facades/Version.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Pterodactyl - Panel | ||||||
|  |  * Copyright (c) 2015 - 2016 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\Facades; | ||||||
|  | 
 | ||||||
|  | use Illuminate\Support\Facades\Facade; | ||||||
|  | 
 | ||||||
|  | class Version extends Facade | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     protected static function getFacadeAccessor() | ||||||
|  |     { | ||||||
|  |         return '\Pterodactyl\Services\VersionService'; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -253,20 +253,22 @@ class NodesController extends Controller | |||||||
| 
 | 
 | ||||||
|     public function deleteNode(Request $request, $id) |     public function deleteNode(Request $request, $id) | ||||||
|     { |     { | ||||||
|         $node = Models\Node::findOrFail($id); |         try { | ||||||
|         $servers = Models\Server::where('node', $id)->count(); |             $repo = new NodeRepository; | ||||||
|         if ($servers > 0) { |             $repo->delete($id); | ||||||
|             Alert::danger('You cannot delete a node with servers currently attached to it.')->flash(); |             Alert::success('Successfully deleted the requested node from the panel.')->flash(); | ||||||
|             return redirect()->route('admin.nodes.view', [ |             return redirect()->route('admin.nodes'); | ||||||
|                 'id' => $id, |         } catch (DisplayException $e) { | ||||||
|                 'tab' => 'tab_delete' |             Alert::danger($e->getMessage())->flash(); | ||||||
|             ]); |         } catch (\Exception $e) { | ||||||
|  |             Log::error($e); | ||||||
|  |             Alert::danger('An unhandled exception occured while attempting to delete this node. Please try again.')->flash(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $node->delete(); |         return redirect()->route('admin.nodes.view', [ | ||||||
|         Alert::success('Node successfully deleted.')->flash(); |             'id' => $id, | ||||||
|         return redirect()->route('admin.nodes'); |             'tab' => 'tab_delete' | ||||||
| 
 |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -68,14 +68,23 @@ class ServersController extends Controller | |||||||
|                 $match = str_replace('"', '', $match); |                 $match = str_replace('"', '', $match); | ||||||
|                 if (strpos($match, ':')) { |                 if (strpos($match, ':')) { | ||||||
|                     list($field, $term) = explode(':', $match); |                     list($field, $term) = explode(':', $match); | ||||||
|                     $field = (strpos($field, '.')) ? $field : 'servers.' . $field; |                     if ($field === 'node') { | ||||||
|  |                         $field = 'nodes.name'; | ||||||
|  |                     } else if ($field === 'owner') { | ||||||
|  |                         $field = 'users.email'; | ||||||
|  |                     } else if (!strpos($field, '.')) { | ||||||
|  |                         $field = 'servers.' . $field; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     $query->orWhere($field, 'LIKE', '%' . $term . '%'); |                     $query->orWhere($field, 'LIKE', '%' . $term . '%'); | ||||||
|                 } else { |                 } else { | ||||||
|                     $query->where('servers.name', 'LIKE', '%' . $match . '%'); |                     $query->where('servers.name', 'LIKE', '%' . $match . '%'); | ||||||
|                     $query->orWhere('servers.username', 'LIKE', '%' . $match . '%'); |                     $query->orWhere([ | ||||||
|                     $query->orWhere('users.email', 'LIKE', '%' . $match . '%'); |                         ['servers.username', 'LIKE', '%' . $match . '%'], | ||||||
|                     $query->orWhere('allocations.port', 'LIKE', '%' . $match . '%'); |                         ['users.email', 'LIKE', '%' . $match . '%'], | ||||||
|                     $query->orWhere('allocations.ip', 'LIKE', '%' . $match . '%'); |                         ['allocations.port', 'LIKE', '%' . $match . '%'], | ||||||
|  |                         ['allocations.ip', 'LIKE', '%' . $match . '%'], | ||||||
|  |                     ]); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -56,13 +56,12 @@ class DatabaseRepository { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         DB::beginTransaction(); |         DB::beginTransaction(); | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
|             $db = new Models\Database; |             $db = new Models\Database; | ||||||
|             $db->fill([ |             $db->fill([ | ||||||
|                 'server_id' => $server->id, |                 'server_id' => $server->id, | ||||||
|                 'db_server' => $options['db_server'], |                 'db_server' => $options['db_server'], | ||||||
|                 'database' => $server->uuidShort . '_' . $options['database'], |                 'database' => "s{$server->id}_{$options['database']}", | ||||||
|                 'username' => $server->uuidShort . '_' . str_random(7), |                 'username' => $server->uuidShort . '_' . str_random(7), | ||||||
|                 'remote' => $options['remote'], |                 'remote' => $options['remote'], | ||||||
|                 'password' => Crypt::encrypt(str_random(20)) |                 'password' => Crypt::encrypt(str_random(20)) | ||||||
| @ -90,16 +89,29 @@ class DatabaseRepository { | |||||||
| 
 | 
 | ||||||
|             $capsule->setAsGlobal(); |             $capsule->setAsGlobal(); | ||||||
| 
 | 
 | ||||||
|             Capsule::statement('CREATE DATABASE ' . $db->database); |  | ||||||
|             Capsule::statement('CREATE USER \'' . $db->username . '\'@\'' . $db->remote . '\' IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); |  | ||||||
|             Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON ' . $db->database . '.* TO \'' . $db->username . '\'@\'' . $db->remote . '\''); |  | ||||||
|             Capsule::statement('FLUSH PRIVILEGES'); |  | ||||||
| 
 |  | ||||||
|             DB::commit(); |  | ||||||
|             return true; |  | ||||||
|         } catch (\Exception $ex) { |         } catch (\Exception $ex) { | ||||||
|             DB::rollback(); |             DB::rollBack(); | ||||||
|             throw $ex; |             throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             Capsule::statement('CREATE DATABASE `' . $db->database . '`'); | ||||||
|  |             Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); | ||||||
|  |             Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`'); | ||||||
|  |             Capsule::statement('FLUSH PRIVILEGES'); | ||||||
|  |             DB::commit(); | ||||||
|  |         } catch (\Exception $ex) { | ||||||
|  |             try { | ||||||
|  |                 Capsule::statement('DROP DATABASE `' . $db->database . '`'); | ||||||
|  |                 Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); | ||||||
|  |             } catch (\Exception $exi) { | ||||||
|  |                 // ignore it, if it fails its probably
 | ||||||
|  |                 // because we failed to ever make the DB
 | ||||||
|  |                 // or the user on the system.
 | ||||||
|  |             } finally { | ||||||
|  |                 DB::rollBack(); | ||||||
|  |                 throw $ex; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -138,7 +150,7 @@ class DatabaseRepository { | |||||||
| 
 | 
 | ||||||
|             $capsule->setAsGlobal(); |             $capsule->setAsGlobal(); | ||||||
|             Capsule::statement(sprintf( |             Capsule::statement(sprintf( | ||||||
|                 'SET PASSWORD FOR \'%s\'@\'%s\' = PASSWORD(\'%s\')', |                 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', | ||||||
|                 $db->username, |                 $db->username, | ||||||
|                 $db->remote, |                 $db->remote, | ||||||
|                 $password |                 $password | ||||||
| @ -182,8 +194,8 @@ class DatabaseRepository { | |||||||
| 
 | 
 | ||||||
|             $capsule->setAsGlobal(); |             $capsule->setAsGlobal(); | ||||||
| 
 | 
 | ||||||
|             Capsule::statement('DROP USER \'' . $db->username . '\'@\'' . $db->remote . '\''); |             Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); | ||||||
|             Capsule::statement('DROP DATABASE ' . $db->database); |             Capsule::statement('DROP DATABASE `' . $db->database . '`'); | ||||||
| 
 | 
 | ||||||
|             $db->delete(); |             $db->delete(); | ||||||
| 
 | 
 | ||||||
| @ -219,6 +231,11 @@ class DatabaseRepository { | |||||||
|      */ |      */ | ||||||
|     public function add(array $data) |     public function add(array $data) | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|  |         if (isset($data['host'])) { | ||||||
|  |             $data['host'] = gethostbyname($data['host']); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $validator = Validator::make($data, [ |         $validator = Validator::make($data, [ | ||||||
|             'name' => 'required|string|max:255', |             'name' => 'required|string|max:255', | ||||||
|             'host' => 'required|ip|unique:database_servers,host', |             'host' => 'required|ip|unique:database_servers,host', | ||||||
|  | |||||||
| @ -229,8 +229,30 @@ class NodeRepository { | |||||||
| 
 | 
 | ||||||
|     public function delete($id) |     public function delete($id) | ||||||
|     { |     { | ||||||
|         // @TODO: add logic;
 |         $node = Models\Node::findOrFail($id); | ||||||
|         return true; |         if (Models\Server::where('node', $id)->count() > 0) { | ||||||
|  |             throw new DisplayException('You cannot delete a node with servers currently attached to it.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         DB::beginTransaction(); | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             // Unlink Database Servers
 | ||||||
|  |             Models\DatabaseServer::where('linked_node', $node->id)->update([ | ||||||
|  |                 'linked_node' => null, | ||||||
|  |             ]); | ||||||
|  | 
 | ||||||
|  |             // Delete Allocations
 | ||||||
|  |             Models\Allocation::where('node', $node->id)->delete(); | ||||||
|  | 
 | ||||||
|  |             // Delete Node
 | ||||||
|  |             $node->delete(); | ||||||
|  | 
 | ||||||
|  |             DB::commit(); | ||||||
|  |         } catch (\Exception $ex) { | ||||||
|  |             DB::rollback(); | ||||||
|  |             throw $ex; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										93
									
								
								app/Services/VersionService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								app/Services/VersionService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * Pterodactyl - Panel | ||||||
|  |  * Copyright (c) 2015 - 2016 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; | ||||||
|  | 
 | ||||||
|  | use Cache; | ||||||
|  | use GuzzleHttp\Client; | ||||||
|  | 
 | ||||||
|  | class VersionService | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     protected static $versions; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Constructor | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         self::$versions = Cache::remember('versions', env('VERSION_CACHE_TIME', 60), function () { | ||||||
|  |             $client = new Client(); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 $response = $client->request('GET', env('VERSION_CHECK_URL', 'https://cdn.pterodactyl.io/releases/latest.json')); | ||||||
|  | 
 | ||||||
|  |                 if ($response->getStatusCode() === 200) { | ||||||
|  |                     return json_decode($response->getBody()); | ||||||
|  |                 } else { | ||||||
|  |                     throw new \Exception('Invalid response code.'); | ||||||
|  |                 } | ||||||
|  |             } catch (\Exception $ex) { | ||||||
|  |                 // Failed request, just return errored version.
 | ||||||
|  |                 return (object) [ | ||||||
|  |                     'panel' => 'error', | ||||||
|  |                     'daemon' => 'error', | ||||||
|  |                 ]; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static function getPanel() | ||||||
|  |     { | ||||||
|  |         return self::$versions->panel; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static function getDaemon() | ||||||
|  |     { | ||||||
|  |         return self::$versions->daemon; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getCurrentPanel() | ||||||
|  |     { | ||||||
|  |         return config('app.version'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static function isLatestPanel() | ||||||
|  |     { | ||||||
|  |         if (config('app.version') === 'canary') { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return (version_compare(config('app.version'), self::$versions->panel) >= 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static function isLatestDaemon($daemon) | ||||||
|  |     { | ||||||
|  |         if ($daemon === '0.0.0-canary') { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return (version_compare($daemon, self::$versions->daemon) >= 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -217,6 +217,7 @@ return [ | |||||||
|         'URL'       => Illuminate\Support\Facades\URL::class, |         'URL'       => Illuminate\Support\Facades\URL::class, | ||||||
|         'Uuid'      => Webpatser\Uuid\Uuid::class, |         'Uuid'      => Webpatser\Uuid\Uuid::class, | ||||||
|         'Validator' => Illuminate\Support\Facades\Validator::class, |         'Validator' => Illuminate\Support\Facades\Validator::class, | ||||||
|  |         'Version'   => Pterodactyl\Facades\Version::class, | ||||||
|         'View'      => Illuminate\Support\Facades\View::class, |         'View'      => Illuminate\Support\Facades\View::class, | ||||||
| 
 | 
 | ||||||
|     ], |     ], | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								public/js/admin.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								public/js/admin.min.js
									
									
									
									
										vendored
									
									
								
							| @ -46,4 +46,24 @@ $(document).ready(function () { | |||||||
|         centerModal($(this)); |         centerModal($(this)); | ||||||
|     }); |     }); | ||||||
|     $(window).on('resize', centerModal); |     $(window).on('resize', centerModal); | ||||||
|  | 
 | ||||||
|  |     // Idea code for multiplicators submitted by @Taronyuu on Github
 | ||||||
|  |     // https://github.com/Pterodactyl/Panel/issues/154#issuecomment-257116078
 | ||||||
|  |     $('input[data-multiplicator="true"]').on('change', function () { | ||||||
|  |         var value = $(this).val(); | ||||||
|  |         if (!/^\d+$/.test(value)) { | ||||||
|  |             var multiplicator = value.replace(/[0-9]/g, '').toLowerCase(); | ||||||
|  |             value = value.replace(/\D/g, ''); | ||||||
|  | 
 | ||||||
|  |             if (multiplicator === 't') { | ||||||
|  |                 value = value * (1024 * 1024); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (multiplicator === 'g') { | ||||||
|  |                 value = value * 1024; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $(this).val(value); | ||||||
|  |     }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -93,7 +93,7 @@ | |||||||
|                                     <td>{{ $db->username }}</td> |                                     <td>{{ $db->username }}</td> | ||||||
|                                     <td class="text-center">{{ $db->c_databases }}</td> |                                     <td class="text-center">{{ $db->c_databases }}</td> | ||||||
|                                     <td>@if(is_null($db->a_linkedNode))<em>unlinked</em>@else{{ $db->a_linkedNode }}@endif</td> |                                     <td>@if(is_null($db->a_linkedNode))<em>unlinked</em>@else{{ $db->a_linkedNode }}@endif</td> | ||||||
|                                     <td class="text-center"><a href="#" class="text-danger" data-action="delete" data-type="delete-dbserver" data-attr="{{ $db->id }}"><i class="fa fa-trash-o"></i></a></td> |                                     <td class="text-center"><a href="#" class="text-danger" data-action="delete" data-type="delete-server" data-attr="{{ $db->id }}"><i class="fa fa-trash-o"></i></a></td> | ||||||
|                                 </tr> |                                 </tr> | ||||||
|                             @endforeach |                             @endforeach | ||||||
|                         </tbody> |                         </tbody> | ||||||
|  | |||||||
| @ -24,13 +24,31 @@ | |||||||
| @endsection | @endsection | ||||||
| 
 | 
 | ||||||
| @section('content') | @section('content') | ||||||
| <div class="col-md-12"> | <div class="row"> | ||||||
|     <ul class="breadcrumb"> |     <div class="col-md-12"> | ||||||
|         <li class="active">Admin Control</li> |         <ul class="breadcrumb"> | ||||||
|     </ul> |             <li class="active">Admin Control</li> | ||||||
|     <h3 class="nopad">Pterodactyl Admin Control Panel</h3><hr /> |         </ul> | ||||||
|     <p>Welcome to the most advanced, lightweight, and user-friendly open source game server control panel.</p> |         <h3 class="nopad">Pterodactyl Admin Control Panel</h3><hr /> | ||||||
|     <p>You are running version <code>{{ config('app.version') }}</code>.</p> |         @if (Version::isLatestPanel()) | ||||||
|  |             <div class="alert alert-success">You are running Pterodactyl Panel version <code>{{ Version::getCurrentPanel() }}</code>. Your panel is up-to-date!</div> | ||||||
|  |         @else | ||||||
|  |             <div class="alert alert-danger"> | ||||||
|  |                 Your panel is <strong>not up-to-date!</strong> The latest version is <a href="https://github.com/Pterodactyl/Panel/releases/v{{ Version::getPanel() }}" target="_blank"><code>{{ Version::getPanel() }}</code></a> and you are currently running version <code>{{ Version::getCurrentPanel() }}</code>. | ||||||
|  |             </div> | ||||||
|  |         @endif | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | <div class="row"> | ||||||
|  |     <div class="col-xs-4 text-center"> | ||||||
|  |         <a href="https://discord.gg/0gYt8oU8QOkDhKLS"><button class="btn btn-sm btn-warning" style="width:100%;"><i class="fa fa-fw fa-support"></i> Get Help <small>(via Discord)</small></button></a> | ||||||
|  |     </div> | ||||||
|  |     <div class="col-xs-4 text-center"> | ||||||
|  |         <a href="https://docs.pterodactyl.io"><button class="btn btn-sm btn-default" style="width:100%;"><i class="fa fa-fw fa-link"></i> Documentation</button></a> | ||||||
|  |     </div> | ||||||
|  |     <div class="col-xs-4 text-center"> | ||||||
|  |         <a href="https://github.com/Pterodactyl/Panel"><button class="btn btn-sm btn-default" style="width:100%;"><i class="fa fa-fw fa-support"></i> Github</button></a> | ||||||
|  |     </div> | ||||||
| </div> | </div> | ||||||
| <script> | <script> | ||||||
| $(document).ready(function () { | $(document).ready(function () { | ||||||
|  | |||||||
| @ -70,21 +70,27 @@ | |||||||
| <script> | <script> | ||||||
| $(document).ready(function () { | $(document).ready(function () { | ||||||
|     $('#sidebar_links').find("a[href='/admin/nodes']").addClass('active'); |     $('#sidebar_links').find("a[href='/admin/nodes']").addClass('active'); | ||||||
|     pingNodes(); |     (function pingNodes() { | ||||||
|     setInterval(pingNodes, 10000); |         $('td[data-action="ping"]').each(function(i, element) { | ||||||
| }); |             $.ajax({ | ||||||
| function pingNodes() { |                 type: 'GET', | ||||||
|     $('td[data-action="ping"]').each(function(i, element) { |                 url: $(element).data('location'), | ||||||
|         $.ajax({ |                 headers: { | ||||||
|             type: 'GET', |                     'X-Access-Token': '{{ $node->daemonSecret }}' | ||||||
|             url: $(element).data('location'), |                 }, | ||||||
|             timeout: 5000 |                 timeout: 5000 | ||||||
|         }).done(function (data) { |             }).done(function (data) { | ||||||
|             $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heartbeat faa-pulse animated').css('color', '#50af51'); |                 $(element).find('i').tooltip({ | ||||||
|         }).fail(function () { |                     title: 'v' + data.version, | ||||||
|             $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heart-o').css('color', '#d9534f'); |                 }); | ||||||
|  |                 $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heartbeat faa-pulse animated').css('color', '#50af51'); | ||||||
|  |             }).fail(function () { | ||||||
|  |                 $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heart-o').css('color', '#d9534f'); | ||||||
|  |             }).always(function () { | ||||||
|  |                 setTimeout(pingNodes, 10000); | ||||||
|  |             }); | ||||||
|         }); |         }); | ||||||
|     }); |     })(); | ||||||
| } | }); | ||||||
| </script> | </script> | ||||||
| @endsection | @endsection | ||||||
|  | |||||||
| @ -92,14 +92,14 @@ | |||||||
|                         <div class="form-group col-md-6 col-xs-6"> |                         <div class="form-group col-md-6 col-xs-6"> | ||||||
|                             <label for="memory" class="control-label">Total Memory</label> |                             <label for="memory" class="control-label">Total Memory</label> | ||||||
|                             <div class="input-group"> |                             <div class="input-group"> | ||||||
|                                 <input type="text" name="memory" class="form-control" value="{{ old('memory') }}"/> |                                 <input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory') }}"/> | ||||||
|                                 <span class="input-group-addon">MB</span> |                                 <span class="input-group-addon">MB</span> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="form-group col-md-6 col-xs-6"> |                         <div class="form-group col-md-6 col-xs-6"> | ||||||
|                             <label for="memory_overallocate" class="control-label">Overallocate</label> |                             <label for="memory_overallocate" class="control-label">Overallocate</label> | ||||||
|                             <div class="input-group"> |                             <div class="input-group"> | ||||||
|                                 <input type="text" name="memory_overallocate" class="form-control" value="{{ old('memory_overallocate', 0) }}"/> |                                 <input type="text" name="memory_overallocate" data-multiplicator="true" class="form-control" value="{{ old('memory_overallocate', 0) }}"/> | ||||||
|                                 <span class="input-group-addon">%</span> |                                 <span class="input-group-addon">%</span> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|  | |||||||
| @ -69,6 +69,18 @@ | |||||||
|                 <div class="panel-body"> |                 <div class="panel-body"> | ||||||
|                     <table class="table table-striped" style="margin-bottom:0;"> |                     <table class="table table-striped" style="margin-bottom:0;"> | ||||||
|                         <tbody> |                         <tbody> | ||||||
|  |                             <tr> | ||||||
|  |                                 <td>Daemon Version</td> | ||||||
|  |                                 <td><code data-attr="info-version"><i class="fa fa-refresh fa-fw fa-spin"></i></code> (Latest: <code>{{ Version::getPanel() }}</code>)</td> | ||||||
|  |                             </tr> | ||||||
|  |                             <tr> | ||||||
|  |                                 <td>System Information</td> | ||||||
|  |                                 <td data-attr="info-system"><i class="fa fa-refresh fa-fw fa-spin"></i></td> | ||||||
|  |                             </tr> | ||||||
|  |                             <tr> | ||||||
|  |                                 <td>Total CPU Cores</td> | ||||||
|  |                                 <td data-attr="info-cpus"><i class="fa fa-refresh fa-fw fa-spin"></i></td> | ||||||
|  |                             </tr> | ||||||
|                             <tr> |                             <tr> | ||||||
|                                 <td>Total Servers</td> |                                 <td>Total Servers</td> | ||||||
|                                 <td>{{ count($servers) }}</td> |                                 <td>{{ count($servers) }}</td> | ||||||
| @ -171,7 +183,7 @@ | |||||||
|                             <div class="form-group col-md-3 col-xs-6"> |                             <div class="form-group col-md-3 col-xs-6"> | ||||||
|                                 <label for="memory" class="control-label">Total Memory</label> |                                 <label for="memory" class="control-label">Total Memory</label> | ||||||
|                                 <div class="input-group"> |                                 <div class="input-group"> | ||||||
|                                     <input type="text" name="memory" class="form-control" value="{{ old('memory', $node->memory) }}"/> |                                     <input type="text" name="memory" class="form-control" data-multiplicator="true" value="{{ old('memory', $node->memory) }}"/> | ||||||
|                                     <span class="input-group-addon">MB</span> |                                     <span class="input-group-addon">MB</span> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
| @ -185,7 +197,7 @@ | |||||||
|                             <div class="form-group col-md-3 col-xs-6"> |                             <div class="form-group col-md-3 col-xs-6"> | ||||||
|                                 <label for="disk" class="control-label">Disk Space</label> |                                 <label for="disk" class="control-label">Disk Space</label> | ||||||
|                                 <div class="input-group"> |                                 <div class="input-group"> | ||||||
|                                     <input type="text" name="disk" class="form-control" value="{{ old('disk', $node->disk) }}"/> |                                     <input type="text" name="disk" class="form-control" data-multiplicator="true" value="{{ old('disk', $node->disk) }}"/> | ||||||
|                                     <span class="input-group-addon">MB</span> |                                     <span class="input-group-addon">MB</span> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
| @ -777,6 +789,24 @@ $(document).ready(function () { | |||||||
|         element.parent().removeClass('has-error has-success'); |         element.parent().removeClass('has-error has-success'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     (function getInformation() { | ||||||
|  |         $.ajax({ | ||||||
|  |             method: 'GET', | ||||||
|  |             url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}', | ||||||
|  |             timeout: 5000, | ||||||
|  |             headers: { | ||||||
|  |                 'X-Access-Token': '{{ $node->daemonSecret }}' | ||||||
|  |             }, | ||||||
|  |         }).done(function (data) { | ||||||
|  |             $('[data-attr="info-version"]').html(data.version); | ||||||
|  |             $('[data-attr="info-system"]').html(data.system.type + '(' + data.system.arch + ') <code>' + data.system.release + '</code>'); | ||||||
|  |             $('[data-attr="info-cpus"]').html(data.system.cpus); | ||||||
|  |         }).fail(function (jqXHR) { | ||||||
|  | 
 | ||||||
|  |         }).always(function() { | ||||||
|  |             setTimeout(getInformation, 10000); | ||||||
|  |         }); | ||||||
|  |     })(); | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
| @endsection | @endsection | ||||||
|  | |||||||
| @ -118,14 +118,14 @@ | |||||||
|                 <div class="form-group col-md-4 col-xs-4"> |                 <div class="form-group col-md-4 col-xs-4"> | ||||||
|                     <label for="memory" class="control-label">Memory</label> |                     <label for="memory" class="control-label">Memory</label> | ||||||
|                     <div class="input-group"> |                     <div class="input-group"> | ||||||
|                         <input type="text" name="memory" class="form-control" value="{{ old('memory') }}"/> |                         <input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory') }}"/> | ||||||
|                         <span class="input-group-addon">MB</span> |                         <span class="input-group-addon">MB</span> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="form-group col-md-4 col-xs-4"> |                 <div class="form-group col-md-4 col-xs-4"> | ||||||
|                     <label for="memory" class="control-label">Swap</label> |                     <label for="memory" class="control-label">Swap</label> | ||||||
|                     <div class="input-group"> |                     <div class="input-group"> | ||||||
|                         <input type="text" name="swap" class="form-control" value="{{ old('swap', 0) }}"/> |                         <input type="text" name="swap" data-multiplicator="true" class="form-control" value="{{ old('swap', 0) }}"/> | ||||||
|                         <span class="input-group-addon">MB</span> |                         <span class="input-group-addon">MB</span> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
| @ -150,7 +150,7 @@ | |||||||
|                 <div class="form-group col-md-4 col-xs-4"> |                 <div class="form-group col-md-4 col-xs-4"> | ||||||
|                     <label for="disk" class="control-label">Disk Space</label> |                     <label for="disk" class="control-label">Disk Space</label> | ||||||
|                     <div class="input-group"> |                     <div class="input-group"> | ||||||
|                         <input type="text" name="disk" class="form-control" value="{{ old('disk') }}"/> |                         <input type="text" name="disk" data-multiplicator="true" class="form-control" value="{{ old('disk') }}"/> | ||||||
|                         <span class="input-group-addon">MB</span> |                         <span class="input-group-addon">MB</span> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|  | |||||||
| @ -228,14 +228,14 @@ | |||||||
|                                 <div class="col-md-6 form-group {{ $errors->has('memory') ? 'has-error' : '' }}"> |                                 <div class="col-md-6 form-group {{ $errors->has('memory') ? 'has-error' : '' }}"> | ||||||
|                                     <label for="memory" class="control-label">Allocated Memory</label> |                                     <label for="memory" class="control-label">Allocated Memory</label> | ||||||
|                                     <div class="input-group"> |                                     <div class="input-group"> | ||||||
|                                         <input type="text" name="memory" class="form-control" value="{{ old('memory', $server->memory) }}"/> |                                         <input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory', $server->memory) }}"/> | ||||||
|                                         <span class="input-group-addon">MB</span> |                                         <span class="input-group-addon">MB</span> | ||||||
|                                     </div> |                                     </div> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="col-md-6 form-group {{ $errors->has('swap') ? 'has-error' : '' }}"> |                                 <div class="col-md-6 form-group {{ $errors->has('swap') ? 'has-error' : '' }}"> | ||||||
|                                     <label for="swap" class="control-label">Allocated Swap</label> |                                     <label for="swap" class="control-label">Allocated Swap</label> | ||||||
|                                     <div class="input-group"> |                                     <div class="input-group"> | ||||||
|                                         <input type="text" name="swap" class="form-control" value="{{ old('swap', $server->swap) }}"/> |                                         <input type="text" name="swap" data-multiplicator="true" class="form-control" value="{{ old('swap', $server->swap) }}"/> | ||||||
|                                         <span class="input-group-addon">MB</span> |                                         <span class="input-group-addon">MB</span> | ||||||
|                                     </div> |                                     </div> | ||||||
|                                     <p class="text-muted"><small>Setting this to <code>0</code> will disable swap space on this server.</small></p> |                                     <p class="text-muted"><small>Setting this to <code>0</code> will disable swap space on this server.</small></p> | ||||||
| @ -373,7 +373,7 @@ | |||||||
|                                 <div class="form-group col-md-6"> |                                 <div class="form-group col-md-6"> | ||||||
|                                     <label class="control-label">Database Name:</label> |                                     <label class="control-label">Database Name:</label> | ||||||
|                                     <div class="input-group"> |                                     <div class="input-group"> | ||||||
|                                         <div class="input-group-addon">{{ $server->uuidShort }}_</div> |                                         <div class="input-group-addon">s{{ $server->id }}_</div> | ||||||
|                                         <input type="text" name="database" value="{{ old('database') }}" class="form-control"> |                                         <input type="text" name="database" value="{{ old('database') }}" class="form-control"> | ||||||
|                                     </div> |                                     </div> | ||||||
|                                 </div> |                                 </div> | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ | |||||||
|                 <div> |                 <div> | ||||||
|                     <select name="default_language" class="form-control"> |                     <select name="default_language" class="form-control"> | ||||||
|                         <option value="de" @if(Settings::get('default_language') === 'de')selected @endif>Deutsch</option> |                         <option value="de" @if(Settings::get('default_language') === 'de')selected @endif>Deutsch</option> | ||||||
|                         <option value="en" @if(Settings::get('default_language') === 'en')selected @endif>English</option> |                         <option value="en" @if(Settings::get('default_language', 'en') === 'en')selected @endif>English</option> | ||||||
|                         <option value="es" @if(Settings::get('default_language') === 'es')selected @endif>Español</option> |                         <option value="es" @if(Settings::get('default_language') === 'es')selected @endif>Español</option> | ||||||
|                         <option value="fr" @if(Settings::get('default_language') === 'fr')selected @endif>Français</option> |                         <option value="fr" @if(Settings::get('default_language') === 'fr')selected @endif>Français</option> | ||||||
|                         <option value="it" @if(Settings::get('default_language') === 'it')selected @endif>Italiano</option> |                         <option value="it" @if(Settings::get('default_language') === 'it')selected @endif>Italiano</option> | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ | |||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                 </button> |                 </button> | ||||||
|                 <a class="navbar-brand" href="/">{{ Settings::get('company') }}</a> |                 <a class="navbar-brand" href="/">{{ Settings::get('company', 'Pterodactyl Panel') }}</a> | ||||||
|             </div> |             </div> | ||||||
|             <div class="navbar-collapse collapse navbar-responsive-collapse"> |             <div class="navbar-collapse collapse navbar-responsive-collapse"> | ||||||
|                 @section('navbar-links') |                 @section('navbar-links') | ||||||
|  | |||||||
| @ -164,7 +164,7 @@ | |||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                 </button> |                 </button> | ||||||
|                 <a class="navbar-brand" href="/">{{ Settings::get('company') }}</a> |                 <a class="navbar-brand" href="/">{{ Settings::get('company', 'Pterodactyl Panel') }}</a> | ||||||
|             </div> |             </div> | ||||||
|             <div class="navbar-collapse collapse navbar-responsive-collapse"> |             <div class="navbar-collapse collapse navbar-responsive-collapse"> | ||||||
|                 @section('server-name') |                 @section('server-name') | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dane Everitt
						Dane Everitt