Add support for file copy and deletion
This commit is contained in:
parent
811026895b
commit
d79fe6982f
|
@ -65,4 +65,20 @@ interface FileRepositoryInterface extends BaseRepositoryInterface
|
|||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function renameFile(string $from, string $to): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Copy a given file and give it a unique name.
|
||||
*
|
||||
* @param string $location
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function copyFile(string $location): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Delete a file or folder for the server.
|
||||
*
|
||||
* @param string $location
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function deleteFile(string $location): ResponseInterface;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ use Illuminate\Http\JsonResponse;
|
|||
use Illuminate\Contracts\Cache\Repository as CacheRepository;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\RenameFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CreateFolderRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DownloadFileRequest;
|
||||
|
@ -86,6 +88,36 @@ class FileController extends ClientApiController
|
|||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a file on the server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function copyFile(CopyFileRequest $request): Response
|
||||
{
|
||||
$this->fileRepository
|
||||
->setServer($request->getModel(Server::class))
|
||||
->copyFile($request->input('location'));
|
||||
|
||||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file or folder from the server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete(DeleteFileRequest $request): Response
|
||||
{
|
||||
$this->fileRepository
|
||||
->setServer($request->getModel(Server::class))
|
||||
->deleteFile($request->input('location'));
|
||||
|
||||
return Response::create('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a reference to a file to download in the cache so that when the
|
||||
* user hits the Daemon and it verifies with the Panel they'll actually be able
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Files;
|
||||
|
||||
use Pterodactyl\Contracts\Http\ClientPermissionsRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class CopyFileRequest extends ClientApiRequest implements ClientPermissionsRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'copy-files';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'location' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Files;
|
||||
|
||||
use Pterodactyl\Contracts\Http\ClientPermissionsRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class DeleteFileRequest extends ClientApiRequest implements ClientPermissionsRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return 'delete-files';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'location' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -106,4 +106,40 @@ class FileRepository extends BaseWingsRepository implements FileRepositoryInterf
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a given file and give it a unique name.
|
||||
*
|
||||
* @param string $location
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function copyFile(string $location): ResponseInterface
|
||||
{
|
||||
return $this->getHttpClient()->post(
|
||||
sprintf('/api/servers/%s/files/copy', $this->getServer()->uuid),
|
||||
[
|
||||
'json' => [
|
||||
'location' => $location,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or folder for the server.
|
||||
*
|
||||
* @param string $location
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function deleteFile(string $location): ResponseInterface
|
||||
{
|
||||
return $this->getHttpClient()->post(
|
||||
sprintf('/api/servers/%s/files/delete', $this->getServer()->uuid),
|
||||
[
|
||||
'json' => [
|
||||
'location' => $location,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import {withCredentials} from "@/api/http";
|
||||
import {ServerApplicationCredentials} from "@/store/types";
|
||||
|
||||
type PathChangeObject = {
|
||||
currentPath: string,
|
||||
newPath: string,
|
||||
}
|
||||
/**
|
||||
* Creates a copy of the given file or directory on the Daemon. Expects a fully resolved path
|
||||
* to be passed through for both data arguments.
|
||||
*/
|
||||
export function copyElement(server: string, credentials: ServerApplicationCredentials, data: PathChangeObject, isMove = false): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
withCredentials(server, credentials).post(`/v1/server/file/${isMove ? 'move' : 'copy'}`, {
|
||||
from: data.currentPath,
|
||||
to: data.newPath,
|
||||
})
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a file or folder to a new location on the server. Works almost exactly the same as the copy
|
||||
* file logic, so it really just passes an extra argument to copy to indicate that it is a move.
|
||||
*/
|
||||
export function moveElement(server: string, credentials: ServerApplicationCredentials, data: PathChangeObject): Promise<void> {
|
||||
return copyElement(server, credentials, data, true);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import http from "@/api/http";
|
||||
|
||||
/**
|
||||
* Creates a copy of the given file or directory on the Daemon. Expects a fully resolved path
|
||||
* to be passed through for both data arguments.
|
||||
*/
|
||||
export function copyFile(server: string, location: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(`/api/client/servers/${server}/files/copy`, {location})
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import {withCredentials} from "@/api/http";
|
||||
import {ServerApplicationCredentials} from "@/store/types";
|
||||
|
||||
/**
|
||||
* Deletes files and/or folders from the server. You should pass through an array of
|
||||
* file or folder paths to be deleted.
|
||||
*/
|
||||
export function deleteElement(server: string, credentials: ServerApplicationCredentials, items: Array<string>): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
withCredentials(server, credentials).post('/v1/server/file/delete', { items })
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import http from "@/api/http";
|
||||
|
||||
/**
|
||||
* Deletes files and/or folders from the server. You should pass through an array of
|
||||
* file or folder paths to be deleted.
|
||||
*/
|
||||
export function deleteFile(server: string, location: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.post(`/api/client/servers/${server}/files/delete`, {location})
|
||||
.then(() => resolve())
|
||||
.catch(reject);
|
||||
})
|
||||
}
|
|
@ -10,12 +10,12 @@
|
|||
import {DirectoryContentObject} from '@/api/server/types';
|
||||
import {mapState} from "vuex";
|
||||
import {ServerState} from '@/store/types';
|
||||
import { join } from 'path';
|
||||
import {copyElement} from '@/api/server/files/copyElement';
|
||||
import {join} from 'path';
|
||||
import {copyFile} from '@/api/server/files/copyFile';
|
||||
import {AxiosError} from "axios";
|
||||
|
||||
export default Vue.extend({
|
||||
components: { SpinnerModal },
|
||||
components: {SpinnerModal},
|
||||
|
||||
computed: mapState('server', {
|
||||
server: (state: ServerState) => state.server,
|
||||
|
@ -24,7 +24,7 @@
|
|||
}),
|
||||
|
||||
props: {
|
||||
file: { type: Object as () => DirectoryContentObject, required: true },
|
||||
file: {type: Object as () => DirectoryContentObject, required: true},
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
copyElement(this.server.uuid, this.credentials, {currentPath: join(this.fm.currentDirectory, this.file.name), newPath})
|
||||
copyFile(this.server.uuid, join(this.fm.currentDirectory, this.file.name))
|
||||
.then(() => this.$emit('close'))
|
||||
.catch((error: AxiosError) => {
|
||||
alert(`There was an error creating a copy of this item: ${error.message}`);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
import Vue from 'vue';
|
||||
import Modal from '@/components/core/Modal.vue';
|
||||
import {DirectoryContentObject} from "@/api/server/types";
|
||||
import {deleteElement} from '@/api/server/files/deleteElement';
|
||||
import {deleteFile} from '@/api/server/files/deleteFile';
|
||||
import {mapState} from "vuex";
|
||||
import {AxiosError} from "axios";
|
||||
import { join } from 'path';
|
||||
|
@ -75,10 +75,7 @@
|
|||
this.isLoading = true;
|
||||
|
||||
// @ts-ignore
|
||||
deleteElement(this.server.uuid, this.credentials, [
|
||||
// @ts-ignore
|
||||
join(this.fm.currentDirectory, this.object.name)
|
||||
])
|
||||
deleteFile(this.server.uuid, join(this.fm.currentDirectory, this.object.name))
|
||||
.then(() => this.$emit('deleted'))
|
||||
.catch((error: AxiosError) => {
|
||||
this.error = `There was an error deleting the requested ${(this.object.directory) ? 'folder' : 'file'}. Response was: ${error.message}`;
|
||||
|
|
|
@ -44,6 +44,8 @@ Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateServ
|
|||
Route::group(['prefix' => '/files'], function () {
|
||||
Route::get('/list', 'Servers\FileController@listDirectory')->name('api.client.servers.files.list');
|
||||
Route::put('/rename', 'Servers\FileController@renameFile')->name('api.client.servers.files.rename');
|
||||
Route::post('/copy', 'Servers\FileController@copyFile')->name('api.client.servers.files.copy');
|
||||
Route::post('/delete', 'Servers\FileController@delete')->name('api.client.servers.files.delete');
|
||||
Route::post('/create-folder', 'Servers\FileController@createFolder')->name('api.client.servers.files.create-folder');
|
||||
|
||||
Route::post('/download/{file}', 'Servers\FileController@download')
|
||||
|
|
Loading…
Reference in New Issue