Skip to content

Commit 1d2acbd

Browse files
committed
Get basic file upload functionality working
1 parent 3ebb6ea commit 1d2acbd

File tree

6 files changed

+152
-9
lines changed

6 files changed

+152
-9
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function __invoke(DownloadBackupRequest $request, Server $server, Backup
8282
throw new BadRequestHttpException;
8383
}
8484

85-
return JsonResponse::create([
85+
return new JsonResponse([
8686
'object' => 'signed_url',
8787
'attributes' => [
8888
'url' => $url,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
4+
5+
use Carbon\CarbonImmutable;
6+
use Pterodactyl\Models\User;
7+
use Pterodactyl\Models\Server;
8+
use Illuminate\Http\JsonResponse;
9+
use Pterodactyl\Services\Nodes\NodeJWTService;
10+
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
11+
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\UploadFileRequest;
12+
13+
class FileUploadController extends ClientApiController
14+
{
15+
/**
16+
* @var \Pterodactyl\Services\Nodes\NodeJWTService
17+
*/
18+
private $jwtService;
19+
20+
/**
21+
* FileUploadController constructor.
22+
*
23+
* @param \Pterodactyl\Services\Nodes\NodeJWTService $jwtService
24+
*/
25+
public function __construct(
26+
NodeJWTService $jwtService
27+
) {
28+
parent::__construct();
29+
30+
$this->jwtService = $jwtService;
31+
}
32+
33+
/**
34+
* Returns a url where files can be uploaded to.
35+
*
36+
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\UploadFileRequest $request
37+
* @param \Pterodactyl\Models\Server $server
38+
*
39+
* @return \Illuminate\Http\JsonResponse
40+
*/
41+
public function __invoke(UploadFileRequest $request, Server $server)
42+
{
43+
return new JsonResponse([
44+
'object' => 'signed_url',
45+
'attributes' => [
46+
'url' => $this->getUploadUrl($server, $request->user()),
47+
],
48+
]);
49+
}
50+
51+
/**
52+
* Returns a url where files can be uploaded to.
53+
*
54+
* @param \Pterodactyl\Models\Server $server
55+
* @param \Pterodactyl\Models\User $user
56+
* @return string
57+
*/
58+
protected function getUploadUrl(Server $server, User $user)
59+
{
60+
$token = $this->jwtService
61+
->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
62+
->setClaims([
63+
'server_uuid' => $server->uuid,
64+
])
65+
->handle($server->node, $user->id . $server->uuid);
66+
67+
return sprintf(
68+
'%s/upload/file?token=%s',
69+
$server->node->getConnectionAddress(),
70+
$token->__toString()
71+
);
72+
}
73+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Files;
4+
5+
use Pterodactyl\Models\Permission;
6+
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
7+
8+
class UploadFileRequest extends ClientApiRequest
9+
{
10+
/**
11+
* @return string
12+
*/
13+
public function permission()
14+
{
15+
return Permission::ACTION_FILE_CREATE;
16+
}
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import http from '@/api/http';
2+
3+
export default (uuid: string): Promise<string> => {
4+
return new Promise((resolve, reject) => {
5+
http.get(`/api/client/servers/${uuid}/files/upload`)
6+
.then(({ data }) => resolve(data.attributes.url))
7+
.catch(reject);
8+
});
9+
};

resources/scripts/components/server/files/UploadButton.tsx

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import axios from 'axios';
2+
import getFileUploadUrl from '@/api/server/files/getFileUploadUrl';
3+
import useServer from '@/plugins/useServer';
14
import tw from 'twin.macro';
25
import Button from '@/components/elements/Button';
3-
import React, { useState } from 'react';
6+
import React, { useEffect, useState } from 'react';
47
import styled from 'styled-components/macro';
58

69
const ModalMask = styled.div`
@@ -9,31 +12,71 @@ const ModalMask = styled.div`
912
`;
1013

1114
export default () => {
15+
const { uuid } = useServer();
1216
const [ visible, setVisible ] = useState(false);
1317

18+
const handleEscapeEvent = (e: KeyboardEvent) => {
19+
setVisible(false);
20+
};
21+
22+
useEffect(() => {
23+
window.addEventListener('keydown', handleEscapeEvent);
24+
25+
return () => window.removeEventListener('keydown', handleEscapeEvent);
26+
}, [ visible ]);
27+
1428
const onDragOver = (e: any) => {
1529
e.preventDefault();
16-
17-
//console.log(e);
1830
};
1931

2032
const onDragEnter = (e: any) => {
2133
e.preventDefault();
22-
23-
//console.log(e);
2434
};
2535

2636
const onDragLeave = (e: any) => {
2737
e.preventDefault();
28-
29-
//console.log(e);
3038
};
3139

3240
const onFileDrop = (e: any) => {
3341
e.preventDefault();
3442

35-
const files = e.dataTransfer.files;
43+
if (e.dataTransfer === undefined || e.dataTransfer === null) {
44+
return;
45+
}
46+
47+
const files: FileList = e.dataTransfer.files;
3648
console.log(files);
49+
50+
const formData = new FormData();
51+
52+
for (let i = 0; i < files.length; i++) {
53+
console.log(files[i]);
54+
// @ts-ignore
55+
formData.append('files', files[i]);
56+
}
57+
58+
console.log('getFileUploadUrl');
59+
getFileUploadUrl(uuid)
60+
.then(url => {
61+
console.log(url);
62+
63+
// `${url}&directory=`
64+
axios.post(url, formData, {
65+
headers: {
66+
'Content-Type': 'multipart/form-data',
67+
},
68+
})
69+
.then(res => {
70+
console.log(res);
71+
setVisible(false);
72+
})
73+
.catch(error => {
74+
console.error(error);
75+
});
76+
})
77+
.catch(error => {
78+
console.error(error);
79+
});
3780
};
3881

3982
return (

routes/api-client.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
Route::post('/compress', 'Servers\FileController@compress');
6363
Route::post('/delete', 'Servers\FileController@delete');
6464
Route::post('/create-folder', 'Servers\FileController@create');
65+
Route::get('/upload', 'Servers\FileUploadController');
6566
});
6667

6768
Route::group(['prefix' => '/schedules'], function () {

0 commit comments

Comments
 (0)