From 85e3945cd7373764dc61405bb361cec10395a549 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 3 Apr 2020 14:43:24 -0700 Subject: [PATCH] Add support for client-side server reinstallation --- .../Api/Client/Servers/SettingsController.php | 36 +++++++- .../Settings/ReinstallServerRequest.php | 17 ++++ .../scripts/api/server/reinstallServer.ts | 9 ++ resources/scripts/components/elements/Can.tsx | 4 - .../server/settings/ReinstallServerBox.tsx | 63 ++++++++++++++ .../server/settings/SettingsContainer.tsx | 86 ++++++++++--------- routes/api-client.php | 1 + 7 files changed, 169 insertions(+), 47 deletions(-) create mode 100644 app/Http/Requests/Api/Client/Servers/Settings/ReinstallServerRequest.php create mode 100644 resources/scripts/api/server/reinstallServer.ts create mode 100644 resources/scripts/components/server/settings/ReinstallServerBox.tsx diff --git a/app/Http/Controllers/Api/Client/Servers/SettingsController.php b/app/Http/Controllers/Api/Client/Servers/SettingsController.php index 5b457fa9c..64c73a8de 100644 --- a/app/Http/Controllers/Api/Client/Servers/SettingsController.php +++ b/app/Http/Controllers/Api/Client/Servers/SettingsController.php @@ -4,9 +4,12 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers; use Illuminate\Http\Response; use Pterodactyl\Models\Server; +use Illuminate\Http\JsonResponse; use Pterodactyl\Repositories\Eloquent\ServerRepository; +use Pterodactyl\Services\Servers\ReinstallServerService; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest; +use Pterodactyl\Http\Requests\Api\Client\Servers\Settings\ReinstallServerRequest; class SettingsController extends ClientApiController { @@ -15,16 +18,25 @@ class SettingsController extends ClientApiController */ private $repository; + /** + * @var \Pterodactyl\Services\Servers\ReinstallServerService + */ + private $reinstallServerService; + /** * SettingsController constructor. * * @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository + * @param \Pterodactyl\Services\Servers\ReinstallServerService $reinstallServerService */ - public function __construct(ServerRepository $repository) - { + public function __construct( + ServerRepository $repository, + ReinstallServerService $reinstallServerService + ) { parent::__construct(); $this->repository = $repository; + $this->reinstallServerService = $reinstallServerService; } /** @@ -32,7 +44,7 @@ class SettingsController extends ClientApiController * * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest $request * @param \Pterodactyl\Models\Server $server - * @return \Illuminate\Http\Response + * @return \Illuminate\Http\JsonResponse * * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException @@ -43,6 +55,22 @@ class SettingsController extends ClientApiController 'name' => $request->input('name'), ]); - return Response::create('', Response::HTTP_NO_CONTENT); + return JsonResponse::create([], Response::HTTP_NO_CONTENT); + } + + /** + * Reinstalls the server on the daemon. + * + * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Settings\ReinstallServerRequest $request + * @param \Pterodactyl\Models\Server $server + * @return \Illuminate\Http\JsonResponse + * + * @throws \Throwable + */ + public function reinstall(ReinstallServerRequest $request, Server $server) + { + $this->reinstallServerService->reinstall($server); + + return JsonResponse::create([], Response::HTTP_ACCEPTED); } } diff --git a/app/Http/Requests/Api/Client/Servers/Settings/ReinstallServerRequest.php b/app/Http/Requests/Api/Client/Servers/Settings/ReinstallServerRequest.php new file mode 100644 index 000000000..9edc8ad1c --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Settings/ReinstallServerRequest.php @@ -0,0 +1,17 @@ + => { + return new Promise((resolve, reject) => { + http.post(`/api/client/servers/${uuid}/settings/reinstall`) + .then(() => resolve()) + .catch(reject); + }); +} diff --git a/resources/scripts/components/elements/Can.tsx b/resources/scripts/components/elements/Can.tsx index 2990f2489..4ea140d3e 100644 --- a/resources/scripts/components/elements/Can.tsx +++ b/resources/scripts/components/elements/Can.tsx @@ -11,10 +11,6 @@ interface Props { const Can = ({ action, matchAny = false, renderOnError, children }: Props) => { const can = usePermissions(action); - if (matchAny) { - console.log('Can.tsx', can); - } - return ( <> { diff --git a/resources/scripts/components/server/settings/ReinstallServerBox.tsx b/resources/scripts/components/server/settings/ReinstallServerBox.tsx new file mode 100644 index 000000000..895901215 --- /dev/null +++ b/resources/scripts/components/server/settings/ReinstallServerBox.tsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { ServerContext } from '@/state/server'; +import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; +import TitledGreyBox from '@/components/elements/TitledGreyBox'; +import ConfirmationModal from '@/components/elements/ConfirmationModal'; +import reinstallServer from '@/api/server/reinstallServer'; +import { Actions, useStoreActions } from 'easy-peasy'; +import { ApplicationStore } from '@/state'; +import { httpErrorToHuman } from '@/api/http'; + +export default () => { + const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); + const [ isSubmitting, setIsSubmitting ] = useState(false); + const [ modalVisible, setModalVisible ] = useState(false); + const { addFlash, clearFlashes } = useStoreActions((actions: Actions) => actions.flashes); + + const reinstall = () => { + clearFlashes('settings'); + setIsSubmitting(true); + reinstallServer(uuid) + .then(() => { + addFlash({ key: 'settings', type: 'success', message: 'Your server has begun the reinstallation process.' }); + }) + .catch(error => { + console.error(error); + + addFlash({ key: 'settings', type: 'error', message: httpErrorToHuman(error) }); + }) + .then(() => { + setIsSubmitting(false); + setModalVisible(false); + }); + } + + return ( + + reinstall()} + showSpinnerOverlay={isSubmitting} + visible={modalVisible} + onDismissed={() => setModalVisible(false)} + > + Your server will be stopped and some files may be deleted or modified during this process, are you sure you wish to continue? + +

+ Reinstalling your server will stop it, and then re-run the installation script that initially + set it up.Some files may be deleted or modified during this process, + please back up your data before continuing. +

+
+ +
+
+ ); +}; diff --git a/resources/scripts/components/server/settings/SettingsContainer.tsx b/resources/scripts/components/server/settings/SettingsContainer.tsx index ffdad1208..25766e80e 100644 --- a/resources/scripts/components/server/settings/SettingsContainer.tsx +++ b/resources/scripts/components/server/settings/SettingsContainer.tsx @@ -7,6 +7,7 @@ import { UserData } from '@/state/user'; import RenameServerBox from '@/components/server/settings/RenameServerBox'; import FlashMessageRender from '@/components/FlashMessageRender'; import Can from '@/components/elements/Can'; +import ReinstallServerBox from '@/components/server/settings/ReinstallServerBox'; export default () => { const user = useStoreState(state => state.user.data!); @@ -17,49 +18,56 @@ export default () => {
- -
- - -
-
- - -
-
-
-
-

- Your SFTP password is the same as the password you use to access this panel. -

+
+ +
+ + +
+
+ + +
+
+
+
+

+ Your SFTP password is the same as the password you use to access this panel. +

+
+
+
- -
- - - -
- +
+
+ +
+ +
+
+ + + +
); diff --git a/routes/api-client.php b/routes/api-client.php index f623d5ec2..0a6fa39e9 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -89,5 +89,6 @@ Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateServ Route::group(['prefix' => '/settings'], function () { Route::post('/rename', 'Servers\SettingsController@rename'); + Route::post('/reinstall', 'Servers\SettingsController@reinstall'); }); });