From a137e6ed72f04cefa8bd70b34478bf937f177d06 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 24 Jan 2017 19:15:03 -0500 Subject: [PATCH 001/112] Add base implementation of extendable events classes Modified server deletion to use internal event handlers from the Eloquent models themselves. Also added a few preliminary event handlers in the `Pterodactyl\Events\ namespace that users can hook into in EventServiceProvider to perform their own actions as they please (such as push notifications and such). --- .../{ServerDeleted.php => Server/Created.php} | 9 +- .../Server/Creating.php} | 37 +++----- app/Events/Server/Deleted.php | 45 ++++++++++ app/Events/Server/Deleting.php | 45 ++++++++++ app/Events/User/Created.php | 45 ++++++++++ app/Events/User/Creating.php | 45 ++++++++++ app/Events/User/Deleted.php | 45 ++++++++++ app/Events/User/Deleting.php | 45 ++++++++++ app/Models/Node.php | 3 + app/Models/Server.php | 3 +- app/Notifications/ServerCreated.php | 22 +++++ app/Observers/ServerObserver.php | 89 +++++++++++++++++++ app/Observers/UserObserver.php | 75 ++++++++++++++++ app/Providers/AppServiceProvider.php | 29 +++++- app/Providers/EventServiceProvider.php | 6 +- app/Repositories/ServerRepository.php | 5 +- 16 files changed, 506 insertions(+), 42 deletions(-) rename app/Events/{ServerDeleted.php => Server/Created.php} (89%) rename app/{Listeners/DeleteServerListener.php => Events/Server/Creating.php} (60%) create mode 100644 app/Events/Server/Deleted.php create mode 100644 app/Events/Server/Deleting.php create mode 100644 app/Events/User/Created.php create mode 100644 app/Events/User/Creating.php create mode 100644 app/Events/User/Deleted.php create mode 100644 app/Events/User/Deleting.php create mode 100644 app/Observers/ServerObserver.php create mode 100644 app/Observers/UserObserver.php diff --git a/app/Events/ServerDeleted.php b/app/Events/Server/Created.php similarity index 89% rename from app/Events/ServerDeleted.php rename to app/Events/Server/Created.php index 95f8e33e1..d5a308876 100644 --- a/app/Events/ServerDeleted.php +++ b/app/Events/Server/Created.php @@ -22,11 +22,12 @@ * SOFTWARE. */ -namespace Pterodactyl\Events; +namespace Pterodactyl\Events\Server; +use Pterodactyl\Models\Server; use Illuminate\Queue\SerializesModels; -class ServerDeleted +class Created { use SerializesModels; @@ -37,8 +38,8 @@ class ServerDeleted * * @return void */ - public function __construct($id) + public function __construct(Server $server) { - $this->server = $id; + $this->server = $server; } } diff --git a/app/Listeners/DeleteServerListener.php b/app/Events/Server/Creating.php similarity index 60% rename from app/Listeners/DeleteServerListener.php rename to app/Events/Server/Creating.php index 616f4c141..cbba63eb1 100644 --- a/app/Listeners/DeleteServerListener.php +++ b/app/Events/Server/Creating.php @@ -22,41 +22,24 @@ * SOFTWARE. */ -namespace Pterodactyl\Listeners; +namespace Pterodactyl\Events\Server; -use Carbon; -use Pterodactyl\Jobs\DeleteServer; -use Pterodactyl\Jobs\SuspendServer; -use Pterodactyl\Events\ServerDeleted; -use Illuminate\Foundation\Bus\DispatchesJobs; +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; -class DeleteServerListener +class Creating { - use DispatchesJobs; + use SerializesModels; + + public $server; /** - * Create the event listener. + * Create a new event instance. * * @return void */ - public function __construct() + public function __construct(Server $server) { - // - } - - /** - * Handle the event. - * - * @param DeleteServerEvent $event - * @return void - */ - public function handle(ServerDeleted $event) - { - $this->dispatch((new SuspendServer($event->server))->onQueue(env('QUEUE_HIGH', 'high'))); - $this->dispatch( - (new DeleteServer($event->server)) - ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) - ->onQueue(env('QUEUE_STANDARD', 'standard')) - ); + $this->server = $server; } } diff --git a/app/Events/Server/Deleted.php b/app/Events/Server/Deleted.php new file mode 100644 index 000000000..b36dca12d --- /dev/null +++ b/app/Events/Server/Deleted.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Deleting.php b/app/Events/Server/Deleting.php new file mode 100644 index 000000000..bb18e1ee9 --- /dev/null +++ b/app/Events/Server/Deleting.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/User/Created.php b/app/Events/User/Created.php new file mode 100644 index 000000000..a00bdd450 --- /dev/null +++ b/app/Events/User/Created.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Created +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Creating.php b/app/Events/User/Creating.php new file mode 100644 index 000000000..39a50f0c8 --- /dev/null +++ b/app/Events/User/Creating.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Creating +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleted.php b/app/Events/User/Deleted.php new file mode 100644 index 000000000..348c859c9 --- /dev/null +++ b/app/Events/User/Deleted.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleted +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Events/User/Deleting.php b/app/Events/User/Deleting.php new file mode 100644 index 000000000..5bbd91366 --- /dev/null +++ b/app/Events/User/Deleting.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\User; + +use Pterodactyl\Models\User; +use Illuminate\Queue\SerializesModels; + +class Deleting +{ + use SerializesModels; + + public $user; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Models/Node.php b/app/Models/Node.php index 5b82a2429..a5cbce464 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -26,9 +26,12 @@ namespace Pterodactyl\Models; use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; class Node extends Model { + use Notifiable; + /** * The table associated with the model. * diff --git a/app/Models/Server.php b/app/Models/Server.php index b90d0c510..3a11603c2 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -26,11 +26,12 @@ namespace Pterodactyl\Models; use Auth; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\SoftDeletes; class Server extends Model { - use SoftDeletes; + use Notifiable, SoftDeletes; /** * The table associated with the model. diff --git a/app/Notifications/ServerCreated.php b/app/Notifications/ServerCreated.php index a581a8fb2..a8e8b59f0 100644 --- a/app/Notifications/ServerCreated.php +++ b/app/Notifications/ServerCreated.php @@ -1,4 +1,26 @@ . + * + * 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\Notifications; diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php new file mode 100644 index 000000000..82c403a8a --- /dev/null +++ b/app/Observers/ServerObserver.php @@ -0,0 +1,89 @@ +. + * + * 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\Observers; + +use Carbon; +use Pterodactyl\Events; +use Pterodactyl\Models\Server; +use Pterodactyl\Jobs\DeleteServer; +use Pterodactyl\Jobs\SuspendServer; +use Illuminate\Foundation\Bus\DispatchesJobs; + +class ServerObserver +{ + use DispatchesJobs; + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function creating(Server $server) + { + event(new Events\Server\Creating($server)); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function created(Server $server) + { + event(new Events\Server\Created($server)); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleting(Server $server) + { + event(new Events\Server\Deleting($server)); + + $this->dispatch((new SuspendServer($server->id))->onQueue(env('QUEUE_HIGH', 'high'))); + } + + /** + * Listen to the Server deleted event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function deleted(Server $server) + { + event(new Events\Server\Deleted($server)); + + $this->dispatch( + (new DeleteServer($server->id)) + ->delay(Carbon::now()->addMinutes(env('APP_DELETE_MINUTES', 10))) + ->onQueue(env('QUEUE_STANDARD', 'standard')) + ); + } +} diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php new file mode 100644 index 000000000..e0624e268 --- /dev/null +++ b/app/Observers/UserObserver.php @@ -0,0 +1,75 @@ +. + * + * 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\Observers; + +use Pterodactyl\Events; +use Pterodactyl\Models\User; + +class UserObserver +{ + /** + * Listen to the User creating event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function creating(User $user) + { + event(new Events\User\Creating($user)); + } + + /** + * Listen to the User created event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function created(User $user) + { + event(new Events\User\Created($user)); + } + + /** + * Listen to the User deleting event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleting(User $user) + { + event(new Events\User\Deleting($user)); + } + + /** + * Listen to the User deleted event. + * + * @param User $user The eloquent User model. + * @return void + */ + public function deleted(User $user) + { + event(new Events\User\Deleted($user)); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index d0d1dd9e4..d71ea056b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,8 +1,34 @@ . + * + * 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\Providers; +use Pterodactyl\Models\User; +use Pterodactyl\Models\Server; use Illuminate\Support\ServiceProvider; +use Pterodactyl\Observers\UserObserver; +use Pterodactyl\Observers\ServerObserver; class AppServiceProvider extends ServiceProvider { @@ -13,7 +39,8 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + User::observe(UserObserver::class); + Server::observe(ServerObserver::class); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 7ec0d48ae..0e31100c3 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -12,11 +12,7 @@ class EventServiceProvider extends ServiceProvider * * @var array */ - protected $listen = [ - 'Pterodactyl\Events\ServerDeleted' => [ - 'Pterodactyl\Listeners\DeleteServerListener', - ], - ]; + protected $listen = []; /** * Register any other events for your application. diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 88618a476..9f762bc4a 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -29,7 +29,6 @@ use Log; use Crypt; use Validator; use Pterodactyl\Models; -use Pterodactyl\Events\ServerDeleted; use Pterodactyl\Services\UuidService; use Pterodactyl\Services\DeploymentService; use Pterodactyl\Exceptions\DisplayException; @@ -797,9 +796,7 @@ class ServerRepository } $server->delete(); - DB::commit(); - - event(new ServerDeleted($server->id)); + return DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; From 58de6125c2cf9ed108b913e44c071e38099289a4 Mon Sep 17 00:00:00 2001 From: Emmet Young Date: Wed, 25 Jan 2017 22:01:57 +1100 Subject: [PATCH 002/112] Location should be validated on creation of a server, --- app/Repositories/ServerRepository.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9f762bc4a..9e16de31e 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -92,6 +92,7 @@ class ServerRepository 'disk' => 'required|numeric|min:0', 'service' => 'required|numeric|min:1|exists:services,id', 'option' => 'required|numeric|min:1|exists:service_options,id', + 'location' => 'required|numeric|min:1|exists:locations,id', 'pack' => 'sometimes|nullable|numeric|min:0', 'startup' => 'string', 'custom_image_name' => 'required_if:use_custom_image,on', From 96e50506a17a40b53a0af50441f24a4c784c75f7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 16:37:01 -0500 Subject: [PATCH 003/112] Move notification email of server created into the event listener --- app/Notifications/ServerCreated.php | 14 +++++++------- app/Observers/ServerObserver.php | 13 +++++++++++++ app/Repositories/ServerRepository.php | 11 ----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/Notifications/ServerCreated.php b/app/Notifications/ServerCreated.php index a8e8b59f0..a867e26c7 100644 --- a/app/Notifications/ServerCreated.php +++ b/app/Notifications/ServerCreated.php @@ -66,12 +66,12 @@ class ServerCreated extends Notification implements ShouldQueue public function toMail($notifiable) { return (new MailMessage) - ->line('A new server as been assigned to your account.') - ->line('Server Name: ' . $this->server->name) - ->line('Memory: ' . $this->server->memory . ' MB') - ->line('Node: ' . $this->server->node) - ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) - ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) - ->line('Please let us know if you have any additional questions or concerns!'); + ->line('A new server as been assigned to your account.') + ->line('Server Name: ' . $this->server->name) + ->line('Memory: ' . $this->server->memory . ' MB') + ->line('Node: ' . $this->server->node) + ->line('Type: ' . $this->server->service . ' - ' . $this->server->option) + ->action('Peel Off the Protective Wrap', route('server.index', $this->server->uuidShort)) + ->line('Please let us know if you have any additional questions or concerns!'); } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 82c403a8a..ed6246ed4 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -26,9 +26,11 @@ namespace Pterodactyl\Observers; use Carbon; use Pterodactyl\Events; +use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Jobs\DeleteServer; use Pterodactyl\Jobs\SuspendServer; +use Pterodactyl\Notifications\ServerCreated; use Illuminate\Foundation\Bus\DispatchesJobs; class ServerObserver @@ -55,6 +57,17 @@ class ServerObserver public function created(Server $server) { event(new Events\Server\Created($server)); + + // Queue Notification Email + $user = User::findOrFail($server->owner); + $user->notify((new ServerCreated([ + 'name' => $server->name, + 'memory' => $server->memory, + 'node' => $node->name, + 'service' => $service->name, + 'option' => $option->name, + 'uuidShort' => $server->uuidShort, + ]))); } /** diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 9e16de31e..324e1f47d 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -32,7 +32,6 @@ use Pterodactyl\Models; use Pterodactyl\Services\UuidService; use Pterodactyl\Services\DeploymentService; use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Notifications\ServerCreated; use Pterodactyl\Exceptions\DisplayValidationException; class ServerRepository @@ -300,16 +299,6 @@ class ServerRepository ]); } - // Queue Notification Email - $user->notify((new ServerCreated([ - 'name' => $server->name, - 'memory' => $server->memory, - 'node' => $node->name, - 'service' => $service->name, - 'option' => $option->name, - 'uuidShort' => $server->uuidShort, - ]))); - $client = Models\Node::guzzleRequest($node->id); $client->request('POST', '/servers', [ 'headers' => [ From 95730da41920a797c74e265eb23696108c2ae606 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 16:57:15 -0500 Subject: [PATCH 004/112] Fix pack edit display --- resources/views/admin/services/packs/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index b7ba5fcde..0c05d4f99 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -65,7 +65,7 @@ @foreach($services as $service => $options) @foreach($options as $option) - + @endforeach @endforeach From 95d0c646f9f64624f37290b44fc68e32b209407b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 18:20:41 -0500 Subject: [PATCH 005/112] Require packs to be a tarball --- app/Repositories/ServiceRepository/Pack.php | 15 +++++---------- .../views/admin/services/packs/edit.blade.php | 2 +- .../views/admin/services/packs/new.blade.php | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index ae68c1a6b..c5dee34a4 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -66,11 +66,8 @@ class Pack throw new DisplayException('The file provided does not appear to be valid.'); } - if (! in_array($data['file_upload']->getMimeType(), [ - 'application/zip', - 'application/gzip', - ])) { - throw new DisplayException('The file provided does not meet the required filetypes of application/zip or application/gzip.'); + if ($data['file_upload']->getMimeType() !== 'application/gzip') { + throw new DisplayException('The file provided does not meet the required filetype of application/gzip.'); } } @@ -95,8 +92,7 @@ class Pack Storage::makeDirectory('packs/' . $pack->uuid); if (isset($data['file_upload'])) { - $filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz'; - $data['file_upload']->storeAs('packs/' . $pack->uuid, $filename); + $data['file_upload']->storeAs('packs/' . $pack->uuid, 'archive.tar.gz'); } DB::commit(); @@ -132,10 +128,9 @@ class Pack throw new DisplayException('The uploaded archive was unable to be opened.'); } - $isZip = $zip->locateName('archive.zip'); $isTar = $zip->locateName('archive.tar.gz'); - if ($zip->locateName('import.json') === false || ($isZip === false && $isTar === false)) { + if (! $zip->locateName('import.json') || ! $isTar) { throw new DisplayException('This contents of the provided archive were in an invalid format.'); } @@ -156,7 +151,7 @@ class Pack ]); $pack = Models\ServicePack::findOrFail($id); - if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), ($isZip === false) ? 'archive.tar.gz' : 'archive.zip')) { + if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { $pack->delete(); throw new DisplayException('Unable to extract the archive file to the correct location.'); } diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index 0c05d4f99..0cdd80705 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -175,7 +175,7 @@ @endforeach -

If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as either archive.zip or archive.tar.gz.

+

If you wish to modify or upload a new file it should be uploaded to {{ storage_path('app/packs/' . $pack->uuid) }} as archive.tar.gz.

diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index c31f1c77e..7a5be8f47 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -150,8 +150,8 @@
- -

This package file must either be a .zip or .tar.gz archive of files to use for either building or running this pack.

If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. + +

This package file must be a .tar.gz archive of files to use for either building or running this pack.

If your file is larger than 20MB we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file. This server is currently configured with the following limits: upload_max_filesize={{ ini_get('upload_max_filesize') }} and post_max_size={{ ini_get('post_max_size') }}. If your file is larger than either of those values this request will fail.

From e6d3e750241d6da988588083784993c872051ef7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 25 Jan 2017 18:25:31 -0500 Subject: [PATCH 006/112] Add new daemon routes for pack handling --- .../Controllers/Daemon/PackController.php | 96 +++++++++++++++++++ app/Http/Routes/DaemonRoutes.php | 9 ++ 2 files changed, 105 insertions(+) create mode 100644 app/Http/Controllers/Daemon/PackController.php diff --git a/app/Http/Controllers/Daemon/PackController.php b/app/Http/Controllers/Daemon/PackController.php new file mode 100644 index 000000000..245b88627 --- /dev/null +++ b/app/Http/Controllers/Daemon/PackController.php @@ -0,0 +1,96 @@ +. + * + * 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\Controllers\Daemon; + +use Storage; +use Pterodactyl\Models; +use Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; + +class PackController extends Controller +{ + /** + * Controller Constructor. + */ + public function __construct() + { + // + } + + /** + * Pulls an install pack archive from the system + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pull(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (!$pack) { + return response()->json([ 'error' => 'No such pack.' ], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + } + + return response()->download(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')); + } + + /** + * Returns the hash information for a pack. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function hash(Request $request, $uuid) + { + $pack = Models\ServicePack::where('uuid', $uuid)->first(); + + if (!$pack) { + return response()->json([ 'error' => 'No such pack.' ], 404); + } + + if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { + return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + } + + return response()->json([ + 'archive.tar.gz' => sha1_file(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')), + ]); + } + + /** + * Pulls an update pack archive from the system + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function pullUpdate(Request $request) + { + + } +} diff --git a/app/Http/Routes/DaemonRoutes.php b/app/Http/Routes/DaemonRoutes.php index b993e3759..3792dc8fd 100644 --- a/app/Http/Routes/DaemonRoutes.php +++ b/app/Http/Routes/DaemonRoutes.php @@ -40,6 +40,15 @@ class DaemonRoutes 'as' => 'remote.install', 'uses' => 'Daemon\ServiceController@pull', ]); + + $router->get('packs/pull/{uuid}', [ + 'as' => 'daemon.pack.pull', + 'uses' => 'Daemon\PackController@pull', + ]); + $router->get('packs/pull/{uuid}/hash', [ + 'as' => 'daemon.pack.hash', + 'uses' => 'Daemon\PackController@hash', + ]); }); } } From 4a6d62fded67466742adbf903ab72a03d5400aef Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 27 Jan 2017 16:21:15 -0500 Subject: [PATCH 007/112] Fix fatal error when trying to send server creation notification --- app/Observers/ServerObserver.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index ed6246ed4..6506f03f2 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -26,7 +26,7 @@ namespace Pterodactyl\Observers; use Carbon; use Pterodactyl\Events; -use Pterodactyl\Models\User; +use Pterodactyl\Models; use Pterodactyl\Models\Server; use Pterodactyl\Jobs\DeleteServer; use Pterodactyl\Jobs\SuspendServer; @@ -59,13 +59,20 @@ class ServerObserver event(new Events\Server\Created($server)); // Queue Notification Email - $user = User::findOrFail($server->owner); + $user = Models\User::findOrFail($server->owner); + $node = Models\Node::select('name')->where('id', $server->node)->first(); + $service = Models\Service::select('services.name', 'service_options.name as optionName') + ->join('service_options', 'service_options.parent_service', '=', 'services.id') + ->where('services.id', $server->service) + ->where('service_options.id', $server->option) + ->first(); + $user->notify((new ServerCreated([ 'name' => $server->name, 'memory' => $server->memory, 'node' => $node->name, 'service' => $service->name, - 'option' => $option->name, + 'option' => $service->optionName, 'uuidShort' => $server->uuidShort, ]))); } From 9087feec4f478f83b5af28c5c24f2fe64292a1c6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 27 Jan 2017 16:21:25 -0500 Subject: [PATCH 008/112] Remove build settings from packs. --- app/Http/Controllers/Admin/PackController.php | 8 --- app/Repositories/ServiceRepository/Pack.php | 36 ----------- .../2016_11_11_220649_add_pack_support.php | 6 -- .../views/admin/services/packs/edit.blade.php | 60 +------------------ .../views/admin/services/packs/new.blade.php | 58 ------------------ 5 files changed, 1 insertion(+), 167 deletions(-) diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index abda49c8e..628cd54b8 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -183,14 +183,6 @@ class PackController extends Controller 'description' => $pack->dscription, 'selectable' => (bool) $pack->selectable, 'visible' => (bool) $pack->visible, - 'build' => [ - 'memory' => $pack->build_memory, - 'swap' => $pack->build_swap, - 'cpu' => $pack->build_cpu, - 'io' => $pack->build_io, - 'container' => $pack->build_container, - 'script' => $pack->build_script, - ], ]; $filename = tempnam(sys_get_temp_dir(), 'pterodactyl_'); diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index c5dee34a4..3cf8588e4 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -49,12 +49,6 @@ class Pack 'option' => 'required|exists:service_options,id', 'selectable' => 'sometimes|boolean', 'visible' => 'sometimes|boolean', - 'build_memory' => 'required|integer|min:0', - 'build_swap' => 'required|integer|min:0', - 'build_cpu' => 'required|integer|min:0', - 'build_io' => 'required|integer|min:10|max:1000', - 'build_container' => 'required|string', - 'build_script' => 'sometimes|nullable|string', ]); if ($validator->fails()) { @@ -77,12 +71,6 @@ class Pack $pack = Models\ServicePack::create([ 'option' => $data['option'], 'uuid' => $uuid->generate('servers', 'uuid'), - 'build_memory' => $data['build_memory'], - 'build_swap' => $data['build_swap'], - 'build_cpu' => $data['build_swap'], - 'build_io' => $data['build_io'], - 'build_script' => (empty($data['build_script'])) ? null : $data['build_script'], - 'build_container' => $data['build_container'], 'name' => $data['name'], 'version' => $data['version'], 'description' => (empty($data['description'])) ? null : $data['description'], @@ -142,12 +130,6 @@ class Pack 'option' => $data['option'], 'selectable' => $json->selectable, 'visible' => $json->visible, - 'build_memory' => $json->build->memory, - 'build_swap' => $json->build->swap, - 'build_cpu' => $json->build->cpu, - 'build_io' => $json->build->io, - 'build_container' => $json->build->container, - 'build_script' => $json->build->script, ]); $pack = Models\ServicePack::findOrFail($id); @@ -169,12 +151,6 @@ class Pack 'option' => $data['option'], 'selectable' => $json->selectable, 'visible' => $json->visible, - 'build_memory' => $json->build->memory, - 'build_swap' => $json->build->swap, - 'build_cpu' => $json->build->cpu, - 'build_io' => $json->build->io, - 'build_container' => $json->build->container, - 'build_script' => $json->build->script, ]); } } @@ -188,12 +164,6 @@ class Pack 'option' => 'required|exists:service_options,id', 'selectable' => 'sometimes|boolean', 'visible' => 'sometimes|boolean', - 'build_memory' => 'required|integer|min:0', - 'build_swap' => 'required|integer|min:0', - 'build_cpu' => 'required|integer|min:0', - 'build_io' => 'required|integer|min:10|max:1000', - 'build_container' => 'required|string', - 'build_script' => 'sometimes|string', ]); if ($validator->fails()) { @@ -203,12 +173,6 @@ class Pack DB::transaction(function () use ($id, $data) { Models\ServicePack::findOrFail($id)->update([ 'option' => $data['option'], - 'build_memory' => $data['build_memory'], - 'build_swap' => $data['build_swap'], - 'build_cpu' => $data['build_swap'], - 'build_io' => $data['build_io'], - 'build_script' => (empty($data['build_script'])) ? null : $data['build_script'], - 'build_container' => $data['build_container'], 'name' => $data['name'], 'version' => $data['version'], 'description' => (empty($data['description'])) ? null : $data['description'], diff --git a/database/migrations/2016_11_11_220649_add_pack_support.php b/database/migrations/2016_11_11_220649_add_pack_support.php index 87a66b40a..7cb3eb10e 100644 --- a/database/migrations/2016_11_11_220649_add_pack_support.php +++ b/database/migrations/2016_11_11_220649_add_pack_support.php @@ -17,12 +17,6 @@ class AddPackSupport extends Migration $table->increments('id'); $table->unsignedInteger('option'); $table->char('uuid', 36)->unique(); - $table->unsignedInteger('build_memory')->nullable(); - $table->unsignedInteger('build_swap')->nullable(); - $table->unsignedInteger('build_cpu')->nullable(); - $table->unsignedInteger('build_io')->nullable(); - $table->text('build_script')->nullable(); - $table->string('build_container')->default('alpine:latest'); $table->string('name'); $table->string('version'); $table->text('description')->nullable(); diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index 0cdd80705..dcb67d5df 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -88,64 +88,6 @@
-
-
-
Build Parameters
-
-
-
- -
- - MB -
-
-
- -
- - MB -
-
-
- -
- - % -
-
-
- -
- - I/O -
-
-
-
-

If you would like to set limits on the build container you may do so above. Setting memory, swap, or cpu to 0 will allow unlimited resource utilization. IO must be in a range between 10 to 1000 and is a relative weighting to other container IO usage.

-
-
-
-
-
- -
- -

Provide the docker container image that will be used to build this service pack. This container is only used if a build script is provided below.

-
-
-
- -
{{ $pack->build_script }}
- -

This script will be run inside the container if provided. You should use this script to download any additional dependencies or compile packages as necessary on the node. Your uploaded archive (if provided), will be available in /input as archive.tar.gz or as archive.zip depending on what format you uploaded as. Your completed pack should be saved as package.tar.gz in the /output directory (e.g. /output/package.tar.gz).

-
-
-
-
-
-
Package Archive
@@ -153,7 +95,7 @@
@if(count($files) > 1) -
Warning! Service packs should only contain a single pack archive in either .zip or .tar.gz format. We've detected more than one file for this pack.
+
Warning! Service packs should only contain a single pack archive in .tar.gz format. We've detected more than one file for this pack.
@endif diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index 7a5be8f47..82601bc62 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -85,64 +85,6 @@
-
-
-
Build Parameters
-
-
-
- -
- - MB -
-
-
- -
- - MB -
-
-
- -
- - % -
-
-
- -
- - I/O -
-
-
-
-

If you would like to set limits on the build container you may do so above. Setting memory, swap, or cpu to 0 will allow unlimited resource utilization. IO must be in a range between 10 to 1000 and is a relative weighting to other container IO usage.

-
-
-
-
-
- -
- -

Provide the docker container image that will be used to build this service pack. This container is only used if a build script is provided below.

-
-
-
- -
- -

This script will be run inside the container if provided. You should use this script to download any additional dependencies or compile packages as necessary on the node. Your uploaded archive (if provided), will be available in /input as archive.tar.gz or as archive.zip depending on what format you uploaded as. Your completed pack should be saved as package.tar.gz in the /output directory (e.g. /output/package.tar.gz).

-
-
-
-
-
-
File Upload
From 4b0197f2be9ce9d2c3e7fa46c77aca0211694081 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 27 Jan 2017 16:34:46 -0500 Subject: [PATCH 009/112] Implement basic security policy on daemon remote routes --- app/Http/Kernel.php | 1 + app/Http/Middleware/DaemonAuthenticate.php | 71 ++++++++++++++++++++++ app/Http/Middleware/VerifyCsrfToken.php | 1 + app/Http/Routes/DaemonRoutes.php | 2 +- app/Http/Routes/RemoteRoutes.php | 5 -- 5 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 app/Http/Middleware/DaemonAuthenticate.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 9e8d9f816..3ab1a1b9d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -51,6 +51,7 @@ class Kernel extends HttpKernel 'guest' => \Pterodactyl\Http\Middleware\RedirectIfAuthenticated::class, 'server' => \Pterodactyl\Http\Middleware\CheckServer::class, 'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class, + 'daemon' => \Pterodactyl\Http\Middleware\DaemonAuthenticate::class, 'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, diff --git a/app/Http/Middleware/DaemonAuthenticate.php b/app/Http/Middleware/DaemonAuthenticate.php new file mode 100644 index 000000000..73cb029d4 --- /dev/null +++ b/app/Http/Middleware/DaemonAuthenticate.php @@ -0,0 +1,71 @@ +. + * + * 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\Middleware; + +use Closure; +use Pterodactyl\Models\Node; +use Illuminate\Contracts\Auth\Guard; + +class DaemonAuthenticate +{ + /** + * The Guard implementation. + * + * @var Guard + */ + protected $auth; + + /** + * Create a new filter instance. + * + * @param Guard $auth + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + if (! $request->header('X-Access-Node')) { + return abort(403); + } + + $node = Node::where('daemonSecret', $request->header('X-Access-Node'))->first(); + if (! $node) { + return abort(404); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index fe23f9e99..08d960353 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -13,6 +13,7 @@ class VerifyCsrfToken extends BaseVerifier */ protected $except = [ 'remote/*', + 'daemon/*', 'api/*', ]; } diff --git a/app/Http/Routes/DaemonRoutes.php b/app/Http/Routes/DaemonRoutes.php index 3792dc8fd..7367fae5f 100644 --- a/app/Http/Routes/DaemonRoutes.php +++ b/app/Http/Routes/DaemonRoutes.php @@ -30,7 +30,7 @@ class DaemonRoutes { public function map(Router $router) { - $router->group(['prefix' => 'daemon'], function () use ($router) { + $router->group(['prefix' => 'daemon', 'middleware' => 'daemon'], function () use ($router) { $router->get('services', [ 'as' => 'daemon.services', 'uses' => 'Daemon\ServiceController@list', diff --git a/app/Http/Routes/RemoteRoutes.php b/app/Http/Routes/RemoteRoutes.php index ba8f47f9b..9ece1fb2e 100644 --- a/app/Http/Routes/RemoteRoutes.php +++ b/app/Http/Routes/RemoteRoutes.php @@ -42,11 +42,6 @@ class RemoteRoutes 'uses' => 'Remote\RemoteController@postInstall', ]); - $router->post('event', [ - 'as' => 'remote.event', - 'uses' => 'Remote\RemoteController@event', - ]); - $router->get('configuration/{token}', [ 'as' => 'remote.configuration', 'uses' => 'Remote\RemoteController@getConfiguration', From 1679d866a5c0f1012f416f97046f6f3386944acf Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 27 Jan 2017 16:47:50 -0500 Subject: [PATCH 010/112] Improved gzip detection --- app/Repositories/ServiceRepository/Pack.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index 3cf8588e4..03858ed67 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -60,8 +60,8 @@ class Pack throw new DisplayException('The file provided does not appear to be valid.'); } - if ($data['file_upload']->getMimeType() !== 'application/gzip') { - throw new DisplayException('The file provided does not meet the required filetype of application/gzip.'); + if (! in_array($data['file_upload']->getMimeType(), ['application/gzip', 'application/x-gzip'])) { + throw new DisplayException('The file provided (' . $data['file_upload']->getMimeType() . ') does not meet the required filetype of application/gzip.'); } } From e5ed1c7f6af9510f0be36dbab5494091a513b68c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 31 Jan 2017 20:04:34 -0500 Subject: [PATCH 011/112] =?UTF-8?q?One=20day=20eslint=20will=20have=20a=20?= =?UTF-8?q?PHP=20counterpart=20that=20works=20in=20Atom...=20=F0=9F=A4=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Daemon/PackController.php | 17 ++++++++--------- app/Repositories/ServerRepository.php | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Daemon/PackController.php b/app/Http/Controllers/Daemon/PackController.php index 245b88627..e96aa6ee5 100644 --- a/app/Http/Controllers/Daemon/PackController.php +++ b/app/Http/Controllers/Daemon/PackController.php @@ -40,7 +40,7 @@ class PackController extends Controller } /** - * Pulls an install pack archive from the system + * Pulls an install pack archive from the system. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response @@ -49,12 +49,12 @@ class PackController extends Controller { $pack = Models\ServicePack::where('uuid', $uuid)->first(); - if (!$pack) { - return response()->json([ 'error' => 'No such pack.' ], 404); + if (! $pack) { + return response()->json(['error' => 'No such pack.'], 404); } if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { - return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + return response()->json(['error' => 'There is no archive available for this pack.'], 503); } return response()->download(storage_path('app/packs/' . $pack->uuid . '/archive.tar.gz')); @@ -70,12 +70,12 @@ class PackController extends Controller { $pack = Models\ServicePack::where('uuid', $uuid)->first(); - if (!$pack) { - return response()->json([ 'error' => 'No such pack.' ], 404); + if (! $pack) { + return response()->json(['error' => 'No such pack.'], 404); } if (! Storage::exists('packs/' . $pack->uuid . '/archive.tar.gz')) { - return response()->json([ 'error' => 'There is no archive available for this pack.' ], 503); + return response()->json(['error' => 'There is no archive available for this pack.'], 503); } return response()->json([ @@ -84,13 +84,12 @@ class PackController extends Controller } /** - * Pulls an update pack archive from the system + * Pulls an update pack archive from the system. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function pullUpdate(Request $request) { - } } diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 324e1f47d..beb5d94a6 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -786,6 +786,7 @@ class ServerRepository } $server->delete(); + return DB::commit(); } catch (\Exception $ex) { DB::rollBack(); From ee26a7e8dd94690ed9a1ecca7eaf2e00d7e1ab4d Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Wed, 1 Feb 2017 20:10:28 +0100 Subject: [PATCH 012/112] add fideloper/proxy to support reverse proxies and load balancers --- .env.example | 1 + app/Http/Kernel.php | 2 ++ composer.json | 3 ++- config/app.php | 1 + config/trustedproxy.php | 59 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 config/trustedproxy.php diff --git a/.env.example b/.env.example index ba98b1c75..7e41a75a0 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,7 @@ APP_CLEAR_TASKLOG=720 APP_DELETE_MINUTES=10 CONSOLE_PUSH_FREQ=250 CONSOLE_PUSH_COUNT=10 +TRUSTED_PROXIES=null DB_HOST=localhost DB_PORT=3306 diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 9e8d9f816..7e03c17ec 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -17,7 +17,9 @@ class Kernel extends HttpKernel \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Pterodactyl\Http\Middleware\LanguageMiddleware::class, + \Fideloper\Proxy\TrustProxies::class, ]; /** diff --git a/composer.json b/composer.json index 3569e3d1b..b015adbd0 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "mtdowling/cron-expression": "1.1.0", "dingo/api": "1.0.0-beta6", "aws/aws-sdk-php": "3.19.20", - "predis/predis": "1.1.1" + "predis/predis": "1.1.1", + "fideloper/proxy": "3.2.0" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/config/app.php b/config/app.php index 3093b43d0..957848eae 100644 --- a/config/app.php +++ b/config/app.php @@ -158,6 +158,7 @@ return [ igaster\laravelTheme\themeServiceProvider::class, Prologue\Alerts\AlertsServiceProvider::class, Krucas\Settings\Providers\SettingsServiceProvider::class, + Fideloper\Proxy\TrustedProxyServiceProvider::class, ], diff --git a/config/trustedproxy.php b/config/trustedproxy.php new file mode 100644 index 000000000..7d7accf0e --- /dev/null +++ b/config/trustedproxy.php @@ -0,0 +1,59 @@ +getClientIp() + * always gets the originating client IP, no matter + * how many proxies that client's request has + * subsequently passed through. + */ + 'proxies' => explode(',', env('TRUSTED_PROXIES', null)), + + /* + * Or, to trust all proxies that connect + * directly to your server, uncomment this: + */ + # 'proxies' => '*', + + /* + * Or, to trust ALL proxies, including those that + * are in a chain of fowarding, uncomment this: + */ + # 'proxies' => '**', + + /* + * Default Header Names + * + * Change these if the proxy does + * not send the default header names. + * + * Note that headers such as X-Forwarded-For + * are transformed to HTTP_X_FORWARDED_FOR format. + * + * The following are Symfony defaults, found in + * \Symfony\Component\HttpFoundation\Request::$trustedHeaders + */ + 'headers' => [ + \Illuminate\Http\Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', + \Illuminate\Http\Request::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', + \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', + \Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', + ] +]; From 8ab4faad8a47d0e4d1db9ff6b07e6d6bf8703490 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Wed, 1 Feb 2017 20:31:24 +0100 Subject: [PATCH 013/112] remove TRUSTED_PROXIES from .env.example make style ci happy --- .env.example | 1 - app/Http/Kernel.php | 2 +- config/trustedproxy.php | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index 7e41a75a0..ba98b1c75 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,6 @@ APP_CLEAR_TASKLOG=720 APP_DELETE_MINUTES=10 CONSOLE_PUSH_FREQ=250 CONSOLE_PUSH_COUNT=10 -TRUSTED_PROXIES=null DB_HOST=localhost DB_PORT=3306 diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 7e03c17ec..d4c1cf1f1 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -17,7 +17,7 @@ class Kernel extends HttpKernel \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, - + \Pterodactyl\Http\Middleware\LanguageMiddleware::class, \Fideloper\Proxy\TrustProxies::class, ]; diff --git a/config/trustedproxy.php b/config/trustedproxy.php index 7d7accf0e..2bf4cd02f 100644 --- a/config/trustedproxy.php +++ b/config/trustedproxy.php @@ -30,13 +30,13 @@ return [ * Or, to trust all proxies that connect * directly to your server, uncomment this: */ - # 'proxies' => '*', + // 'proxies' => '*', /* * Or, to trust ALL proxies, including those that * are in a chain of fowarding, uncomment this: - */ - # 'proxies' => '**', + */ + // 'proxies' => '**', /* * Default Header Names @@ -55,5 +55,5 @@ return [ \Illuminate\Http\Request::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', \Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ] + ], ]; From a1a81ac98078d0a9850626cfb201860d0850018d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 1 Feb 2017 22:28:50 -0500 Subject: [PATCH 014/112] Fix auth page not remembering users. --- public/themes/pterodactyl/css/pterodactyl.css | 13 ++++++++++--- resources/themes/pterodactyl/auth/login.blade.php | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 5c849120d..342b993b9 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -20,10 +20,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + .login-box, .register-box { + width: 40%; + margin: 7% auto + } -.login-box, .register-box { - width: 460px; -} + @media (max-width:768px) { + .login-box, .register-box { + width: 90%; + margin-top: 20px + } + } .weight-100 { font-weight: 100; diff --git a/resources/themes/pterodactyl/auth/login.blade.php b/resources/themes/pterodactyl/auth/login.blade.php index 82ff3d564..cf18d9b4f 100644 --- a/resources/themes/pterodactyl/auth/login.blade.php +++ b/resources/themes/pterodactyl/auth/login.blade.php @@ -57,7 +57,7 @@
- +
From 4abdee0efbe84a14a88ee3281a0bb5b68760f1bb Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 1 Feb 2017 22:58:48 -0500 Subject: [PATCH 015/112] Better 2FA implementation on logins --- CHANGELOG.md | 3 +- app/Http/Controllers/Auth/LoginController.php | 72 +++++++++++++------ app/Http/Routes/AuthRoutes.php | 8 ++- resources/lang/en/auth.php | 2 + .../themes/pterodactyl/auth/totp.blade.php | 46 ++++++++++++ 5 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 resources/themes/pterodactyl/auth/totp.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f2ee47a5c..3c582aa84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * Admin API and base routes for user management now define the fields that should be passed to repositories rather than passing all fields. * User model now defines mass assignment fields using `$fillable` rather than `$guarded`. - -### Deprecated +* 2FA checkpoint on login is now its own page, and not an AJAX based call. Improves security on that front. ## v0.5.6 (Bodacious Boreopterus) ### Added diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 9890077f1..8d9c94eb9 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -27,6 +27,7 @@ namespace Pterodactyl\Http\Controllers\Auth; use Auth; use Alert; +use Cache; use Illuminate\Http\Request; use Pterodactyl\Models\User; use PragmaRX\Google2FA\Google2FA; @@ -110,33 +111,62 @@ class LoginController extends Controller } // Verify TOTP Token was Valid - if (Auth::user()->use_totp === 1) { - $G2FA = new Google2FA(); - if (is_null($request->input('totp_token')) || ! $G2FA->verifyKey(Auth::user()->totp_secret, $request->input('totp_token'))) { - if (! $lockedOut) { - $this->incrementLoginAttempts($request); - } + if (Auth::user()->use_totp) { + $verifyKey = str_random(64); + Cache::put($verifyKey, Auth::user()->id, 5); - Alert::danger(trans('auth.totp_failed'))->flash(); + return redirect()->route('auth.totp')->with('authentication_token', $verifyKey); + } else { + Auth::login(Auth::user(), $request->has('remember')); - return $this->sendFailedLoginResponse($request); - } + return $this->sendLoginResponse($request); + } + } + + public function totp(Request $request) + { + $verifyKey = $request->session()->get('authentication_token'); + + if (is_null($verifyKey) || Auth::user()) { + return redirect()->route('auth.login'); } - // Successfully Authenticated. - Auth::login(Auth::user(), $request->has('remember')); - - return $this->sendLoginResponse($request); + return view('auth.totp', [ + 'verify_key' => $verifyKey, + 'remember' => $request->has('remember'), + ]); } - /** - * Check if the provided user has TOTP enabled. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ - public function checkTotp(Request $request) + public function totpCheckpoint(Request $request) { - return response()->json(User::select('id')->where('email', $request->input('email'))->where('use_totp', 1)->first()); + $G2FA = new Google2FA(); + + if (is_null($request->input('verify_token'))) { + $this->incrementLoginAttempts($request); + Alert::danger(trans('auth.totp_failed'))->flash(); + + return redirect()->route('auth.login'); + } + + $user = User::where('id', Cache::pull($request->input('verify_token')))->first(); + if (! $user) { + $this->incrementLoginAttempts($request); + Alert::danger(trans('auth.totp_failed'))->flash(); + + return redirect()->route('auth.login'); + } + + + if (! is_null($request->input('2fa_token')) && $G2FA->verifyKey($user->totp_secret, $request->input('2fa_token'))) { + Auth::login($user, $request->has('remember')); + + return redirect()->intended($this->redirectPath()); + } else { + $this->incrementLoginAttempts($request); + Alert::danger(trans('auth.2fa_failed'))->flash(); + + return redirect()->route('auth.login'); + } } + } diff --git a/app/Http/Routes/AuthRoutes.php b/app/Http/Routes/AuthRoutes.php index 491bebe41..77968321c 100644 --- a/app/Http/Routes/AuthRoutes.php +++ b/app/Http/Routes/AuthRoutes.php @@ -51,9 +51,13 @@ class AuthRoutes 'uses' => 'Auth\LoginController@login', ]); - // Determine if we need to ask for a TOTP Token + $router->get('login/totp', [ + 'as' => 'auth.totp', + 'uses' => 'Auth\LoginController@totp', + ]); + $router->post('login/totp', [ - 'uses' => 'Auth\LoginController@checkTotp', + 'uses' => 'Auth\LoginController@totpCheckpoint', ]); // Show Password Reset Form diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index 0d2e305a8..3748167f6 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -15,4 +15,6 @@ return [ 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 'password_requirements' => 'Passwords must contain at least one uppercase, lowecase, and numeric character and must be at least 8 characters in length.', 'request_reset' => 'Locate Account', + '2fa_required' => '2-Factor Authentication', + '2fa_failed' => 'The 2FA token provided was invalid.', ]; diff --git a/resources/themes/pterodactyl/auth/totp.blade.php b/resources/themes/pterodactyl/auth/totp.blade.php new file mode 100644 index 000000000..4a021603d --- /dev/null +++ b/resources/themes/pterodactyl/auth/totp.blade.php @@ -0,0 +1,46 @@ +{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} + +{{-- 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. --}} +@extends('layouts.auth') + +@section('title') + 2FA Checkpoint +@endsection + +@section('content') + +@endsection From a93adce303fa98c9a8c81a3ebb6f3ebc6596ee57 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 1 Feb 2017 23:02:54 -0500 Subject: [PATCH 016/112] Only allow up to 30 seconds of overlap on comparing the 2FA tokens. --- app/Http/Controllers/Auth/LoginController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 8d9c94eb9..0be73ddd2 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -157,7 +157,7 @@ class LoginController extends Controller } - if (! is_null($request->input('2fa_token')) && $G2FA->verifyKey($user->totp_secret, $request->input('2fa_token'))) { + if (! is_null($request->input('2fa_token')) && $G2FA->verifyKey($user->totp_secret, $request->input('2fa_token'), 1)) { Auth::login($user, $request->has('remember')); return redirect()->intended($this->redirectPath()); From 4be9e30eee18e5b868da05eb42b7e59f7f3cb6b5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 1 Feb 2017 23:05:19 -0500 Subject: [PATCH 017/112] Include that 30 second limit on other 2FA checks --- app/Models/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/User.php b/app/Models/User.php index 8d1d7fb71..80d9192fa 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -105,7 +105,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac */ public function toggleTotp($token) { - if (! Google2FA::verifyKey($this->totp_secret, $token)) { + if (! Google2FA::verifyKey($this->totp_secret, $token, 1)) { return false; } From 8fc30fbe3a7ba7cba081f2af82bbe8b81f089469 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 2 Feb 2017 15:05:33 +0100 Subject: [PATCH 018/112] add phraseapp in context editor --- app/Extensions/Translator.php | 45 +++++++++++++ app/Providers/TranslationProvider.php | 63 +++++++++++++++++++ config/app.php | 5 +- .../themes/pterodactyl/layouts/auth.blade.php | 13 ++++ .../pterodactyl/layouts/master.blade.php | 13 ++++ 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 app/Extensions/Translator.php create mode 100644 app/Providers/TranslationProvider.php diff --git a/app/Extensions/Translator.php b/app/Extensions/Translator.php new file mode 100644 index 000000000..5a3edcf4f --- /dev/null +++ b/app/Extensions/Translator.php @@ -0,0 +1,45 @@ +. + * + * 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\Extensions; + +use Illuminate\Translation\Translator as LaravelTranslator; + +class Translator extends LaravelTranslator +{ + /** + * Get the translation for the given key. + * + * @param string $key + * @param array $replace + * @param string|null $locale + * @param bool $fallback + * @return string|array|null + */ + public function get($key, array $replace = [], $locale = null, $fallback = true) + { + $key = substr($key, strpos($key, '.') + 1); + return "{{__phrase_${key}__}}"; + } +} diff --git a/app/Providers/TranslationProvider.php b/app/Providers/TranslationProvider.php new file mode 100644 index 000000000..474737b50 --- /dev/null +++ b/app/Providers/TranslationProvider.php @@ -0,0 +1,63 @@ +. + * + * 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\Providers; + +use Pterodactyl\Extensions\Translator as PterodactylTranslator; +use Illuminate\Translation\Translator; +use Illuminate\Translation\TranslationServiceProvider; + +class TranslationProvider extends TranslationServiceProvider { + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->registerLoader(); + + $this->app->singleton('translator', function ($app) { + $loader = $app['translation.loader']; + + // When registering the translator component, we'll need to set the default + // locale as well as the fallback locale. So, we'll grab the application + // configuration so we can easily get both of these values from there. + $locale = $app['config']['app.locale']; + + if ($app['config']['app.phrase_in_context']) { + $trans = new PterodactylTranslator($loader, $locale); + } else { + $trans = new Translator($loader, $locale); + } + + $trans->setFallback($app['config']['app.fallback_locale']); + + return $trans; + }); + } + + +} diff --git a/config/app.php b/config/app.php index bb517f5f7..abaabe25b 100644 --- a/config/app.php +++ b/config/app.php @@ -6,6 +6,8 @@ return [ 'version' => env('APP_VERSION', 'canary'), + 'phrase_in_context' => env('PHRASE_IN_CONTEXT', false), + /* |-------------------------------------------------------------------------- | Application Debug Mode @@ -137,7 +139,7 @@ return [ Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, - Illuminate\Translation\TranslationServiceProvider::class, + //Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, @@ -149,6 +151,7 @@ return [ Pterodactyl\Providers\AuthServiceProvider::class, Pterodactyl\Providers\EventServiceProvider::class, Pterodactyl\Providers\RouteServiceProvider::class, + Pterodactyl\Providers\TranslationProvider::class, /* * Additional Dependencies diff --git a/resources/themes/pterodactyl/layouts/auth.blade.php b/resources/themes/pterodactyl/layouts/auth.blade.php index 58758f4fa..2163c9cc5 100644 --- a/resources/themes/pterodactyl/layouts/auth.blade.php +++ b/resources/themes/pterodactyl/layouts/auth.blade.php @@ -49,5 +49,18 @@
{!! Theme::js('js/vendor/jquery/jquery.min.js') !!} {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} + + @if(config('app.phrase_in_context')) + + @endif diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 19b03380f..250eb894d 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -281,6 +281,19 @@ {!! Theme::js('vendor/adminlte/app.min.js') !!} {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js') !!} + + @if(config('app.phrase_in_context')) + + @endif @show From d9225e65dfe26226965829d689442b352fbb253c Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 2 Feb 2017 15:30:40 +0100 Subject: [PATCH 019/112] move phraseapp js into own file --- public/js/phraseapp.js | 8 ++++++++ resources/themes/pterodactyl/layouts/auth.blade.php | 13 +------------ .../themes/pterodactyl/layouts/master.blade.php | 13 +------------ 3 files changed, 10 insertions(+), 24 deletions(-) create mode 100644 public/js/phraseapp.js diff --git a/public/js/phraseapp.js b/public/js/phraseapp.js new file mode 100644 index 000000000..a11a22655 --- /dev/null +++ b/public/js/phraseapp.js @@ -0,0 +1,8 @@ +window.PHRASEAPP_CONFIG = { + projectId: '94f8b39450cd749ae9c3cc0ab8cdb61d' +}; +(function() { + var phraseapp = document.createElement('script'); phraseapp.type = 'text/javascript'; phraseapp.async = true; + phraseapp.src = ['https://', 'phraseapp.com/assets/in-context-editor/2.0/app.js?', new Date().getTime()].join(''); + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(phraseapp, s); +})(); diff --git a/resources/themes/pterodactyl/layouts/auth.blade.php b/resources/themes/pterodactyl/layouts/auth.blade.php index 2163c9cc5..a6fbf86f5 100644 --- a/resources/themes/pterodactyl/layouts/auth.blade.php +++ b/resources/themes/pterodactyl/layouts/auth.blade.php @@ -50,17 +50,6 @@ {!! Theme::js('js/vendor/jquery/jquery.min.js') !!} {!! Theme::js('vendor/bootstrap/bootstrap.min.js') !!} - @if(config('app.phrase_in_context')) - - @endif + @if(config('app.phrase_in_context')) {!! Theme::js('js/phraseapp.js') !!} @endif diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 250eb894d..57c7383e0 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -282,18 +282,7 @@ {!! Theme::js('js/vendor/socketio/socket.io.min.js') !!} {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js') !!} - @if(config('app.phrase_in_context')) - - @endif + @if(config('app.phrase_in_context')) {!! Theme::js('js/phraseapp.js') !!} @endif @show From e18391e98ad576fac91cda01aeeec2935489f300 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 15:01:15 -0500 Subject: [PATCH 020/112] Commit composer lock and use config:cache for security purposes. --- .gitignore | 10 +- composer.json | 17 +- composer.lock | 5129 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 5134 insertions(+), 22 deletions(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 595557b70..cbc5340b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,4 @@ /vendor *.DS_Store* .env -.vagrant/* - -composer.lock - -Homestead.yaml -Vagrantfile -Vagrantfile - -node_modules \ No newline at end of file +node_modules diff --git a/composer.json b/composer.json index 902eb86e6..2d152c3a9 100644 --- a/composer.json +++ b/composer.json @@ -60,27 +60,18 @@ ], "post-install-cmd": [ "Illuminate\\Foundation\\ComposerScripts::postInstall", - "php artisan optimize" + "php artisan optimize", + "php artisan config:cache" ], "post-update-cmd": [ "Illuminate\\Foundation\\ComposerScripts::postUpdate", - "php artisan optimize" - ], - "setup-dev": [ - "composer install", - "php -r \"copy('.env.example', '.env');\"", - "php vendor/bin/homestead make --ip=192.168.10.32", - "sed -i.bak 's/homestead.app/pterodactyl.local/g' Homestead.yaml", - "rm Homestead.yaml.bak", - "php artisan key:generate" + "php artisan optimize", + "php artisan config:cache" ], "setup": [ "composer install --ansi --no-dev", "php -r \"file_exists('.env') || copy('.env.example', '.env');\"", "php artisan key:generate" - ], - "upgrade": [ - "composer update --ansi --no-dev" ] }, "config": { diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..652012070 --- /dev/null +++ b/composer.lock @@ -0,0 +1,5129 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "fdb1b936e5e2eb93d6a0f11f8f7fd286", + "content-hash": "5c21ca5723b8bfc6134cc8c529257686", + "packages": [ + { + "name": "aws/aws-sdk-php", + "version": "3.19.20", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "36a05623d5f7f4a001cd3396ce0f000262c75062" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/36a05623d5f7f4a001cd3396ce0f000262c75062", + "reference": "36a05623d5f7f4a001cd3396ce0f000262c75062", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^5.3.1|^6.2.1", + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.3.1", + "mtdowling/jmespath.php": "~2.2", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-json": "*", + "ext-openssl": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "nette/neon": "^2.3", + "phpunit/phpunit": "~4.0|~5.0", + "psr/cache": "^1.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "time": "2016-10-25 19:23:39" + }, + { + "name": "barryvdh/laravel-debugbar", + "version": "V2.2.3", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd", + "reference": "ecd1ce5c4a827e2f6a8fb41bcf67713beb1c1cbd", + "shasum": "" + }, + "require": { + "illuminate/support": "5.1.*|5.2.*|5.3.*", + "maximebf/debugbar": "~1.11.0|~1.12.0", + "php": ">=5.5.9", + "symfony/finder": "~2.7|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "time": "2016-07-29 15:00:36" + }, + { + "name": "christian-riesen/base32", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/ChristianRiesen/base32.git", + "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "0.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Base32\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Riesen", + "email": "chris.riesen@gmail.com", + "homepage": "http://christianriesen.com", + "role": "Developer" + } + ], + "description": "Base32 encoder/decoder according to RFC 4648", + "homepage": "https://github.com/ChristianRiesen/base32", + "keywords": [ + "base32", + "decode", + "encode", + "rfc4648" + ], + "time": "2016-05-05 11:49:03" + }, + { + "name": "classpreloader/classpreloader", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/ClassPreloader/ClassPreloader.git", + "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", + "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.0|^2.0", + "php": ">=5.5.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "ClassPreloader\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", + "keywords": [ + "autoload", + "class", + "preload" + ], + "time": "2015-11-09 22:51:51" + }, + { + "name": "dingo/api", + "version": "v1.0.0-beta6", + "source": { + "type": "git", + "url": "https://github.com/dingo/api.git", + "reference": "cac67ab05da38c3de6d48c7146b700a13ed54cd0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dingo/api/zipball/cac67ab05da38c3de6d48c7146b700a13ed54cd0", + "reference": "cac67ab05da38c3de6d48c7146b700a13ed54cd0", + "shasum": "" + }, + "require": { + "dingo/blueprint": "0.2.*", + "doctrine/annotations": "1.2.*", + "illuminate/routing": "5.1.* || 5.2.* || 5.3.*", + "illuminate/support": "5.1.* || 5.2.* || 5.3.*", + "league/fractal": ">=0.12.0", + "php": "^5.5.9 || ^7.0" + }, + "require-dev": { + "illuminate/auth": "5.1.* || 5.2.* || 5.3.*", + "illuminate/cache": "5.1.* || 5.2.* || 5.3.*", + "illuminate/console": "5.1.* || 5.2.* || 5.3.*", + "illuminate/database": "5.1.* || 5.2.* || 5.3.*", + "illuminate/events": "5.1.* || 5.2.* || 5.3.*", + "illuminate/filesystem": "5.1.* || 5.2.* || 5.3.*", + "illuminate/log": "5.1.* || 5.2.* || 5.3.*", + "illuminate/pagination": "5.1.* || 5.2.* || 5.3.*", + "laravel/lumen-framework": "5.1.* || 5.2.*", + "lucadegasperi/oauth2-server-laravel": "5.0.*", + "mockery/mockery": "~0.9", + "phpunit/phpunit": "^4.8 || ^5.0", + "squizlabs/php_codesniffer": "~2.0", + "tymon/jwt-auth": "1.0.*" + }, + "suggest": { + "lucadegasperi/oauth2-server-laravel": "Protect your API with OAuth 2.0.", + "tymon/jwt-auth": "Protect your API with JSON Web Tokens." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Dingo\\Api\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jason Lewis", + "email": "jason.lewis1991@gmail.com" + } + ], + "description": "A RESTful API package for the Laravel and Lumen frameworks.", + "keywords": [ + "api", + "dingo", + "laravel", + "restful" + ], + "time": "2016-08-30 03:57:04" + }, + { + "name": "dingo/blueprint", + "version": "v0.2.0", + "source": { + "type": "git", + "url": "https://github.com/dingo/blueprint.git", + "reference": "d37fb7433aeadb3d40d5e790978c3c8d229d0e7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dingo/blueprint/zipball/d37fb7433aeadb3d40d5e790978c3c8d229d0e7d", + "reference": "d37fb7433aeadb3d40d5e790978c3c8d229d0e7d", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.2.*", + "illuminate/filesystem": "5.1.* || 5.2.* || 5.3.*", + "illuminate/support": "5.1.* || 5.2.* || 5.3.*", + "php": ">=5.5.9", + "phpdocumentor/reflection-docblock": "3.1.*" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2-dev" + } + }, + "autoload": { + "psr-4": { + "Dingo\\Blueprint\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jason Lewis", + "email": "jason.lewis1991@gmail.com" + } + ], + "description": "API Blueprint documentation generator.", + "keywords": [ + "api", + "blueprint", + "dingo", + "docs", + "laravel" + ], + "time": "2016-08-30 03:27:49" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24 07:27:01" + }, + { + "name": "doctrine/annotations", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2015-08-31 12:32:49" + }, + { + "name": "doctrine/cache", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3", + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3", + "shasum": "" + }, + "require": { + "php": "~5.5|~7.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2016-10-29 11:16:17" + }, + { + "name": "doctrine/collections", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2015-04-14 22:21:58" + }, + { + "name": "doctrine/common", + "version": "v2.6.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "a579557bc689580c19fee4e27487a67fe60defc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", + "reference": "a579557bc689580c19fee4e27487a67fe60defc0", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": "~5.5|~7.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2015-12-25 13:18:31" + }, + { + "name": "doctrine/dbal", + "version": "v2.5.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.4,<2.7-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "symfony/console": "2.*||^3.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2016-09-09 19:13:33" + }, + { + "name": "doctrine/inflector", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2015-11-06 14:35:42" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09 13:34:57" + }, + { + "name": "edvinaskrucas/settings", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/edvinaskrucas/settings.git", + "reference": "23f2a912ca8f5b6ba550721a6fc0e6d1acaa9022" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/edvinaskrucas/settings/zipball/23f2a912ca8f5b6ba550721a6fc0e6d1acaa9022", + "reference": "23f2a912ca8f5b6ba550721a6fc0e6d1acaa9022", + "shasum": "" + }, + "require": { + "illuminate/console": "^5.2", + "illuminate/database": "^5.2", + "illuminate/filesystem": "^5.2", + "illuminate/support": "^5.2", + "php": "^5.5|^7.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Krucas\\Settings\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Edvinas Kručas", + "email": "edv.krucas@gmail.com" + } + ], + "description": "Persistent settings package for Laravel framework.", + "keywords": [ + "Settings", + "laravel", + "persistent settings" + ], + "time": "2016-01-19 13:50:39" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.2.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.3.1", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2016-10-08 15:01:37" + }, + { + "name": "guzzlehttp/promises", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-05-18 16:56:05" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-06-24 23:00:38" + }, + { + "name": "igaster/laravel-theme", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/igaster/laravel-theme.git", + "reference": "d1b504b80e45a9fb40dffa1ae3d34ea364691da1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igaster/laravel-theme/zipball/d1b504b80e45a9fb40dffa1ae3d34ea364691da1", + "reference": "d1b504b80e45a9fb40dffa1ae3d34ea364691da1", + "shasum": "" + }, + "require": { + "illuminate/support": ">=5.2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "illuminate/database": "~5.2", + "orchestra/testbench": "~3.0", + "phpunit/phpunit": "~4.0", + "vlucas/phpdotenv": "~2.0" + }, + "suggest": { + "orchestra/asset": "Use '@css' and '@js' in Blade files" + }, + "type": "library", + "autoload": { + "psr-4": { + "igaster\\laravelTheme\\": "src/", + "igaster\\laravelTheme\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Giannis Gasteratos", + "email": "igasteratos@gmail.com" + } + ], + "description": "Laravel 5 Themes: Asset & Views folder per theme. Theme inheritance. Blade integration and more...", + "homepage": "https://github.com/igaster/laravel-theme", + "keywords": [ + "assets", + "blade", + "laravel-5", + "package", + "themes", + "views" + ], + "time": "2016-06-04 07:19:01" + }, + { + "name": "jakub-onderka/php-console-color", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleColor": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com", + "homepage": "http://www.acci.cz" + } + ], + "time": "2014-04-08 15:00:19" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.3.2", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", + "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", + "shasum": "" + }, + "require": { + "jakub-onderka/php-console-color": "~0.1", + "php": ">=5.3.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~0.5", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleHighlighter": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "time": "2015-04-20 18:58:01" + }, + { + "name": "jeremeamia/SuperClosure", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938", + "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.2|^2.0", + "php": ">=5.4", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", + "homepage": "https://github.com/jeremeamia/super_closure", + "keywords": [ + "closure", + "function", + "lambda", + "parser", + "serializable", + "serialize", + "tokenizer" + ], + "time": "2015-12-05 17:17:57" + }, + { + "name": "laracasts/utilities", + "version": "2.1", + "source": { + "type": "git", + "url": "https://github.com/laracasts/PHP-Vars-To-Js-Transformer.git", + "reference": "4402a0ed774f8eb36ea7ba169341d9d5b6049378" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laracasts/PHP-Vars-To-Js-Transformer/zipball/4402a0ed774f8eb36ea7ba169341d9d5b6049378", + "reference": "4402a0ed774f8eb36ea7ba169341d9d5b6049378", + "shasum": "" + }, + "require": { + "illuminate/support": "~5.0", + "php": ">=5.4.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laracasts\\Utilities\\JavaScript\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeffrey Way", + "email": "jeffrey@laracasts.com" + } + ], + "description": "Transform your PHP to JavaScript", + "keywords": [ + "javascript", + "laravel" + ], + "time": "2015-10-01 05:16:28" + }, + { + "name": "laravel/framework", + "version": "v5.3.21", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "140ad823863d5cc6f4580f1cdf9b18b9a6a457f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/140ad823863d5cc6f4580f1cdf9b18b9a6a457f4", + "reference": "140ad823863d5cc6f4580f1cdf9b18b9a6a457f4", + "shasum": "" + }, + "require": { + "classpreloader/classpreloader": "~3.0", + "doctrine/inflector": "~1.0", + "ext-mbstring": "*", + "ext-openssl": "*", + "jeremeamia/superclosure": "~2.2", + "league/flysystem": "~1.0", + "monolog/monolog": "~1.11", + "mtdowling/cron-expression": "~1.0", + "nesbot/carbon": "~1.20", + "paragonie/random_compat": "~1.4|~2.0", + "php": ">=5.6.4", + "psy/psysh": "0.7.*", + "ramsey/uuid": "~3.0", + "swiftmailer/swiftmailer": "~5.1", + "symfony/console": "3.1.*", + "symfony/debug": "3.1.*", + "symfony/finder": "3.1.*", + "symfony/http-foundation": "3.1.*", + "symfony/http-kernel": "3.1.*", + "symfony/process": "3.1.*", + "symfony/routing": "3.1.*", + "symfony/translation": "3.1.*", + "symfony/var-dumper": "3.1.*", + "vlucas/phpdotenv": "~2.2" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/exception": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "tightenco/collect": "self.version" + }, + "require-dev": { + "aws/aws-sdk-php": "~3.0", + "mockery/mockery": "~0.9.4", + "pda/pheanstalk": "~3.0", + "phpunit/phpunit": "~5.4", + "predis/predis": "~1.0", + "symfony/css-selector": "3.1.*", + "symfony/dom-crawler": "3.1.*" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", + "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", + "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (3.1.*).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (3.1.*).", + "symfony/psr-http-message-bridge": "Required to use psr7 bridging features (0.2.*)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.3-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "time": "2016-10-26 13:27:05" + }, + { + "name": "league/flysystem", + "version": "1.0.32", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b5c4a0031697f46e779a9d1b309c2e1b24daeab", + "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "ext-fileinfo": "*", + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^2.2", + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-copy": "Allows you to use Copy.com storage", + "league/flysystem-dropbox": "Allows you to use Dropbox storage", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2016-10-19 20:38:46" + }, + { + "name": "league/fractal", + "version": "0.14.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/fractal.git", + "reference": "56ad8933fbb40328ca3321c84143b2c16186eebf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/fractal/zipball/56ad8933fbb40328ca3321c84143b2c16186eebf", + "reference": "56ad8933fbb40328ca3321c84143b2c16186eebf", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "illuminate/contracts": "~5.0", + "mockery/mockery": "~0.9", + "pagerfanta/pagerfanta": "~1.0.0", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5", + "zendframework/zend-paginator": "~2.3" + }, + "suggest": { + "illuminate/pagination": "The Illuminate Pagination component.", + "pagerfanta/pagerfanta": "Pagerfanta Paginator", + "zendframework/zend-paginator": "Zend Framework Paginator" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.13-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Fractal\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Sturgeon", + "email": "me@philsturgeon.uk", + "homepage": "http://philsturgeon.uk/", + "role": "Developer" + } + ], + "description": "Handle the output of complex data structures ready for API output.", + "homepage": "http://fractal.thephpleague.com/", + "keywords": [ + "api", + "json", + "league", + "rest" + ], + "time": "2016-07-21 09:56:14" + }, + { + "name": "lord/laroute", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/aaronlord/laroute.git", + "reference": "97a3812af4bcc4cad87c52c142f407c270e20f09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aaronlord/laroute/zipball/97a3812af4bcc4cad87c52c142f407c270e20f09", + "reference": "97a3812af4bcc4cad87c52c142f407c270e20f09", + "shasum": "" + }, + "require": { + "illuminate/config": "5.0.*|5.1.*|5.2.*|5.3.*", + "illuminate/console": "5.0.*|5.1.*|5.2.*|5.3.*", + "illuminate/filesystem": "5.0.*|5.1.*|5.2.*|5.3.*", + "illuminate/routing": "5.0.*|5.1.*|5.2.*|5.3.*", + "illuminate/support": "5.0.*|5.1.*|5.2.*|5.3.*", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "dev-master", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lord\\Laroute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Lord", + "email": "hello@aaronlord.is" + } + ], + "description": "Access Laravels URL/Route helper functions, from JavaScript.", + "keywords": [ + "javascript", + "laravel", + "routes", + "routing" + ], + "time": "2016-08-12 13:38:39" + }, + { + "name": "maximebf/debugbar", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988", + "reference": "e634fbd32cd6bc3fa0e8c972b52d4bf49bab3988", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "time": "2016-05-15 13:11:34" + }, + { + "name": "monolog/monolog", + "version": "1.21.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952", + "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "~5.3" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2016-07-29 03:23:52" + }, + { + "name": "mtdowling/cron-expression", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/mtdowling/cron-expression.git", + "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", + "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Cron": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2016-01-26 21:23:30" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "192f93e43c2c97acde7694993ab171b3de284093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/192f93e43c2c97acde7694993ab171b3de284093", + "reference": "192f93e43c2c97acde7694993ab171b3de284093", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "time": "2016-01-05 18:25:05" + }, + { + "name": "nesbot/carbon", + "version": "1.21.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7", + "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "symfony/translation": "~2.6|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2015-11-04 20:07:17" + }, + { + "name": "nikic/php-parser", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0", + "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2016-09-16 12:04:44" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2016-11-07 23:38:38" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30 07:12:33" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-06-10 07:14:17" + }, + { + "name": "pragmarx/google2fa", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "b346dc138339b745c5831405d00cff7c1351aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/b346dc138339b745c5831405d00cff7c1351aa0d", + "reference": "b346dc138339b745c5831405d00cff7c1351aa0d", + "shasum": "" + }, + "require": { + "christian-riesen/base32": "~1.3", + "paragonie/random_compat": "~1.4|~2.0", + "php": ">=5.4", + "symfony/polyfill-php56": "~1.2" + }, + "require-dev": { + "phpspec/phpspec": "~2.1" + }, + "suggest": { + "bacon/bacon-qr-code": "Required to generate inline QR Codes." + }, + "type": "library", + "extra": { + "component": "package", + "frameworks": [ + "Laravel" + ], + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "Authentication", + "Two Factor Authentication", + "google2fa", + "laravel" + ], + "time": "2016-07-18 20:25:04" + }, + { + "name": "predis/predis", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/nrk/predis.git", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/nrk/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "time": "2016-06-16 16:22:20" + }, + { + "name": "prologue/alerts", + "version": "0.4.0", + "source": { + "type": "git", + "url": "git@github.com:driesvints/Alerts.git", + "reference": "f4ea1e784070f43ddd12dab732552809e54ff7d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/driesvints/Alerts/zipball/f4ea1e784070f43ddd12dab732552809e54ff7d5", + "reference": "f4ea1e784070f43ddd12dab732552809e54ff7d5", + "shasum": "" + }, + "require": { + "illuminate/config": "~5", + "illuminate/session": "~5", + "illuminate/support": "~5", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Prologue\\Alerts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dries Vints", + "email": "dries.vints@gmail.com", + "homepage": "http://driesvints.com", + "role": "Maintainer" + } + ], + "description": "Prologue Alerts is a package that handles global site messages.", + "keywords": [ + "alerts", + "laravel", + "messages" + ], + "time": "2015-04-13 17:27:18" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06 14:39:51" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10 12:19:37" + }, + { + "name": "psy/psysh", + "version": "v0.7.2", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280", + "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "jakub-onderka/php-console-highlighter": "0.3.*", + "nikic/php-parser": "^1.2.1|~2.0", + "php": ">=5.3.9", + "symfony/console": "~2.3.10|^2.4.2|~3.0", + "symfony/var-dumper": "~2.7|~3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "~1.5", + "phpunit/phpunit": "~3.7|~4.0|~5.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/finder": "~2.1|~3.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.8.x-dev" + } + }, + "autoload": { + "files": [ + "src/Psy/functions.php" + ], + "psr-4": { + "Psy\\": "src/Psy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2016-03-09 05:03:14" + }, + { + "name": "ramsey/uuid", + "version": "3.5.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "a07797b986671b0dc823885a81d5e3516b931599" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/a07797b986671b0dc823885a81d5e3516b931599", + "reference": "a07797b986671b0dc823885a81d5e3516b931599", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.0|^2.0", + "php": ">=5.4" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "apigen/apigen": "^4.1", + "codeception/aspect-mock": "1.0.0", + "goaop/framework": "1.0.0-alpha.2", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.4", + "moontoast/math": "^1.1", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "satooshi/php-coveralls": "^0.6.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2016-10-02 15:51:17" + }, + { + "name": "s1lentium/iptools", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/S1lentium/IPTools.git", + "reference": "cb4843d4077872643b5d38d18b8591b4aaf605ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/S1lentium/IPTools/zipball/cb4843d4077872643b5d38d18b8591b4aaf605ea", + "reference": "cb4843d4077872643b5d38d18b8591b4aaf605ea", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "satooshi/php-coveralls": "~1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "IPTools\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Safarov Alisher", + "email": "alisher.safarov@outlook.com", + "homepage": "https://github.com/S1lentium" + } + ], + "description": "PHP Library for manipulating network addresses (IPv4 and IPv6)", + "keywords": [ + "IP", + "IP-Tools", + "cidr", + "ipv4", + "ipv6", + "network", + "subnet" + ], + "time": "2016-08-21 15:57:09" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2016-07-08 11:51:25" + }, + { + "name": "symfony/console", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c99da1119ae61e15de0e4829196b9fba6f73d065", + "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2016-10-06 01:44:51" + }, + { + "name": "symfony/debug", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", + "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2016-09-06 11:02:40" + }, + { + "name": "symfony/event-dispatcher", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/28b0832b2553ffb80cabef6a7a812ff1e670c0bc", + "reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2016-10-13 06:28:43" + }, + { + "name": "symfony/finder", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", + "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2016-09-28 00:11:12" + }, + { + "name": "symfony/http-foundation", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "f21e5a8b88274b7720779aa88f9c02c6d6ec08d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f21e5a8b88274b7720779aa88f9c02c6d6ec08d7", + "reference": "f21e5a8b88274b7720779aa88f9c02c6d6ec08d7", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "symfony/expression-language": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2016-10-24 15:52:44" + }, + { + "name": "symfony/http-kernel", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "c235f1b13ba67012e283996a5427f22e2e04be14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c235f1b13ba67012e283996a5427f22e2e04be14", + "reference": "c235f1b13ba67012e283996a5427f22e2e04be14", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0", + "symfony/debug": "~2.8|~3.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/http-foundation": "~2.8.13|~3.1.6|~3.2" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "symfony/browser-kit": "~2.8|~3.0", + "symfony/class-loader": "~2.8|~3.0", + "symfony/config": "~2.8|~3.0", + "symfony/console": "~2.8|~3.0", + "symfony/css-selector": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/dom-crawler": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/finder": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0", + "symfony/routing": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0", + "symfony/templating": "~2.8|~3.0", + "symfony/translation": "~2.8|~3.0", + "symfony/var-dumper": "~2.8|~3.0" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2016-10-27 02:38:31" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-11-14 01:06:16" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c", + "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php56\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2016-11-14 01:06:16" + }, + { + "name": "symfony/polyfill-util", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-util.git", + "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb", + "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Util\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony utilities for portability of PHP codes", + "homepage": "https://symfony.com", + "keywords": [ + "compat", + "compatibility", + "polyfill", + "shim" + ], + "time": "2016-11-14 01:06:16" + }, + { + "name": "symfony/process", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "66de154ae86b1a07001da9fbffd620206e4faf94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/66de154ae86b1a07001da9fbffd620206e4faf94", + "reference": "66de154ae86b1a07001da9fbffd620206e4faf94", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2016-09-29 14:13:09" + }, + { + "name": "symfony/routing", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/8edf62498a1a4c57ba317664a4b698339c10cdf6", + "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/dependency-injection": "For loading routes from a service", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2016-08-16 14:58:24" + }, + { + "name": "symfony/translation", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "ff1285087397d2f64041b35e591f3025881c90cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/ff1285087397d2f64041b35e591f3025881c90cd", + "reference": "ff1285087397d2f64041b35e591f3025881c90cd", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2016-10-18 04:30:12" + }, + { + "name": "symfony/var-dumper", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "4dc2f03b480c43f1665d3317d827a04ed6ffd11e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4dc2f03b480c43f1665d3317d827a04ed6ffd11e", + "reference": "4dc2f03b480c43f1665d3317d827a04ed6ffd11e", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "twig/twig": "~1.20|~2.0" + }, + "suggest": { + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2016-10-18 15:46:07" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause-Attribution" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2016-09-01 10:05:43" + }, + { + "name": "webmozart/assert", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-08-09 15:02:57" + }, + { + "name": "webpatser/laravel-uuid", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/webpatser/laravel-uuid.git", + "reference": "6ed2705775e3edf066b90e1292f76f157ec00507" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webpatser/laravel-uuid/zipball/6ed2705775e3edf066b90e1292f76f157ec00507", + "reference": "6ed2705775e3edf066b90e1292f76f157ec00507", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "fzaninotto/faker": "1.5.*", + "phpunit/phpunit": "4.7.*" + }, + "suggest": { + "paragonie/random_compat": "A random_bytes Php 5.x polyfill." + }, + "type": "library", + "autoload": { + "psr-0": { + "Webpatser\\Uuid": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christoph Kempen", + "email": "christoph@downsized.nl" + } + ], + "description": "Class to generate a UUID according to the RFC 4122 standard. Support for version 1, 3, 4 and 5 UUID are built-in.", + "homepage": "https://github.com/webpatser/uuid", + "keywords": [ + "UUID RFC4122" + ], + "time": "2016-05-09 09:22:18" + } + ], + "packages-dev": [ + { + "name": "chumper/zipper", + "version": "0.6.1", + "source": { + "type": "git", + "url": "https://github.com/Chumper/Zipper.git", + "reference": "313e364259398557bdcc2f68e6ff20d71aaea811" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Chumper/Zipper/zipball/313e364259398557bdcc2f68e6ff20d71aaea811", + "reference": "313e364259398557bdcc2f68e6ff20d71aaea811", + "shasum": "" + }, + "require": { + "illuminate/filesystem": "5.x", + "illuminate/support": "5.x", + "php": ">=5.3.0" + }, + "require-dev": { + "mockery/mockery": "dev-master", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Chumper\\Zipper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Nils Plaschke", + "email": "github@nilsplaschke.de", + "homepage": "http://nilsplaschke.de", + "role": "Developer" + } + ], + "description": "This is a little neat helper for the ZipArchive methods with handy functions", + "homepage": "http://github.com/Chumper/zipper", + "keywords": [ + "archive", + "laravel", + "zip" + ], + "time": "2015-02-16 11:38:11" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "fzaninotto/faker", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2016-04-29 12:21:54" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "hamcrest" + ], + "files": [ + "hamcrest/Hamcrest.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2015-05-11 14:41:42" + }, + { + "name": "laravel/homestead", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/homestead.git", + "reference": "705449c3dbedbded4bd4f3ed725303c69253cad4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/homestead/zipball/705449c3dbedbded4bd4f3ed725303c69253cad4", + "reference": "705449c3dbedbded4bd4f3ed725303c69253cad4", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/console": "~2.3|~3.0", + "symfony/process": "~2.3|~3.0" + }, + "bin": [ + "homestead" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Homestead\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "A virtual machine for web artisans.", + "time": "2016-02-16 22:31:00" + }, + { + "name": "mockery/mockery", + "version": "0.9.5", + "source": { + "type": "git", + "url": "https://github.com/padraic/mockery.git", + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2", + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~1.1", + "lib-pcre": ">=7.0", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.9.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/padraic/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2016-05-22 21:52:33" + }, + { + "name": "myclabs/deep-copy", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2016-10-31 17:19:45" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-06-07 08:13:47" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6cba06ff75a1a63a71033e1a01b89056f3af1e8d", + "reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "~1.0|~2.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.4.0", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2016-11-01 05:06:24" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "5.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9de0dbafeb6b1391b391fbb034734cb0af9f67c", + "reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "^4.0.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3 || ^2.0", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/object-enumerator": "~1.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.6.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-11-14 06:39:40" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", + "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2016-10-09 07:01:45" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2016-02-13 06:45:14" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18 05:49:44" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17 09:04:28" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/object-enumerator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-01-28 13:25:10" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "938df7a6478e72795e5f8266cff24d06e3136f2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/938df7a6478e72795e5f8266cff24d06e3136f2e", + "reference": "938df7a6478e72795e5f8266cff24d06e3136f2e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-15 06:55:36" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" + }, + { + "name": "sebastian/version", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-02-04 12:56:52" + }, + { + "name": "symfony/css-selector", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "ca809c64072e0fe61c1c7fb3c76cdc32265042ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ca809c64072e0fe61c1c7fb3c76cdc32265042ac", + "reference": "ca809c64072e0fe61c1c7fb3c76cdc32265042ac", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2016-09-06 11:02:40" + }, + { + "name": "symfony/dom-crawler", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "59eee3c76eb89f21857798620ebdad7a05ad14f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/59eee3c76eb89f21857798620ebdad7a05ad14f4", + "reference": "59eee3c76eb89f21857798620ebdad7a05ad14f4", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2016-10-18 15:46:07" + }, + { + "name": "symfony/yaml", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27", + "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2016-10-24 18:41:13" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "dingo/api": 10 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.6.4" + }, + "platform-dev": [] +} From 6220f710df4f5410a2c07e349d971663381a4572 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 15:06:35 -0500 Subject: [PATCH 021/112] Cache configuration file when editing environment or mail settings. --- app/Console/Commands/UpdateEmailSettings.php | 3 +++ app/Console/Commands/UpdateEnvironment.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/app/Console/Commands/UpdateEmailSettings.php b/app/Console/Commands/UpdateEmailSettings.php index 620982b98..edffd9fa6 100644 --- a/app/Console/Commands/UpdateEmailSettings.php +++ b/app/Console/Commands/UpdateEmailSettings.php @@ -155,6 +155,9 @@ class UpdateEmailSettings extends Command file_put_contents($file, $envContents); $bar->finish(); + + $this->line('Updating evironment configuration cache file.'); + $this->call('config:cache'); echo "\n"; } } diff --git a/app/Console/Commands/UpdateEnvironment.php b/app/Console/Commands/UpdateEnvironment.php index 085b081df..3805ffd51 100644 --- a/app/Console/Commands/UpdateEnvironment.php +++ b/app/Console/Commands/UpdateEnvironment.php @@ -150,6 +150,9 @@ class UpdateEnvironment extends Command file_put_contents($file, $envContents); $bar->finish(); + + $this->line('Updating evironment configuration cache file.'); + $this->call('config:cache'); echo "\n"; } } From 32c21baab0964f2c9dd8a93b7c32ad2c8dbc4f88 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 16:01:18 -0500 Subject: [PATCH 022/112] Return packs associated with a service when viewing it on the API. --- app/Http/Controllers/API/ServiceController.php | 1 + app/Models/ServiceOptions.php | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index aa8b4ac29..257ace766 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -55,6 +55,7 @@ class ServiceController extends BaseController 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') ->where('parent_service', $service->id) ->with('variables') + ->with('packs') ->get(), ]; } diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index fe7e23f10..9b4a3a7ae 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -60,4 +60,14 @@ class ServiceOptions extends Model { return $this->hasMany(ServiceVariables::class, 'option_id'); } + + /** + * Gets all packs associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function packs() + { + return $this->hasMany(ServicePack::class, 'option'); + } } From 7f51e5df620d0bfecad1a116ee613e74ef9006ae Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 16:24:08 -0500 Subject: [PATCH 023/112] API tweaks to return more relevant information on server listing --- app/Http/Controllers/API/ServerController.php | 5 +- app/Models/Server.php | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index b24cdac62..bc0d04a40 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -117,7 +117,10 @@ class ServerController extends BaseController } // Requested Daemon Stats - $server = $query->first(); + $server = $query->with( + 'allocations', + 'pack' + )->first(); if ($request->input('daemon') === 'true') { $node = Models\Node::findOrFail($server->node); $client = Models\Node::guzzleRequest($node->id); diff --git a/app/Models/Server.php b/app/Models/Server.php index 3a11603c2..a9f9bd087 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -208,4 +208,54 @@ class Server extends Model return []; } + + /** + * Gets all allocations associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function allocations() + { + return $this->hasMany(Allocation::class, 'assigned_to'); + } + + /** + * Gets information for the pack associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function pack() + { + return $this->hasOne(ServicePack::class, 'id', 'pack'); + } + + /** + * Gets information for the service associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function service() + { + return $this->hasOne(Service::class, 'id', 'service'); + } + + /** + * Gets information for the service option associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function option() + { + return $this->hasOne(ServiceOptions::class, 'id', 'option'); + } + + /** + * Gets information for the service variables associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function variables() + { + return $this->hasMany(ServerVariables::class); + } } From fb589a7f4e151fe537c53beb2a5c0cea0da5cf6f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 16:29:37 -0500 Subject: [PATCH 024/112] Fix session timeout issues on browser close. --- CHANGELOG.md | 1 + config/session.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c582aa84..8922f5620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Bug causing error logs to be spammed if someone timed out on an ajax based page. * Fixes edge case where specific server names could cause daemon errors due to an invalid SFTP username being created by the panel. +* Fixes sessions being removed on browser close, and set sessions to idle for up to 3 hours before being marked as expired. ### Changed * Admin API and base routes for user management now define the fields that should be passed to repositories rather than passing all fields. diff --git a/config/session.php b/config/session.php index 59ad9182f..f1b004214 100644 --- a/config/session.php +++ b/config/session.php @@ -29,9 +29,9 @@ return [ | */ - 'lifetime' => 30, + 'lifetime' => 120, - 'expire_on_close' => true, + 'expire_on_close' => false, /* |-------------------------------------------------------------------------- From 7f0608d412ae6e601154f5e7bbba62a062bfd393 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 2 Feb 2017 23:14:53 +0100 Subject: [PATCH 025/112] better naming of PhraseApp related stuff --- .../{Translator.php => PhraseAppTranslator.php} | 2 +- ...onProvider.php => PhraseAppTranslationProvider.php} | 10 +++++----- config/app.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename app/Extensions/{Translator.php => PhraseAppTranslator.php} (97%) rename app/Providers/{TranslationProvider.php => PhraseAppTranslationProvider.php} (86%) diff --git a/app/Extensions/Translator.php b/app/Extensions/PhraseAppTranslator.php similarity index 97% rename from app/Extensions/Translator.php rename to app/Extensions/PhraseAppTranslator.php index 5a3edcf4f..0d755664d 100644 --- a/app/Extensions/Translator.php +++ b/app/Extensions/PhraseAppTranslator.php @@ -26,7 +26,7 @@ namespace Pterodactyl\Extensions; use Illuminate\Translation\Translator as LaravelTranslator; -class Translator extends LaravelTranslator +class PhraseAppTranslator extends LaravelTranslator { /** * Get the translation for the given key. diff --git a/app/Providers/TranslationProvider.php b/app/Providers/PhraseAppTranslationProvider.php similarity index 86% rename from app/Providers/TranslationProvider.php rename to app/Providers/PhraseAppTranslationProvider.php index 474737b50..76de046ec 100644 --- a/app/Providers/TranslationProvider.php +++ b/app/Providers/PhraseAppTranslationProvider.php @@ -24,11 +24,11 @@ namespace Pterodactyl\Providers; -use Pterodactyl\Extensions\Translator as PterodactylTranslator; -use Illuminate\Translation\Translator; +use Pterodactyl\Extensions\PhraseAppTranslator; use Illuminate\Translation\TranslationServiceProvider; +use Illuminate\Translation\Translator as IlluminateTranslator; -class TranslationProvider extends TranslationServiceProvider { +class PhraseAppTranslationProvider extends TranslationServiceProvider { /** * Register the service provider. @@ -48,9 +48,9 @@ class TranslationProvider extends TranslationServiceProvider { $locale = $app['config']['app.locale']; if ($app['config']['app.phrase_in_context']) { - $trans = new PterodactylTranslator($loader, $locale); + $trans = new PhraseAppTranslator($loader, $locale); } else { - $trans = new Translator($loader, $locale); + $trans = new IlluminateTranslator($loader, $locale); } $trans->setFallback($app['config']['app.fallback_locale']); diff --git a/config/app.php b/config/app.php index abaabe25b..79bd1c07b 100644 --- a/config/app.php +++ b/config/app.php @@ -151,7 +151,7 @@ return [ Pterodactyl\Providers\AuthServiceProvider::class, Pterodactyl\Providers\EventServiceProvider::class, Pterodactyl\Providers\RouteServiceProvider::class, - Pterodactyl\Providers\TranslationProvider::class, + Pterodactyl\Providers\PhraseAppTranslationProvider::class, /* * Additional Dependencies From 7b659a773ee2cff875d5d992e13d6c7ac38a10ae Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Thu, 2 Feb 2017 23:31:42 +0100 Subject: [PATCH 026/112] handle * and ** for TRUSTED_PROXIES --- config/trustedproxy.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/trustedproxy.php b/config/trustedproxy.php index 2bf4cd02f..a1fac334a 100644 --- a/config/trustedproxy.php +++ b/config/trustedproxy.php @@ -24,7 +24,8 @@ return [ * how many proxies that client's request has * subsequently passed through. */ - 'proxies' => explode(',', env('TRUSTED_PROXIES', null)), + 'proxies' => in_array(env('TRUSTED_PROXIES', ['*', '**'])) ? + env('TRUSTED_PROXIES') : explode(',', env('TRUSTED_PROXIES', null)), /* * Or, to trust all proxies that connect From 7f1000dd8ac80e04ae221de3fdff52ed12a31cfd Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Fri, 3 Feb 2017 00:08:10 +0100 Subject: [PATCH 027/112] make dane and styleci happy --- app/Extensions/PhraseAppTranslator.php | 1 + app/Providers/PhraseAppTranslationProvider.php | 6 ++---- config/app.php | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/Extensions/PhraseAppTranslator.php b/app/Extensions/PhraseAppTranslator.php index 0d755664d..5a8d4a84e 100644 --- a/app/Extensions/PhraseAppTranslator.php +++ b/app/Extensions/PhraseAppTranslator.php @@ -40,6 +40,7 @@ class PhraseAppTranslator extends LaravelTranslator public function get($key, array $replace = [], $locale = null, $fallback = true) { $key = substr($key, strpos($key, '.') + 1); + return "{{__phrase_${key}__}}"; } } diff --git a/app/Providers/PhraseAppTranslationProvider.php b/app/Providers/PhraseAppTranslationProvider.php index 76de046ec..e6ba42116 100644 --- a/app/Providers/PhraseAppTranslationProvider.php +++ b/app/Providers/PhraseAppTranslationProvider.php @@ -28,8 +28,8 @@ use Pterodactyl\Extensions\PhraseAppTranslator; use Illuminate\Translation\TranslationServiceProvider; use Illuminate\Translation\Translator as IlluminateTranslator; -class PhraseAppTranslationProvider extends TranslationServiceProvider { - +class PhraseAppTranslationProvider extends TranslationServiceProvider +{ /** * Register the service provider. * @@ -58,6 +58,4 @@ class PhraseAppTranslationProvider extends TranslationServiceProvider { return $trans; }); } - - } diff --git a/config/app.php b/config/app.php index 79bd1c07b..58a095c40 100644 --- a/config/app.php +++ b/config/app.php @@ -139,7 +139,6 @@ return [ Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, - //Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, From d4bcf0be594e09c187763e9ca56463d7f287037a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 18:21:36 -0500 Subject: [PATCH 028/112] Initial implementation of improved sever model and logic --- CHANGELOG.md | 3 + app/Http/Controllers/API/ServerController.php | 2 +- .../Controllers/API/User/InfoController.php | 2 +- .../Controllers/API/User/ServerController.php | 6 +- .../Controllers/Admin/NodesController.php | 4 +- .../Controllers/Admin/ServersController.php | 32 ++++---- .../Controllers/Admin/ServiceController.php | 2 +- app/Http/Controllers/Admin/UserController.php | 2 +- .../Controllers/Remote/RemoteController.php | 4 +- .../Controllers/Server/AjaxController.php | 4 +- .../Controllers/Server/ServerController.php | 35 ++++---- .../Controllers/Server/SubuserController.php | 6 +- .../Controllers/Server/TaskController.php | 4 +- app/Http/Middleware/CheckServer.php | 9 ++- app/Models/Server.php | 81 +++++++------------ app/Models/User.php | 21 +++++ app/Observers/ServerObserver.php | 8 +- app/Policies/ServerPolicy.php | 2 +- app/Repositories/ServerRepository.php | 44 +++++----- app/Repositories/SubuserRepository.php | 14 ++-- app/Services/NotificationService.php | 2 +- ..._08_30_213301_modify_ip_storage_method.php | 4 +- ...6_09_17_194246_add_docker_image_column.php | 2 +- .../2017_02_02_175548_UpdateColumnNames.php | 66 +++++++++++++++ .../themes/pterodactyl/base/index.blade.php | 2 +- .../server/settings/allocation.blade.php | 2 +- resources/views/admin/nodes/view.blade.php | 2 +- resources/views/admin/servers/index.blade.php | 4 +- resources/views/admin/servers/view.blade.php | 8 +- .../admin/services/options/view.blade.php | 2 +- resources/views/admin/users/view.blade.php | 2 +- 31 files changed, 223 insertions(+), 158 deletions(-) create mode 100644 database/migrations/2017_02_02_175548_UpdateColumnNames.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8922f5620..80b459be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * User model now defines mass assignment fields using `$fillable` rather than `$guarded`. * 2FA checkpoint on login is now its own page, and not an AJAX based call. Improves security on that front. +### Removed +* `Server::getUserDaemonSecret(Server $server)` was removed and replaced with `User::daemonSecret(Server $server)` in order to clean up models. + ## v0.5.6 (Bodacious Boreopterus) ### Added * Added the following languages: Estonian `et`, Dutch `nl`, Norwegian `nb` (partial), Romanian `ro`, and Russian `ru`. Interested in helping us translate the panel into more languages, or improving existing translations? Contact us on Discord and let us know. diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index bc0d04a40..24a2bc00e 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -122,7 +122,7 @@ class ServerController extends BaseController 'pack' )->first(); if ($request->input('daemon') === 'true') { - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); $client = Models\Node::guzzleRequest($node->id); $response = $client->request('GET', '/servers', [ diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 00923b866..228a66819 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -37,7 +37,7 @@ class InfoController extends BaseController 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, - 'node' => $server->nodeName, + 'node' => $server->node_idName, 'ip' => [ 'set' => $server->ip, 'alias' => $server->ip_alias, diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index c63a482fa..128c5cf68 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -35,7 +35,7 @@ class ServerController extends BaseController public function info(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); $client = Models\Node::guzzleRequest($node->id); try { @@ -61,7 +61,7 @@ class ServerController extends BaseController $allocations = Models\Allocation::select('id', 'ip', 'port', 'ip_alias as alias')->where('assigned_to', $server->id)->get(); foreach ($allocations as &$allocation) { - $allocation->default = ($allocation->id === $server->allocation); + $allocation->default = ($allocation->id === $server->allocation_id); unset($allocation->id); } @@ -92,7 +92,7 @@ class ServerController extends BaseController public function power(Request $request, $uuid) { $server = Models\Server::getByUUID($uuid); - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); Auth::user()->can('power-' . $request->input('action'), $server); diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 594365f73..506d8434e 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -108,8 +108,8 @@ class NodesController extends Controller return view('admin.nodes.view', [ 'node' => $node, 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName') - ->join('users', 'users.id', '=', 'servers.owner') - ->join('services', 'services.id', '=', 'servers.service') + ->join('users', 'users.id', '=', 'servers.owner_id') + ->join('services', 'services.id', '=', 'servers.service_id') ->where('node', $id)->paginate(10, ['*'], 'servers'), 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(), 'locations' => Models\Location::all(), diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 9aece9c4e..f75508139 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -54,9 +54,9 @@ class ServersController extends Controller 'allocations.ip', 'allocations.port', 'allocations.ip_alias' - )->join('nodes', 'servers.node', '=', 'nodes.id') - ->join('users', 'servers.owner', '=', 'users.id') - ->join('allocations', 'servers.allocation', '=', 'allocations.id'); + )->join('nodes', 'servers.node_id', '=', 'nodes.id') + ->join('users', 'servers.owner_id', '=', 'users.id') + ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); if ($request->input('filter') && ! is_null($request->input('filter'))) { preg_match_all('/[^\s"\']+|"([^"]*)"|\'([^\']*)\'/', urldecode($request->input('filter')), $matches); @@ -96,9 +96,9 @@ class ServersController extends Controller 'allocations.ip', 'allocations.port', 'allocations.ip_alias' - )->join('nodes', 'servers.node', '=', 'nodes.id') - ->join('users', 'servers.owner', '=', 'users.id') - ->join('allocations', 'servers.allocation', '=', 'allocations.id') + )->join('nodes', 'servers.node_id', '=', 'nodes.id') + ->join('users', 'servers.owner_id', '=', 'users.id') + ->join('allocations', 'servers.allocation_id', '=', 'allocations.id') ->paginate(20); } @@ -127,11 +127,11 @@ class ServersController extends Controller 'allocations.ip', 'allocations.port', 'allocations.ip_alias' - )->join('nodes', 'servers.node', '=', 'nodes.id') - ->join('users', 'servers.owner', '=', 'users.id') - ->join('services', 'servers.service', '=', 'services.id') - ->join('service_options', 'servers.option', '=', 'service_options.id') - ->join('allocations', 'servers.allocation', '=', 'allocations.id') + )->join('nodes', 'servers.node_id', '=', 'nodes.id') + ->join('users', 'servers.owner_id', '=', 'users.id') + ->join('services', 'servers.service_id', '=', 'services.id') + ->join('service_options', 'servers.option_id', '=', 'service_options.id') + ->join('allocations', 'servers.allocation_id', '=', 'allocations.id') ->where('servers.id', $id) ->first(); @@ -145,13 +145,13 @@ class ServersController extends Controller 'nodes.*', 'locations.long as a_locationName' )->join('locations', 'nodes.location', '=', 'locations.id') - ->where('nodes.id', $server->node) + ->where('nodes.id', $server->node_id) ->first(), 'assigned' => Models\Allocation::where('assigned_to', $id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), - 'unassigned' => Models\Allocation::where('node', $server->node)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), + 'unassigned' => Models\Allocation::where('node', $server->node_id)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), 'startup' => Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue') ->join('server_variables', 'server_variables.variable_id', '=', 'service_variables.id') - ->where('service_variables.option_id', $server->option) + ->where('service_variables.option_id', $server->option_id) ->where('server_variables.server_id', $server->id) ->get(), 'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port') @@ -334,8 +334,8 @@ class ServersController extends Controller public function postUpdateServerToggleBuild(Request $request, $id) { $server = Models\Server::findOrFail($id); - $node = Models\Node::findOrFail($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::findOrFail($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); try { $res = $client->request('POST', '/server/rebuild', [ diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 7a70c58da..70de4f88e 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -137,7 +137,7 @@ class ServiceController extends Controller 'option' => $opt, 'variables' => Models\ServiceVariables::where('option_id', $option)->get(), 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail') - ->join('users', 'users.id', '=', 'servers.owner') + ->join('users', 'users.id', '=', 'servers.owner_id') ->where('option', $option) ->paginate(10), ]); diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 9a2c6fd04..c2dea5f54 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -87,7 +87,7 @@ class UserController extends Controller return view('admin.users.view', [ 'user' => User::findOrFail($id), 'servers' => Server::select('servers.*', 'nodes.name as nodeName', 'locations.long as location') - ->join('nodes', 'servers.node', '=', 'nodes.id') + ->join('nodes', 'servers.node_id', '=', 'nodes.id') ->join('locations', 'nodes.location', '=', 'locations.id') ->where('owner', $id) ->get(), diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index b0aa0983e..0f168c04b 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -66,7 +66,7 @@ class RemoteController extends Controller ], 422); } - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); $hmac = $request->input('signed'); $status = $request->input('installed'); @@ -93,7 +93,7 @@ class RemoteController extends Controller ], 422); } - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); $hmac = $request->input('signed'); if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index da4d058ac..9ee9f4284 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -73,7 +73,7 @@ class AjaxController extends Controller return response()->json([], 404); } - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); try { $res = $client->request('GET', '/server', [ @@ -178,7 +178,7 @@ class AjaxController extends Controller $server = Models\Server::getByUUID($uuid); $this->authorize('set-connection', $server); - if ((int) $request->input('allocation') === $server->allocation) { + if ((int) $request->input('allocation') === $server->allocation_id) { return response()->json([ 'error' => 'You are already using this as your default connection.', ], 409); diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 593049ca1..7f07f977c 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -55,14 +55,13 @@ class ServerController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Contracts\View\View */ - public function getIndex(Request $request) + public function getIndex(Request $request, $uuid) { - $server = Models\Server::getByUUID($request->route()->server); - $node = Models\Node::find($server->node); + $server = Models\Server::byUuid($uuid); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + 'node' => collect($server->node_id)->only('fqdn', 'scheme', 'daemonListen'), 'meta' => [ 'saveFile' => route('server.files.save', $server->uuidShort), 'csrfToken' => csrf_token(), @@ -71,7 +70,7 @@ class ServerController extends Controller return view('server.index', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node_id, ]); } @@ -86,7 +85,7 @@ class ServerController extends Controller $server = Models\Server::getByUUID($uuid); $this->authorize('list-files', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only('uuid', 'uuidShort', 'daemonSecret'), @@ -122,7 +121,7 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('add-files', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -148,7 +147,7 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('edit-files', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); $fileInfo = (object) pathinfo($file); $controller = new FileRepository($uuid); @@ -193,7 +192,7 @@ class ServerController extends Controller public function getDownloadFile(Request $request, $uuid, $file) { $server = Models\Server::getByUUID($uuid); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); $this->authorize('download-files', $server); @@ -212,7 +211,7 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-allocation', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -230,8 +229,8 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-startup', $server); - $node = Models\Node::find($server->node); - $allocation = Models\Allocation::findOrFail($server->allocation); + $node = Models\Node::find($server->node_id); + $allocation = Models\Allocation::findOrFail($server->allocation_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -242,15 +241,15 @@ class ServerController extends Controller 'service_variables.*', DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_serverValue') )->leftJoin('server_variables', 'server_variables.variable_id', '=', 'service_variables.id') - ->where('service_variables.option_id', $server->option) + ->where('service_variables.option_id', $server->option_id) ->where('server_variables.server_id', $server->id) ->get(); $service = Models\Service::select( DB::raw('IFNULL(service_options.executable, services.executable) as executable') )->leftJoin('service_options', 'service_options.parent_service', '=', 'services.id') - ->where('service_options.id', $server->option) - ->where('services.id', $server->service) + ->where('service_options.id', $server->option_id) + ->where('services.id', $server->service_id) ->first(); $serverVariables = [ @@ -267,7 +266,7 @@ class ServerController extends Controller return view('server.settings.startup', [ 'server' => $server, - 'node' => Models\Node::find($server->node), + 'node' => Models\Node::find($server->node_id), 'variables' => $variables->where('user_viewable', 1), 'service' => $service, 'processedStartup' => $processed, @@ -278,7 +277,7 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-databases', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -299,7 +298,7 @@ class ServerController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-sftp', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index a8761c717..1d07b47f7 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -52,7 +52,7 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-subusers', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -73,7 +73,7 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('view-subuser', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -150,7 +150,7 @@ class SubuserController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-subuser', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 8c49ad6bc..51243cc8f 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -45,7 +45,7 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-tasks', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), @@ -67,7 +67,7 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-task', $server); - $node = Models\Node::find($server->node); + $node = Models\Node::find($server->node_id); Javascript::put([ 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/CheckServer.php index cd83bd9d1..dba9395ac 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/CheckServer.php @@ -26,6 +26,7 @@ namespace Pterodactyl\Http\Middleware; use Auth; use Closure; +use Illuminate\Http\Request; use Pterodactyl\Models\Server; class CheckServer @@ -37,22 +38,22 @@ class CheckServer * @param \Closure $next * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { if (! Auth::user()) { return redirect()->guest('auth/login'); } - $server = Server::getByUUID($request->route()->server); + $server = Server::byUuid($request->route()->server); if (! $server) { return response()->view('errors.404', [], 404); } - if ($server->suspended === 1) { + if ($server->suspended) { return response()->view('errors.suspended', [], 403); } - if ($server->installed !== 1) { + if (! $server->installed) { return response()->view('errors.installing', [], 403); } diff --git a/app/Models/Server.php b/app/Models/Server.php index a9f9bd087..32240da44 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -101,28 +101,6 @@ class Server extends Model self::$user = Auth::user(); } - /** - * Determine if we need to change the server's daemonSecret value to - * match that of the user if they are a subuser. - * - * @param Illuminate\Database\Eloquent\Model\Server $server - * @return string - */ - public static function getUserDaemonSecret(Server $server) - { - if (self::$user->id === $server->owner || self::$user->root_admin === 1) { - return $server->daemonSecret; - } - - $subuser = Subuser::where('server_id', $server->id)->where('user_id', self::$user->id)->first(); - - if (is_null($subuser)) { - return null; - } - - return $subuser->daemonSecret; - } - /** * Returns array of all servers owned by the logged in user. * Returns all users servers if user is a root admin. @@ -140,11 +118,11 @@ class Server extends Model 'allocations.port', 'services.name as a_serviceName', 'service_options.name as a_serviceOptionName' - )->join('nodes', 'servers.node', '=', 'nodes.id') + )->join('nodes', 'servers.node_id', '=', 'nodes.id') ->join('locations', 'nodes.location', '=', 'locations.id') - ->join('services', 'servers.service', '=', 'services.id') - ->join('service_options', 'servers.option', '=', 'service_options.id') - ->join('allocations', 'servers.allocation', '=', 'allocations.id'); + ->join('services', 'servers.service_id', '=', 'services.id') + ->join('service_options', 'servers.option_id', '=', 'service_options.id') + ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); if (self::$user->root_admin !== 1) { $query->whereIn('servers.id', Subuser::accessServers()); @@ -165,30 +143,21 @@ class Server extends Model * @param string $uuid The Short-UUID of the server to return an object about. * @return \Illuminate\Database\Eloquent\Collection */ - public static function getByUUID($uuid) + public static function byUuid($uuid) { - if (array_key_exists($uuid, self::$serverUUIDInstance)) { - return self::$serverUUIDInstance[$uuid]; - } + $query = self::with('service', 'node')->where('uuidShort', $uuid)->orWhere('uuid', $uuid); - $query = self::select('servers.*', 'services.file as a_serviceFile') - ->join('services', 'services.id', '=', 'servers.service') - ->where('uuidShort', $uuid) - ->orWhere('uuid', $uuid); - - if (self::$user->root_admin !== 1) { - $query->whereIn('servers.id', Subuser::accessServers()); + if (! Auth::user()->isRootAdmin()) { + $query->whereIn('id', Subuser::accessServers()); } $result = $query->first(); if (! is_null($result)) { - $result->daemonSecret = self::getUserDaemonSecret($result); + $result->daemonSecret = Auth::user()->daemonToken($result); } - self::$serverUUIDInstance[$uuid] = $result; - - return self::$serverUUIDInstance[$uuid]; + return $result; } /** @@ -197,16 +166,12 @@ class Server extends Model * @param string $uuid * @return array */ - public static function getGuzzleHeaders($uuid) + public function getHeaders() { - if (array_key_exists($uuid, self::$serverUUIDInstance)) { - return [ - 'X-Access-Server' => self::$serverUUIDInstance[$uuid]->uuid, - 'X-Access-Token' => self::$serverUUIDInstance[$uuid]->daemonSecret, - ]; - } - - return []; + return [ + 'X-Access-Server' => $this->uuid, + 'X-Access-Token' => Auth::user()->daemonToken($this), + ]; } /** @@ -226,7 +191,7 @@ class Server extends Model */ public function pack() { - return $this->hasOne(ServicePack::class, 'id', 'pack'); + return $this->hasOne(ServicePack::class, 'id', 'pack_id'); } /** @@ -236,7 +201,7 @@ class Server extends Model */ public function service() { - return $this->hasOne(Service::class, 'id', 'service'); + return $this->hasOne(Service::class, 'id', 'service_id'); } /** @@ -246,7 +211,7 @@ class Server extends Model */ public function option() { - return $this->hasOne(ServiceOptions::class, 'id', 'option'); + return $this->hasOne(ServiceOptions::class, 'id', 'option_id'); } /** @@ -258,4 +223,14 @@ class Server extends Model { return $this->hasMany(ServerVariables::class); } + + /** + * Gets information for the node associated with this server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function node() + { + return $this->hasOne(Node::class, 'id', 'node_id'); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 80d9192fa..0de3eb5ae 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Models; +use Auth; use Hash; use Google2FA; use Illuminate\Auth\Authenticatable; @@ -156,4 +157,24 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac { return $this->root_admin === 1; } + + /** + * Returns the user's daemon secret for a given server. + * @param Server $server \Pterodactyl\Models\Server + * @return null|string + */ + public function daemonToken(Server $server) + { + if ($this->id === $server->owner_id || $this->isRootAdmin()) { + return $server->daemonSecret; + } + + $subuser = Subuser::where('server_id', $server->id)->where('user_id', $this->id)->first(); + + if (is_null($subuser)) { + return null; + } + + return $subuser->daemonSecret; + } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 6506f03f2..cacb9c82f 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -59,12 +59,12 @@ class ServerObserver event(new Events\Server\Created($server)); // Queue Notification Email - $user = Models\User::findOrFail($server->owner); - $node = Models\Node::select('name')->where('id', $server->node)->first(); + $user = Models\User::findOrFail($server->owner_id); + $node = Models\Node::select('name')->where('id', $server->node_id)->first(); $service = Models\Service::select('services.name', 'service_options.name as optionName') ->join('service_options', 'service_options.parent_service', '=', 'services.id') - ->where('services.id', $server->service) - ->where('service_options.id', $server->option) + ->where('services.id', $server->service_id) + ->where('service_options.id', $server->option_id) ->first(); $user->notify((new ServerCreated([ diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index f297fe829..3ef54f436 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -48,7 +48,7 @@ class ServerPolicy */ protected function isOwner(User $user, Server $server) { - return $server->owner === $user->id; + return $server->owner_id === $user->id; } /** diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index beb5d94a6..3cd3d32ba 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -374,7 +374,7 @@ class ServerRepository try { $server = Models\Server::findOrFail($id); - $owner = Models\User::findOrFail($server->owner); + $owner = Models\User::findOrFail($server->owner_id); // Update daemon secret if it was passed. if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $owner->email)) { @@ -386,7 +386,7 @@ class ServerRepository // Update Server Owner if it was passed. if (isset($data['owner']) && $data['owner'] !== $owner->email) { $newOwner = Models\User::select('id')->where('email', $data['owner'])->first(); - $server->owner = $newOwner->id; + $server->owner_id = $newOwner->id; } // Update Server Name if it was passed. @@ -405,8 +405,8 @@ class ServerRepository } // If we need to update do it here. - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $res = $client->request('PATCH', '/server', [ 'headers' => [ @@ -461,8 +461,8 @@ class ServerRepository $server->image = $data['image']; $server->save(); - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('PATCH', '/server', [ 'headers' => [ @@ -520,7 +520,7 @@ class ServerRepository try { $server = Models\Server::findOrFail($id); - $allocation = Models\Allocation::findOrFail($server->allocation); + $allocation = Models\Allocation::findOrFail($server->allocation_id); $newBuild = []; @@ -532,14 +532,14 @@ class ServerRepository throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.'); } - $server->allocation = $selection->id; + $server->allocation_id = $selection->id; $newBuild['default'] = [ 'ip' => $ip, 'port' => (int) $port, ]; // Re-Run to keep updated for rest of function - $allocation = Models\Allocation::findOrFail($server->allocation); + $allocation = Models\Allocation::findOrFail($server->allocation_id); } } @@ -635,8 +635,8 @@ class ServerRepository $server->save(); if (! empty($newBuild)) { - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('PATCH', '/server', [ 'headers' => [ @@ -679,7 +679,7 @@ class ServerRepository 'service_variables.*', DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_currentValue') )->leftJoin('server_variables', 'server_variables.variable_id', '=', 'service_variables.id') - ->where('option_id', $server->option) + ->where('option_id', $server->option_id) ->get(); $variableList = []; @@ -747,8 +747,8 @@ class ServerRepository $model->save(); } - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('PATCH', '/server', [ 'headers' => [ @@ -797,7 +797,7 @@ class ServerRepository public function deleteNow($id, $force = false) { $server = Models\Server::withTrashed()->findOrFail($id); - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); // Handle server being restored previously or // an accidental queue. @@ -835,7 +835,7 @@ class ServerRepository $repository->drop($database->id); } - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('DELETE', '/servers', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, @@ -888,7 +888,7 @@ class ServerRepository public function suspend($id, $deleted = false) { $server = ($deleted) ? Models\Server::withTrashed()->findOrFail($id) : Models\Server::findOrFail($id); - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); DB::beginTransaction(); @@ -902,7 +902,7 @@ class ServerRepository $server->suspended = 1; $server->save(); - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('POST', '/server/suspend', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, @@ -928,7 +928,7 @@ class ServerRepository public function unsuspend($id) { $server = Models\Server::findOrFail($id); - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); DB::beginTransaction(); @@ -942,7 +942,7 @@ class ServerRepository $server->suspended = 0; $server->save(); - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('POST', '/server/unsuspend', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, @@ -963,7 +963,7 @@ class ServerRepository public function updateSFTPPassword($id, $password) { $server = Models\Server::findOrFail($id); - $node = Models\Node::findOrFail($server->node); + $node = Models\Node::findOrFail($server->node_id); $validator = Validator::make([ 'password' => $password, @@ -981,7 +981,7 @@ class ServerRepository try { $server->save(); - $client = Models\Node::guzzleRequest($server->node); + $client = Models\Node::guzzleRequest($server->node_id); $client->request('POST', '/server/password', [ 'headers' => [ 'X-Access-Token' => $node->daemonSecret, diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index afa27493e..335e6926d 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -146,7 +146,7 @@ class SubuserRepository } catch (\Exception $ex) { throw $ex; } - } elseif ($server->owner === $user->id) { + } elseif ($server->owner_id === $user->id) { throw new DisplayException('You cannot add the owner of a server as a subuser.'); } elseif (Models\Subuser::select('id')->where('user_id', $user->id)->where('server_id', $server->id)->first()) { throw new DisplayException('A subuser with that email already exists for this server.'); @@ -184,8 +184,8 @@ class SubuserRepository // We contact even if they don't have any daemon permissions to overwrite // if they did have them previously. - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $res = $client->request('PATCH', '/server', [ 'headers' => [ @@ -240,8 +240,8 @@ class SubuserRepository try { Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $res = $client->request('PATCH', '/server', [ 'headers' => [ @@ -318,8 +318,8 @@ class SubuserRepository // Contact Daemon // We contact even if they don't have any daemon permissions to overwrite // if they did have them previously. - $node = Models\Node::getByID($server->node); - $client = Models\Node::guzzleRequest($server->node); + $node = Models\Node::getByID($server->node_id); + $client = Models\Node::guzzleRequest($server->node_id); $res = $client->request('PATCH', '/server', [ 'headers' => [ diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index bb76db9b6..abd2155b1 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -48,7 +48,7 @@ class NotificationService public function __construct(Server $server) { $this->server = $server; - $this->user = User::findOrFail($server->owner); + $this->user = User::findOrFail($server->owner_id); } public function pass(array $notification) diff --git a/database/migrations/2016_08_30_213301_modify_ip_storage_method.php b/database/migrations/2016_08_30_213301_modify_ip_storage_method.php index b77ccbea6..768ef0b55 100644 --- a/database/migrations/2016_08_30_213301_modify_ip_storage_method.php +++ b/database/migrations/2016_08_30_213301_modify_ip_storage_method.php @@ -24,7 +24,7 @@ class ModifyIpStorageMethod extends Migration [ 'ip' => $server->ip, 'port' => $server->port, - 'node' => $server->node, + 'node' => $server->node_id, ] ); @@ -61,7 +61,7 @@ class ModifyIpStorageMethod extends Migration // Find the allocations and reset the servers... $servers = DB::select('SELECT id, allocation FROM servers'); foreach ($servers as $server) { - $allocation = DB::select('SELECT * FROM allocations WHERE id = :alocid', ['alocid' => $server->allocation]); + $allocation = DB::select('SELECT * FROM allocations WHERE id = :alocid', ['alocid' => $server->allocation_id]); if (isset($allocation[0])) { DB::update( diff --git a/database/migrations/2016_09_17_194246_add_docker_image_column.php b/database/migrations/2016_09_17_194246_add_docker_image_column.php index 58e4b87a3..ce7d91203 100644 --- a/database/migrations/2016_09_17_194246_add_docker_image_column.php +++ b/database/migrations/2016_09_17_194246_add_docker_image_column.php @@ -22,7 +22,7 @@ class AddDockerImageColumn extends Migration $servers = DB::table('servers')->select( 'servers.id', 'service_options.docker_image as s_optionImage' - )->join('service_options', 'service_options.id', '=', 'servers.option')->get(); + )->join('service_options', 'service_options.id', '=', 'servers.option_id')->get(); foreach ($servers as $server) { $server->image = $server->s_optionImage; diff --git a/database/migrations/2017_02_02_175548_UpdateColumnNames.php b/database/migrations/2017_02_02_175548_UpdateColumnNames.php new file mode 100644 index 000000000..bc49c7d45 --- /dev/null +++ b/database/migrations/2017_02_02_175548_UpdateColumnNames.php @@ -0,0 +1,66 @@ +dropForeign('servers_node_foreign'); + $table->dropForeign('servers_owner_foreign'); + $table->dropForeign('servers_allocation_foreign'); + $table->dropForeign('servers_service_foreign'); + $table->dropForeign('servers_option_foreign'); + + $table->dropIndex('servers_node_foreign'); + $table->dropIndex('servers_owner_foreign'); + $table->dropIndex('servers_allocation_foreign'); + $table->dropIndex('servers_service_foreign'); + $table->dropIndex('servers_option_foreign'); + + $table->renameColumn('node', 'node_id'); + $table->renameColumn('owner', 'owner_id'); + $table->renameColumn('allocation', 'allocation_id'); + $table->renameColumn('service', 'service_id'); + $table->renameColumn('option', 'option_id'); + $table->renameColumn('pack', 'pack_id'); + + $table->foreign('node_id')->references('id')->on('nodes'); + $table->foreign('owner_id')->references('id')->on('users'); + $table->foreign('allocation_id')->references('id')->on('allocations'); + $table->foreign('service_id')->references('id')->on('services'); + $table->foreign('option_id')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('servers', function (Blueprint $table) { + $table->renameColumn('node_id', 'node'); + $table->renameColumn('owner_id', 'owner'); + $table->renameColumn('allocation_id', 'allocation'); + $table->renameColumn('service_id', 'service'); + $table->renameColumn('option_id', 'option'); + $table->renameColumn('pack_id', 'pack'); + + $table->foreign('node')->references('id')->on('nodes'); + $table->foreign('owner')->references('id')->on('users'); + $table->foreign('allocation')->references('id')->on('allocations'); + $table->foreign('service')->references('id')->on('services'); + $table->foreign('option')->references('id')->on('service_options'); + }); + } +} diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index c6066c25a..d029a37a9 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -62,7 +62,7 @@
- + diff --git a/resources/themes/pterodactyl/server/settings/allocation.blade.php b/resources/themes/pterodactyl/server/settings/allocation.blade.php index f2782a88c..773281e96 100644 --- a/resources/themes/pterodactyl/server/settings/allocation.blade.php +++ b/resources/themes/pterodactyl/server/settings/allocation.blade.php @@ -63,7 +63,7 @@ - + diff --git a/resources/views/admin/servers/index.blade.php b/resources/views/admin/servers/index.blade.php index 612d2905c..11d852ecf 100644 --- a/resources/views/admin/servers/index.blade.php +++ b/resources/views/admin/servers/index.blade.php @@ -64,8 +64,8 @@ Pending Deletion @endif - - + + @endforeach diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php index abad871d9..7def73236 100644 --- a/resources/views/admin/servers/view.blade.php +++ b/resources/views/admin/servers/view.blade.php @@ -89,7 +89,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -304,7 +304,7 @@
@@ -398,7 +398,7 @@ diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index bffb2057e..e3eb61a12 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -178,7 +178,7 @@ @foreach ($servers as $server) - + @endforeach diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php index 0a5d8230d..314fc8ba7 100644 --- a/resources/views/admin/users/view.blade.php +++ b/resources/views/admin/users/view.blade.php @@ -117,7 +117,7 @@ - + From c4b76bf48e05a2d0f0bb7ee687644ee7e518cbe1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 18:25:11 -0500 Subject: [PATCH 029/112] Remove FKs correctly --- .../2017_02_02_175548_UpdateColumnNames.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/database/migrations/2017_02_02_175548_UpdateColumnNames.php b/database/migrations/2017_02_02_175548_UpdateColumnNames.php index bc49c7d45..7e281af8e 100644 --- a/database/migrations/2017_02_02_175548_UpdateColumnNames.php +++ b/database/migrations/2017_02_02_175548_UpdateColumnNames.php @@ -49,6 +49,18 @@ class UpdateColumnNames extends Migration public function down() { Schema::table('servers', function (Blueprint $table) { + $table->dropForeign('servers_node_id_foreign'); + $table->dropForeign('servers_owner_id_foreign'); + $table->dropForeign('servers_allocation_id_foreign'); + $table->dropForeign('servers_service_id_foreign'); + $table->dropForeign('servers_option_id_foreign'); + + $table->dropIndex('servers_node_id_foreign'); + $table->dropIndex('servers_owner_id_foreign'); + $table->dropIndex('servers_allocation_id_foreign'); + $table->dropIndex('servers_service_id_foreign'); + $table->dropIndex('servers_option_id_foreign'); + $table->renameColumn('node_id', 'node'); $table->renameColumn('owner_id', 'owner'); $table->renameColumn('allocation_id', 'allocation'); From 644ee85f59fa4bfb6475ef116b69be1ad97d8046 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 18:25:46 -0500 Subject: [PATCH 030/112] Fix for StyleCI --- app/Models/User.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Models/User.php b/app/Models/User.php index 0de3eb5ae..7dba0cf0d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Models; -use Auth; use Hash; use Google2FA; use Illuminate\Auth\Authenticatable; From 600cc756370b22e989aba3f39a7f16f7be633b39 Mon Sep 17 00:00:00 2001 From: Jakob Schrettenbrunner Date: Fri, 3 Feb 2017 00:29:50 +0100 Subject: [PATCH 031/112] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2ee47a5c..78c3f20d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Users can now have a username as well as client name assigned to their account. * Ability to create a node through the CLI using `pterodactyl:node` as well as locations via `pterodactyl:location`. * New theme (AdminLTE) for front-end with tweaks to backend files to work properly with it. +* Add support for PhraseApp's in-context editor ### Fixed * Bug causing error logs to be spammed if someone timed out on an ajax based page. From 3114b7e52a1a078a0d05ec2d8b22fe9073a5bf9b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 19:41:38 -0500 Subject: [PATCH 032/112] Complete implementation of new Server model. --- CHANGELOG.md | 5 +- .../Controllers/API/User/ServerController.php | 28 ++--- .../Controllers/Server/AjaxController.php | 24 ++-- .../Controllers/Server/ServerController.php | 103 +++++++----------- .../Controllers/Server/SubuserController.php | 39 +++---- .../Controllers/Server/TaskController.php | 40 +++---- app/Models/Node.php | 16 +++ app/Models/Server.php | 67 +++++++++++- app/Repositories/Daemon/FileRepository.php | 48 ++------ .../server/settings/allocation.blade.php | 2 +- 10 files changed, 170 insertions(+), 202 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b459be5..cc093ab76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,9 +20,12 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Admin API and base routes for user management now define the fields that should be passed to repositories rather than passing all fields. * User model now defines mass assignment fields using `$fillable` rather than `$guarded`. * 2FA checkpoint on login is now its own page, and not an AJAX based call. Improves security on that front. +* Updated Server model code to be more efficient, as well as make life easier for backend changes and work. -### Removed +### Deprecated * `Server::getUserDaemonSecret(Server $server)` was removed and replaced with `User::daemonSecret(Server $server)` in order to clean up models. +* `Server::getByUUID()` was replaced with `Server::byUuid()` as well as various other functions through-out the Server model. +* `Server::getHeaders()` was removed and replaced with `Server::getClient()` which returns a Guzzle Client with the correct headers already assigned. ## v0.5.6 (Bodacious Boreopterus) ### Added diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 128c5cf68..c6091f0b1 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -34,17 +34,10 @@ class ServerController extends BaseController { public function info(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); - $node = Models\Node::findOrFail($server->node_id); - $client = Models\Node::guzzleRequest($node->id); + $server = Models\Server::byUuid($uuid)->load('allocations'); try { - $response = $client->request('GET', '/server', [ - 'headers' => [ - 'X-Access-Token' => $server->daemonSecret, - 'X-Access-Server' => $server->uuid, - ], - ]); + $response = $server->guzzleClient()->request('GET', '/server'); $json = json_decode($response->getBody()); $daemon = [ @@ -59,8 +52,7 @@ class ServerController extends BaseController Log::error($ex); } - $allocations = Models\Allocation::select('id', 'ip', 'port', 'ip_alias as alias')->where('assigned_to', $server->id)->get(); - foreach ($allocations as &$allocation) { + foreach ($server->allocations as &$allocation) { $allocation->default = ($allocation->id === $server->allocation_id); unset($allocation->id); } @@ -69,7 +61,7 @@ class ServerController extends BaseController 'uuidShort' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, - 'node' => $node->name, + 'node' => $server->node->name, 'limits' => [ 'memory' => $server->memory, 'swap' => $server->swap, @@ -78,7 +70,7 @@ class ServerController extends BaseController 'cpu' => $server->cpu, 'oom_disabled' => (bool) $server->oom_disabled, ], - 'allocations' => $allocations, + 'allocations' => $server->allocations, 'sftp' => [ 'username' => (Auth::user()->can('view-sftp', $server)) ? $server->username : null, ], @@ -91,16 +83,10 @@ class ServerController extends BaseController public function power(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); - $client = Models\Node::guzzleRequest($server->node_id); - + $server = Models\Server::byUuid($uuid); Auth::user()->can('power-' . $request->input('action'), $server); - $res = $client->request('PUT', '/server/power', [ - 'headers' => [ - 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $server->daemonSecret, - ], + $res = $server->guzzleClient()->request('PUT', '/server/power', [ 'exceptions' => false, 'json' => [ 'action' => $request->input('action'), diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index 9ee9f4284..9493bc0f0 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -67,18 +67,14 @@ class AjaxController extends Controller */ public function getStatus(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); if (! $server) { return response()->json([], 404); } - $client = Models\Node::guzzleRequest($server->node_id); - try { - $res = $client->request('GET', '/server', [ - 'headers' => Models\Server::getGuzzleHeaders($uuid), - ]); + $res = $server->guzzleClient()->request('GET', '/server'); if ($res->getStatusCode() === 200) { return response()->json(json_decode($res->getBody())); } @@ -98,10 +94,10 @@ class AjaxController extends Controller */ public function postDirectoryList(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); - $this->directory = '/' . trim(urldecode($request->input('directory', '/')), '/'); + $server = Models\Server::byUuid($uuid); $this->authorize('list-files', $server); + $this->directory = '/' . trim(urldecode($request->input('directory', '/')), '/'); $prevDir = [ 'header' => ($this->directory !== '/') ? $this->directory : '', ]; @@ -149,7 +145,7 @@ class AjaxController extends Controller */ public function postSaveFile(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('save-files', $server); $controller = new Repositories\Daemon\FileRepository($uuid); @@ -175,7 +171,7 @@ class AjaxController extends Controller */ public function postSetPrimary(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid)->load('allocations'); $this->authorize('set-connection', $server); if ((int) $request->input('allocation') === $server->allocation_id) { @@ -185,7 +181,7 @@ class AjaxController extends Controller } try { - $allocation = Models\Allocation::where('id', $request->input('allocation'))->where('assigned_to', $server->id)->first(); + $allocation = $server->allocations->where('id', $request->input('allocation'))->where('assigned_to', $server->id)->first(); if (! $allocation) { return response()->json([ 'error' => 'No allocation matching your request was found in the system.', @@ -217,10 +213,10 @@ class AjaxController extends Controller public function postResetDatabasePassword(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); - $database = Models\Database::where('id', $request->input('database'))->where('server_id', $server->id)->firstOrFail(); - + $server = Models\Server::byUuid($uuid); $this->authorize('reset-db-password', $server); + + $database = Models\Database::where('id', $request->input('database'))->where('server_id', $server->id)->firstOrFail(); try { $repo = new Repositories\DatabaseRepository; $password = str_random(16); diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 7f07f977c..0b423cc97 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -59,9 +59,7 @@ class ServerController extends Controller { $server = Models\Server::byUuid($uuid); - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), - 'node' => collect($server->node_id)->only('fqdn', 'scheme', 'daemonListen'), + $server->js([ 'meta' => [ 'saveFile' => route('server.files.save', $server->uuidShort), 'csrfToken' => csrf_token(), @@ -70,7 +68,7 @@ class ServerController extends Controller return view('server.index', [ 'server' => $server, - 'node' => $server->node_id, + 'node' => $server->node, ]); } @@ -82,14 +80,10 @@ class ServerController extends Controller */ public function getFiles(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('list-files', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only('uuid', 'uuidShort', 'daemonSecret'), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + $server->js([ 'meta' => [ 'directoryList' => route('server.files.directory-list', $server->uuidShort), 'csrftoken' => csrf_token(), @@ -107,7 +101,7 @@ class ServerController extends Controller return view('server.files.index', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, ]); } @@ -119,18 +113,14 @@ class ServerController extends Controller */ public function getAddFile(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('add-files', $server); - $node = Models\Node::find($server->node_id); - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.files.add', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, 'directory' => (in_array($request->get('dir'), [null, '/', ''])) ? '' : trim($request->get('dir'), '/') . '/', ]); } @@ -145,9 +135,8 @@ class ServerController extends Controller */ public function getEditFile(Request $request, $uuid, $file) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('edit-files', $server); - $node = Models\Node::find($server->node_id); $fileInfo = (object) pathinfo($file); $controller = new FileRepository($uuid); @@ -165,15 +154,13 @@ class ServerController extends Controller return redirect()->route('server.files.index', $uuid); } - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + $server->js([ 'stat' => $fileContent['stat'], ]); return view('server.files.edit', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, 'file' => $file, 'stat' => $fileContent['stat'], 'contents' => $fileContent['file']->content, @@ -191,9 +178,7 @@ class ServerController extends Controller */ public function getDownloadFile(Request $request, $uuid, $file) { - $server = Models\Server::getByUUID($uuid); - $node = Models\Node::find($server->node_id); - + $server = Models\Server::byUuid($uuid); $this->authorize('download-files', $server); $download = new Models\Download; @@ -204,38 +189,31 @@ class ServerController extends Controller $download->save(); - return redirect($node->scheme . '://' . $node->fqdn . ':' . $node->daemonListen . '/server/file/download/' . $download->token); + return redirect($server->node->scheme . '://' . $server->node->fqdn . ':' . $server->node->daemonListen . '/server/file/download/' . $download->token); } public function getAllocation(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('view-allocation', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.settings.allocation', [ - 'server' => $server, - 'allocations' => Models\Allocation::where('assigned_to', $server->id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), - 'node' => $node, + 'server' => $server->load(['allocations' => function ($query) { + $query->orderBy('ip', 'asc'); + $query->orderBy('port', 'asc'); + }]), + 'node' => $server->node, ]); } public function getStartup(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); + $server->load(['allocations' => function ($query) use ($server) { + $query->where('id', $server->allocation_id); + }]); $this->authorize('view-startup', $server); - $node = Models\Node::find($server->node_id); - $allocation = Models\Allocation::findOrFail($server->allocation_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); $variables = Models\ServiceVariables::select( 'service_variables.*', @@ -252,6 +230,7 @@ class ServerController extends Controller ->where('services.id', $server->service_id) ->first(); + $allocation = $server->allocations->pop(); $serverVariables = [ '{{SERVER_MEMORY}}' => $server->memory, '{{SERVER_IP}}' => $allocation->ip, @@ -260,13 +239,15 @@ class ServerController extends Controller $processed = str_replace(array_keys($serverVariables), array_values($serverVariables), $server->startup); foreach ($variables as &$variable) { - $replace = ($variable->user_viewable === 1) ? $variable->a_serverValue : '**'; + $replace = ($variable->user_viewable === 1) ? $variable->a_serverValue : '[hidden]'; $processed = str_replace('{{' . $variable->env_variable . '}}', $replace, $processed); } + $server->js(); + return view('server.settings.startup', [ 'server' => $server, - 'node' => Models\Node::find($server->node_id), + 'node' => $server->node, 'variables' => $variables->where('user_viewable', 1), 'service' => $service, 'processedStartup' => $processed, @@ -275,18 +256,13 @@ class ServerController extends Controller public function getDatabases(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('view-databases', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.settings.databases', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, 'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port') ->where('server_id', $server->id) ->join('database_servers', 'database_servers.id', '=', 'databases.db_server') @@ -296,24 +272,19 @@ class ServerController extends Controller public function getSFTP(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('view-sftp', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.settings.sftp', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, ]); } public function postSettingsSFTP(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('reset-sftp', $server); try { @@ -334,7 +305,7 @@ class ServerController extends Controller public function postSettingsStartup(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('edit-startup', $server); try { diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 1d07b47f7..9badfef45 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -50,18 +50,14 @@ class SubuserController extends Controller public function getIndex(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('list-subusers', $server); - $node = Models\Node::find($server->node_id); - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.users.index', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username', 'users.use_totp') ->join('users', 'users.id', '=', 'subusers.user_id') ->where('server_id', $server->id) @@ -71,14 +67,8 @@ class SubuserController extends Controller public function getView(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('view-subuser', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); $subuser = Models\Subuser::select('subusers.*', 'users.email as a_userEmail') ->join('users', 'users.id', '=', 'subusers.user_id') @@ -98,9 +88,11 @@ class SubuserController extends Controller $permissions[$perm->permission] = true; } + $server->js(); + return view('server.users.view', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, 'subuser' => $subuser, 'permissions' => $permissions, ]); @@ -108,7 +100,7 @@ class SubuserController extends Controller public function postView(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('edit-subuser', $server); $subuser = Models\Subuser::where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); @@ -148,24 +140,19 @@ class SubuserController extends Controller public function getNew(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('create-subuser', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.users.new', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, ]); } public function postNew(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('create-subuser', $server); try { @@ -193,7 +180,7 @@ class SubuserController extends Controller public function deleteSubuser(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('delete-subuser', $server); try { diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 51243cc8f..4fb492afc 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -43,19 +43,14 @@ class TaskController extends Controller public function getIndex(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('list-tasks', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.tasks.index', [ 'server' => $server, - 'node' => $node, - 'tasks' => Models\Task::where('server', $server->id)->get(), + 'node' => $server->node, + 'tasks' => $server->tasks, 'actions' => [ 'command' => trans('server.tasks.actions.command'), 'power' => trans('server.tasks.actions.power'), @@ -65,24 +60,19 @@ class TaskController extends Controller public function getNew(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('create-task', $server); - $node = Models\Node::find($server->node_id); - - Javascript::put([ - 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), - 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), - ]); + $server->js(); return view('server.tasks.new', [ 'server' => $server, - 'node' => $node, + 'node' => $server->node, ]); } public function postNew(Request $request, $uuid) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid); $this->authorize('create-task', $server); try { @@ -106,12 +96,11 @@ class TaskController extends Controller public function deleteTask(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('delete-task', $server); - $task = Models\Task::findOrFail($id); - - if (! $task || $server->id !== $task->server) { + $task = $server->tasks->where('id', $id)->first(); + if (! $task) { return response()->json([ 'error' => 'No task by that ID was found associated with this server.', ], 404); @@ -133,12 +122,11 @@ class TaskController extends Controller public function toggleTask(Request $request, $uuid, $id) { - $server = Models\Server::getByUUID($uuid); + $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('toggle-task', $server); - $task = Models\Task::findOrFail($id); - - if (! $task || $server->id !== $task->server) { + $task = $server->tasks->where('id', $id)->first(); + if (! $task) { return response()->json([ 'error' => 'No task by that ID was found associated with this server.', ], 404); diff --git a/app/Models/Node.php b/app/Models/Node.php index a5cbce464..8e82ef935 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -96,11 +96,27 @@ class Node extends Model return self::$nodes[$id]; } + /** + * Return an instance of the Guzzle client for this specific node. + * + * @return \GuzzleHttp\Client + */ + public function guzzleClient($headers = []) + { + return new Client([ + 'base_uri' => sprintf('%s://%s:%s/', $this->scheme, $this->fqdn, $this->daemonListen), + 'timeout' => env('GUZZLE_TIMEOUT', 5.0), + 'connect_timeout' => env('GUZZLE_CONNECT_TIMEOUT', 3.0), + 'headers' => $headers, + ]); + } + /** * Returns a Guzzle Client for the node in question. * * @param int $node * @return \GuzzleHttp\Client + * @deprecated */ public static function guzzleRequest($node) { diff --git a/app/Models/Server.php b/app/Models/Server.php index 32240da44..d0d02bc58 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Models; use Auth; +use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\SoftDeletes; @@ -67,18 +68,19 @@ class Server extends Model * @var array */ protected $casts = [ - 'node' => 'integer', + 'node_id' => 'integer', 'suspended' => 'integer', - 'owner' => 'integer', + 'owner_id' => 'integer', 'memory' => 'integer', 'swap' => 'integer', 'disk' => 'integer', 'io' => 'integer', 'cpu' => 'integer', 'oom_disabled' => 'integer', - 'port' => 'integer', - 'service' => 'integer', - 'option' => 'integer', + 'allocation_id' => 'integer', + 'service_id' => 'integer', + 'option_id' => 'integer', + 'pack_id' => 'integer', 'installed' => 'integer', ]; @@ -166,7 +168,7 @@ class Server extends Model * @param string $uuid * @return array */ - public function getHeaders() + public function guzzleHeaders() { return [ 'X-Access-Server' => $this->uuid, @@ -174,6 +176,48 @@ class Server extends Model ]; } + /** + * Return an instance of the Guzzle client for this specific server using defined access token. + * + * @return \GuzzleHttp\Client + */ + public function guzzleClient() + { + return $this->node->guzzleClient($this->guzzleHeaders()); + } + + /** + * Returns javascript object to be embedded on server view pages with relevant information. + * + * @return \Laracasts\Utilities\JavaScript\JavaScriptFacade + */ + public function js($additional = null, $overwrite = null) + { + $response = [ + 'server' => collect($this->makeVisible('daemonSecret'))->only([ + 'uuid', + 'uuidShort', + 'daemonSecret', + 'username' + ]), + 'node' => collect($this->node)->only([ + 'fqdn', + 'scheme', + 'daemonListen' + ]), + ]; + + if (is_array($additional)) { + $response = array_merge($response, $additional); + } + + if (is_array($overwrite)) { + $response = $overwrite; + } + + return Javascript::put($response); + } + /** * Gets all allocations associated with this server. * @@ -233,4 +277,15 @@ class Server extends Model { return $this->hasOne(Node::class, 'id', 'node_id'); } + + /** + * Gets information for the tasks associated with this server. + * + * @TODO adjust server column in tasks to be server_id + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function tasks() + { + return $this->hasMany(Task::class, 'server', 'id'); + } } diff --git a/app/Repositories/Daemon/FileRepository.php b/app/Repositories/Daemon/FileRepository.php index d1319cf91..cb5f92a28 100644 --- a/app/Repositories/Daemon/FileRepository.php +++ b/app/Repositories/Daemon/FileRepository.php @@ -40,28 +40,6 @@ class FileRepository */ protected $server; - /** - * The Eloquent Model for the node corresponding with the requested server. - * - * @var \Illuminate\Database\Eloquent\Model - */ - protected $node; - - /** - * The Guzzle Client associated with the requested server and node. - * - * @var \GuzzleHttp\Client - */ - protected $client; - - /** - * The Guzzle Client headers associated with the requested server and node. - * (non-administrative headers). - * - * @var array - */ - protected $headers; - /** * Constructor. * @@ -69,10 +47,7 @@ class FileRepository */ public function __construct($uuid) { - $this->server = Server::getByUUID($uuid); - $this->node = Node::getByID($this->server->node); - $this->client = Node::guzzleRequest($this->server->node); - $this->headers = Server::getGuzzleHeaders($uuid); + $this->server = Server::byUuid($uuid); } /** @@ -88,12 +63,9 @@ class FileRepository } $file = (object) pathinfo($file); - $file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/'; - $res = $this->client->request('GET', '/server/file/stat/' . rawurlencode($file->dirname . $file->basename), [ - 'headers' => $this->headers, - ]); + $res = $this->server->guzzleClient()->request('GET', '/server/file/stat/' . rawurlencode($file->dirname . $file->basename)); $stat = json_decode($res->getBody()); if ($res->getStatusCode() !== 200 || ! isset($stat->size)) { @@ -108,9 +80,7 @@ class FileRepository throw new DisplayException('That file is too large to open in the browser, consider using a SFTP client.'); } - $res = $this->client->request('GET', '/server/file/f/' . rawurlencode($file->dirname . $file->basename), [ - 'headers' => $this->headers, - ]); + $res = $this->server->guzzleClient()->request('GET', '/server/file/f/' . rawurlencode($file->dirname . $file->basename)); $json = json_decode($res->getBody()); if ($res->getStatusCode() !== 200 || ! isset($json->content)) { @@ -137,11 +107,9 @@ class FileRepository } $file = (object) pathinfo($file); - $file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/'; - $res = $this->client->request('POST', '/server/file/save', [ - 'headers' => $this->headers, + $res = $this->server->guzzleClient()->request('POST', '/server/file/save', [ 'json' => [ 'path' => rawurlencode($file->dirname . $file->basename), 'content' => $content, @@ -167,9 +135,7 @@ class FileRepository throw new Exception('A valid directory must be specified in order to list its contents.'); } - $res = $this->client->request('GET', '/server/directory/' . rawurlencode($directory), [ - 'headers' => $this->headers, - ]); + $res = $this->server->guzzleClient()->request('GET', '/server/directory/' . rawurlencode($directory)); $json = json_decode($res->getBody()); if ($res->getStatusCode() !== 200) { @@ -180,7 +146,7 @@ class FileRepository $files = []; $folders = []; foreach ($json as &$value) { - if ($value->directory === true) { + if ($value->directory) { // @TODO Handle Symlinks $folders[] = [ 'entry' => $value->name, @@ -189,7 +155,7 @@ class FileRepository 'date' => strtotime($value->modified), 'mime' => $value->mime, ]; - } elseif ($value->file === true) { + } elseif ($value->file) { $files[] = [ 'entry' => $value->name, 'directory' => trim($directory, '/'), diff --git a/resources/themes/pterodactyl/server/settings/allocation.blade.php b/resources/themes/pterodactyl/server/settings/allocation.blade.php index 773281e96..a6a0c36ad 100644 --- a/resources/themes/pterodactyl/server/settings/allocation.blade.php +++ b/resources/themes/pterodactyl/server/settings/allocation.blade.php @@ -49,7 +49,7 @@ - @foreach ($allocations as $allocation) + @foreach ($server->allocations as $allocation) - @foreach($databases as $db) + @foreach($databases as $database) - - - - - - + + + + where('id', $database->db_server)->first(); ?> + + + @endforeach
{{ $server->uuidShort }} {{ $server->name }}{{ $server->nodeName }}{{ $server->node_idName }} @if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }} {{ $allocation->port }} - @if($allocation->id === $server->allocation) + @if($allocation->id === $server->allocation_id) @lang('strings.primary') @else @lang('strings.make_primary') diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index a0ed696e7..8485c9a50 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -405,7 +405,7 @@ @foreach($servers as $server)
{{ $server->name }}{{ $server->a_ownerEmail }}{{ $server->a_ownerEmail }} {{ $server->a_serviceName }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB {{ $server->disk }} MB{{ $server->a_ownerEmail }}{{ $server->a_nodeName }}{{ $server->a_ownerEmail }}{{ $server->a_nodeName }}
Owner{{ $server->a_ownerEmail }}{{ $server->a_ownerEmail }}
Location
Node{{ $node->name }}{{ $node->name }}
Service
{{ $server->name }}{{ $server->a_ownerEmail }}{{ $server->a_ownerEmail }} {{ $server->updated_at }}
{{ $server->uuidShort }} {{ $server->name }}{{ $server->nodeName }}{{ $server->node_idName }} {{ $server->username }} @if($server->suspended === 0)Active@elseSuspended@endif @lang('strings.port')
{{ $allocation->ip }} From 3baa21a6eb20d53e03154d853d4b8be2ad9aff98 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 19:43:55 -0500 Subject: [PATCH 033/112] StyleCI fixes. --- app/Http/Controllers/Server/ServerController.php | 1 - app/Http/Controllers/Server/SubuserController.php | 1 - app/Http/Controllers/Server/TaskController.php | 1 - app/Models/Server.php | 4 ++-- app/Repositories/Daemon/FileRepository.php | 1 - 5 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 0b423cc97..75378ddc1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -28,7 +28,6 @@ use DB; use Log; use Uuid; use Alert; -use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 9badfef45..8c4452457 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -28,7 +28,6 @@ use DB; use Log; use Auth; use Alert; -use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 4fb492afc..643e70a45 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -26,7 +26,6 @@ namespace Pterodactyl\Http\Controllers\Server; use Log; use Alert; -use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Repositories; diff --git a/app/Models/Server.php b/app/Models/Server.php index d0d02bc58..db8ba6381 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -198,12 +198,12 @@ class Server extends Model 'uuid', 'uuidShort', 'daemonSecret', - 'username' + 'username', ]), 'node' => collect($this->node)->only([ 'fqdn', 'scheme', - 'daemonListen' + 'daemonListen', ]), ]; diff --git a/app/Repositories/Daemon/FileRepository.php b/app/Repositories/Daemon/FileRepository.php index cb5f92a28..5fc2245fb 100644 --- a/app/Repositories/Daemon/FileRepository.php +++ b/app/Repositories/Daemon/FileRepository.php @@ -26,7 +26,6 @@ namespace Pterodactyl\Repositories\Daemon; use Exception; use GuzzleHttp\Client; -use Pterodactyl\Models\Node; use Pterodactyl\Models\Server; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Repositories\HelperRepository; From 533e2bcafb95f096487aa51e82ed70dba23be825 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 19:46:46 -0500 Subject: [PATCH 034/112] Fix database column references in ACP --- app/Http/Controllers/Admin/LocationsController.php | 4 ++-- app/Http/Controllers/Admin/NodesController.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index 889123b43..9ef004bed 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -46,7 +46,7 @@ class LocationsController extends Controller 'locations' => Models\Location::select( 'locations.*', DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') )->paginate(20), ]); } @@ -56,7 +56,7 @@ class LocationsController extends Controller $model = Models\Location::select( 'locations.id', DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') )->where('id', $id)->first(); if (! $model) { diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 506d8434e..600ecb932 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -57,7 +57,7 @@ class NodesController extends Controller 'nodes' => Models\Node::select( 'nodes.*', 'locations.long as a_locationName', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node = nodes.id) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id = nodes.id) as a_serverCount') )->join('locations', 'nodes.location', '=', 'locations.id')->paginate(20), ]); } @@ -110,8 +110,8 @@ class NodesController extends Controller 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName') ->join('users', 'users.id', '=', 'servers.owner_id') ->join('services', 'services.id', '=', 'servers.service_id') - ->where('node', $id)->paginate(10, ['*'], 'servers'), - 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(), + ->where('node_id', $id)->paginate(10, ['*'], 'servers'), + 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node_id', $node->id)->first(), 'locations' => Models\Location::all(), 'allocations' => Models\Allocation::select('allocations.*', 'servers.name as assigned_to_name') ->where('allocations.node', $node->id) From 9c2d34d6e695f2790a394601526021267265deb9 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Feb 2017 19:48:13 -0500 Subject: [PATCH 035/112] Mo' StyleCI fixes... :crab: --- app/Http/Controllers/Auth/LoginController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 0be73ddd2..4ce580445 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -156,7 +156,6 @@ class LoginController extends Controller return redirect()->route('auth.login'); } - if (! is_null($request->input('2fa_token')) && $G2FA->verifyKey($user->totp_secret, $request->input('2fa_token'), 1)) { Auth::login($user, $request->has('remember')); @@ -168,5 +167,4 @@ class LoginController extends Controller return redirect()->route('auth.login'); } } - } From 96d3aa767f297d242469319fb16f7f4161fcfd6d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Feb 2017 15:19:14 -0500 Subject: [PATCH 036/112] Model updates for Database Management in ACP --- .../Controllers/Admin/DatabaseController.php | 34 ++++++---------- app/Models/Database.php | 22 +++++++++- app/Models/DatabaseServer.php | 10 +++++ app/Models/Node.php | 39 ++++++++++++++++-- .../2017_02_03_140948_UpdateNodesTable.php | 40 +++++++++++++++++++ .../views/admin/databases/index.blade.php | 33 +++++++-------- resources/views/admin/databases/new.blade.php | 2 +- 7 files changed, 137 insertions(+), 43 deletions(-) create mode 100644 database/migrations/2017_02_03_140948_UpdateNodesTable.php diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 4a7fc3631..6cfa73041 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -47,30 +47,18 @@ class DatabaseController extends Controller public function getIndex(Request $request) { return view('admin.databases.index', [ - 'databases' => Models\Database::select( - 'databases.*', - 'database_servers.host as a_host', - 'database_servers.port as a_port', - 'servers.id as a_serverId', - 'servers.name as a_serverName' - )->join('database_servers', 'database_servers.id', '=', 'databases.db_server') - ->join('servers', 'databases.server_id', '=', 'servers.id') - ->paginate(20), - 'dbh' => Models\DatabaseServer::select( + 'databases' => Models\Database::with('server')->paginate(50), + 'hosts' => Models\DatabaseServer::select( 'database_servers.*', - 'nodes.name as a_linkedNode', DB::raw('(SELECT COUNT(*) FROM `databases` WHERE `databases`.`db_server` = database_servers.id) as c_databases') - )->leftJoin('nodes', 'nodes.id', '=', 'database_servers.linked_node') - ->paginate(20), + )->with('node')->paginate(20), ]); } public function getNew(Request $request) { return view('admin.databases.new', [ - 'nodes' => Models\Node::select('nodes.id', 'nodes.name', 'locations.long as a_location') - ->join('locations', 'locations.id', '=', 'nodes.location') - ->get(), + 'nodes' => Models\Node::all()->load('location'), ]); } @@ -78,15 +66,17 @@ class DatabaseController extends Controller { try { $repo = new DatabaseRepository; - $repo->add($request->except([ - '_token', + $repo->add($request->only([ + 'name', + 'host', + 'port', + 'username', + 'password', + 'linked_node', ])); - Alert::success('Successfully added a new database server to the system.')->flash(); - return redirect()->route('admin.databases', [ - 'tab' => 'tab_dbservers', - ]); + return redirect()->route('admin.databases', ['tab' => 'tab_dbservers']); } catch (DisplayValidationException $ex) { return redirect()->route('admin.databases.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (\Exception $ex) { diff --git a/app/Models/Database.php b/app/Models/Database.php index 99e768c29..c316d6e0a 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -55,7 +55,27 @@ class Database extends Model * @var array */ protected $casts = [ - 'server' => 'integer', + 'server_id' => 'integer', 'db_server' => 'integer', ]; + + /** + * Gets the host database server associated with a database. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function host() + { + return $this->hasOne(DatabaseServer::class, 'id', 'db_server'); + } + + /** + * Gets the server associated with a database. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function server() + { + return $this->hasOne(Server::class, 'id', 'server_id'); + } } diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseServer.php index 74fd88694..7713f59bf 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseServer.php @@ -59,4 +59,14 @@ class DatabaseServer extends Model 'server_id' => 'integer', 'db_server' => 'integer', ]; + + /** + * Gets the node associated with a database host. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function node() + { + return $this->hasOne(Node::class, 'id', 'linked_node'); + } } diff --git a/app/Models/Node.php b/app/Models/Node.php index 8e82ef935..0c4d8fb3c 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -53,7 +53,7 @@ class Node extends Model */ protected $casts = [ 'public' => 'integer', - 'location' => 'integer', + 'location_id' => 'integer', 'memory' => 'integer', 'disk' => 'integer', 'daemonListen' => 'integer', @@ -61,11 +61,34 @@ class Node extends Model ]; /** - * Fields that are not mass assignable. + * Fields that are mass assignable. * * @var array */ - protected $guarded = ['id', 'created_at', 'updated_at']; + protected $fillable = [ + 'uuid', + 'uuidShort', + 'node_id', + 'name', + 'suspended', + 'owner_id', + 'memory', + 'swap', + 'disk', + 'io', + 'cpu', + 'oom_disabled', + 'allocation_id', + 'service_id', + 'option_id', + 'pack_id', + 'startup', + 'daemonSecret', + 'image', + 'username', + 'sftp_password', + 'installed', + ]; /** * @var array @@ -193,4 +216,14 @@ class Node extends Model return json_encode($config, $json_options); } + + /** + * Gets the location associated with a node. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function location() + { + return $this->hasOne(Location::class, 'id', 'location_id'); + } } diff --git a/database/migrations/2017_02_03_140948_UpdateNodesTable.php b/database/migrations/2017_02_03_140948_UpdateNodesTable.php new file mode 100644 index 000000000..4408e612b --- /dev/null +++ b/database/migrations/2017_02_03_140948_UpdateNodesTable.php @@ -0,0 +1,40 @@ +dropForeign('nodes_location_foreign'); + $table->dropIndex('nodes_location_foreign'); + + $table->renameColumn('location', 'location_id'); + $table->foreign('location_id')->references('id')->on('locations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('nodes', function (Blueprint $table) { + $table->dropForeign('nodes_location_id_foreign'); + $table->dropIndex('nodes_location_id_foreign'); + + $table->renameColumn('location_id', 'location'); + $table->foreign('location')->references('id')->on('locations'); + }); + } +} diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index f45e70192..bb7be1e3f 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -52,20 +52,21 @@
{{ $db->a_serverName }}{{ $db->database }}{{ $db->username }} ({{ $db->remote }}){{ $db->a_host }}:{{ $db->a_port }}{{ $database->server->name }}{{ $database->database }}{{ $database->username }} ({{ $database->remote }}){{ $host->host }}:{{ $host->port }}
- {{ $databases->appends('tab', 'tab_databases')->render() }} + {{ $databases->appends(['tab' => 'tab_databases'])->links() }}
@@ -86,20 +87,20 @@ - @foreach($dbh as $db) + @foreach($hosts as $database) - {{ $db->name }} - {{ $db->host }}:{{ $db->port }} - {{ $db->username }} - {{ $db->c_databases }} - @if(is_null($db->a_linkedNode))unlinked@else{{ $db->a_linkedNode }}@endif - + {{ $database->name }} + {{ $database->host }}:{{ $database->port }} + {{ $database->username }} + {{ $database->c_databases }} + @if(is_null($database->node))unlinked@else{{ $database->node->name }}@endif + @endforeach
- {{ $dbh->appends('tab', 'tab_dbservers')->render() }} + {{ $hosts->appends('tab', 'tab_dbservers')->render() }}
diff --git a/resources/views/admin/databases/new.blade.php b/resources/views/admin/databases/new.blade.php index 24ff27007..c9625cd75 100644 --- a/resources/views/admin/databases/new.blade.php +++ b/resources/views/admin/databases/new.blade.php @@ -47,7 +47,7 @@

A linked node implies that this Database Server is running on that node and it will be auto-selected when adding a database to servers on that node.

From 09d23deed69edf6582e814d459e50682833c6852 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Feb 2017 16:50:28 -0500 Subject: [PATCH 037/112] New models for node and location admin pages. --- .../Controllers/Admin/LocationsController.php | 16 ++--- .../Controllers/Admin/NodesController.php | 71 +++++++++++-------- app/Models/Allocation.php | 4 +- app/Models/Node.php | 20 ++++++ app/Models/Server.php | 14 +++- app/Repositories/LocationRepository.php | 18 ++--- app/Repositories/NodeRepository.php | 12 +--- .../2017_02_03_155554_RenameColumns.php | 48 +++++++++++++ resources/views/admin/nodes/index.blade.php | 4 +- resources/views/admin/nodes/view.blade.php | 23 +++--- 10 files changed, 152 insertions(+), 78 deletions(-) create mode 100644 database/migrations/2017_02_03_155554_RenameColumns.php diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index 9ef004bed..93a45fb66 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -45,8 +45,8 @@ class LocationsController extends Controller return view('admin.locations.index', [ 'locations' => Models\Location::select( 'locations.*', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') )->paginate(20), ]); } @@ -55,8 +55,8 @@ class LocationsController extends Controller { $model = Models\Location::select( 'locations.id', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') )->where('id', $id)->first(); if (! $model) { @@ -80,12 +80,12 @@ class LocationsController extends Controller { try { $location = new LocationRepository; - $location->edit($id, $request->all()); + $location->edit($id, $request->only(['long', 'short'])); return response('', 204); } catch (DisplayValidationException $ex) { return response()->json([ - 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 10 characters with no spaces or special characters.', + 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 20 characters with no spaces or special characters.', ], 422); } catch (\Exception $ex) { // This gets caught and processed into JSON anyways. @@ -97,9 +97,7 @@ class LocationsController extends Controller { try { $location = new LocationRepository; - $id = $location->create($request->except([ - '_token', - ])); + $id = $location->create($request->only(['long', 'short'])); Alert::success('New location successfully added.')->flash(); return redirect()->route('admin.locations'); diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 600ecb932..9cfac1fde 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -48,17 +48,15 @@ class NodesController extends Controller public function getScript(Request $request, $id) { - return response()->view('admin.nodes.remote.deploy', ['node' => Models\Node::findOrFail($id)])->header('Content-Type', 'text/plain'); + return response()->view('admin.nodes.remote.deploy', [ + 'node' => Models\Node::findOrFail($id), + ])->header('Content-Type', 'text/plain'); } public function getIndex(Request $request) { return view('admin.nodes.index', [ - 'nodes' => Models\Node::select( - 'nodes.*', - 'locations.long as a_locationName', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id = nodes.id) as a_serverCount') - )->join('locations', 'nodes.location', '=', 'locations.id')->paginate(20), + 'nodes' => Models\Node::with('location')->withCount('servers')->paginate(20), ]); } @@ -78,15 +76,25 @@ class NodesController extends Controller public function postNew(Request $request) { try { - $node = new NodeRepository; - $new = $node->create($request->except([ - '_token', + $repo = new NodeRepository; + $node = $repo->create($request->only([ + 'name', + 'location', + 'public', + 'fqdn', + 'scheme', + 'memory', + 'memory_overallocate', + 'disk', + 'disk_overallocate', + 'daemonBase', + 'daemonSFTP', + 'daemonListen', ])); - Alert::success('Successfully created new node. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); - Alert::info('To simplify the node setup you can generate a token on the configuration tab.')->flash(); + Alert::success('Successfully created new node that can be configured automatically on your remote machine by visiting the configuration tab. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); return redirect()->route('admin.nodes.view', [ - 'id' => $new, + 'id' => $node->id, 'tab' => 'tab_allocation', ]); } catch (DisplayValidationException $e) { @@ -103,26 +111,18 @@ class NodesController extends Controller public function getView(Request $request, $id) { - $node = Models\Node::findOrFail($id); + $node = Models\Node::with( + 'servers.user', + 'servers.service', + 'servers.allocations', + 'location' + )->findOrFail($id); + $node->setRelation('allocations', $node->allocations()->paginate(40)); return view('admin.nodes.view', [ 'node' => $node, - 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName') - ->join('users', 'users.id', '=', 'servers.owner_id') - ->join('services', 'services.id', '=', 'servers.service_id') - ->where('node_id', $id)->paginate(10, ['*'], 'servers'), 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node_id', $node->id)->first(), 'locations' => Models\Location::all(), - 'allocations' => Models\Allocation::select('allocations.*', 'servers.name as assigned_to_name') - ->where('allocations.node', $node->id) - ->leftJoin('servers', 'servers.id', '=', 'allocations.assigned_to') - ->orderBy('allocations.ip', 'asc') - ->orderBy('allocations.port', 'asc') - ->paginate(20, ['*'], 'allocations'), - 'allocation_ips' => Models\Allocation::select('id', 'ip') - ->where('node', $node->id) - ->groupBy('ip') - ->get(), ]); } @@ -130,8 +130,21 @@ class NodesController extends Controller { try { $node = new NodeRepository; - $node->update($id, $request->except([ - '_token', + $node->update($id, $request->only([ + 'name', + 'location', + 'public', + 'fqdn', + 'scheme', + 'memory', + 'memory_overallocate', + 'disk', + 'disk_overallocate', + 'upload_size', + 'daemonBase', + 'daemonSFTP', + 'daemonListen', + 'reset_secret', ])); Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 10308ebdd..34b6baec5 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -48,8 +48,8 @@ class Allocation extends Model * @var array */ protected $casts = [ - 'node' => 'integer', + 'node_id' => 'integer', 'port' => 'integer', - 'assigned_to' => 'integer', + 'server_id' => 'integer', ]; } diff --git a/app/Models/Node.php b/app/Models/Node.php index 0c4d8fb3c..2be35568e 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -226,4 +226,24 @@ class Node extends Model { return $this->hasOne(Location::class, 'id', 'location_id'); } + + /** + * Gets the servers associated with a node. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class); + } + + /** + * Gets the allocations associated with a node. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function allocations() + { + return $this->hasMany(Allocation::class); + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index db8ba6381..f7e8bdbed 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -121,7 +121,7 @@ class Server extends Model 'services.name as a_serviceName', 'service_options.name as a_serviceOptionName' )->join('nodes', 'servers.node_id', '=', 'nodes.id') - ->join('locations', 'nodes.location', '=', 'locations.id') + ->join('locations', 'nodes.location_id', '=', 'locations.id') ->join('services', 'servers.service_id', '=', 'services.id') ->join('service_options', 'servers.option_id', '=', 'service_options.id') ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); @@ -218,6 +218,16 @@ class Server extends Model return Javascript::put($response); } + /** + * Gets the user who owns the server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function user() + { + return $this->hasOne(User::class, 'id', 'owner_id'); + } + /** * Gets all allocations associated with this server. * @@ -225,7 +235,7 @@ class Server extends Model */ public function allocations() { - return $this->hasMany(Allocation::class, 'assigned_to'); + return $this->hasMany(Allocation::class, 'server_id'); } /** diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index 79196ff35..e25446d31 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -44,7 +44,7 @@ class LocationRepository public function create(array $data) { $validator = Validator::make($data, [ - 'short' => 'required|regex:/^[a-z0-9_.-]{1,10}$/i|unique:locations,short', + 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short', 'long' => 'required|string|min:1|max:255', ]); @@ -73,9 +73,11 @@ class LocationRepository */ public function edit($id, array $data) { + $location = Models\Location::findOrFail($id); + $validator = Validator::make($data, [ - 'short' => 'regex:/^[a-z0-9_.-]{1,10}$/i', - 'long' => 'string|min:1|max:255', + 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short,' . $location->id, + 'long' => 'required|string|min:1|max:255', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -84,15 +86,7 @@ class LocationRepository throw new DisplayValidationException($validator->errors()); } - $location = Models\Location::findOrFail($id); - - if (isset($data['short'])) { - $location->short = $data['short']; - } - - if (isset($data['long'])) { - $location->long = $data['long']; - } + $location->fill($data); return $location->save(); } diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index d55446196..b9ba82e4b 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -65,7 +65,7 @@ class NodeRepository // Verify the FQDN if using SSL if (filter_var($data['fqdn'], FILTER_VALIDATE_IP) && $data['scheme'] === 'https') { - throw new DisplayException('A fully qualified domain name is required to use secure comunication on this node.'); + throw new DisplayException('A fully qualified domain name is required to use a secure comunication method on this node.'); } // Verify FQDN is resolvable, or if not using SSL that the IP is valid. @@ -86,7 +86,7 @@ class NodeRepository $node->fill($data); $node->save(); - return $node->id; + return $node; } public function update($id, array $data) @@ -152,18 +152,12 @@ class NodeRepository $oldDaemonKey = $node->daemonSecret; $node->update($data); try { - $client = Models\Node::guzzleRequest($node->id); - $client->request('PATCH', '/config', [ - 'headers' => [ - 'X-Access-Token' => $oldDaemonKey, - ], + $node->guzzleClient(['X-Access-Token' => $oldDaemonKey])->request('PATCH', '/config', [ 'json' => [ 'web' => [ 'listen' => $node->daemonListen, 'ssl' => [ 'enabled' => ($node->scheme === 'https'), - 'certificate' => '/etc/letsencrypt/live/' . $node->fqdn . '/fullchain.pem', - 'key' => '/etc/letsencrypt/live/' . $node->fqdn . '/privkey.pem', ], ], 'sftp' => [ diff --git a/database/migrations/2017_02_03_155554_RenameColumns.php b/database/migrations/2017_02_03_155554_RenameColumns.php new file mode 100644 index 000000000..519ccc826 --- /dev/null +++ b/database/migrations/2017_02_03_155554_RenameColumns.php @@ -0,0 +1,48 @@ +dropForeign('allocations_node_foreign'); + $table->dropForeign('allocations_assigned_to_foreign'); + $table->dropIndex('allocations_node_foreign'); + $table->dropIndex('allocations_assigned_to_foreign'); + + $table->renameColumn('node', 'node_id'); + $table->renameColumn('assigned_to', 'server_id'); + $table->foreign('node_id')->references('id')->on('nodes'); + $table->foreign('server_id')->references('id')->on('servers'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('allocations', function (Blueprint $table) { + $table->dropForeign('allocations_node_id_foreign'); + $table->dropForeign('allocations_server_id_foreign'); + $table->dropIndex('allocations_node_id_foreign'); + $table->dropIndex('allocations_server_id_foreign'); + + $table->renameColumn('node_id', 'node'); + $table->renameColumn('server_id', 'assigned_to'); + $table->foreign('node')->references('id')->on('nodes'); + $table->foreign('assigned_to')->references('id')->on('servers'); + }); + } +} diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 29546d4ea..de1687087 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -53,10 +53,10 @@ {{ $node->name }} - {{ $node->a_locationName }} + {{ $node->location->short }} {{ $node->memory }} MB {{ $node->disk }} MB - {{ $node->a_serverCount }} + {{ $node->servers_count }} diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 8485c9a50..5fa054703 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -60,7 +60,7 @@
  • Configuration
  • Allocation
  • Servers
  • - @if(count($servers) === 0)
  • Delete
  • @endif + @if(count($node->servers) === 0)
  • Delete
  • @endif
    @@ -83,7 +83,7 @@ Total Servers - {{ count($servers) }} + {{ count($node->servers) }} Memory Allocated @@ -309,7 +309,7 @@
    @@ -355,7 +355,7 @@ - @foreach($allocations as $allocation) + @foreach($node->allocations as $allocation) {{ $allocation->ip }} @@ -376,7 +376,7 @@
    - {{ $allocations->appends(['tab' => 'tab_allocation'])->links() }} + {{ $node->allocations->appends(['tab' => 'tab_allocation'])->render() }}
    @@ -402,11 +402,11 @@ - @foreach($servers as $server) + @foreach($node->servers as $server) {{ $server->name }} - {{ $server->a_ownerEmail }} - {{ $server->a_serviceName }} + {{ $server->user->email }} + {{ $server->service->name }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB {{ $server->disk }} MB -- % @@ -415,13 +415,10 @@ @endforeach -
    -
    {!! $servers->appends(['tab' => 'tab_servers'])->render() !!}
    -
    - @if(count($servers) === 0) + @if(count($node->servers) === 0)
    @@ -459,7 +456,7 @@
    From 323f1d943f17250b7ed2ab1506869b4bc479c93e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 17:58:17 -0500 Subject: [PATCH 038/112] Completed model updates for Services --- .../Controllers/API/ServiceController.php | 2 +- app/Http/Controllers/Admin/PackController.php | 80 ++++++------------- .../Controllers/Admin/ServersController.php | 4 +- .../Controllers/Admin/ServiceController.php | 71 ++++++++-------- .../Controllers/Server/ServerController.php | 2 +- app/Models/Service.php | 35 +++++++- app/Models/ServiceOptions.php | 24 +++++- app/Models/ServicePack.php | 10 +++ app/Models/ServiceVariables.php | 5 ++ app/Observers/ServerObserver.php | 2 +- app/Repositories/ServerRepository.php | 4 +- app/Repositories/ServiceRepository/Option.php | 2 +- app/Repositories/ServiceRepository/Pack.php | 31 ++++--- .../ServiceRepository/Service.php | 15 ++-- .../ServiceRepository/Variable.php | 28 +++++-- .../2017_02_05_164123_AdjustColumnNames.php | 40 ++++++++++ ...64516_AdjustColumnNamesForServicePacks.php | 40 ++++++++++ .../views/admin/services/index.blade.php | 2 +- .../admin/services/options/variable.blade.php | 6 +- .../admin/services/options/view.blade.php | 23 +++--- .../admin/services/packs/byoption.blade.php | 4 +- .../admin/services/packs/byservice.blade.php | 4 +- .../views/admin/services/packs/edit.blade.php | 12 +-- .../views/admin/services/packs/new.blade.php | 8 +- .../admin/services/packs/upload.blade.php | 8 +- resources/views/admin/services/view.blade.php | 4 +- 26 files changed, 299 insertions(+), 167 deletions(-) create mode 100644 database/migrations/2017_02_05_164123_AdjustColumnNames.php create mode 100644 database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 257ace766..81d5a955d 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -53,7 +53,7 @@ class ServiceController extends BaseController return [ 'service' => $service, 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') - ->where('parent_service', $service->id) + ->where('service_id', $service->id) ->with('variables') ->with('packs') ->get(), diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 628cd54b8..3e6685f28 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -42,64 +42,29 @@ class PackController extends Controller // } - protected function formatServices() - { - $options = Models\ServiceOptions::select( - 'services.name AS p_service', - 'service_options.id', - 'service_options.name' - )->join('services', 'services.id', '=', 'service_options.parent_service')->get(); - - $array = []; - foreach ($options as &$option) { - if (! array_key_exists($option->p_service, $array)) { - $array[$option->p_service] = []; - } - - $array[$option->p_service] = array_merge($array[$option->p_service], [[ - 'id' => $option->id, - 'name' => $option->name, - ]]); - } - - return $array; - } - public function listAll(Request $request) { - return view('admin.services.packs.index', [ - 'services' => Models\Service::all(), - ]); + return view('admin.services.packs.index', ['services' => Models\Service::all()]); } public function listByOption(Request $request, $id) { - $option = Models\ServiceOptions::findOrFail($id); - return view('admin.services.packs.byoption', [ - 'packs' => Models\ServicePack::where('option', $option->id)->get(), - 'service' => Models\Service::findOrFail($option->parent_service), - 'option' => $option, + 'option' => Models\ServiceOptions::with('service', 'packs')->findOrFail($id) ]); } public function listByService(Request $request, $id) { return view('admin.services.packs.byservice', [ - 'service' => Models\Service::findOrFail($id), - 'options' => Models\ServiceOptions::select( - 'service_options.id', - 'service_options.name', - DB::raw('(SELECT COUNT(id) FROM service_packs WHERE service_packs.option = service_options.id) AS p_count') - )->where('parent_service', $id)->get(), + 'service' => Models\Service::with('options', 'options.packs')->findOrFail($id), ]); } public function new(Request $request, $opt = null) { return view('admin.services.packs.new', [ - 'services' => $this->formatServices(), - 'packFor' => $opt, + 'services' => Models\Service::with('options')->get(), ]); } @@ -107,12 +72,18 @@ class PackController extends Controller { try { $repo = new Pack; - $id = $repo->create($request->except([ - '_token', + $pack = $repo->create($request->only([ + 'name', + 'version', + 'description', + 'option', + 'selectable', + 'visible', + 'file_upload', ])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.packs.edit', $id)->withInput(); + return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.packs.new', $request->input('option'))->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -127,15 +98,12 @@ class PackController extends Controller public function edit(Request $request, $id) { - $pack = Models\ServicePack::findOrFail($id); - $option = Models\ServiceOptions::select('id', 'parent_service', 'name')->where('id', $pack->option)->first(); + $pack = Models\ServicePack::with('option.service')->findOrFail($id); return view('admin.services.packs.edit', [ 'pack' => $pack, - 'services' => $this->formatServices(), + 'services' => Models\Service::all()->load('options'), 'files' => Storage::files('packs/' . $pack->uuid), - 'service' => Models\Service::findOrFail($option->parent_service), - 'option' => $option, ]); } @@ -159,8 +127,13 @@ class PackController extends Controller } else { try { $repo = new Pack; - $repo->update($id, $request->except([ - '_token', + $repo->update($id, $request->only([ + 'name', + 'version', + 'description', + 'option', + 'selectable', + 'visible', ])); Alert::success('Service pack has been successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -215,8 +188,7 @@ class PackController extends Controller public function uploadForm(Request $request, $for = null) { return view('admin.services.packs.upload', [ - 'services' => $this->formatServices(), - 'for' => $for, + 'services' => Models\Service::all()->load('options'), ]); } @@ -224,12 +196,10 @@ class PackController extends Controller { try { $repo = new Pack; - $id = $repo->createWithTemplate($request->except([ - '_token', - ])); + $pack = $repo->createWithTemplate($request->only(['option', 'file_upload'])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.packs.edit', $id)->withInput(); + return redirect()->route('admin.services.packs.edit', $pack->id)->withInput(); } catch (DisplayValidationException $ex) { return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index f75508139..eee134d3e 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -244,7 +244,7 @@ class ServersController extends Controller $service = Models\Service::select('executable', 'startup')->where('id', $request->input('service'))->first(); - return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get()); + return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('service_id', $request->input('service'))->orderBy('name', 'asc')->get()); } /** @@ -264,7 +264,7 @@ class ServersController extends Controller $option = Models\ServiceOptions::select( DB::raw('COALESCE(service_options.executable, services.executable) as executable'), DB::raw('COALESCE(service_options.startup, services.startup) as startup') - )->leftJoin('services', 'services.id', '=', 'service_options.parent_service') + )->leftJoin('services', 'services.id', '=', 'service_options.service_id') ->where('service_options.id', $request->input('option')) ->first(); diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 70de4f88e..f8951993a 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -45,10 +45,7 @@ class ServiceController extends Controller public function getIndex(Request $request) { return view('admin.services.index', [ - 'services' => Models\Service::select( - 'services.*', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.service = services.id) as c_servers') - )->get(), + 'services' => Models\Service::withCount('servers')->get(), ]); } @@ -61,12 +58,16 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $id = $repo->create($request->except([ - '_token', + $service = $repo->create($request->only([ + 'name', + 'description', + 'file', + 'executable', + 'startup', ])); Alert::success('Successfully created new service!')->flash(); - return redirect()->route('admin.services.service', $id); + return redirect()->route('admin.services.service', $service->id); } catch (DisplayValidationException $ex) { return redirect()->route('admin.services.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -82,11 +83,7 @@ class ServiceController extends Controller public function getService(Request $request, $service) { return view('admin.services.view', [ - 'service' => Models\Service::findOrFail($service), - 'options' => Models\ServiceOptions::select( - 'service_options.*', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.option = service_options.id) as c_servers') - )->where('parent_service', $service)->get(), + 'service' => Models\Service::with('options', 'options.servers')->findOrFail($service), ]); } @@ -94,8 +91,12 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->update($service, $request->except([ - '_token', + $repo->update($service, $request->only([ + 'name', + 'description', + 'file', + 'executable', + 'startup', ])); Alert::success('Successfully updated this service.')->flash(); } catch (DisplayValidationException $ex) { @@ -130,16 +131,11 @@ class ServiceController extends Controller public function getOption(Request $request, $service, $option) { - $opt = Models\ServiceOptions::findOrFail($option); + $option = Models\ServiceOptions::with('service', 'variables')->findOrFail($option); + $option->setRelation('servers', $option->servers()->with('user')->paginate(25)); return view('admin.services.options.view', [ - 'service' => Models\Service::findOrFail($opt->parent_service), - 'option' => $opt, - 'variables' => Models\ServiceVariables::where('option_id', $option)->get(), - 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail') - ->join('users', 'users.id', '=', 'servers.owner_id') - ->where('option', $option) - ->paginate(10), + 'option' => $option, ]); } @@ -147,8 +143,13 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Option; - $repo->update($option, $request->except([ - '_token', + $repo->update($option, $request->only([ + 'name', + 'description', + 'tag', + 'executable', + 'docker_image', + 'startup', ])); Alert::success('Option settings successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -164,13 +165,12 @@ class ServiceController extends Controller public function deleteOption(Request $request, $service, $option) { try { - $service = Models\ServiceOptions::select('parent_service')->where('id', $option)->first(); $repo = new ServiceRepository\Option; $repo->delete($option); Alert::success('Successfully deleted that option.')->flash(); - return redirect()->route('admin.services.service', $service->parent_service); + return redirect()->route('admin.services.service', $service); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { @@ -218,8 +218,7 @@ class ServiceController extends Controller public function getNewVariable(Request $request, $service, $option) { return view('admin.services.options.variable', [ - 'service' => Models\Service::findOrFail($service), - 'option' => Models\ServiceOptions::where('parent_service', $service)->where('id', $option)->firstOrFail(), + 'option' => Models\ServiceOptions::with('service')->findOrFail($option), ]); } @@ -227,8 +226,15 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Variable; - $repo->create($option, $request->except([ - '_token', + $repo->create($option, $request->only([ + 'name', + 'description', + 'env_variable', + 'default_value', + 'user_viewable', + 'user_editable', + 'required', + 'regex', ])); Alert::success('Successfully added new variable to this option.')->flash(); @@ -305,8 +311,9 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->updateFile($serviceId, $request->except([ - '_token', + $repo->updateFile($serviceId, $request->only([ + 'file', + 'contents', ])); return response('', 204); diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 75378ddc1..12fb41ad1 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -224,7 +224,7 @@ class ServerController extends Controller $service = Models\Service::select( DB::raw('IFNULL(service_options.executable, services.executable) as executable') - )->leftJoin('service_options', 'service_options.parent_service', '=', 'services.id') + )->leftJoin('service_options', 'service_options.service_id', '=', 'services.id') ->where('service_options.id', $server->option_id) ->where('services.id', $server->service_id) ->first(); diff --git a/app/Models/Service.php b/app/Models/Service.php index 8c0f27790..d7900b632 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -40,5 +40,38 @@ class Service extends Model * * @var array */ - protected $guarded = ['id', 'created_at', 'updated_at']; + protected $fillable = ['id', 'created_at', 'updated_at']; + + /** + * Gets all service options associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function options() + { + return $this->hasMany(ServiceOptions::class); + } + + /** + * Returns all of the packs associated with a service, regardless of the service option. + * + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function packs() + { + return $this->hasManyThrough( + 'Pterodactyl\Models\ServicePack', 'Pterodactyl\Models\ServiceOptions', + 'service_id', 'option_id' + ); + } + + /** + * Gets all servers associated with this service. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class); + } } diff --git a/app/Models/ServiceOptions.php b/app/Models/ServiceOptions.php index 9b4a3a7ae..9cd61a702 100644 --- a/app/Models/ServiceOptions.php +++ b/app/Models/ServiceOptions.php @@ -48,9 +48,29 @@ class ServiceOptions extends Model * @var array */ protected $casts = [ - 'parent_service' => 'integer', + 'service_id' => 'integer', ]; + /** + * Gets service associated with a service option. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function service() + { + return $this->belongsTo(Service::class); + } + + /** + * Gets all servers associated with this service option. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class, 'option_id'); + } + /** * Gets all variables associated with this service. * @@ -68,6 +88,6 @@ class ServiceOptions extends Model */ public function packs() { - return $this->hasMany(ServicePack::class, 'option'); + return $this->hasMany(ServicePack::class, 'option_id'); } } diff --git a/app/Models/ServicePack.php b/app/Models/ServicePack.php index cefcc0a32..7c9a624ff 100644 --- a/app/Models/ServicePack.php +++ b/app/Models/ServicePack.php @@ -56,4 +56,14 @@ class ServicePack extends Model 'selectable' => 'boolean', 'visible' => 'boolean', ]; + + /** + * Gets option associated with a service pack. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function option() + { + return $this->belongsTo(ServiceOptions::class); + } } diff --git a/app/Models/ServiceVariables.php b/app/Models/ServiceVariables.php index 5082d714e..f088202e7 100644 --- a/app/Models/ServiceVariables.php +++ b/app/Models/ServiceVariables.php @@ -53,4 +53,9 @@ class ServiceVariables extends Model 'user_editable' => 'integer', 'required' => 'integer', ]; + + public function serverVariables() + { + return $this->hasMany(ServerVariables::class, 'variable_id'); + } } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index cacb9c82f..626847aa4 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -62,7 +62,7 @@ class ServerObserver $user = Models\User::findOrFail($server->owner_id); $node = Models\Node::select('name')->where('id', $server->node_id)->first(); $service = Models\Service::select('services.name', 'service_options.name as optionName') - ->join('service_options', 'service_options.parent_service', '=', 'services.id') + ->join('service_options', 'service_options.service_id', '=', 'services.id') ->where('services.id', $server->service_id) ->where('service_options.id', $server->option_id) ->first(); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 3cd3d32ba..fe2a2f840 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -163,7 +163,7 @@ class ServerRepository // We know the service and option exists because of the validation. // We need to verify that the option exists for the service, and then check for // any required variable fields. (fields are labeled env_) - $option = Models\ServiceOptions::where('id', $data['option'])->where('parent_service', $data['service'])->first(); + $option = Models\ServiceOptions::where('id', $data['option'])->where('service_id', $data['service'])->first(); if (! $option) { throw new DisplayException('The requested service option does not exist for the specified service.'); } @@ -181,7 +181,7 @@ class ServerRepository } // Load up the Service Information - $service = Models\Service::find($option->parent_service); + $service = Models\Service::find($option->service_id); // Check those Variables $variables = Models\ServiceVariables::where('option_id', $data['option'])->get(); diff --git a/app/Repositories/ServiceRepository/Option.php b/app/Repositories/ServiceRepository/Option.php index 8ddcdc006..ddac543d6 100644 --- a/app/Repositories/ServiceRepository/Option.php +++ b/app/Repositories/ServiceRepository/Option.php @@ -63,7 +63,7 @@ class Option } $option = new Models\ServiceOptions; - $option->parent_service = $service->id; + $option->service_id = $service->id; $option->fill($data); $option->save(); diff --git a/app/Repositories/ServiceRepository/Pack.php b/app/Repositories/ServiceRepository/Pack.php index 03858ed67..c3cc2dc9c 100644 --- a/app/Repositories/ServiceRepository/Pack.php +++ b/app/Repositories/ServiceRepository/Pack.php @@ -69,8 +69,8 @@ class Pack try { $uuid = new UuidService; $pack = Models\ServicePack::create([ - 'option' => $data['option'], - 'uuid' => $uuid->generate('servers', 'uuid'), + 'option_id' => $data['option'], + 'uuid' => $uuid->generate('service_packs', 'uuid'), 'name' => $data['name'], 'version' => $data['version'], 'description' => (empty($data['description'])) ? null : $data['description'], @@ -89,7 +89,7 @@ class Pack throw $ex; } - return $pack->id; + return $pack; } public function createWithTemplate(array $data) @@ -123,7 +123,7 @@ class Pack } $json = json_decode($zip->getFromName('import.json')); - $id = $this->create([ + $pack = $this->create([ 'name' => $json->name, 'version' => $json->version, 'description' => $json->description, @@ -132,7 +132,6 @@ class Pack 'visible' => $json->visible, ]); - $pack = Models\ServicePack::findOrFail($id); if (! $zip->extractTo(storage_path('app/packs/' . $pack->uuid), 'archive.tar.gz')) { $pack->delete(); throw new DisplayException('Unable to extract the archive file to the correct location.'); @@ -140,7 +139,7 @@ class Pack $zip->close(); - return $pack->id; + return $pack; } else { $json = json_decode(file_get_contents($data['file_upload']->path())); @@ -170,18 +169,16 @@ class Pack throw new DisplayValidationException($validator->errors()); } - DB::transaction(function () use ($id, $data) { - Models\ServicePack::findOrFail($id)->update([ - 'option' => $data['option'], - 'name' => $data['name'], - 'version' => $data['version'], - 'description' => (empty($data['description'])) ? null : $data['description'], - 'selectable' => isset($data['selectable']), - 'visible' => isset($data['visible']), - ]); + Models\ServicePack::findOrFail($id)->update([ + 'option_id' => $data['option'], + 'name' => $data['name'], + 'version' => $data['version'], + 'description' => (empty($data['description'])) ? null : $data['description'], + 'selectable' => isset($data['selectable']), + 'visible' => isset($data['visible']), + ]); - return true; - }); + return; } public function delete($id) diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index eb41a9fee..fd6ffe629 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -55,23 +55,18 @@ class Service $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); - $service = new Models\Service; DB::beginTransaction(); - try { - $service->fill($data); - $service->save(); - - Storage::put('services/' . $data['file'] . '/main.json', '{}'); - Storage::copy('services/.templates/index.js', 'services/' . $data['file'] . '/index.js'); - + $service = Models\Service::create($data); + Storage::put('services/' . $service->file . '/main.json', '{}'); + Storage::copy('services/.templates/index.js', 'services/' . $service->file . '/index.js'); DB::commit(); } catch (\Exception $ex) { DB::rollBack(); throw $ex; } - return $service->id; + return $service; } public function update($id, array $data) @@ -99,7 +94,7 @@ class Service { $service = Models\Service::findOrFail($id); $servers = Models\Server::where('service', $service->id)->get(); - $options = Models\ServiceOptions::select('id')->where('parent_service', $service->id); + $options = Models\ServiceOptions::select('id')->where('service_id', $service->id); if (count($servers) !== 0) { throw new DisplayException('You cannot delete a service that has servers associated with it.'); diff --git a/app/Repositories/ServiceRepository/Variable.php b/app/Repositories/ServiceRepository/Variable.php index fbd258444..bc7ab4c13 100644 --- a/app/Repositories/ServiceRepository/Variable.php +++ b/app/Repositories/ServiceRepository/Variable.php @@ -39,7 +39,7 @@ class Variable public function create($id, array $data) { - $option = Models\ServiceOptions::findOrFail($id); + $option = Models\ServiceOptions::select('id')->findOrFail($id); $validator = Validator::make($data, [ 'name' => 'required|string|min:1|max:255', @@ -67,21 +67,22 @@ class Variable $data['user_viewable'] = (isset($data['user_viewable']) && in_array((int) $data['user_viewable'], [0, 1])) ? $data['user_viewable'] : 0; $data['user_editable'] = (isset($data['user_editable']) && in_array((int) $data['user_editable'], [0, 1])) ? $data['user_editable'] : 0; $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : 0; + $data['option_id'] = $option->id; - $variable = new Models\ServiceVariables; - $variable->option_id = $option->id; - $variable->fill($data); + $variable = Models\ServiceVariables::create($data); - return $variable->save(); + return $variable; } public function delete($id) { - $variable = Models\ServiceVariables::findOrFail($id); + $variable = Models\ServiceVariables::with('serverVariables')->findOrFail($id); DB::beginTransaction(); try { - Models\ServerVariables::where('variable_id', $variable->id)->delete(); + foreach($variable->serverVariables as $svar) { + $svar->delete(); + } $variable->delete(); DB::commit(); @@ -125,7 +126,18 @@ class Variable $data['user_editable'] = (isset($data['user_editable']) && in_array((int) $data['user_editable'], [0, 1])) ? $data['user_editable'] : $variable->user_editable; $data['required'] = (isset($data['required']) && in_array((int) $data['required'], [0, 1])) ? $data['required'] : $variable->required; - $variable->fill($data); + // Not using $data because the function that passes into this function + // can't do $requst->only() due to the page setup. + $variable->fill([ + 'name' => $data['name'], + 'description' => $data['description'], + 'env_variable' => $data['env_variable'], + 'default_value' => $data['default_value'], + 'user_viewable' => $data['user_viewable'], + 'user_editable' => $data['user_editable'], + 'required' => $data['required'], + 'regex' => $data['regex'], + ]); return $variable->save(); } diff --git a/database/migrations/2017_02_05_164123_AdjustColumnNames.php b/database/migrations/2017_02_05_164123_AdjustColumnNames.php new file mode 100644 index 000000000..ddb37b891 --- /dev/null +++ b/database/migrations/2017_02_05_164123_AdjustColumnNames.php @@ -0,0 +1,40 @@ +dropForeign('service_options_parent_service_foreign'); + $table->dropIndex('service_options_parent_service_foreign'); + + $table->renameColumn('parent_service', 'service_id'); + $table->foreign('service_id')->references('id')->on('services'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('service_options', function (Blueprint $table) { + $table->dropForeign('service_options_service_id_foreign'); + $table->dropIndex('service_options_service_id_foreign'); + + $table->renameColumn('service_id', 'parent_service'); + $table->foreign('parent_service')->references('id')->on('services'); + }); + } +} diff --git a/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php new file mode 100644 index 000000000..5e57ffef3 --- /dev/null +++ b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php @@ -0,0 +1,40 @@ +dropForeign('service_packs_option_foreign'); + $table->dropIndex('service_packs_option_foreign'); + + $table->renameColumn('option', 'option_id'); + $table->foreign('option_id')->references('id')->on('service_options'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('service_packs', function (Blueprint $table) { + $table->dropForeign('service_packs_option_id_foreign'); + $table->dropIndex('service_packs_option_id_foreign'); + + $table->renameColumn('option_id', 'option'); + $table->foreign('option')->references('id')->on('service_options'); + }); + } +} diff --git a/resources/views/admin/services/index.blade.php b/resources/views/admin/services/index.blade.php index 453f1582f..c97df4cf1 100644 --- a/resources/views/admin/services/index.blade.php +++ b/resources/views/admin/services/index.blade.php @@ -44,7 +44,7 @@ {{ $service->name }} {!! $service->description !!} - {{ $service->c_servers }} + {{ $service->servers_count }} @endforeach diff --git a/resources/views/admin/services/options/variable.blade.php b/resources/views/admin/services/options/variable.blade.php index 2c8ff8957..5ed9540c3 100644 --- a/resources/views/admin/services/options/variable.blade.php +++ b/resources/views/admin/services/options/variable.blade.php @@ -28,12 +28,12 @@

    New Option Variable


    -
    +
    diff --git a/resources/views/admin/services/options/view.blade.php b/resources/views/admin/services/options/view.blade.php index e3eb61a12..f40bc8154 100644 --- a/resources/views/admin/services/options/view.blade.php +++ b/resources/views/admin/services/options/view.blade.php @@ -28,12 +28,12 @@
    Warning! This page contains advanced settings that the panel and daemon use to control servers. Modifying information on this page is not recommended unless you are absolutely sure of what you are doing.

    Settings


    - +
    @@ -74,7 +74,7 @@
    - +

    To use the default startup of the parent service simply leave this field blank.

    @@ -88,9 +88,9 @@
    -

    Variables


    - @foreach($variables as $variable) -
    +

    Variables


    + @foreach($option->variables as $variable) +
    @@ -158,7 +158,7 @@
    {!! csrf_field() !!} - +
    @@ -175,16 +175,19 @@ - @foreach ($servers as $server) + @foreach ($option->servers as $server) {{ $server->name }} - {{ $server->a_ownerEmail }} + {{ $server->user->email }} {{ $server->updated_at }} @endforeach - +
    + {!! $option->servers->render() !!} +
    +
    diff --git a/resources/views/admin/services/packs/byoption.blade.php b/resources/views/admin/services/packs/byoption.blade.php index 23dbf2951..f781a3a3c 100644 --- a/resources/views/admin/services/packs/byoption.blade.php +++ b/resources/views/admin/services/packs/byoption.blade.php @@ -29,7 +29,7 @@
  • Admin Control
  • Services
  • Packs
  • -
  • {{ $service->name }}
  • +
  • {{ $option->service->name }}
  • {{ $option->name }}
  • Service Packs


    @@ -44,7 +44,7 @@ - @foreach ($packs as $pack) + @foreach ($option->packs as $pack) {{ $pack->name }} {{ $pack->version }} diff --git a/resources/views/admin/services/packs/byservice.blade.php b/resources/views/admin/services/packs/byservice.blade.php index 8475de289..f36ce4e4c 100644 --- a/resources/views/admin/services/packs/byservice.blade.php +++ b/resources/views/admin/services/packs/byservice.blade.php @@ -40,10 +40,10 @@ - @foreach ($options as $option) + @foreach ($service->options as $option) {{ $option->name }} - {{ $option->p_count }} + {{ $option->packs->count() }} @endforeach diff --git a/resources/views/admin/services/packs/edit.blade.php b/resources/views/admin/services/packs/edit.blade.php index dcb67d5df..cc6470b3b 100644 --- a/resources/views/admin/services/packs/edit.blade.php +++ b/resources/views/admin/services/packs/edit.blade.php @@ -29,8 +29,8 @@
  • Admin Control
  • Services
  • Packs
  • -
  • {{ $service->name }}
  • -
  • {{ $option->name }}
  • +
  • {{ $pack->option->service->name }}
  • +
  • {{ $pack->option->name }}
  • {{ $pack->name }} ({{ $pack->version }})
  • Manage Service Pack


    @@ -62,10 +62,10 @@
    diff --git a/resources/views/admin/services/packs/new.blade.php b/resources/views/admin/services/packs/new.blade.php index 82601bc62..d5b0440da 100644 --- a/resources/views/admin/services/packs/new.blade.php +++ b/resources/views/admin/services/packs/new.blade.php @@ -59,10 +59,10 @@
    diff --git a/resources/views/admin/services/packs/upload.blade.php b/resources/views/admin/services/packs/upload.blade.php index e9ca020fa..cb5e548d8 100644 --- a/resources/views/admin/services/packs/upload.blade.php +++ b/resources/views/admin/services/packs/upload.blade.php @@ -12,10 +12,10 @@
    diff --git a/resources/views/admin/services/view.blade.php b/resources/views/admin/services/view.blade.php index 887478aca..6b660a5ac 100644 --- a/resources/views/admin/services/view.blade.php +++ b/resources/views/admin/services/view.blade.php @@ -41,12 +41,12 @@ - @foreach($options as $option) + @foreach($service->options as $option) {{ $option->name }} {!! $option->description !!} {{ $option->tag }} - {{ $option->c_servers }} + {{ $option->servers->count() }} @endforeach From b1389262e2c333d740e889e0d96baf3651133db1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 18:00:39 -0500 Subject: [PATCH 039/112] Use belongsTo versus hasOne when more logical. --- app/Models/Database.php | 8 ++++---- app/Models/DatabaseServer.php | 4 ++-- app/Models/Node.php | 4 ++-- app/Models/Server.php | 16 ++++++++-------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/Models/Database.php b/app/Models/Database.php index c316d6e0a..b5e9d39ad 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -62,20 +62,20 @@ class Database extends Model /** * Gets the host database server associated with a database. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function host() { - return $this->hasOne(DatabaseServer::class, 'id', 'db_server'); + return $this->belongsTo(DatabaseServer::class, 'db_server'); } /** * Gets the server associated with a database. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function server() { - return $this->hasOne(Server::class, 'id', 'server_id'); + return $this->belongsTo(Server::class); } } diff --git a/app/Models/DatabaseServer.php b/app/Models/DatabaseServer.php index 7713f59bf..c71d1b8d7 100644 --- a/app/Models/DatabaseServer.php +++ b/app/Models/DatabaseServer.php @@ -63,10 +63,10 @@ class DatabaseServer extends Model /** * Gets the node associated with a database host. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function node() { - return $this->hasOne(Node::class, 'id', 'linked_node'); + return $this->belongsTo(Node::class, 'linked_node'); } } diff --git a/app/Models/Node.php b/app/Models/Node.php index 2be35568e..936682644 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -220,11 +220,11 @@ class Node extends Model /** * Gets the location associated with a node. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function location() { - return $this->hasOne(Location::class, 'id', 'location_id'); + return $this->belongsTo(Location::class); } /** diff --git a/app/Models/Server.php b/app/Models/Server.php index f7e8bdbed..abe512e69 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -221,11 +221,11 @@ class Server extends Model /** * Gets the user who owns the server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function user() { - return $this->hasOne(User::class, 'id', 'owner_id'); + return $this->belongsTo(User::class, 'owner_id'); } /** @@ -251,21 +251,21 @@ class Server extends Model /** * Gets information for the service associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function service() { - return $this->hasOne(Service::class, 'id', 'service_id'); + return $this->belongsTo(Service::class); } /** * Gets information for the service option associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function option() { - return $this->hasOne(ServiceOptions::class, 'id', 'option_id'); + return $this->belongsTo(ServiceOptions::class); } /** @@ -281,11 +281,11 @@ class Server extends Model /** * Gets information for the node associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\HasOne + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function node() { - return $this->hasOne(Node::class, 'id', 'node_id'); + return $this->belongsTo(Node::class); } /** From 02458c909d3110a56004e3da5ed19afe16077f12 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 5 Feb 2017 19:19:46 -0500 Subject: [PATCH 040/112] Improves server model and cleans up model code calls. --- .../Controllers/API/User/InfoController.php | 2 +- app/Http/Controllers/Base/IndexController.php | 2 +- app/Models/Allocation.php | 11 +++++ app/Models/Server.php | 46 +++++------------ app/Models/Subuser.php | 33 ++----------- app/Models/User.php | 49 +++++++++++++++---- .../themes/pterodactyl/base/index.blade.php | 4 +- .../pterodactyl/layouts/master.blade.php | 4 +- 8 files changed, 71 insertions(+), 80 deletions(-) diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 228a66819..844e493dc 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -32,7 +32,7 @@ class InfoController extends BaseController { public function me(Request $request) { - return Models\Server::getUserServers()->map(function ($server) { + return $request->user()->serverAccessCollection()->map(function ($server) { return [ 'id' => $server->uuidShort, 'uuid' => $server->uuid, diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 160bc67e6..e59ceb068 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -48,7 +48,7 @@ class IndexController extends Controller public function getIndex(Request $request) { return view('base.index', [ - 'servers' => Server::getUserServers(10), + 'servers' => $request->user()->serverAccessCollection(10)->load('node', 'allocation'), ]); } diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 34b6baec5..2df21976f 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -52,4 +52,15 @@ class Allocation extends Model 'port' => 'integer', 'server_id' => 'integer', ]; + + /** + * Accessor to automatically provide the IP alias if defined. + * + * @param null|string $value + * @return string + */ + public function getAliasAttribute($value) + { + return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias; + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index abe512e69..ff63af0e5 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -103,40 +103,6 @@ class Server extends Model self::$user = Auth::user(); } - /** - * Returns array of all servers owned by the logged in user. - * Returns all users servers if user is a root admin. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public static function getUserServers($paginate = null) - { - $query = self::select( - 'servers.*', - 'nodes.name as nodeName', - 'locations.short as a_locationShort', - 'allocations.ip', - 'allocations.ip_alias', - 'allocations.port', - 'services.name as a_serviceName', - 'service_options.name as a_serviceOptionName' - )->join('nodes', 'servers.node_id', '=', 'nodes.id') - ->join('locations', 'nodes.location_id', '=', 'locations.id') - ->join('services', 'servers.service_id', '=', 'services.id') - ->join('service_options', 'servers.option_id', '=', 'service_options.id') - ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); - - if (self::$user->root_admin !== 1) { - $query->whereIn('servers.id', Subuser::accessServers()); - } - - if (is_numeric($paginate)) { - return $query->paginate($paginate); - } - - return $query->get(); - } - /** * Returns a single server specified by UUID. * DO NOT USE THIS TO MODIFY SERVER DETAILS OR SAVE THOSE DETAILS. @@ -150,7 +116,7 @@ class Server extends Model $query = self::with('service', 'node')->where('uuidShort', $uuid)->orWhere('uuid', $uuid); if (! Auth::user()->isRootAdmin()) { - $query->whereIn('id', Subuser::accessServers()); + $query->whereIn('id', Auth::user()->serverAccessArray()); } $result = $query->first(); @@ -228,6 +194,16 @@ class Server extends Model return $this->belongsTo(User::class, 'owner_id'); } + /** + * Gets the default allocation for a server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function allocation() + { + return $this->hasOne(Allocation::class, 'id', 'allocation_id'); + } + /** * Gets all allocations associated with this server. * diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 8d4a5b133..ea855d671 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -55,33 +55,8 @@ class Subuser extends Model * * @var array */ - protected $casts = [ - 'user_id' => 'integer', - 'server_id' => 'integer', - ]; - - /** - * @var mixed - */ - protected static $user; - - /** - * Constructor. - */ - public function __construct() - { - self::$user = Auth::user(); - } - - /** - * Returns an array of each server ID that the user has access to. - * - * @return array - */ - public static function accessServers() - { - $union = self::select('server_id')->where('user_id', self::$user->id); - - return Server::select('id')->where('owner', self::$user->id)->union($union)->pluck('id'); - } + protected $casts = [ + 'user_id' => 'integer', + 'server_id' => 'integer', + ]; } diff --git a/app/Models/User.php b/app/Models/User.php index 7dba0cf0d..1714dcebf 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -87,16 +87,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac */ protected $hidden = ['password', 'remember_token', 'totp_secret']; - /** - * Determines if a user has permissions. - * - * @return bool - */ - public function permissions() - { - return $this->hasMany(Permission::class); - } - /** * Enables or disables TOTP on an account if the token is valid. * @@ -176,4 +166,43 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return $subuser->daemonSecret; } + + /** + * Returns all permissions that a user has. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(Permission::class); + } + + /** + * Returns an array of all servers a user is able to access. + * Note: does not account for user admin status. + * + * @return array + */ + public function serverAccessArray() + { + $union = Subuser::select('server_id')->where('user_id', $this->id); + + return Server::select('id')->where('owner_id', $this->id)->union($union)->pluck('id')->all(); + } + + /** + * Returns an array of all servers a user is able to access. + * Note: does not account for user admin status. + * + * @return Collection + */ + public function serverAccessCollection($paginate = null) + { + $query = Server::with('service', 'node'); + if (! $this->isRootAdmin()) { + $query->whereIn('id', $this->serverAccessArray()); + } + + return (is_numeric($paginate)) ? $query->paginate($paginate) : $query->get(); + } } diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index d029a37a9..71efda93f 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -62,8 +62,8 @@ {{ $server->uuidShort }} {{ $server->name }} - {{ $server->node_idName }} - @if(!is_null($server->ip_alias)){{ $server->ip_alias }}@else{{ $server->ip }}@endif:{{ $server->port }} + {{ $server->node->name }} + {{ $server->allocation->alias }}:{{ $server->allocation->port }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB -- % diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 57c7383e0..d478bd372 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -245,7 +245,7 @@
    - @if(count($databases) > 0) + @if(count($server->databases) > 0)
    @@ -426,12 +432,12 @@ - @foreach($databases as $database) + @foreach($server->databases as $database) - + @endforeach @@ -568,7 +574,7 @@ $(document).ready(function () { 'X-Access-Token': '{{ $server->daemonSecret }}', 'X-Access-Server': '{{ $server->uuid }}' }, - url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server', + url: '{{ $server->node->scheme }}://{{ $server->node->fqdn }}:{{ $server->node->daemonListen }}/server', dataType: 'json', timeout: 5000, }).done(function (data) { diff --git a/resources/views/admin/users/view.blade.php b/resources/views/admin/users/view.blade.php index 314fc8ba7..3ba9ec035 100644 --- a/resources/views/admin/users/view.blade.php +++ b/resources/views/admin/users/view.blade.php @@ -39,7 +39,7 @@
    - +
    @@ -64,7 +64,7 @@
    {!! csrf_field() !!} - +
    @@ -72,7 +72,7 @@
    - +
    @@ -83,7 +83,7 @@
    - +
    {{ $database->database }} {{ $database->username }} ({{ $database->remote }}) {{ Crypt::decrypt($database->password) }} {{ $database->a_host }}:{{ $database->a_port }}{{ $database->host->host }}:{{ $database->host->port }}
    @@ -112,12 +112,12 @@ - @foreach($servers as $server) + @foreach($user->servers as $server) - + @@ -127,7 +127,7 @@ @else
    There are no servers associated with this account.
    @endif - +
    From c8f6c93d26445ef8bc366612c82d84514bc650b8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 9 Feb 2017 18:44:07 -0500 Subject: [PATCH 043/112] Modify subusers model setup --- app/Models/Permission.php | 33 ++++++--- app/Models/Subuser.php | 10 +++ app/Models/User.php | 4 +- app/Policies/ServerPolicy.php | 34 ++++----- ...2_09_174834_SetupPermissionsPivotTable.php | 72 +++++++++++++++++++ 5 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 008473f3c..391f5e8d2 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -42,22 +42,35 @@ class Permission extends Model */ protected $guarded = ['id', 'created_at', 'updated_at']; - /** - * Cast values to correct type. - * - * @var array - */ - protected $casts = [ - 'user_id' => 'integer', - 'server_id' => 'integer', - ]; + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'subuser_id' => 'integer', + ]; + /** + * Find permission by permission node. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $permission + * @return \Illuminate\Database\Query\Builder + */ public function scopePermission($query, $permission) { return $query->where('permission', $permission); } - public function scopeServer($query, $server) + /** + * Filter permission by server. + * + * @param \Illuminate\Database\Query\Builder $query + * @param \Pterodactyl\Models\Server $server + * @return \Illuminate\Database\Query\Builder + */ + public function scopeServer($query, Server $server) { return $query->where('server_id', $server->id); } diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 826995d0c..6d390df95 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -79,4 +79,14 @@ class Subuser extends Model { return $this->belongsTo(User::class); } + + /** + * Gets the permissions associated with a subuser. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(Pemission::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 6d1bfa19b..abcddf227 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -199,11 +199,11 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac /** * Returns all permissions that a user has. * - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough */ public function permissions() { - return $this->hasMany(Permission::class); + return $this->hasManyThrough(Permission::class, Subuser::class); } /** diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 3ef54f436..d67f3aced 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -39,6 +39,23 @@ class ServerPolicy // } + /** + * Checks if the user has the given permission on/for the server. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\Server $server + * @param $permission + * @return bool + */ + private function checkPermission(User $user, Server $server, $permission) + { + if ($this->isOwner($user, $server)) { + return true; + } + + return $user->permissions()->server($server)->permission($permission)->exists(); + } + /** * Determine if current user is the owner of a server. * @@ -521,21 +538,4 @@ class ServerPolicy { return $this->checkPermission($user, $server, 'set-allocation'); } - - /** - * Checks if the user has the given permission on/for the server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @param $permission - * @return bool - */ - private function checkPermission(User $user, Server $server, $permission) - { - if ($this->isOwner($user, $server)) { - return true; - } - - return $user->permissions()->server($server)->permission($permission)->exists(); - } } diff --git a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php new file mode 100644 index 000000000..fe87c4f77 --- /dev/null +++ b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php @@ -0,0 +1,72 @@ +unsignedInteger('subuser_id')->after('id'); + }); + + DB::transaction(function () { + foreach(Subuser::all() as &$subuser) { + Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->update([ + 'subuser_id' => $subuser->id, + ]); + } + }); + + Schema::table('permissions', function (Blueprint $table) { + $table->dropForeign('permissions_server_id_foreign'); + $table->dropIndex('permissions_server_id_foreign'); + $table->dropForeign('permissions_user_id_foreign'); + $table->dropIndex('permissions_user_id_foreign'); + + $table->dropColumn('server_id'); + $table->dropColumn('user_id'); + $table->foreign('subuser_id')->references('id')->on('subusers'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('permissions', function (Blueprint $table) { + $table->unsignedInteger('server_id')->after('subuser_id'); + $table->unsignedInteger('user_id')->after('server_id'); + }); + + DB::transaction(function () { + foreach(Subuser::all() as &$subuser) { + Permission::where('subuser_id', $subuser->id)->update([ + 'user_id' => $subuser->user_id, + 'server_id' => $subuser->server_id, + ]); + } + }); + + Schema::table('permissions', function (Blueprint $table) { + $table->dropForeign('permissions_subuser_id_foreign'); + $table->dropIndex('permissions_subuser_id_foreign'); + $table->dropColumn('subuser_id'); + + $table->foreign('server_id')->references('id')->on('servers'); + $table->foreign('user_id')->references('id')->on('users'); + }); + } +} From 99812b040731b90854598ce8c48c3a2fc0572b97 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 9 Feb 2017 19:38:54 -0500 Subject: [PATCH 044/112] More subuser Model updates. --- .../Controllers/Server/SubuserController.php | 45 +++++-------------- app/Models/Permission.php | 8 ++++ app/Models/Server.php | 10 +++++ app/Models/Subuser.php | 2 +- app/Repositories/SubuserRepository.php | 21 +++++---- ...2_09_174834_SetupPermissionsPivotTable.php | 3 ++ .../pterodactyl/server/users/index.blade.php | 16 +++---- .../pterodactyl/server/users/view.blade.php | 4 +- 8 files changed, 54 insertions(+), 55 deletions(-) diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index ed25d4a2c..76735e351 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -49,7 +49,7 @@ class SubuserController extends Controller public function getIndex(Request $request, $uuid) { - $server = Models\Server::byUuid($uuid); + $server = Models\Server::byUuid($uuid)->load('subusers.user'); $this->authorize('list-subusers', $server); $server->js(); @@ -57,35 +57,17 @@ class SubuserController extends Controller return view('server.users.index', [ 'server' => $server, 'node' => $server->node, - 'subusers' => Models\Subuser::select('subusers.*', 'users.email', 'users.username', 'users.use_totp') - ->join('users', 'users.id', '=', 'subusers.user_id') - ->where('server_id', $server->id) - ->get(), + 'subusers' => $server->subusers, ]); } public function getView(Request $request, $uuid, $id) { - $server = Models\Server::byUuid($uuid); + $server = Models\Server::byUuid($uuid)->load('node'); $this->authorize('view-subuser', $server); - $subuser = Models\Subuser::select('subusers.*', 'users.email as a_userEmail') - ->join('users', 'users.id', '=', 'subusers.user_id') - ->where(DB::raw('md5(subusers.id)'), $id)->where('subusers.server_id', $server->id) - ->first(); - - if (! $subuser) { - abort(404); - } - - $permissions = []; - $modelPermissions = Models\Permission::select('permission') - ->where('user_id', $subuser->user_id)->where('server_id', $server->id) - ->get(); - - foreach ($modelPermissions as &$perm) { - $permissions[$perm->permission] = true; - } + $subuser = Models\Subuser::with('permissions', 'user') + ->where('server_id', $server->id)->findOrFail($id); $server->js(); @@ -93,7 +75,9 @@ class SubuserController extends Controller 'server' => $server, 'node' => $server->node, 'subuser' => $subuser, - 'permissions' => $permissions, + 'permissions' => $subuser->permissions->mapWithKeys(function ($item, $key) { + return [$item->permission => true]; + }), ]); } @@ -102,12 +86,10 @@ class SubuserController extends Controller $server = Models\Server::byUuid($uuid); $this->authorize('edit-subuser', $server); - $subuser = Models\Subuser::where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); + $subuser = Models\Subuser::where('server_id', $server->id)->findOrFail($id); try { - if (! $subuser) { - throw new DisplayException('Unable to locate a subuser by that ID.'); - } elseif ($subuser->user_id === Auth::user()->id) { + if ($subuser->user_id === Auth::user()->id) { throw new DisplayException('You are not authorized to edit you own account.'); } @@ -163,7 +145,7 @@ class SubuserController extends Controller return redirect()->route('server.subusers.view', [ 'uuid' => $uuid, - 'id' => md5($subuser->id), + 'id' => $subuser->id, ]); } catch (DisplayValidationException $ex) { return redirect()->route('server.subusers.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); @@ -183,10 +165,7 @@ class SubuserController extends Controller $this->authorize('delete-subuser', $server); try { - $subuser = Models\Subuser::select('id')->where(DB::raw('md5(id)'), $id)->where('server_id', $server->id)->first(); - if (! $subuser) { - throw new DisplayException('No subuser by that ID was found on the system.'); - } + $subuser = Models\Subuser::where('server_id', $server->id)->findOrFail($id); $repo = new SubuserRepository; $repo->delete($subuser->id); diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 391f5e8d2..fe7221719 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -28,6 +28,14 @@ use Illuminate\Database\Eloquent\Model; class Permission extends Model { + + /** + * Should timestamps be used on this model. + * + * @var boolean + */ + public $timestamps = false; + /** * The table associated with the model. * diff --git a/app/Models/Server.php b/app/Models/Server.php index 3ea72e2b9..1ce041ca7 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -196,6 +196,16 @@ class Server extends Model return $this->belongsTo(User::class, 'owner_id'); } + /** + * Gets the subusers associated with a server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function subusers() + { + return $this->hasMany(Subuser::class); + } + /** * Gets the default allocation for a server. * diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 6d390df95..25a82f615 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -87,6 +87,6 @@ class Subuser extends Model */ public function permissions() { - return $this->hasMany(Pemission::class); + return $this->hasMany(Permission::class); } } diff --git a/app/Repositories/SubuserRepository.php b/app/Repositories/SubuserRepository.php index 94a8ccecb..4e4691dda 100644 --- a/app/Repositories/SubuserRepository.php +++ b/app/Repositories/SubuserRepository.php @@ -167,8 +167,7 @@ class SubuserRepository } Models\Permission::create([ - 'user_id' => $user->id, - 'server_id' => $server->id, + 'subuser_id' => $subuser->id, 'permission' => $permission, ]); } @@ -213,14 +212,12 @@ class SubuserRepository */ public function delete($id) { - $subuser = Models\Subuser::with('server.node', 'permissions')->findOrFail($id); + $subuser = Models\Subuser::with('server.node')->findOrFail($id); $server = $subuser->server; DB::beginTransaction(); try { - Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); - $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, 'X-Access-Token' => $server->node->daemonSecret, @@ -232,6 +229,9 @@ class SubuserRepository ], ]); + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } $subuser->delete(); DB::commit(); @@ -273,7 +273,9 @@ class SubuserRepository DB::beginTransaction(); try { - Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } $daemonPermissions = $this->coreDaemonPermissions; foreach ($data['permissions'] as $permission) { @@ -282,13 +284,10 @@ class SubuserRepository if (! is_null($this->permissions[$permission])) { array_push($daemonPermissions, $this->permissions[$permission]); } - $model = new Models\Permission; - $model->fill([ - 'user_id' => $data['user'], - 'server_id' => $data['server'], + Models\Permission::create([ + 'subuser_id' => $subuser->id, 'permission' => $permission, ]); - $model->save(); } } diff --git a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php index fe87c4f77..ce5e3ae89 100644 --- a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php +++ b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php @@ -35,6 +35,8 @@ class SetupPermissionsPivotTable extends Migration $table->dropColumn('server_id'); $table->dropColumn('user_id'); + $table->dropColumn('created_at'); + $table->dropColumn('updated_at'); $table->foreign('subuser_id')->references('id')->on('subusers'); }); } @@ -49,6 +51,7 @@ class SetupPermissionsPivotTable extends Migration Schema::table('permissions', function (Blueprint $table) { $table->unsignedInteger('server_id')->after('subuser_id'); $table->unsignedInteger('user_id')->after('server_id'); + $table->timestamps(); }); DB::transaction(function () { diff --git a/resources/themes/pterodactyl/server/users/index.blade.php b/resources/themes/pterodactyl/server/users/index.blade.php index f44849758..daffcb611 100644 --- a/resources/themes/pterodactyl/server/users/index.blade.php +++ b/resources/themes/pterodactyl/server/users/index.blade.php @@ -51,29 +51,29 @@ @can('view-subuser', $server)
    @endcan @can('delete-subuser', $server)@endcan - @foreach($subusers as $user) + @foreach($subusers as $subuser) - - + + - + @can('view-subuser', $server) @endcan @can('delete-subuser', $server) diff --git a/resources/themes/pterodactyl/server/users/view.blade.php b/resources/themes/pterodactyl/server/users/view.blade.php index b697edc34..925fbdf05 100644 --- a/resources/themes/pterodactyl/server/users/view.blade.php +++ b/resources/themes/pterodactyl/server/users/view.blade.php @@ -35,7 +35,7 @@ @section('content') @can('edit-subuser', $server) - + @endcan
    @@ -45,7 +45,7 @@
    {!! csrf_field() !!} - +
    From 0720bfe62f4fad89158b00f0fecab3111b92e365 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:03:58 -0500 Subject: [PATCH 045/112] Cleanup database query code. --- app/Http/Controllers/Admin/DatabaseController.php | 5 +---- resources/views/admin/databases/index.blade.php | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index 6cfa73041..1b7dcb5a2 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -48,10 +48,7 @@ class DatabaseController extends Controller { return view('admin.databases.index', [ 'databases' => Models\Database::with('server')->paginate(50), - 'hosts' => Models\DatabaseServer::select( - 'database_servers.*', - DB::raw('(SELECT COUNT(*) FROM `databases` WHERE `databases`.`db_server` = database_servers.id) as c_databases') - )->with('node')->paginate(20), + 'hosts' => Models\DatabaseServer::withCount('databases')->with('node')->paginate(20), ]); } diff --git a/resources/views/admin/databases/index.blade.php b/resources/views/admin/databases/index.blade.php index bb7be1e3f..f1c2a4aac 100644 --- a/resources/views/admin/databases/index.blade.php +++ b/resources/views/admin/databases/index.blade.php @@ -92,7 +92,7 @@ - + From ba175e6b55348e0bf9b5bc81d979e6f247aa9019 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:09:56 -0500 Subject: [PATCH 046/112] Cleanup location model and controller for Admin. --- .../Controllers/Admin/LocationsController.php | 24 ++++--------------- app/Models/Location.php | 20 ++++++++++++++++ .../views/admin/locations/index.blade.php | 4 ++-- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index d74f05d18..4f6343e5f 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -43,35 +43,21 @@ class LocationsController extends Controller public function getIndex(Request $request) { return view('admin.locations.index', [ - 'locations' => Models\Location::select( - 'locations.*', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') - )->paginate(20), + 'locations' => Models\Location::withCount('nodes', 'servers')->paginate(20), ]); } public function deleteLocation(Request $request, $id) { - $model = Models\Location::select( - 'locations.id', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') - )->where('id', $id)->first(); + $location = Models\Location::withCount('nodes')->findOrFail($id); - if (! $model) { + if ($location->nodes_count > 0) { return response()->json([ - 'error' => 'No location with that ID exists on the system.', - ], 404); - } - - if ($model->a_nodeCount > 0 || $model->a_serverCount > 0) { - return response()->json([ - 'error' => 'You cannot remove a location that is currently assigned to a node or server.', + 'error' => 'You cannot remove a location that is currently assigned to a node.', ], 422); } - $model->delete(); + $location->delete(); return response('', 204); } diff --git a/app/Models/Location.php b/app/Models/Location.php index 5c8feb9fa..f9ceec767 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -41,4 +41,24 @@ class Location extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Gets the nodes in a specificed location. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function nodes() + { + return $this->hasMany(Node::class); + } + + /** + * Gets the servers within a given location. + * + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function servers() + { + return $this->hasManyThrough(Server::class, Node::class); + } } diff --git a/resources/views/admin/locations/index.blade.php b/resources/views/admin/locations/index.blade.php index 9aaf49faa..2fbd4b05a 100644 --- a/resources/views/admin/locations/index.blade.php +++ b/resources/views/admin/locations/index.blade.php @@ -46,8 +46,8 @@ - - + + From efef3568706e77f71214c5ec4160c0e4d00ba6b4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:18:46 -0500 Subject: [PATCH 047/112] Assorted model code updates. --- .../Controllers/Admin/NodesController.php | 26 ++++-------- app/Http/Controllers/Admin/PackController.php | 16 ++----- .../Controllers/Admin/ServersController.php | 14 ++----- .../Controllers/Admin/ServiceController.php | 42 +++++-------------- app/Http/Controllers/Admin/UserController.php | 16 ++----- 5 files changed, 31 insertions(+), 83 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 9cfac1fde..fc32f3929 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -112,10 +112,8 @@ class NodesController extends Controller public function getView(Request $request, $id) { $node = Models\Node::with( - 'servers.user', - 'servers.service', - 'servers.allocations', - 'location' + 'servers.user', 'servers.service', + 'servers.allocations', 'location' )->findOrFail($id); $node->setRelation('allocations', $node->allocations()->paginate(40)); @@ -131,20 +129,12 @@ class NodesController extends Controller try { $node = new NodeRepository; $node->update($id, $request->only([ - 'name', - 'location', - 'public', - 'fqdn', - 'scheme', - 'memory', - 'memory_overallocate', - 'disk', - 'disk_overallocate', - 'upload_size', - 'daemonBase', - 'daemonSFTP', - 'daemonListen', - 'reset_secret', + 'name', 'location', 'public', + 'fqdn', 'scheme', 'memory', + 'memory_overallocate', 'disk', + 'disk_overallocate', 'upload_size', + 'daemonBase', 'daemonSFTP', + 'daemonListen', 'reset_secret', ])); Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 3e6685f28..c86e2ada4 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -73,12 +73,8 @@ class PackController extends Controller try { $repo = new Pack; $pack = $repo->create($request->only([ - 'name', - 'version', - 'description', - 'option', - 'selectable', - 'visible', + 'name', 'version', 'description', + 'option', 'selectable', 'visible', 'file_upload', ])); Alert::success('Successfully created new service!')->flash(); @@ -128,12 +124,8 @@ class PackController extends Controller try { $repo = new Pack; $repo->update($id, $request->only([ - 'name', - 'version', - 'description', - 'option', - 'selectable', - 'visible', + 'name', 'version', 'description', + 'option', 'selectable', 'visible', ])); Alert::success('Service pack has been successfully updated.')->flash(); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index d287e7819..b68f8d01c 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -279,13 +279,9 @@ class ServersController extends Controller try { $server = new ServerRepository; $server->changeBuild($id, $request->only([ - 'default', - 'add_additional', - 'remove_additional', - 'memory', - 'swap', - 'io', - 'cpu', + 'default', 'add_additional', + 'remove_additional', 'memory', + 'swap', 'io', 'cpu', ])); Alert::success('Server details were successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -377,9 +373,7 @@ class ServersController extends Controller try { $repo = new DatabaseRepository; $repo->create($id, $request->only([ - 'db_server', - 'database', - 'remote', + 'db_server', 'database', 'remote', ])); Alert::success('Added new database to this server.')->flash(); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index f8951993a..5aad76fd3 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -59,11 +59,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $service = $repo->create($request->only([ - 'name', - 'description', - 'file', - 'executable', - 'startup', + 'name', 'description', 'file', + 'executable', 'startup', ])); Alert::success('Successfully created new service!')->flash(); @@ -92,11 +89,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Service; $repo->update($service, $request->only([ - 'name', - 'description', - 'file', - 'executable', - 'startup', + 'name', 'description', 'file', + 'executable', 'startup', ])); Alert::success('Successfully updated this service.')->flash(); } catch (DisplayValidationException $ex) { @@ -134,9 +128,7 @@ class ServiceController extends Controller $option = Models\ServiceOptions::with('service', 'variables')->findOrFail($option); $option->setRelation('servers', $option->servers()->with('user')->paginate(25)); - return view('admin.services.options.view', [ - 'option' => $option, - ]); + return view('admin.services.options.view', ['option' => $option]); } public function postOption(Request $request, $service, $option) @@ -144,12 +136,8 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Option; $repo->update($option, $request->only([ - 'name', - 'description', - 'tag', - 'executable', - 'docker_image', - 'startup', + 'name', 'description', 'tag', + 'executable', 'docker_image', 'startup', ])); Alert::success('Option settings successfully updated.')->flash(); } catch (DisplayValidationException $ex) { @@ -227,14 +215,9 @@ class ServiceController extends Controller try { $repo = new ServiceRepository\Variable; $repo->create($option, $request->only([ - 'name', - 'description', - 'env_variable', - 'default_value', - 'user_viewable', - 'user_editable', - 'required', - 'regex', + 'name', 'description', 'env_variable', + 'default_value', 'user_viewable', + 'user_editable', 'required', 'regex', ])); Alert::success('Successfully added new variable to this option.')->flash(); @@ -311,10 +294,7 @@ class ServiceController extends Controller { try { $repo = new ServiceRepository\Service; - $repo->updateFile($serviceId, $request->only([ - 'file', - 'contents', - ])); + $repo->updateFile($serviceId, $request->only(['file', 'contents'])); return response('', 204); } catch (DisplayException $ex) { diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index eef57a895..5ebce1b42 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -88,12 +88,8 @@ class UserController extends Controller try { $user = new UserRepository; $userid = $user->create($request->only([ - 'email', - 'password', - 'name_first', - 'name_last', - 'username', - 'root_admin', + 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', ])); Alert::success('Account has been successfully created.')->flash(); @@ -113,12 +109,8 @@ class UserController extends Controller try { $repo = new UserRepository; $repo->update($user, $request->only([ - 'email', - 'password', - 'name_first', - 'name_last', - 'username', - 'root_admin', + 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', ])); Alert::success('User account was successfully updated.')->flash(); } catch (DisplayValidationException $ex) { From 3b3002b77a73375aee5f230d25e401632aeb2e46 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:29:10 -0500 Subject: [PATCH 048/112] API Model updates. --- app/Http/Controllers/Base/APIController.php | 14 +++---- app/Models/APIKey.php | 10 +++++ app/Repositories/APIRepository.php | 4 +- ...7_02_10_171858_UpdateAPIKeyColumnNames.php | 38 +++++++++++++++++++ 4 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index 611638c95..2130ee760 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -38,13 +38,8 @@ class APIController extends Controller { public function index(Request $request) { - $keys = Models\APIKey::where('user', $request->user()->id)->get(); - foreach ($keys as &$key) { - $key->permissions = Models\APIPermission::where('key_id', $key->id)->get(); - } - return view('base.api.index', [ - 'keys' => $keys, + 'keys' => Models\APIKey::where('user_id', $request->user()->id)->get(), ]); } @@ -57,8 +52,11 @@ class APIController extends Controller { try { $repo = new APIRepository($request->user()); - $secret = $repo->create($request->except(['_token'])); - Alert::success('An API Keypair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

    ' . $secret . '')->flash(); + $secret = $repo->create($request->only([ + 'memo', 'allowed_ips', + 'adminPermissions', 'permissions', + ])); + Alert::success('An API Key-Pair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

    ' . $secret . '')->flash(); return redirect()->route('account.api'); } catch (DisplayValidationException $ex) { diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index 4b94b6782..68e481712 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -48,4 +48,14 @@ class APIKey extends Model * @var array */ protected $guarded = ['id', 'created_at', 'updated_at']; + + /** + * Gets the permissions associated with a key. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function permissions() + { + return $this->hasMany(APIPermission::class, 'key_id'); + } } diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 7ce94f34b..382e6a274 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -102,7 +102,7 @@ class APIRepository { $this->user = is_null($user) ? Auth::user() : $user; if (is_null($this->user)) { - throw new \Exception('Cannot access API Repository without passing a user to __construct().'); + throw new \Exception('Cannot access API Repository without passing a user to constructor.'); } } @@ -178,7 +178,7 @@ class APIRepository } } - if ($this->user->root_admin === 1 && isset($data['adminPermissions'])) { + if ($this->user->isRootAdmin() && isset($data['adminPermissions'])) { foreach ($data['adminPermissions'] as $permNode) { if (! strpos($permNode, ':')) { continue; diff --git a/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php new file mode 100644 index 000000000..358f9938d --- /dev/null +++ b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php @@ -0,0 +1,38 @@ +dropForeign('api_keys_user_foreign')->dropIndex('api_keys_user_foreign'); + + $table->renameColumn('user', 'user_id'); + $table->foreign('user_id')->references('id')->on('users'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('api_keys', function (Blueprint $table) { + $table->dropForeign('api_keys_user_id_foreign')->dropIndex('api_keys_user_id_foreign'); + + $table->renameColumn('user_id', 'user'); + $table->foreign('user')->references('id')->on('users'); + }); + } +} From c70d31c08f1f2d6c0bb95d7db790c8b064c6f0d1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:36:58 -0500 Subject: [PATCH 049/112] More model updates. --- .../Controllers/Base/SecurityController.php | 3 +-- .../Controllers/Remote/RemoteController.php | 17 ++++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/Base/SecurityController.php b/app/Http/Controllers/Base/SecurityController.php index cf8bf2dc1..23b6f0d68 100644 --- a/app/Http/Controllers/Base/SecurityController.php +++ b/app/Http/Controllers/Base/SecurityController.php @@ -118,8 +118,7 @@ class SecurityController extends Controller public function revoke(Request $request, $id) { - $session = Session::where('id', $id)->where('user_id', $request->user()->id)->firstOrFail(); - $session->delete(); + Session::where('user_id', $request->user()->id)->findOrFail($id)->delete(); return redirect()->route('account.security'); } diff --git a/app/Http/Controllers/Remote/RemoteController.php b/app/Http/Controllers/Remote/RemoteController.php index 0f168c04b..95ff6ab3e 100644 --- a/app/Http/Controllers/Remote/RemoteController.php +++ b/app/Http/Controllers/Remote/RemoteController.php @@ -28,7 +28,6 @@ use Carbon\Carbon; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Services\NotificationService; class RemoteController extends Controller { @@ -42,7 +41,7 @@ class RemoteController extends Controller public function postDownload(Request $request) { - $download = Models\Download::where('token', $request->input('token', '00'))->first(); + $download = Models\Download::where('token', $request->input('token'))->first(); if (! $download) { return response()->json([ 'error' => 'An invalid request token was recieved with this request.', @@ -59,18 +58,17 @@ class RemoteController extends Controller public function postInstall(Request $request) { - $server = Models\Server::where('uuid', $request->input('server'))->first(); + $server = Models\Server::where('uuid', $request->input('server'))->with('node')->first(); if (! $server) { return response()->json([ 'error' => 'No server by that ID was found on the system.', ], 422); } - $node = Models\Node::findOrFail($server->node_id); $hmac = $request->input('signed'); $status = $request->input('installed'); - if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { + if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $server->node->daemonSecret, true)) { return response()->json([ 'error' => 'Signed HMAC was invalid.', ], 403); @@ -86,17 +84,15 @@ class RemoteController extends Controller public function event(Request $request) { - $server = Models\Server::where('uuid', $request->input('server'))->first(); + $server = Models\Server::where('uuid', $request->input('server'))->with('node')->first(); if (! $server) { return response()->json([ 'error' => 'No server by that ID was found on the system.', ], 422); } - $node = Models\Node::findOrFail($server->node_id); - $hmac = $request->input('signed'); - if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $node->daemonSecret, true)) { + if (base64_decode($hmac) !== hash_hmac('sha256', $server->uuid, $server->node->daemonSecret, true)) { return response()->json([ 'error' => 'Signed HMAC was invalid.', ], 403); @@ -130,7 +126,6 @@ class RemoteController extends Controller $token->delete(); // Manually as getConfigurationAsJson() returns it in correct format already - return response($node->getConfigurationAsJson(), 200) - ->header('Content-Type', 'application/json'); + return response()->json($node->getConfigurationAsJson(), 200); } } From 8dc1f41b73c7211b39e1dd8bbeacee01f1700641 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 17:41:56 -0500 Subject: [PATCH 050/112] More code cleanup. --- app/Repositories/APIRepository.php | 2 +- app/Services/NotificationService.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 382e6a274..14348b2db 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -149,7 +149,7 @@ class APIRepository $secretKey = str_random(16) . '.' . str_random(7) . '.' . str_random(7); $key = new Models\APIKey; $key->fill([ - 'user' => $this->user->id, + 'user_id' => $this->user->id, 'public' => str_random(16), 'secret' => Crypt::encrypt($secretKey), 'allowed_ips' => empty($this->allowed) ? null : json_encode($this->allowed), diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index abd2155b1..53a6e0ff9 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -48,7 +48,6 @@ class NotificationService public function __construct(Server $server) { $this->server = $server; - $this->user = User::findOrFail($server->owner_id); } public function pass(array $notification) From 32a1dc17eddd8e1d69180607cbdad8ceb2670c62 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 10 Feb 2017 20:26:38 -0500 Subject: [PATCH 051/112] API model updates, as well as general model updates and code fixes. --- .../Controllers/API/LocationController.php | 13 +- app/Http/Controllers/API/NodeController.php | 118 +++++------------- app/Http/Controllers/API/ServerController.php | 81 +++++------- .../Controllers/API/ServiceController.php | 11 +- .../Controllers/API/User/InfoController.php | 15 +-- .../Controllers/API/User/ServerController.php | 21 ++-- app/Http/Controllers/API/UserController.php | 44 +++---- .../Controllers/Admin/ServersController.php | 13 +- app/Http/Middleware/APISecretToken.php | 2 +- app/Models/Node.php | 28 +---- app/Repositories/APIRepository.php | 2 +- app/Repositories/NodeRepository.php | 14 +-- app/Repositories/ServerRepository.php | 48 +++---- resources/views/admin/nodes/new.blade.php | 4 +- resources/views/admin/nodes/view.blade.php | 4 +- resources/views/admin/servers/new.blade.php | 16 +-- 16 files changed, 162 insertions(+), 272 deletions(-) diff --git a/app/Http/Controllers/API/LocationController.php b/app/Http/Controllers/API/LocationController.php index 3bae975d8..94ec5fe7d 100755 --- a/app/Http/Controllers/API/LocationController.php +++ b/app/Http/Controllers/API/LocationController.php @@ -49,11 +49,12 @@ class LocationController extends BaseController */ public function lists(Request $request) { - return Location::select('locations.*', DB::raw('GROUP_CONCAT(nodes.id) as nodes')) - ->join('nodes', 'locations.id', '=', 'nodes.location') - ->groupBy('locations.id') - ->get()->each(function ($location) { - $location->nodes = explode(',', $location->nodes); - })->all(); + return Location::with('nodes')->get()->map(function ($item) { + $item->nodes->transform(function ($item) { + return collect($item)->only(['id', 'name', 'fqdn', 'scheme', 'daemonListen', 'daemonSFTP']); + }); + + return $item; + })->toArray(); } } diff --git a/app/Http/Controllers/API/NodeController.php b/app/Http/Controllers/API/NodeController.php index 0eda949f4..fd87770f7 100755 --- a/app/Http/Controllers/API/NodeController.php +++ b/app/Http/Controllers/API/NodeController.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Http\Controllers\API; +use Log; use Pterodactyl\Models; use Illuminate\Http\Request; use Dingo\Api\Exception\ResourceException; @@ -96,15 +97,21 @@ class NodeController extends BaseController public function create(Request $request) { try { - $node = new NodeRepository; - $new = $node->create($request->all()); + $repo = new NodeRepository; + $node = $repo->create($request->only([ + 'name', 'location_id', 'public', 'fqdn', + 'scheme', 'memory', 'memory_overallocate', + 'disk', 'disk_overallocate', 'daemonBase', + 'daemonSFTP', 'daemonListen', + ])); - return ['id' => $new]; + return ['id' => $repo->id]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { throw new ResourceException($ex->getMessage()); - } catch (\Exception $e) { + } catch (\Exception $ex) { + Log::error($ex); throw new BadRequestHttpException('There was an error while attempting to add this node to the system.'); } } @@ -124,88 +131,35 @@ class NodeController extends BaseController */ public function view(Request $request, $id, $fields = null) { - $node = Models\Node::where('id', $id); + $node = Models\Node::with('allocations')->where('id', $id)->first(); + if (! $node) { + throw new NotFoundHttpException('No node by that ID was found.'); + } + + $node->allocations->transform(function ($item) { + return collect($item)->only([ + 'id', 'ip', 'ip_alias', 'port', 'server_id' + ]); + }); if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $node->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($node)->only($fields); } } - try { - if (! $node->first()) { - throw new NotFoundHttpException('No node by that ID was found.'); - } - - return [ - 'node' => $node->first(), - 'allocations' => [ - 'assigned' => Models\Allocation::where('node', $id)->whereNotNull('assigned_to')->get(), - 'unassigned' => Models\Allocation::where('node', $id)->whereNull('assigned_to')->get(), - ], - ]; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return $node; } public function config(Request $request, $id) { - if (! $request->secure()) { - throw new BadRequestHttpException('This API route can only be accessed using a secure connection.'); - } - $node = Models\Node::where('id', $id)->first(); if (! $node) { throw new NotFoundHttpException('No node by that ID was found.'); } - return [ - 'web' => [ - 'listen' => $node->daemonListen, - 'host' => '0.0.0.0', - 'ssl' => [ - 'enabled' => ($node->scheme === 'https'), - 'certificate' => '/etc/certs/' . $node->fqdn . '/fullchain.pem', - 'key' => '/etc/certs/' . $node->fqdn . '/privkey.pem', - ], - ], - 'docker' => [ - 'socket' => '/var/run/docker.sock', - 'autoupdate_images' => true, - ], - 'sftp' => [ - 'path' => $node->daemonBase, - 'port' => (int) $node->daemonSFTP, - 'container' => 'ptdl-sftp', - ], - 'query' => [ - 'kill_on_fail' => true, - 'fail_limit' => 5, - ], - 'logger' => [ - 'path' => 'logs/', - 'src' => false, - 'level' => 'info', - 'period' => '1d', - 'count' => 3, - ], - 'remote' => [ - 'base' => config('app.url'), - 'download' => route('remote.download'), - 'installed' => route('remote.install'), - ], - 'uploads' => [ - 'size_limit' => $node->upload_size, - ], - 'keys' => [ - $node->daemonSecret, - ], - ]; + return $node->getConfigurationAsJson(); } /** @@ -219,12 +173,7 @@ class NodeController extends BaseController */ public function allocations(Request $request) { - $allocations = Models\Allocation::all(); - if ($allocations->count() < 1) { - throw new NotFoundHttpException('No allocations have been created.'); - } - - return $allocations; + return Models\Allocation::all()->toArray(); } /** @@ -238,18 +187,7 @@ class NodeController extends BaseController */ public function allocationsView(Request $request, $id) { - $query = Models\Allocation::where('assigned_to', $id)->get(); - try { - if (empty($query)) { - throw new NotFoundHttpException('No allocations for that server were found.'); - } - - return $query; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return Models\Allocation::where('assigned_to', $id)->get()->toArray(); } /** diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API/ServerController.php index 24a2bc00e..e6b2add2c 100755 --- a/app/Http/Controllers/API/ServerController.php +++ b/app/Http/Controllers/API/ServerController.php @@ -72,10 +72,10 @@ class ServerController extends BaseController public function create(Request $request) { try { - $server = new ServerRepository; - $new = $server->create($request->all()); + $repo = new ServerRepository; + $server = $repo->create($request->all()); - return ['id' => $new]; + return ['id' => $server->id]; } catch (DisplayValidationException $ex) { throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); } catch (DisplayException $ex) { @@ -101,58 +101,38 @@ class ServerController extends BaseController */ public function view(Request $request, $id) { - $query = Models\Server::where('id', $id); + $server = Models\Server::with('node', 'allocations', 'pack')->where('id', $id)->first(); + if (! $server) { + throw new NotFoundHttpException('No server by that ID was found.'); + } if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $query->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($server)->only($fields); } } - try { - if (! $query->first()) { - throw new NotFoundHttpException('No server by that ID was found.'); - } + if ($request->input('daemon') === 'true') { + try { + $response = $server->node->guzzleClient([ + 'X-Access-Token' => $server->node->daemonSecret, + ])->request('GET', '/servers'); - // Requested Daemon Stats - $server = $query->with( - 'allocations', - 'pack' - )->first(); - if ($request->input('daemon') === 'true') { - $node = Models\Node::findOrFail($server->node_id); - $client = Models\Node::guzzleRequest($node->id); - - $response = $client->request('GET', '/servers', [ - 'headers' => [ - 'X-Access-Token' => $node->daemonSecret, - ], - ]); - - // Only return the daemon token if the request is using HTTPS - if ($request->secure()) { - $server->daemon_token = $server->daemonSecret; - } $server->daemon = json_decode($response->getBody())->{$server->uuid}; - - return $server->toArray(); + } catch (\GuzzleHttp\Exception\TransferException $ex) { + // Couldn't hit the daemon, return what we have though. + $server->daemon = [ + 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', + ]; } - - return $server->toArray(); - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\GuzzleHttp\Exception\TransferException $ex) { - // Couldn't hit the daemon, return what we have though. - $server->daemon = [ - 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', - ]; - - return $server->toArray(); - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); } + + $server->allocations->transform(function ($item) { + return collect($item)->except(['created_at', 'updated_at']); + }); + + return $server->toArray(); } /** @@ -179,7 +159,9 @@ class ServerController extends BaseController { try { $server = new ServerRepository; - $server->updateDetails($id, $request->all()); + $server->updateDetails($id, $request->only([ + 'owner', 'name', 'reset_token', + ])); return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { @@ -224,7 +206,10 @@ class ServerController extends BaseController { try { $server = new ServerRepository; - $server->changeBuild($id, $request->all()); + $server->changeBuild($id, $request->only([ + 'default', 'add_additional', 'remove_additional', + 'memory', 'swap', 'io', 'cpu', 'disk', + ])); return Models\Server::findOrFail($id); } catch (DisplayValidationException $ex) { diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API/ServiceController.php index 81d5a955d..b1c600e27 100755 --- a/app/Http/Controllers/API/ServiceController.php +++ b/app/Http/Controllers/API/ServiceController.php @@ -45,18 +45,11 @@ class ServiceController extends BaseController public function view(Request $request, $id) { - $service = Models\Service::find($id); + $service = Models\Service::with('options.variables', 'options.packs')->find($id); if (! $service) { throw new NotFoundHttpException('No service by that ID was found.'); } - return [ - 'service' => $service, - 'options' => Models\ServiceOptions::select('id', 'name', 'description', 'tag', 'docker_image') - ->where('service_id', $service->id) - ->with('variables') - ->with('packs') - ->get(), - ]; + return $service->toArray(); } } diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API/User/InfoController.php index 844e493dc..6ef84ce50 100644 --- a/app/Http/Controllers/API/User/InfoController.php +++ b/app/Http/Controllers/API/User/InfoController.php @@ -32,19 +32,16 @@ class InfoController extends BaseController { public function me(Request $request) { - return $request->user()->serverAccessCollection()->map(function ($server) { + return $request->user()->serverAccessCollection()->load('allocation', 'option')->map(function ($server) { return [ 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, - 'node' => $server->node_idName, - 'ip' => [ - 'set' => $server->ip, - 'alias' => $server->ip_alias, - ], - 'port' => $server->port, - 'service' => $server->a_serviceName, - 'option' => $server->a_serviceOptionName, + 'node' => $server->node->name, + 'ip' => $server->allocation->alias, + 'port' => $server->allocation->port, + 'service' => $server->service->name, + 'option' => $server->option->name, ]; })->all(); } diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index c6091f0b1..465c7a345 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -25,7 +25,6 @@ namespace Pterodactyl\Http\Controllers\API\User; use Log; -use Auth; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\API\BaseController; @@ -43,20 +42,14 @@ class ServerController extends BaseController $daemon = [ 'status' => $json->status, 'stats' => $json->proc, - 'query' => $json->query, ]; } catch (\Exception $ex) { $daemon = [ - 'error' => 'An error was encountered while trying to connect to the daemon to collece information. It might be offline.', + 'error' => 'An error was encountered while trying to connect to the daemon to collect information. It might be offline.', ]; Log::error($ex); } - foreach ($server->allocations as &$allocation) { - $allocation->default = ($allocation->id === $server->allocation_id); - unset($allocation->id); - } - return [ 'uuidShort' => $server->uuidShort, 'uuid' => $server->uuid, @@ -70,12 +63,18 @@ class ServerController extends BaseController 'cpu' => $server->cpu, 'oom_disabled' => (bool) $server->oom_disabled, ], - 'allocations' => $server->allocations, + 'allocations' => $server->allocations->map(function ($item) use ($server) { + return [ + 'ip' => $item->alias, + 'port' => $item->port, + 'default' => ($item->id === $server->allocation_id), + ]; + }), 'sftp' => [ - 'username' => (Auth::user()->can('view-sftp', $server)) ? $server->username : null, + 'username' => ($request->user()->can('view-sftp', $server)) ? $server->username : null, ], 'daemon' => [ - 'token' => ($request->secure()) ? $server->daemonSecret : false, + 'token' => $server->daemonSecret, 'response' => $daemon, ], ]; diff --git a/app/Http/Controllers/API/UserController.php b/app/Http/Controllers/API/UserController.php index a330ef61c..14c212f77 100755 --- a/app/Http/Controllers/API/UserController.php +++ b/app/Http/Controllers/API/UserController.php @@ -75,31 +75,27 @@ class UserController extends BaseController */ public function view(Request $request, $id) { - $query = Models\User::where((is_numeric($id) ? 'id' : 'email'), $id); + $user = Models\User::with('servers')->where((is_numeric($id) ? 'id' : 'email'), $id)->first(); + if (! $user->first()) { + throw new NotFoundHttpException('No user by that ID was found.'); + } + + $user->servers->transform(function ($item) { + return collect($item)->only([ + 'id', 'node_id', 'uuidShort', + 'uuid', 'name', 'suspended', + 'owner_id', + ]); + }); if (! is_null($request->input('fields'))) { - foreach (explode(',', $request->input('fields')) as $field) { - if (! empty($field)) { - $query->addSelect($field); - } + $fields = explode(',', $request->input('fields')); + if (! empty($fields) && is_array($fields)) { + return collect($user)->only($fields); } } - try { - if (! $query->first()) { - throw new NotFoundHttpException('No user by that ID was found.'); - } - - $user = $query->first(); - $userArray = $user->toArray(); - $userArray['servers'] = Models\Server::select('id', 'uuid', 'node', 'suspended')->where('owner', $user->id)->get(); - - return $userArray; - } catch (NotFoundHttpException $ex) { - throw $ex; - } catch (\Exception $ex) { - throw new BadRequestHttpException('There was an issue with the fields passed in the request.'); - } + return $user->toArray(); } /** @@ -123,7 +119,9 @@ class UserController extends BaseController try { $user = new UserRepository; $create = $user->create($request->only([ - 'email', 'username', 'name_first', 'name_last', 'password', 'root_admin', 'custom_id', + 'email', 'username', 'name_first', + 'name_last', 'password', + 'root_admin', 'custom_id', ])); $create = $user->create($request->input('email'), $request->input('password'), $request->input('admin'), $request->input('custom_id')); @@ -160,7 +158,9 @@ class UserController extends BaseController try { $user = new UserRepository; $user->update($id, $request->only([ - 'username', 'email', 'name_first', 'name_last', 'password', 'root_admin', 'language', + 'username', 'email', 'name_first', + 'name_last', 'password', + 'root_admin', 'language', ])); return Models\User::findOrFail($id); diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index b68f8d01c..ab73937c4 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -86,16 +86,9 @@ class ServersController extends Controller { try { $server = new ServerRepository; - $response = $server->create($request->only([ - 'owner', 'name', 'memory', 'swap', - 'node', 'ip', 'port', 'allocation', - 'cpu', 'disk', 'service', - 'option', 'location', 'pack', - 'startup', 'custom_image_name', - 'auto_deploy', 'custom_id', - ])); + $response = $server->create($request->except('_token')); - return redirect()->route('admin.servers.view', ['id' => $response]); + return redirect()->route('admin.servers.view', ['id' => $response->id]); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { @@ -188,7 +181,7 @@ class ServersController extends Controller ], 500); } - $option = Models\ServiceOptions::with('variables', ['packs' => function ($query) { + $option = Models\ServiceOptions::with('variables')->with(['packs' => function ($query) { $query->where('selectable', true); }])->findOrFail($request->input('option')); diff --git a/app/Http/Middleware/APISecretToken.php b/app/Http/Middleware/APISecretToken.php index a1c203c9d..25bf891ba 100755 --- a/app/Http/Middleware/APISecretToken.php +++ b/app/Http/Middleware/APISecretToken.php @@ -121,7 +121,7 @@ class APISecretToken extends Authorization // Log the Route Access APILogService::log($request, null, true); - return Auth::loginUsingId($key->user); + return Auth::loginUsingId($key->user_id); } protected function _generateHMAC($body, $key) diff --git a/app/Models/Node.php b/app/Models/Node.php index 3da24531c..78e0828f7 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -66,28 +66,12 @@ class Node extends Model * @var array */ protected $fillable = [ - 'uuid', - 'uuidShort', - 'node_id', - 'name', - 'suspended', - 'owner_id', - 'memory', - 'swap', - 'disk', - 'io', - 'cpu', - 'oom_disabled', - 'allocation_id', - 'service_id', - 'option_id', - 'pack_id', - 'startup', - 'daemonSecret', - 'image', - 'username', - 'sftp_password', - 'installed', + 'public', 'name', 'location_id', + 'fqdn', 'scheme', 'memory', + 'memory_overallocate', 'disk', + 'disk_overallocate', 'upload_size', + 'daemonSecret', 'daemonBase', + 'daemonSFTP', 'daemonListen', ]; /** diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 14348b2db..71fbb88b5 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -62,8 +62,8 @@ class APIRepository // Node Management Routes 'nodes.list', + 'nodes.view', 'nodes.create', - 'nodes.list', 'nodes.allocations', 'nodes.delete', diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index e409a011a..1af316b23 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -44,7 +44,7 @@ class NodeRepository // Validate Fields $validator = Validator::make($data, [ 'name' => 'required|regex:/^([\w .-]{1,100})$/', - 'location' => 'required|numeric|min:1|exists:locations,id', + 'location_id' => 'required|numeric|min:1|exists:locations,id', 'public' => 'required|numeric|between:0,1', 'fqdn' => 'required|string|unique:nodes,fqdn', 'scheme' => 'required|regex:/^(http(s)?)$/', @@ -91,7 +91,7 @@ class NodeRepository // Validate Fields $validator = $validator = Validator::make($data, [ 'name' => 'regex:/^([\w .-]{1,100})$/', - 'location' => 'numeric|min:1|exists:locations,id', + 'location_id' => 'numeric|min:1|exists:locations,id', 'public' => 'numeric|between:0,1', 'fqdn' => 'string|unique:nodes,fqdn,' . $id, 'scheme' => 'regex:/^(http(s)?)$/', @@ -210,13 +210,13 @@ class NodeRepository foreach ($portBlock as $assignPort) { $alloc = Models\Allocation::firstOrNew([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $assignPort, ]); if (! $alloc->exists) { $alloc->fill([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $assignPort, 'ip_alias' => $setAlias, @@ -227,13 +227,13 @@ class NodeRepository } } else { $alloc = Models\Allocation::firstOrNew([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $port, ]); if (! $alloc->exists) { $alloc->fill([ - 'node' => $node->id, + 'node_id' => $node->id, 'ip' => $ip, 'port' => $port, 'ip_alias' => $setAlias, @@ -269,7 +269,7 @@ class NodeRepository ]); // Delete Allocations - Models\Allocation::where('node', $node->id)->delete(); + Models\Allocation::where('node_id', $node->id)->delete(); // Delete configure tokens Models\NodeConfigurationToken::where('node', $node->id)->delete(); diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 13caf0a5c..6e441666a 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -90,17 +90,17 @@ class ServerRepository 'io' => 'required|numeric|min:10|max:1000', 'cpu' => 'required|numeric|min:0', 'disk' => 'required|numeric|min:0', - 'service' => 'required|numeric|min:1|exists:services,id', - 'option' => 'required|numeric|min:1|exists:service_options,id', - 'location' => 'required|numeric|min:1|exists:locations,id', - 'pack' => 'sometimes|nullable|numeric|min:0', + 'service_id' => 'required|numeric|min:1|exists:services,id', + 'option_id' => 'required|numeric|min:1|exists:service_options,id', + 'location_id' => 'required|numeric|min:1|exists:locations,id', + 'pack_id' => 'sometimes|nullable|numeric|min:0', 'startup' => 'string', 'custom_image_name' => 'required_if:use_custom_image,on', 'auto_deploy' => 'sometimes|boolean', 'custom_id' => 'sometimes|required|numeric|unique:servers,id', ]); - $validator->sometimes('node', 'bail|required|numeric|min:1|exists:nodes,id', function ($input) { + $validator->sometimes('node_id', 'bail|required|numeric|min:1|exists:nodes,id', function ($input) { return ! ($input->auto_deploy); }); @@ -112,7 +112,7 @@ class ServerRepository return ! $input->auto_deploy && ! $input->allocation; }); - $validator->sometimes('allocation', 'numeric|exists:allocations,id', function ($input) { + $validator->sometimes('allocation_id', 'numeric|exists:allocations,id', function ($input) { return ! ($input->auto_deploy || ($input->port && $input->ip)); }); @@ -131,19 +131,19 @@ class ServerRepository if (isset($data['auto_deploy']) && in_array($data['auto_deploy'], [true, 1, '1'])) { // This is an auto-deployment situation // Ignore any other passed node data - unset($data['node'], $data['ip'], $data['port'], $data['allocation']); + unset($data['node_id'], $data['ip'], $data['port'], $data['allocation_id']); $autoDeployed = true; - $node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location']); + $node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location_id']); $allocation = DeploymentService::randomAllocation($node->id); } else { - $node = Models\Node::findOrFail($data['node']); + $node = Models\Node::findOrFail($data['node_id']); } // Verify IP & Port are a.) free and b.) assigned to the node. // We know the node exists because of 'exists:nodes,id' in the validation if (! $autoDeployed) { - if (! isset($data['allocation'])) { + if (! isset($data['allocation_id'])) { $allocation = Models\Allocation::where('ip', $data['ip'])->where('port', $data['port'])->where('node', $data['node'])->whereNull('assigned_to')->first(); } else { $allocation = Models\Allocation::where('id', $data['allocation'])->where('node', $data['node'])->whereNull('assigned_to')->first(); @@ -165,12 +165,12 @@ class ServerRepository } // Validate the Pack - if ($data['pack'] == 0) { - $data['pack'] = null; + if ($data['pack_id'] == 0) { + $data['pack_id'] = null; } - if (! is_null($data['pack'])) { - $pack = Models\ServicePack::where('id', $data['pack'])->where('option', $data['option'])->first(); + if (! is_null($data['pack_id'])) { + $pack = Models\ServicePack::where('id', $data['pack_id'])->where('option', $data['option_id'])->first(); if (! $pack) { throw new DisplayException('The requested service pack does not seem to exist for this combination.'); } @@ -180,7 +180,7 @@ class ServerRepository $service = Models\Service::find($option->service_id); // Check those Variables - $variables = Models\ServiceVariables::where('option_id', $data['option'])->get(); + $variables = Models\ServiceVariables::where('option_id', $data['option_id'])->get(); $variableList = []; if ($variables) { foreach ($variables as $variable) { @@ -254,10 +254,10 @@ class ServerRepository $server->fill([ 'uuid' => $genUuid, 'uuidShort' => $genShortUuid, - 'node' => $node->id, + 'node_id' => $node->id, 'name' => $data['name'], 'suspended' => 0, - 'owner' => $user->id, + 'owner_id' => $user->id, 'memory' => $data['memory'], 'swap' => $data['swap'], 'disk' => $data['disk'], @@ -265,9 +265,9 @@ class ServerRepository 'cpu' => $data['cpu'], 'oom_disabled' => (isset($data['oom_disabled'])) ? true : false, 'allocation' => $allocation->id, - 'service' => $data['service'], - 'option' => $data['option'], - 'pack' => $data['pack'], + 'service_id' => $data['service_id'], + 'option_id' => $data['option_id'], + 'pack_id' => $data['pack_id'], 'startup' => $data['startup'], 'daemonSecret' => $uuid->generate('servers', 'daemonSecret'), 'image' => (isset($data['custom_image_name'])) ? $data['custom_image_name'] : $option->docker_image, @@ -277,7 +277,7 @@ class ServerRepository $server->save(); // Mark Allocation in Use - $allocation->assigned_to = $server->id; + $allocation->server_id = $server->id; $allocation->save(); // Add Variables @@ -329,7 +329,7 @@ class ServerRepository DB::commit(); - return $server->id; + return $server; } catch (TransferException $ex) { DB::rollBack(); throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex); @@ -782,8 +782,8 @@ class ServerRepository DB::beginTransaction(); try { // Unassign Allocations - Models\Allocation::where('assigned_to', $server->id)->update([ - 'assigned_to' => null, + Models\Allocation::where('server_id', $server->id)->update([ + 'server_id' => null, ]); // Remove Variables diff --git a/resources/views/admin/nodes/new.blade.php b/resources/views/admin/nodes/new.blade.php index 07227daa7..37add9812 100644 --- a/resources/views/admin/nodes/new.blade.php +++ b/resources/views/admin/nodes/new.blade.php @@ -44,9 +44,9 @@
    - @foreach($locations as $location) - + @endforeach
    diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 5fa054703..9b569d5c8 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -138,9 +138,9 @@
    - @foreach($locations as $location) - + @endforeach
    diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php index 2c3d655a2..2fe12b1dd 100644 --- a/resources/views/admin/servers/new.blade.php +++ b/resources/views/admin/servers/new.blade.php @@ -63,7 +63,7 @@
    - @foreach($locations as $location) @@ -75,7 +75,7 @@ @section('footer-scripts') diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index d478bd372..ad8644648 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -236,7 +236,7 @@ - Copyright © 2015 - {{ date('Y') }} Pterodactyl Software & Design. + Copyright © 2015 - {{ date('Y') }} Pterodactyl Software.
    - - + + - - + @if (isset($directory['first']) && $directory['first'] === true) - - - - + + + + @endif @if (isset($directory['show']) && $directory['show'] === true) - + - - + + @endif @@ -69,8 +69,8 @@ - - + - - + @@ -176,7 +176,7 @@ $style = [ From 397172de3b5f0dda7495565ec2bf2b0da89b9d3f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:26:02 -0500 Subject: [PATCH 096/112] Better notification for user creation, only add button if needed. --- app/Notifications/AccountCreated.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index e7daff927..8e66a7485 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -69,11 +69,16 @@ class AccountCreated extends Notification implements ShouldQueue */ public function toMail($notifiable) { - return (new MailMessage) + $message = (new MailMessage) ->greeting('Hello ' . $this->user->name . '!') ->line('You are recieving this email because an account has been created for you on Pterodactyl Panel.') ->line('Username: ' . $this->user->username) - ->line('Email: ' . $notifiable->email) - ->action('Setup Your Account', url('/auth/password/reset/' . $this->user->token . '?email=' . $notifiable->email)); + ->line('Email: ' . $notifiable->email); + + if (! is_null($this->user->token)) { + return $message->action('Setup Your Account', url('/auth/password/reset/' . $this->user->token . '?email=' . $notifiable->email)); + } + + return $message; } } From 054e65b78fddb3bc37090882a62e8e49442f154f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:28:23 -0500 Subject: [PATCH 097/112] Fix user deletion --- app/Repositories/UserRepository.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 5ab2edbbf..c59637783 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -165,7 +165,7 @@ class UserRepository */ public function delete($id) { - if (Models\Server::where('owner', $id)->count() > 0) { + if (Models\Server::where('owner_id', $id)->count() > 0) { throw new DisplayException('Cannot delete a user with active servers attached to thier account.'); } @@ -177,10 +177,15 @@ class UserRepository DB::beginTransaction(); try { - Models\Permission::where('user_id', $id)->delete(); - Models\Subuser::where('user_id', $id)->delete(); - Models\User::destroy($id); + foreach(Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { + foreach($subuser->permissions as &$permission) { + $permission->delete(); + } + $subuser->delete(); + } + + Models\User::destroy($id); DB::commit(); return true; From 6a996c7c0cf9ab1836d85d19a78fae734f432b71 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:35:26 -0500 Subject: [PATCH 098/112] Fix account creation email --- app/Notifications/AccountCreated.php | 2 +- app/Observers/UserObserver.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Notifications/AccountCreated.php b/app/Notifications/AccountCreated.php index 8e66a7485..b7f86361c 100644 --- a/app/Notifications/AccountCreated.php +++ b/app/Notifications/AccountCreated.php @@ -38,7 +38,7 @@ class AccountCreated extends Notification implements ShouldQueue * * @var string */ - public $token; + public $user; /** * Create a new notification instance. diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index 437a82a69..258174ffb 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use DB; use Pterodactyl\Events; use Pterodactyl\Models\User; use Pterodactyl\Notifications\AccountCreated; @@ -51,10 +52,11 @@ class UserObserver { event(new Events\User\Created($user)); + $token = DB::table('password_resets')->where('email', $user->email)->orderBy('created_at', 'desc')->first(); $user->notify((new AccountCreated([ 'name' => $user->name_first, 'username' => $user->username, - 'token' => DB::table('password_resets')->where('email', $user->email)->orderBy('created_at', 'desc')->first(), + 'token' => (! is_null($token)) ? $token->token : null, ]))); } From 5f8572fe1aa61321da1d1241c32e01a6614b49f3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:37:35 -0500 Subject: [PATCH 099/112] Fix power button permissions checking --- resources/themes/pterodactyl/server/index.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/themes/pterodactyl/server/index.blade.php b/resources/themes/pterodactyl/server/index.blade.php index 8774b5284..14a099406 100644 --- a/resources/themes/pterodactyl/server/index.blade.php +++ b/resources/themes/pterodactyl/server/index.blade.php @@ -45,8 +45,8 @@ From 0f93ba2495132a3ff527c484625958e5112e5430 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:45:03 -0500 Subject: [PATCH 100/112] Add permissions checking to sidebar --- .../pterodactyl/layouts/master.blade.php | 132 ++++++++++-------- 1 file changed, 75 insertions(+), 57 deletions(-) diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 9df07de6e..ce881ada5 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -116,63 +116,81 @@ @lang('navigation.server.console') -
  • - - - @lang('navigation.server.file_management') - - - - - -
  • -
  • - - Subusers - -
  • -
  • - - @lang('navigation.server.task_management') - - {{ \Pterodactyl\Models\Task::select('id')->where('server', $server->id)->where('active', 1)->count() }} - - -
  • -
  • - - - @lang('navigation.server.configuration') - - - - - -
  • + @can('list-files', $server) +
  • + + + @lang('navigation.server.file_management') + + + + + +
  • + @endcan + @can('list-subusers', $server) +
  • + + Subusers + +
  • + @endcan + @can('list-tasks', $server) +
  • + + @lang('navigation.server.task_management') + + {{ \Pterodactyl\Models\Task::select('id')->where('server', $server->id)->where('active', 1)->count() }} + + +
  • + @endcan + @if(Gate::allows('view-startup', $server) || Gate::allows('view-sftp', $server) || Gate::allows('view-databases', $server) || Gate::allows('view-allocation', $server)) +
  • + + + @lang('navigation.server.configuration') + + + + + +
  • + @endif @endif From 22da8d47c827c0b5a1a9f5fe970c89cd0cabfc57 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:45:14 -0500 Subject: [PATCH 101/112] Auto-fill emails when resetting password --- app/Notifications/SendPasswordReset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Notifications/SendPasswordReset.php b/app/Notifications/SendPasswordReset.php index a3bddb825..0037fb7f3 100644 --- a/app/Notifications/SendPasswordReset.php +++ b/app/Notifications/SendPasswordReset.php @@ -72,7 +72,7 @@ class SendPasswordReset extends Notification implements ShouldQueue return (new MailMessage) ->subject('Reset Password') ->line('You are receiving this email because we received a password reset request for your account.') - ->action('Reset Password', url('auth/password/reset', $this->token)) + ->action('Reset Password', url('/auth/password/reset/' . $this->token . '?email=' . $notifiable->email)) ->line('If you did not request a password reset, no further action is required.'); } } From e9762b427705ff3a89f501580eecd4b26a3bb23a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 19:59:40 -0500 Subject: [PATCH 102/112] Fixes port deletion for node allocations as well as server notes on allocations. closes #305 --- CHANGELOG.md | 4 ++++ app/Http/Controllers/Admin/NodesController.php | 4 ++-- app/Models/Allocation.php | 10 ++++++++++ resources/views/admin/nodes/view.blade.php | 10 +++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a0972fb..1334a5e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,15 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.2]` — Fixes inability to edit a server due to owner_id issues. * `[pre.2]` — Fixes bug when trying to add new subusers. * Emails sending with 'Pterodactyl Panel' as the from name. Now configurable by using `php artisan pterodactyl:mail` to update. +* `[pre.2]` — Fixes inability to delete accounts due to SQL changes. +* `[pre.2]` — Fixes bug with checking power-permissions that showed the wrong buttons. Also adds check back to sidebar to only show options a user can use. +* `[pre.2]` — Fixes allocation listing on node allocations tab as well as bug preventing deletion of port. ### Changed * `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. * Reduced the number of database queries being executed when viewing a specific server. This is done by caching the query for up to 60 minutes in memcached. * User creation emails include more information and are sent by the event listener rather than the repository. +* Account password reset emails now auto-fill the email when clicking the link. ### Added * Notifications when a user is added or removed as a subuser for a server. diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index f90cab991..f4a60b5b2 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -108,7 +108,7 @@ class NodesController extends Controller 'servers.user', 'servers.service', 'servers.allocations', 'location' )->findOrFail($id); - $node->setRelation('allocations', $node->allocations()->paginate(40)); + $node->setRelation('allocations', $node->allocations()->with('server')->paginate(40)); return view('admin.nodes.view', [ 'node' => $node, @@ -151,7 +151,7 @@ class NodesController extends Controller public function deallocateSingle(Request $request, $node, $allocation) { - $query = Models\Allocation::where('node', $node)->whereNull('server_id')->where('id', $allocation)->delete(); + $query = Models\Allocation::where('node_id', $node)->whereNull('server_id')->where('id', $allocation)->delete(); if ((int) $query === 0) { return response()->json([ 'error' => 'Unable to find an allocation matching those details to delete.', diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index aad98ac63..cdcf79782 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -74,4 +74,14 @@ class Allocation extends Model { return ! is_null($this->ip_alias); } + + /** + * Gets information for the server associated with this allocation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function server() + { + return $this->belongsTo(Server::class); + } } diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 9b569d5c8..5a0879b72 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -356,16 +356,20 @@
    @foreach($node->allocations as $allocation) - + - +
    {{ $server->uuidShort }} {{ $server->name }}{{ $server->node_idName }}{{ $server->node->name }} {{ $server->username }} @if($server->suspended === 0)Active@elseSuspended@endif
    User Image{{ $user->username }} - {{ $user->email }}User Image{{ $subuser->user->username }} + {{ $subuser->user->email }} - @if($user->use_totp) + @if($subuser->user->use_totp) @else @endif - + - +
    {{ $database->name }} {{ $database->host }}:{{ $database->port }} {{ $database->username }}{{ $database->c_databases }}{{ $database->databases_count }} @if(is_null($database->node))unlinked@else{{ $database->node->name }}@endif
    {{ $location->short }} {{ $location->long }}{{ $location->a_nodeCount }}{{ $location->a_serverCount }}{{ $location->nodes_count }}{{ $location->servers_count }}
    @lang('server.files.file_name')@lang('server.files.size')@lang('server.files.last_modified')
    + /home/container{{ $directory['header'] }} @@ -45,21 +45,21 @@
    ← {{ $directory['link_show'] }}
    {{ $folder['entry'] }} {{ $folder['size'] }} timezone(env('APP_TIMEZONE', 'America/New_York')); ?> @if($carbon->diffInMinutes(Carbon::now()) > 60) {{ $carbon->format('m/d/y H:i:s') }} @@ -146,8 +146,8 @@ {{ $file['entry'] }} @endif {{ $file['size'] }} timezone(env('APP_TIMEZONE', 'America/New_York')); ?> @if($carbon->diffInMinutes(Carbon::now()) > 60) {{ $carbon->format('m/d/y H:i:s') }} From ff9904227b66b0fb705ec09a1b9b55a8df64ecac Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 18:17:28 -0500 Subject: [PATCH 091/112] Fix server editing --- app/Repositories/ServerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index 33e446e36..b6047739d 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -376,7 +376,7 @@ class ServerRepository } // Update Server Owner if it was passed. - if (isset($data['owner']) && $data['owner'] !== $owner->email) { + if (isset($data['owner']) && $data['owner'] !== $server->user->email) { $newOwner = Models\User::select('id')->where('email', $data['owner'])->first(); $server->owner_id = $newOwner->id; } From 9af06b4b59b8cb3d6c0c0ea0cebe757638e6a90d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 18:19:53 -0500 Subject: [PATCH 092/112] Add in query caching on server view --- .env.example | 2 +- CHANGELOG.md | 5 ++ app/Console/Commands/UpdateEnvironment.php | 4 ++ app/Events/Server/Saved.php | 45 +++++++++++++++++ app/Events/Server/Saving.php | 45 +++++++++++++++++ app/Events/Server/Updated.php | 45 +++++++++++++++++ app/Events/Server/Updating.php | 45 +++++++++++++++++ app/Http/Controllers/Base/IndexController.php | 2 +- app/Models/Server.php | 20 +++++--- app/Models/User.php | 4 +- app/Observers/ServerObserver.php | 49 +++++++++++++++++++ config/cache.php | 6 ++- config/debugbar.php | 8 +-- .../pterodactyl/layouts/master.blade.php | 2 +- 14 files changed, 263 insertions(+), 19 deletions(-) create mode 100644 app/Events/Server/Saved.php create mode 100644 app/Events/Server/Saving.php create mode 100644 app/Events/Server/Updated.php create mode 100644 app/Events/Server/Updating.php diff --git a/.env.example b/.env.example index fa7e20965..ed3a56b68 100644 --- a/.env.example +++ b/.env.example @@ -13,7 +13,7 @@ DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret -CACHE_DRIVER=file +CACHE_DRIVER=memcached SESSION_DRIVER=database MAIL_DRIVER=smtp diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f206283..12a23d724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. +* `[pre.2]` — Fixes inability to edit a server due to owner_id issues. + +### Changed +* `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. +* Reduced the number of database queries being executed when viewing a specific server. This is done by caching the query for up to 60 minutes in memcached. ## v0.6.0-pre.2 (Courageous Carniadactylus) ### Fixed diff --git a/app/Console/Commands/UpdateEnvironment.php b/app/Console/Commands/UpdateEnvironment.php index 3805ffd51..aa3dcfe7f 100644 --- a/app/Console/Commands/UpdateEnvironment.php +++ b/app/Console/Commands/UpdateEnvironment.php @@ -134,6 +134,10 @@ class UpdateEnvironment extends Command $variables['APP_TIMEZONE'] = $this->option('timezone'); } + $variables['APP_THEME'] = 'pterodactyl'; + $variables['CACHE_DRIVER'] = 'memcached'; + $variables['SESSION_DRIVER'] = 'database'; + $bar = $this->output->createProgressBar(count($variables)); $this->line('Writing new environment configuration to file.'); diff --git a/app/Events/Server/Saved.php b/app/Events/Server/Saved.php new file mode 100644 index 000000000..08700e3cb --- /dev/null +++ b/app/Events/Server/Saved.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Saved +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Saving.php b/app/Events/Server/Saving.php new file mode 100644 index 000000000..2c6d3cb4e --- /dev/null +++ b/app/Events/Server/Saving.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Saving +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Updated.php b/app/Events/Server/Updated.php new file mode 100644 index 000000000..0310e20c6 --- /dev/null +++ b/app/Events/Server/Updated.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Updated +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Events/Server/Updating.php b/app/Events/Server/Updating.php new file mode 100644 index 000000000..f333ede6b --- /dev/null +++ b/app/Events/Server/Updating.php @@ -0,0 +1,45 @@ +. + * + * 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\Events\Server; + +use Pterodactyl\Models\Server; +use Illuminate\Queue\SerializesModels; + +class Updating +{ + use SerializesModels; + + public $server; + + /** + * Create a new event instance. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } +} diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 6b0bd273e..f6abf4ea4 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -47,7 +47,7 @@ class IndexController extends Controller public function getIndex(Request $request) { return view('base.index', [ - 'servers' => $request->user()->serverAccessCollection(10)->load('node', 'allocation'), + 'servers' => $request->user()->serverAccessCollection(10), ]); } diff --git a/app/Models/Server.php b/app/Models/Server.php index 5dd5bb357..5e8179254 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Models; use Auth; +use Cache; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; @@ -113,16 +114,19 @@ class Server extends Model */ public static function byUuid($uuid) { - $query = self::with('service', 'node')->where(function ($q) use ($uuid) { - $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); + // Results are cached because we call this functions a few times on page load. + $result = Cache::remember('Server.byUuid.' . $uuid, 60, function () use ($uuid) { + $query = self::with('service', 'node')->where(function ($q) use ($uuid) { + $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); + }); + + if (! Auth::user()->isRootAdmin()) { + $query->whereIn('id', Auth::user()->serverAccessArray()); + } + + return $query->first(); }); - if (! Auth::user()->isRootAdmin()) { - $query->whereIn('id', Auth::user()->serverAccessArray()); - } - - $result = $query->first(); - if (! is_null($result)) { $result->daemonSecret = Auth::user()->daemonToken($result); } diff --git a/app/Models/User.php b/app/Models/User.php index abcddf227..131192264 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -186,9 +186,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac * * @return Collection */ - public function serverAccessCollection($paginate = null) + public function serverAccessCollection($paginate = null, $load = ['service', 'node', 'allocation']) { - $query = Server::with('service', 'node'); + $query = Server::with($load); if (! $this->isRootAdmin()) { $query->whereIn('id', $this->serverAccessArray()); } diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 06778c674..556d1c165 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use Cache; use Carbon; use Pterodactyl\Events; use Pterodactyl\Models\Server; @@ -97,4 +98,52 @@ class ServerObserver ->onQueue(env('QUEUE_STANDARD', 'standard')) ); } + + /** + * Listen to the Server saving event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function saving(Server $server) + { + event(new Events\Server\Saving($server)); + } + + /** + * Listen to the Server saved event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function saved(Server $server) + { + event(new Events\Server\Saved($server)); + } + + /** + * Listen to the Server saving event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function updating(Server $server) + { + event(new Events\Server\Updating($server)); + } + + /** + * Listen to the Server saved event. + * + * @param Server $server [description] + * @return [type] [description] + */ + public function updated(Server $server) + { + // Clear Caches + Cache::forget('Server.byUuid.' . $server->uuid); + Cache::forget('Server.byUuid.' . $server->uuidShort); + + event(new Events\Server\Updated($server)); + } } diff --git a/config/cache.php b/config/cache.php index 379135b0e..cb4bbd25d 100644 --- a/config/cache.php +++ b/config/cache.php @@ -13,7 +13,7 @@ return [ | */ - 'default' => env('CACHE_DRIVER', 'file'), + 'default' => env('CACHE_DRIVER', 'memcached'), /* |-------------------------------------------------------------------------- @@ -51,7 +51,9 @@ return [ 'driver' => 'memcached', 'servers' => [ [ - 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100, + 'host' => env('MEMCACHE_DRIVER_HOST', '127.0.0.1'), + 'port' => env('MEMCACHE_DRIVER_PORT', 11211), + 'weight' => 100, ], ], ], diff --git a/config/debugbar.php b/config/debugbar.php index 4c1349b40..4d9d8c45e 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -92,7 +92,7 @@ return [ 'views' => true, // Views with their data 'route' => true, // Current route information 'laravel' => false, // Laravel version and environment - 'events' => false, // All events fired + 'events' => true, // All events fired 'default_request' => false, // Regular or special Symfony request logger 'symfony_request' => true, // Only one can be enabled.. 'mail' => true, // Catch mail messages @@ -119,11 +119,11 @@ return [ ], 'db' => [ 'with_params' => true, // Render SQL with the parameters substituted - 'timeline' => false, // Add the queries to the timeline - 'backtrace' => false, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files. + 'timeline' => true, // Add the queries to the timeline + 'backtrace' => true, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files. 'explain' => [ // EXPERIMENTAL: Show EXPLAIN output on queries 'enabled' => false, - 'types' => ['SELECT'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ + 'types' => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ ], 'hints' => true, // Show hints for common mistakes ], diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 6c6307367..9df07de6e 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -219,7 +219,7 @@
    - {{ Settings::get('company') }} + {{ Settings::get('company', 'Pterodactyl Panel') }}

    © {{ date('Y') }} - {{ Settings::get('company') }}. + {{ Settings::get('company', 'Pterodactyl Panel') }}. All rights reserved.

    {{ $allocation->ip }} {{ $allocation->port }}@if(!is_null($allocation->assigned_to)){{ $allocation->assigned_to_name }}@endif + @if(! is_null($allocation->server)) + {{ $allocation->server->name }} + @endif + - @if(is_null($allocation->assigned_to)) + @if(is_null($allocation->server_id)) @else From 99497adcb2a070d038695e9011b015cb97c17c2f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 20:34:57 -0500 Subject: [PATCH 103/112] Show proper server status when viewing listing. closes #308 --- app/Http/Controllers/Server/AjaxController.php | 8 ++++++++ app/Http/Routes/ServerRoutes.php | 13 +++++++------ public/themes/pterodactyl/js/frontend/serverlist.js | 9 ++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Server/AjaxController.php b/app/Http/Controllers/Server/AjaxController.php index d18aee7bf..8f3736da7 100644 --- a/app/Http/Controllers/Server/AjaxController.php +++ b/app/Http/Controllers/Server/AjaxController.php @@ -73,6 +73,14 @@ class AjaxController extends Controller return response()->json([], 404); } + if (! $server->installed) { + return response()->json(['status' => 20]); + } + + if ($server->suspended) { + return response()->json(['status' => 30]); + } + try { $res = $server->guzzleClient()->request('GET', '/server'); if ($res->getStatusCode() === 200) { diff --git a/app/Http/Routes/ServerRoutes.php b/app/Http/Routes/ServerRoutes.php index 284822db4..36c95827b 100644 --- a/app/Http/Routes/ServerRoutes.php +++ b/app/Http/Routes/ServerRoutes.php @@ -30,6 +30,13 @@ class ServerRoutes { public function map(Router $router) { + // Returns Server Status + $router->get('/server/{server}/ajax/status', [ + 'middleware' => ['auth', 'csrf'], + 'as' => 'server.ajax.status', + 'uses' => 'Server\AjaxController@getStatus', + ]); + $router->group([ 'prefix' => 'server/{server}', 'middleware' => [ @@ -164,12 +171,6 @@ class ServerRoutes // Assorted AJAX Routes $router->group(['prefix' => 'ajax'], function ($server) use ($router) { - // Returns Server Status - $router->get('status', [ - 'as' => 'server.ajax.status', - 'uses' => 'Server\AjaxController@getStatus', - ]); - // Sets the Default Connection for the Server $router->post('set-primary', [ 'uses' => 'Server\AjaxController@postSetPrimary', diff --git a/public/themes/pterodactyl/js/frontend/serverlist.js b/public/themes/pterodactyl/js/frontend/serverlist.js index 605c33d2f..fc2ae0aff 100644 --- a/public/themes/pterodactyl/js/frontend/serverlist.js +++ b/public/themes/pterodactyl/js/frontend/serverlist.js @@ -28,6 +28,7 @@ var Status = { $('.dynamic-update').each(function (index, data) { var element = $(this); var serverShortUUID = $(this).data('server'); + $.ajax({ type: 'GET', url: Router.route('server.ajax.status', { server: serverShortUUID }), @@ -53,8 +54,14 @@ var Status = { case 3: element.find('[data-action="status"]').html('Stopping'); break; + case 20: + element.find('[data-action="status"]').html('Installing'); + break; + case 30: + element.find('[data-action="status"]').html('Suspended'); + break; } - if (data.status !== 0) { + if (data.status > 0 && data.status < 4) { var cpuMax = element.find('[data-action="cpu"]').data('cpumax'); var currentCpu = data.proc.cpu.total; if (cpuMax !== 0) { From 824041f6ca30defacf585cb7b37d01533eff3764 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 17 Feb 2017 20:40:50 -0500 Subject: [PATCH 104/112] Fix service creation/updates, closes #306 --- CHANGELOG.md | 1 + app/Models/Service.php | 6 ++++-- app/Repositories/ServiceRepository/Service.php | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1334a5e54..3c186e143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * `[pre.2]` — Fixes inability to delete accounts due to SQL changes. * `[pre.2]` — Fixes bug with checking power-permissions that showed the wrong buttons. Also adds check back to sidebar to only show options a user can use. * `[pre.2]` — Fixes allocation listing on node allocations tab as well as bug preventing deletion of port. +* `[pre.2]` — Fixes bug in services that prevented saving updated settings or creating new services. ### Changed * `[pre.2]` — File Manager now displays relevant information on all screen sizes, and includes better button clicking mechanics for dropdown menu. diff --git a/app/Models/Service.php b/app/Models/Service.php index 39e74e5b8..83cdb70b0 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -36,11 +36,13 @@ class Service extends Model protected $table = 'services'; /** - * Fields that are not mass assignable. + * Fields that are mass assignable. * * @var array */ - protected $fillable = ['id', 'created_at', 'updated_at']; + protected $fillable = [ + 'name', 'description', 'file', 'executable', 'startup', + ]; /** * Gets all service options associated with this service. diff --git a/app/Repositories/ServiceRepository/Service.php b/app/Repositories/ServiceRepository/Service.php index 6ebb76142..206479a0a 100644 --- a/app/Repositories/ServiceRepository/Service.php +++ b/app/Repositories/ServiceRepository/Service.php @@ -53,11 +53,13 @@ class Service throw new DisplayValidationException($validator->errors()); } - $data['author'] = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); - DB::beginTransaction(); try { - $service = Models\Service::create($data); + $service = new Models\Service; + $service->author = env('SERVICE_AUTHOR', (string) Uuid::generate(4)); + $service->fill($data); + $service->save(); + Storage::put('services/' . $service->file . '/main.json', '{}'); Storage::copy('services/.templates/index.js', 'services/' . $service->file . '/index.js'); DB::commit(); From 911434d033e4e8bd5a762ea6593e19ba7349b3be Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 12:47:49 -0500 Subject: [PATCH 105/112] Only apache could manage to do something this ridiculous --- public/.htaccess | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/.htaccess b/public/.htaccess index 8eb2dd0dd..342448645 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -8,6 +8,10 @@ # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] + + # Prevent stripping authorization headers + RewriteCond %{HTTP:Authorization} ^(.*) + RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d From f91e4c511ec7061050f41997674d9d83dda11b1b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 21:45:11 -0500 Subject: [PATCH 106/112] Attach user to cache to prevent showing servers they can't access. --- CHANGELOG.md | 4 ++++ app/Models/Server.php | 2 +- app/Observers/ServerObserver.php | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c186e143..d90ec523e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ 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. +## v0.6.0-pre.4 (Courageous Carniadactylus) +### Fixed +* `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. + ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. diff --git a/app/Models/Server.php b/app/Models/Server.php index 8527e6a14..7c69c763f 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -96,7 +96,7 @@ class Server extends Model public static function byUuid($uuid) { // Results are cached because we call this functions a few times on page load. - $result = Cache::remember('Server.byUuid.' . $uuid, 60, function () use ($uuid) { + $result = Cache::remember('Server.byUuid.' . $uuid . Auth::user()->uuid, 60, function () use ($uuid) { $query = self::with('service', 'node')->where(function ($q) use ($uuid) { $q->where('uuidShort', $uuid)->orWhere('uuid', $uuid); }); diff --git a/app/Observers/ServerObserver.php b/app/Observers/ServerObserver.php index 556d1c165..5d919a559 100644 --- a/app/Observers/ServerObserver.php +++ b/app/Observers/ServerObserver.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Observers; +use Auth; use Cache; use Carbon; use Pterodactyl\Events; @@ -141,8 +142,8 @@ class ServerObserver public function updated(Server $server) { // Clear Caches - Cache::forget('Server.byUuid.' . $server->uuid); - Cache::forget('Server.byUuid.' . $server->uuidShort); + Cache::forget('Server.byUuid.' . $server->uuid . Auth::user()->uuid); + Cache::forget('Server.byUuid.' . $server->uuidShort . Auth::user()->uuid); event(new Events\Server\Updated($server)); } From efdc3e6fd8f43165bb694cf8987b57baac0c3087 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:26:07 -0500 Subject: [PATCH 107/112] Add cache policy for ServerPolicy 10 second cache, just long enough to handle the page load without making more than one MySQL call. --- CHANGELOG.md | 3 +++ app/Policies/ServerPolicy.php | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d90ec523e..82fc3ecfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. +### Added +* New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. + ## v0.6.0-pre.3 (Courageous Carniadactylus) ### Fixed * `[pre.2]` — Fixes bug where servers could not be manually deployed to nodes due to a broken SQL call. diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index d67f3aced..adb4f3850 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -24,11 +24,14 @@ namespace Pterodactyl\Policies; +use Cache; +use Carbon; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; class ServerPolicy { + /** * Create a new policy instance. * @@ -53,7 +56,13 @@ class ServerPolicy return true; } - return $user->permissions()->server($server)->permission($permission)->exists(); + $permissions = Cache::remember('ServerPolicy.' . $user->uuid . $server->uuid, Carbon::now()->addSeconds(10), function () use ($user, $server) { + return $user->permissions()->server($server)->get()->transform(function ($item) { + return $item->permission; + })->values(); + }); + + return ($permissions->search($permission, true) !== false); } /** From 644c07ea3a847747c3f121e10adeec9a1de2b706 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:32:16 -0500 Subject: [PATCH 108/112] Fix broken port deletion --- CHANGELOG.md | 1 + app/Http/Controllers/Admin/NodesController.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82fc3ecfe..e88c0ec6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.6.0-pre.4 (Courageous Carniadactylus) ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. +* `[pre.3]` — Fixes misnamed MySQL column that was causing the inability to delete certain port ranges from the database. ### Added * New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index f4a60b5b2..877c44995 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -163,7 +163,7 @@ class NodesController extends Controller public function deallocateBlock(Request $request, $node) { - $query = Models\Allocation::where('node', $node)->whereNull('server_id')->where('ip', $request->input('ip'))->delete(); + $query = Models\Allocation::where('node_id', $node)->whereNull('server_id')->where('ip', $request->input('ip'))->delete(); if ((int) $query === 0) { Alert::danger('There was an error while attempting to delete allocations on that IP.')->flash(); @@ -199,7 +199,7 @@ class NodesController extends Controller public function getAllocationsJson(Request $request, $id) { - $allocations = Models\Allocation::select('ip')->where('node', $id)->groupBy('ip')->get(); + $allocations = Models\Allocation::select('ip')->where('node_id', $id)->groupBy('ip')->get(); return response()->json($allocations); } From ed4068bdb9038d72e27158e5ba89cb62d837e5ed Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:33:15 -0500 Subject: [PATCH 109/112] Fix bug preventing server container rebuilds. --- CHANGELOG.md | 1 + app/Http/Controllers/Admin/ServersController.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e88c0ec6d..8b856fd7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * `[pre.3]` — Fixes bug in cache handler that doesn't cache against the user making the request. Would have allowed for users to access servers not belonging to themselves in production. * `[pre.3]` — Fixes misnamed MySQL column that was causing the inability to delete certain port ranges from the database. +* `[pre.3]` — Fixes bug preventing rebuilding server containers through the Admin CP. ### Added * New cache policy for ServerPolicy to avoid making 15+ queries per page load when confirming if a user has permission to perform an action. diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 0f5cf495d..017dc1fcc 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -251,7 +251,7 @@ class ServersController extends Controller try { $res = $server->node->guzzleClient([ 'X-Access-Server' => $server->uuid, - 'X-Access-Token' => $node->daemonSecret, + 'X-Access-Token' => $server->node->daemonSecret, ])->request('POST', '/server/rebuild'); Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash(); } catch (\GuzzleHttp\Exception\TransferException $ex) { From b11029a666b0491c600811f34fcd7deba6139cee Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:57:50 -0500 Subject: [PATCH 110/112] Apply fixes from StyleCI (#312) * Bump for release * Apply fixes from StyleCI --- app/Http/Controllers/Base/APIController.php | 1 + app/Policies/ServerPolicy.php | 3 +-- app/Repositories/APIRepository.php | 2 +- app/Repositories/Daemon/CommandRepository.php | 1 - app/Repositories/Daemon/PowerRepository.php | 1 - app/Repositories/ServerRepository.php | 4 ++-- app/Repositories/UserRepository.php | 5 ++--- config/app.php | 2 +- 8 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index e80f07033..68045a722 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -80,6 +80,7 @@ class APIController extends Controller return response('', 204); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An error occured while attempting to remove this key.', ], 503); diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index adb4f3850..767dec13c 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -31,7 +31,6 @@ use Pterodactyl\Models\Server; class ServerPolicy { - /** * Create a new policy instance. * @@ -62,7 +61,7 @@ class ServerPolicy })->values(); }); - return ($permissions->search($permission, true) !== false); + return $permissions->search($permission, true) !== false; } /** diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index c18f1f993..5f148eda6 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -225,7 +225,7 @@ class APIRepository try { $model = Models\APIKey::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail(); - foreach($model->permissions as &$permission) { + foreach ($model->permissions as &$permission) { $permission->delete(); } diff --git a/app/Repositories/Daemon/CommandRepository.php b/app/Repositories/Daemon/CommandRepository.php index 1905478e7..76ac93178 100644 --- a/app/Repositories/Daemon/CommandRepository.php +++ b/app/Repositories/Daemon/CommandRepository.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Repositories\Daemon; -use GuzzleHttp\Client; use Pterodactyl\Models; use GuzzleHttp\Exception\RequestException; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Repositories/Daemon/PowerRepository.php b/app/Repositories/Daemon/PowerRepository.php index d43ec1a7d..b31c0cda0 100644 --- a/app/Repositories/Daemon/PowerRepository.php +++ b/app/Repositories/Daemon/PowerRepository.php @@ -24,7 +24,6 @@ namespace Pterodactyl\Repositories\Daemon; -use GuzzleHttp\Client; use Pterodactyl\Models; use Pterodactyl\Exceptions\DisplayException; diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index b6047739d..4b5ed1f15 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -791,8 +791,8 @@ class ServerRepository Models\ServerVariable::where('server_id', $server->id)->delete(); // Remove SubUsers - foreach(Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { - foreach($subuser->permissions as &$permission) { + foreach (Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { + foreach ($subuser->permissions as &$permission) { $permission->delete(); } $subuser->delete(); diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index c59637783..e9cd8580f 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -34,7 +34,6 @@ use Validator; use Pterodactyl\Models; use Pterodactyl\Services\UuidService; use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Notifications\AccountCreated; use Pterodactyl\Exceptions\DisplayValidationException; class UserRepository @@ -177,8 +176,8 @@ class UserRepository DB::beginTransaction(); try { - foreach(Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { - foreach($subuser->permissions as &$permission) { + foreach (Models\Subuser::with('permissions')->where('user_id', $id)->get() as &$subuser) { + foreach ($subuser->permissions as &$permission) { $permission->delete(); } diff --git a/config/app.php b/config/app.php index 622098a9b..e6b955156 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', 'canary'), + 'version' => env('APP_VERSION', '0.6.0-pre.4'), 'phrase_in_context' => env('PHRASE_IN_CONTEXT', false), From b82c67424ff9ed510467cab546213146e1f348f3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Feb 2017 22:59:08 -0500 Subject: [PATCH 111/112] Slow ya roll StyleCI... --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index e6b955156..622098a9b 100644 --- a/config/app.php +++ b/config/app.php @@ -4,7 +4,7 @@ return [ 'env' => env('APP_ENV', 'production'), - 'version' => env('APP_VERSION', '0.6.0-pre.4'), + 'version' => env('APP_VERSION', 'canary'), 'phrase_in_context' => env('PHRASE_IN_CONTEXT', false), From c021872a9cf765c4f8fd8d6649d561ea0f7b6e3e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 2 Mar 2017 12:17:52 -0500 Subject: [PATCH 112/112] Update database.php --- config/database.php | 1 + 1 file changed, 1 insertion(+) diff --git a/config/database.php b/config/database.php index f6cf86b4c..420cd6184 100644 --- a/config/database.php +++ b/config/database.php @@ -55,6 +55,7 @@ return [ 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''),