Skip to content

Commit 8737190

Browse files
committed
Add base logic to support sending a request to restore a backup for a server
1 parent 805952a commit 8737190

File tree

9 files changed

+229
-237
lines changed

9 files changed

+229
-237
lines changed

app/Http/Controllers/Api/Client/Servers/BackupController.php

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
44

5+
use Illuminate\Http\Request;
56
use Pterodactyl\Models\Backup;
67
use Pterodactyl\Models\Server;
78
use Pterodactyl\Models\AuditLog;
89
use Illuminate\Http\JsonResponse;
10+
use Pterodactyl\Models\Permission;
11+
use Illuminate\Validation\UnauthorizedException;
912
use Pterodactyl\Services\Backups\DeleteBackupService;
10-
use Pterodactyl\Repositories\Eloquent\BackupRepository;
13+
use Pterodactyl\Services\Backups\DownloadLinkService;
1114
use Pterodactyl\Services\Backups\InitiateBackupService;
1215
use Pterodactyl\Transformers\Api\Client\BackupTransformer;
16+
use Pterodactyl\Repositories\Wings\DaemonBackupRepository;
1317
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
14-
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest;
18+
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
1519
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest;
16-
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\DeleteBackupRequest;
1720

1821
class BackupController extends ClientApiController
1922
{
@@ -28,39 +31,51 @@ class BackupController extends ClientApiController
2831
private $deleteBackupService;
2932

3033
/**
31-
* @var \Pterodactyl\Repositories\Eloquent\BackupRepository
34+
* @var \Pterodactyl\Services\Backups\DownloadLinkService
35+
*/
36+
private $downloadLinkService;
37+
38+
/**
39+
* @var \Pterodactyl\Repositories\Wings\DaemonBackupRepository
3240
*/
3341
private $repository;
3442

3543
/**
3644
* BackupController constructor.
3745
*
38-
* @param \Pterodactyl\Repositories\Eloquent\BackupRepository $repository
46+
* @param \Pterodactyl\Repositories\Wings\DaemonBackupRepository $repository
3947
* @param \Pterodactyl\Services\Backups\DeleteBackupService $deleteBackupService
4048
* @param \Pterodactyl\Services\Backups\InitiateBackupService $initiateBackupService
49+
* @param \Pterodactyl\Services\Backups\DownloadLinkService $downloadLinkService
4150
*/
4251
public function __construct(
43-
BackupRepository $repository,
52+
DaemonBackupRepository $repository,
4453
DeleteBackupService $deleteBackupService,
45-
InitiateBackupService $initiateBackupService
54+
InitiateBackupService $initiateBackupService,
55+
DownloadLinkService $downloadLinkService
4656
) {
4757
parent::__construct();
4858

59+
$this->repository = $repository;
4960
$this->initiateBackupService = $initiateBackupService;
5061
$this->deleteBackupService = $deleteBackupService;
51-
$this->repository = $repository;
62+
$this->downloadLinkService = $downloadLinkService;
5263
}
5364

5465
/**
5566
* Returns all of the backups for a given server instance in a paginated
5667
* result set.
5768
*
58-
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest $request
69+
* @param \Illuminate\Http\Request $request
5970
* @param \Pterodactyl\Models\Server $server
6071
* @return array
6172
*/
62-
public function index(GetBackupsRequest $request, Server $server)
73+
public function index(Request $request, Server $server)
6374
{
75+
if (! $request->user()->can(Permission::ACTION_BACKUP_READ, $server)) {
76+
throw new UnauthorizedException;
77+
}
78+
6479
$limit = min($request->query('per_page') ?? 20, 50);
6580

6681
return $this->fractal->collection($server->backups()->paginate($limit))
@@ -100,13 +115,17 @@ public function store(StoreBackupRequest $request, Server $server)
100115
/**
101116
* Returns information about a single backup.
102117
*
103-
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest $request
118+
* @param \Illuminate\Http\Request $request
104119
* @param \Pterodactyl\Models\Server $server
105120
* @param \Pterodactyl\Models\Backup $backup
106121
* @return array
107122
*/
108-
public function view(GetBackupsRequest $request, Server $server, Backup $backup)
123+
public function view(Request $request, Server $server, Backup $backup)
109124
{
125+
if (! $request->user()->can(Permission::ACTION_BACKUP_READ, $server)) {
126+
throw new UnauthorizedException;
127+
}
128+
110129
return $this->fractal->item($backup)
111130
->transformWith($this->getTransformer(BackupTransformer::class))
112131
->toArray();
@@ -116,15 +135,19 @@ public function view(GetBackupsRequest $request, Server $server, Backup $backup)
116135
* Deletes a backup from the panel as well as the remote source where it is currently
117136
* being stored.
118137
*
119-
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Backups\DeleteBackupRequest $request
138+
* @param \Illuminate\Http\Request $request
120139
* @param \Pterodactyl\Models\Server $server
121140
* @param \Pterodactyl\Models\Backup $backup
122141
* @return \Illuminate\Http\JsonResponse
123142
*
124143
* @throws \Throwable
125144
*/
126-
public function delete(DeleteBackupRequest $request, Server $server, Backup $backup)
145+
public function delete(Request $request, Server $server, Backup $backup)
127146
{
147+
if (! $request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
148+
throw new UnauthorizedException;
149+
}
150+
128151
$server->audit(AuditLog::SERVER__BACKUP_DELETED, function (AuditLog $audit) use ($backup) {
129152
$audit->metadata = ['backup_uuid' => $backup->uuid];
130153

@@ -133,4 +156,79 @@ public function delete(DeleteBackupRequest $request, Server $server, Backup $bac
133156

134157
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
135158
}
159+
160+
/**
161+
* Download the backup for a given server instance. For daemon local files, the file
162+
* will be streamed back through the Panel. For AWS S3 files, a signed URL will be generated
163+
* which the user is redirected to.
164+
*
165+
* @param \Illuminate\Http\Request $request
166+
* @param \Pterodactyl\Models\Server $server
167+
* @param \Pterodactyl\Models\Backup $backup
168+
* @return \Illuminate\Http\JsonResponse
169+
*/
170+
public function download(Request $request, Server $server, Backup $backup)
171+
{
172+
if (! $request->user()->can(Permission::ACTION_BACKUP_DOWNLOAD, $server)) {
173+
throw new UnauthorizedException;
174+
}
175+
176+
switch ($backup->disk) {
177+
case Backup::ADAPTER_WINGS:
178+
case Backup::ADAPTER_AWS_S3:
179+
return new JsonResponse([
180+
'object' => 'signed_url',
181+
'attributes' => ['url' => ''],
182+
]);
183+
default:
184+
throw new BadRequestHttpException;
185+
}
186+
}
187+
188+
/**
189+
* Handles restoring a backup by making a request to the Wings instance telling it
190+
* to begin the process of finding (or downloading) the backup and unpacking it
191+
* over the server files.
192+
*
193+
* If the "truncate" flag is passed through in this request then all of the
194+
* files that currently exist on the server will be deleted before restoring.
195+
* Otherwise the archive will simply be unpacked over the existing files.
196+
*
197+
* @param \Illuminate\Http\Request $request
198+
* @param \Pterodactyl\Models\Server $server
199+
* @param \Pterodactyl\Models\Backup $backup
200+
* @return \Illuminate\Http\JsonResponse
201+
*
202+
* @throws \Throwable
203+
*/
204+
public function restore(Request $request, Server $server, Backup $backup)
205+
{
206+
if (! $request->user()->can(Permission::ACTION_BACKUP_RESTORE, $server)) {
207+
throw new UnauthorizedException;
208+
}
209+
210+
// Cannot restore a backup unless a server is fully installed and not currently
211+
// processing a different backup restoration request.
212+
if (! is_null($server->status)) {
213+
throw new BadRequestHttpException('This server is not currently in a state that allows for a backup to be restored.');
214+
}
215+
216+
$server->audit(AuditLog::SERVER__BACKUP_RESTORE_STARTED, function (AuditLog $audit, Server $server) use ($backup, $request) {
217+
$audit->metadata = ['backup_uuid' => $backup->uuid];
218+
219+
// If the backup is for an S3 file we need to generate a unique Download link for
220+
// it that will allow Wings to actually access the file.
221+
if ($backup->disk === Backup::ADAPTER_AWS_S3) {
222+
$url = $this->downloadLinkService->handle($backup, $request->user());
223+
}
224+
225+
// Update the status right away for the server so that we know not to allow certain
226+
// actions against it via the Panel API.
227+
$server->update(['status' => Server::STATUS_RESTORING_BACKUP]);
228+
229+
$this->repository->restore($backup, $url ?? null, $request->input('truncate') === 'true');
230+
});
231+
232+
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
233+
}
136234
}

app/Http/Controllers/Api/Client/Servers/DownloadBackupController.php

Lines changed: 0 additions & 144 deletions
This file was deleted.

app/Http/Requests/Api/Client/Servers/Backups/DeleteBackupRequest.php

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)