File transfer
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* File Revision Controller — client API
|
||||
*
|
||||
* @author Ball Studios <https://git.balls.studio>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Addons\AdvancedAdmin\Http\Controllers\Client;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Models\FileRevision;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Services\Revisions\DiffService;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Services\Revisions\RevisionService;
|
||||
use Pterodactyl\Addons\AdvancedAdmin\Services\Revisions\RevisionStorageService;
|
||||
use Pterodactyl\Models\Server;
|
||||
|
||||
class FileRevisionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RevisionService $revisionService,
|
||||
private readonly DiffService $diffService,
|
||||
private readonly RevisionStorageService $storage,
|
||||
) {}
|
||||
|
||||
/** GET /api/client/servers/{server}/addons/files/revisions?path= */
|
||||
public function index(Request $request, Server $server): JsonResponse
|
||||
{
|
||||
$this->requirePermission($request, $server, 'file.read');
|
||||
|
||||
$path = $request->string('path', '')->toString();
|
||||
abort_if(empty($path), 422, 'path parameter is required.');
|
||||
|
||||
$path = $this->storage->guardFilePath($path);
|
||||
$pathHash = $this->storage->pathHash($server->id, $path);
|
||||
|
||||
$revisions = FileRevision::query()
|
||||
->where('server_id', $server->id)
|
||||
->where('path_hash', $pathHash)
|
||||
->with('author:id,username,email')
|
||||
->orderByDesc('revision_number')
|
||||
->paginate(25);
|
||||
|
||||
return response()->json($revisions);
|
||||
}
|
||||
|
||||
/** GET /api/client/servers/{server}/addons/files/revisions/{revision} */
|
||||
public function show(Request $request, Server $server, FileRevision $revision): JsonResponse
|
||||
{
|
||||
$this->requirePermission($request, $server, 'file.read');
|
||||
$this->assertBelongsToServer($revision, $server);
|
||||
|
||||
return response()->json(['data' => $revision->load('author:id,username,email')]);
|
||||
}
|
||||
|
||||
/** GET /api/client/servers/{server}/addons/files/revisions/{revision}/diff */
|
||||
public function diff(Request $request, Server $server, FileRevision $revision): JsonResponse
|
||||
{
|
||||
$this->requirePermission($request, $server, 'file.read');
|
||||
$this->assertBelongsToServer($revision, $server);
|
||||
|
||||
$content = $this->storage->retrieve($revision->storage_key);
|
||||
|
||||
// If binary, return a placeholder diff
|
||||
if ($this->storage->isBinary($content)) {
|
||||
return response()->json(['binary' => true, 'lines' => []]);
|
||||
}
|
||||
|
||||
// Fetch previous revision for comparison
|
||||
$previous = FileRevision::query()
|
||||
->where('server_id', $server->id)
|
||||
->where('path_hash', $revision->path_hash)
|
||||
->where('revision_number', $revision->revision_number - 1)
|
||||
->first();
|
||||
|
||||
$oldContent = $previous ? $this->storage->retrieve($previous->storage_key) : '';
|
||||
|
||||
$lines = $this->diffService->diff($oldContent, $content, basename($revision->file_path));
|
||||
return response()->json(['binary' => false, 'lines' => $lines]);
|
||||
}
|
||||
|
||||
/** GET /api/client/servers/{server}/addons/files/revisions/{revision}/download */
|
||||
public function download(Request $request, Server $server, FileRevision $revision): StreamedResponse
|
||||
{
|
||||
$this->requirePermission($request, $server, 'file.read');
|
||||
$this->assertBelongsToServer($revision, $server);
|
||||
|
||||
$content = $this->storage->retrieve($revision->storage_key);
|
||||
$filename = basename($revision->file_path) . ".rev{$revision->revision_number}";
|
||||
|
||||
return response()->streamDownload(function () use ($content) {
|
||||
echo $content;
|
||||
}, $filename, ['Content-Type' => 'application/octet-stream']);
|
||||
}
|
||||
|
||||
/** POST /api/client/servers/{server}/addons/files/revisions/{revision}/restore */
|
||||
public function restore(Request $request, Server $server, FileRevision $revision): JsonResponse
|
||||
{
|
||||
$this->requirePermission($request, $server, 'file.update');
|
||||
$this->assertBelongsToServer($revision, $server);
|
||||
|
||||
$content = $this->revisionService->restore($revision, $request->user()->id);
|
||||
|
||||
return response()->json([
|
||||
'restored' => true,
|
||||
'content' => $content,
|
||||
'revision' => $revision->revision_number,
|
||||
]);
|
||||
}
|
||||
|
||||
/** DELETE /api/client/servers/{server}/addons/files/revisions/{revision} */
|
||||
public function destroy(Request $request, Server $server, FileRevision $revision): JsonResponse
|
||||
{
|
||||
// Only admins can manually delete revisions
|
||||
abort_unless($request->user()?->root_admin, 403, 'Admin access required.');
|
||||
$this->assertBelongsToServer($revision, $server);
|
||||
|
||||
$this->revisionService->delete($revision);
|
||||
return response()->json(['deleted' => true]);
|
||||
}
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
private function requirePermission(Request $request, Server $server, string $permission): void
|
||||
{
|
||||
$user = $request->user();
|
||||
abort_unless($user, 401);
|
||||
|
||||
$isOwner = $server->owner_id === $user->id;
|
||||
$isAdmin = $user->root_admin;
|
||||
|
||||
if (!$isOwner && !$isAdmin) {
|
||||
$subuser = $server->subusers()->where('user_id', $user->id)->first();
|
||||
abort_unless(
|
||||
$subuser && in_array($permission, $subuser->permissions ?? [], true),
|
||||
403,
|
||||
"Permission '{$permission}' required."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function assertBelongsToServer(FileRevision $revision, Server $server): void
|
||||
{
|
||||
abort_unless($revision->server_id === $server->id, 404);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user