mirror of https://github.com/Duxez/PteroPack.git
Installs actually work what
This commit is contained in:
parent
3bbf0b5199
commit
11a2f2f272
|
|
@ -5,17 +5,21 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers\CurseForge;
|
||||||
|
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Nette\NotImplementedException;
|
use Nette\NotImplementedException;
|
||||||
use Pterodactyl\Exceptions\DisplayException;
|
use Pterodactyl\Exceptions\DisplayException;
|
||||||
|
use Pterodactyl\Jobs\ModInstall;
|
||||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||||
|
use Pterodactyl\Repositories\Wings\DaemonFileRepository;
|
||||||
|
|
||||||
class ModpackController extends ClientApiController {
|
class ModpackController extends ClientApiController {
|
||||||
private $http_client;
|
private $http_client;
|
||||||
private $minecraft_game_id;
|
private $minecraft_game_id;
|
||||||
private $modpack_class_id;
|
private $modpack_class_id;
|
||||||
|
private $api_key;
|
||||||
|
private DaemonFileRepository $fileRepository;
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
|
public function __construct(DaemonFileRepository $fileRepository) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
if(!config('curseforge.api_key')) {
|
if(!config('curseforge.api_key')) {
|
||||||
|
|
@ -29,8 +33,11 @@ class ModpackController extends ClientApiController {
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->api_key = config('curseforge.api_key');
|
||||||
$this->minecraft_game_id = config('curseforge.minecraft_game_id');
|
$this->minecraft_game_id = config('curseforge.minecraft_game_id');
|
||||||
$this->modpack_class_id = config('curseforge.minecraft_modpack_class_id');
|
$this->modpack_class_id = config('curseforge.minecraft_modpack_class_id');
|
||||||
|
|
||||||
|
$this->fileRepository = $fileRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index(Request $request) {
|
public function index(Request $request) {
|
||||||
|
|
@ -68,7 +75,55 @@ class ModpackController extends ClientApiController {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function install() {
|
public function install($server, $modId, $fileId) {
|
||||||
throw new NotImplementedException();
|
$this->fileRepository->setServer($server)->deleteFiles('/', ['mods']);
|
||||||
|
$this->fileRepository->setServer($server)->deleteFiles('/', ['uninstallable.txt']);
|
||||||
|
|
||||||
|
$modpackFile = json_decode($this->getFileById($modId, $fileId));
|
||||||
|
|
||||||
|
$data = $modpackFile->data;
|
||||||
|
$modpackFileUrl = $this->traceUrl($data->downloadUrl);
|
||||||
|
|
||||||
|
$this->fileRepository->setServer($server)->pull(
|
||||||
|
$modpackFileUrl,
|
||||||
|
'/',
|
||||||
|
['filename' => 'modpack.zip', 'foreground' => true]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->fileRepository->setServer($server)->decompressFile('', 'modpack.zip');
|
||||||
|
$modpackManifest = json_decode($this->fileRepository->setServer($server)->getContent('manifest.json'));
|
||||||
|
|
||||||
|
$job = ModInstall::dispatch($modpackManifest, $server, $this->api_key);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function traceUrl(string $url): string {
|
||||||
|
$httpCode = '';
|
||||||
|
while (!str_contains($httpCode, '200 OK')) {
|
||||||
|
$headers = get_headers($url, 5);
|
||||||
|
$httpCode = $headers[0];
|
||||||
|
if (array_key_exists('Location', $headers) && !empty($headers['Location'])) {
|
||||||
|
$url = $headers['Location'];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getModById(int $modId): string {
|
||||||
|
$result = $this->http_client->get("mods/$modId");
|
||||||
|
|
||||||
|
return $result->getBody()->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFileById(int $modId, int $fileId): string {
|
||||||
|
$result = $this->http_client->get("mods/$modId/files/$fileId");
|
||||||
|
|
||||||
|
return $result->getBody()->getContents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Jobs;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Pterodactyl\Repositories\Wings\DaemonFileRepository;
|
||||||
|
|
||||||
|
class ModInstall implements ShouldQueue {
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
private $http_client;
|
||||||
|
private $api_key;
|
||||||
|
private $modpackManifest;
|
||||||
|
private $server;
|
||||||
|
|
||||||
|
public function __construct(object $modpackManifest, $server, $api_key){
|
||||||
|
$this->api_key = $api_key;
|
||||||
|
$this->modpackManifest = $modpackManifest;
|
||||||
|
$this->server = $server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(DaemonFileRepository $fileRepository) {
|
||||||
|
$this->http_client = new Client([
|
||||||
|
'base_uri' => 'https://api.curseforge.com/v1/',
|
||||||
|
'headers' => [
|
||||||
|
'x-api-key' => $this->api_key,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uninstallable = [];
|
||||||
|
|
||||||
|
foreach($this->modpackManifest->files as $file) {
|
||||||
|
$modFile = json_decode($this->getFileById($file->projectID, $file->fileID));
|
||||||
|
$modFileUrl = $this->traceUrl($modFile->data->downloadUrl);
|
||||||
|
|
||||||
|
if($modFileUrl == null) {
|
||||||
|
$uninstallable[] = $modFile->data->fileName;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileRepository->setServer($this->server)->pull(
|
||||||
|
$modFileUrl,
|
||||||
|
'mods',
|
||||||
|
['filename' => $modFile->data->fileName, 'foreground' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileRepository->putContent('uninstallable.txt', print_r($uninstallable));
|
||||||
|
$fileRepository->deleteFiles('/', ['modpack.zip', 'manifest.json', $this->modpackManifest->overrides]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFileById(int $modId, int $fileId): string {
|
||||||
|
$result = $this->http_client->get("mods/$modId/files/$fileId");
|
||||||
|
|
||||||
|
return $result->getBody()->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function traceUrl(string $url): string {
|
||||||
|
$httpCode = '';
|
||||||
|
while (!str_contains($httpCode, '200 OK')) {
|
||||||
|
$headers = get_headers($url, 5);
|
||||||
|
$httpCode = $headers[0];
|
||||||
|
if (array_key_exists('Location', $headers) && !empty($headers['Location'])) {
|
||||||
|
$url = $headers['Location'];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'api_key' => env('CURSEFORGE_API_KEY'),
|
||||||
|
'minecraft_game_id' => '432',
|
||||||
|
'minecraft_modpack_class_id' => '4471',
|
||||||
|
];
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import http from "@/api/http";
|
||||||
|
|
||||||
|
export default (server: string, modpackId: number, fileId: number): Promise<string> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
http.get(`/api/client/servers/${server}/modpacks/${modpackId}/install/${fileId}`)
|
||||||
|
.then(({ data }) => {
|
||||||
|
console.log(data);
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -8,20 +8,38 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faDownload, faGamepad } from '@fortawesome/free-solid-svg-icons';
|
import { faDownload, faGamepad } from '@fortawesome/free-solid-svg-icons';
|
||||||
import getModpackDescription from '@/api/server/modpacks/getModpackDescription';
|
import getModpackDescription from '@/api/server/modpacks/getModpackDescription';
|
||||||
import { ServerContext } from '@/state/server';
|
import { ServerContext } from '@/state/server';
|
||||||
import { get } from 'http';
|
|
||||||
import pullFile from '@/api/server/files/pullFile';
|
|
||||||
import getFileExists from '@/api/server/files/getFileExists';
|
|
||||||
import Spinner from '@/components/elements/Spinner';
|
import Spinner from '@/components/elements/Spinner';
|
||||||
import decompressFiles from '@/api/server/files/decompressFiles';
|
import installModpack from '@/api/server/modpacks/installModpack';
|
||||||
|
import getFileExists from '@/api/server/files/getFileExists';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modpack: Modpack;
|
modpack: Modpack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ModpackManifest {
|
||||||
|
author: string;
|
||||||
|
files: ModpackFile[]
|
||||||
|
manifestType: string;
|
||||||
|
manifestVersion: number;
|
||||||
|
minecraft: {};
|
||||||
|
name: string;
|
||||||
|
overrides: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModpackFile {
|
||||||
|
projectID: number;
|
||||||
|
fileID: number;
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timer = (ms: number) => new Promise(res => setTimeout(res, ms))
|
||||||
|
|
||||||
export default ({ modpack }: Props) => {
|
export default ({ modpack }: Props) => {
|
||||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||||
const [visible, setVisible] = React.useState(false);
|
const [visible, setVisible] = React.useState(false);
|
||||||
const [installVisible, setInstallVisible] = React.useState(false);
|
const [installVisible, setInstallVisible] = React.useState(false);
|
||||||
|
const [installed, setInstalled] = React.useState(false);
|
||||||
const [modpackDesc, setModpackDesc] = React.useState<string>('');
|
const [modpackDesc, setModpackDesc] = React.useState<string>('');
|
||||||
const [installing, setInstalling] = React.useState(false);
|
const [installing, setInstalling] = React.useState(false);
|
||||||
|
|
||||||
|
|
@ -35,22 +53,17 @@ export default ({ modpack }: Props) => {
|
||||||
|
|
||||||
const install = async (latestFile: File): Promise<void> => {
|
const install = async (latestFile: File): Promise<void> => {
|
||||||
setInstalling(true);
|
setInstalling(true);
|
||||||
pullFile(uuid, {
|
|
||||||
url: latestFile.downloadUrl,
|
|
||||||
directory: '/home/container',
|
|
||||||
filename: 'modpack.zip',
|
|
||||||
use_header: true,
|
|
||||||
foreground: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
let modpackDownloaded = await getFileExists(uuid, '/home/container/modpack.zip');
|
await installModpack(uuid, modpack.id, latestFile.id);
|
||||||
while (!modpackDownloaded) {
|
|
||||||
modpackDownloaded = await getFileExists(uuid, '/home/container/modpack.zip');
|
let uninstallableExists = false;
|
||||||
|
while (!uninstallableExists) {
|
||||||
|
uninstallableExists = await getFileExists(uuid, 'uninstallable.txt') as unknown as boolean;
|
||||||
|
await timer(6500);
|
||||||
}
|
}
|
||||||
|
|
||||||
decompressFiles(uuid, '/home/container/modpack', '/home/container/modpack.zip');
|
|
||||||
|
|
||||||
setInstalling(false);
|
setInstalling(false);
|
||||||
|
setInstalled(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDescription = (): void => {
|
const getDescription = (): void => {
|
||||||
|
|
@ -94,26 +107,31 @@ export default ({ modpack }: Props) => {
|
||||||
<div style={{ maxHeight: '50vh' }}>
|
<div style={{ maxHeight: '50vh' }}>
|
||||||
{installing ? (
|
{installing ? (
|
||||||
<div>
|
<div>
|
||||||
<p>Installing...</p>
|
<p>Installing... This can take a while, sit back, grab a drink and relax</p>
|
||||||
<Spinner centered size='base' />
|
<Spinner centered size='base' />
|
||||||
</div>
|
</div>
|
||||||
|
) : (<>{installed ? (
|
||||||
|
<p>Modpack insatlled, if any mods couldn't be manually installed you can find them in the file 'uninstallable.txt', install them manually before playing.</p>
|
||||||
) : (
|
) : (
|
||||||
modpack.latestFiles.map((file) => (
|
modpack.latestFiles.map((file) => (
|
||||||
<div className='grid grid-cols-3 gap-4'>
|
<div className='grid grid-cols-3 gap-4'>
|
||||||
<p>{file.displayName}</p>
|
<p>{file.displayName}</p>
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
<FontAwesomeIcon icon={faGamepad} style={{ marginRight: '10px' }} />
|
<FontAwesomeIcon icon={faGamepad} style={{ marginRight: '10px' }} />
|
||||||
{file.gameVersions[0]}
|
{file.gameVersions[0]}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
install(file);
|
install(file);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Install
|
Install
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)))}
|
))
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ModpackModal>
|
</ModpackModal>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,150 @@
|
||||||
import { Modpack } from "@/api/server/modpacks/Modpack";
|
<?php
|
||||||
import PortaledModal, { ModalProps } from "@/components/elements/Modal";
|
|
||||||
import React, { PropsWithChildren } from "react";
|
|
||||||
|
|
||||||
export interface ModpackModalProps extends ModalProps {
|
use Illuminate\Support\Facades\Route;
|
||||||
modpack: Modpack;
|
use Pterodactyl\Http\Controllers\Api\Client;
|
||||||
}
|
use Pterodactyl\Http\Middleware\Activity\ServerSubject;
|
||||||
|
use Pterodactyl\Http\Middleware\Activity\AccountSubject;
|
||||||
|
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||||
|
use Pterodactyl\Http\Middleware\Api\Client\Server\ResourceBelongsToServer;
|
||||||
|
use Pterodactyl\Http\Middleware\Api\Client\Server\AuthenticateServerAccess;
|
||||||
|
|
||||||
export default(props: PropsWithChildren<ModpackModalProps>) => {
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Client Control API
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Endpoint: /api/client
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
Route::get('/', [Client\ClientController::class, 'index'])->name('api:client.index');
|
||||||
|
Route::get('/permissions', [Client\ClientController::class, 'permissions']);
|
||||||
|
|
||||||
return (
|
Route::prefix('/account')->middleware(AccountSubject::class)->group(function () {
|
||||||
<PortaledModal visible={props.visible} onDismissed={props.onDismissed} appear={props.appear} top={props.top}>
|
Route::prefix('/')->withoutMiddleware(RequireTwoFactorAuthentication::class)->group(function () {
|
||||||
{props.children}
|
Route::get('/', [Client\AccountController::class, 'index'])->name('api:client.account');
|
||||||
</PortaledModal>
|
Route::get('/two-factor', [Client\TwoFactorController::class, 'index']);
|
||||||
)
|
Route::post('/two-factor', [Client\TwoFactorController::class, 'store']);
|
||||||
}
|
Route::delete('/two-factor', [Client\TwoFactorController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::put('/email', [Client\AccountController::class, 'updateEmail'])->name('api:client.account.update-email');
|
||||||
|
Route::put('/password', [Client\AccountController::class, 'updatePassword'])->name('api:client.account.update-password');
|
||||||
|
|
||||||
|
Route::get('/activity', Client\ActivityLogController::class)->name('api:client.account.activity');
|
||||||
|
|
||||||
|
Route::get('/api-keys', [Client\ApiKeyController::class, 'index']);
|
||||||
|
Route::post('/api-keys', [Client\ApiKeyController::class, 'store']);
|
||||||
|
Route::delete('/api-keys/{identifier}', [Client\ApiKeyController::class, 'delete']);
|
||||||
|
|
||||||
|
Route::prefix('/ssh-keys')->group(function () {
|
||||||
|
Route::get('/', [Client\SSHKeyController::class, 'index']);
|
||||||
|
Route::post('/', [Client\SSHKeyController::class, 'store']);
|
||||||
|
Route::post('/remove', [Client\SSHKeyController::class, 'delete']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Client Control API
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Endpoint: /api/client/servers/{server}
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
Route::group([
|
||||||
|
'prefix' => '/servers/{server}',
|
||||||
|
'middleware' => [
|
||||||
|
ServerSubject::class,
|
||||||
|
AuthenticateServerAccess::class,
|
||||||
|
ResourceBelongsToServer::class,
|
||||||
|
],
|
||||||
|
], function () {
|
||||||
|
Route::get('/', [Client\Servers\ServerController::class, 'index'])->name('api:client:server.view');
|
||||||
|
Route::get('/websocket', Client\Servers\WebsocketController::class)->name('api:client:server.ws');
|
||||||
|
Route::get('/resources', Client\Servers\ResourceUtilizationController::class)->name('api:client:server.resources');
|
||||||
|
Route::get('/activity', Client\Servers\ActivityLogController::class)->name('api:client:server.activity');
|
||||||
|
|
||||||
|
Route::post('/command', [Client\Servers\CommandController::class, 'index']);
|
||||||
|
Route::post('/power', [Client\Servers\PowerController::class, 'index']);
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/modpacks'], function () {
|
||||||
|
Route::get('/', [Client\Servers\CurseForge\ModpackController::class, 'index']);
|
||||||
|
Route::get('/{modpack}', [Client\Servers\CurseForge\ModpackController::class, 'show']);
|
||||||
|
Route::get('/{modpack}/install/{file}', [Client\Servers\CurseForge\ModpackController::class, 'install']);
|
||||||
|
Route::get('/{modpack}/description', [Client\Servers\CurseForge\ModpackController::class, 'description']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/databases'], function () {
|
||||||
|
Route::get('/', [Client\Servers\DatabaseController::class, 'index']);
|
||||||
|
Route::post('/', [Client\Servers\DatabaseController::class, 'store']);
|
||||||
|
Route::post('/{database}/rotate-password', [Client\Servers\DatabaseController::class, 'rotatePassword']);
|
||||||
|
Route::delete('/{database}', [Client\Servers\DatabaseController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/files'], function () {
|
||||||
|
Route::get('/list', [Client\Servers\FileController::class, 'directory']);
|
||||||
|
Route::get('/contents', [Client\Servers\FileController::class, 'contents']);
|
||||||
|
Route::get('/exists', [Client\Servers\FileController::class, 'exists']);
|
||||||
|
Route::get('/download', [Client\Servers\FileController::class, 'download']);
|
||||||
|
Route::put('/rename', [Client\Servers\FileController::class, 'rename']);
|
||||||
|
Route::post('/copy', [Client\Servers\FileController::class, 'copy']);
|
||||||
|
Route::post('/write', [Client\Servers\FileController::class, 'write']);
|
||||||
|
Route::post('/compress', [Client\Servers\FileController::class, 'compress']);
|
||||||
|
Route::post('/decompress', [Client\Servers\FileController::class, 'decompress']);
|
||||||
|
Route::post('/delete', [Client\Servers\FileController::class, 'delete']);
|
||||||
|
Route::post('/create-folder', [Client\Servers\FileController::class, 'create']);
|
||||||
|
Route::post('/chmod', [Client\Servers\FileController::class, 'chmod']);
|
||||||
|
Route::post('/pull', [Client\Servers\FileController::class, 'pull'])->middleware(['throttle:10,5']);
|
||||||
|
Route::get('/upload', Client\Servers\FileUploadController::class);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/schedules'], function () {
|
||||||
|
Route::get('/', [Client\Servers\ScheduleController::class, 'index']);
|
||||||
|
Route::post('/', [Client\Servers\ScheduleController::class, 'store']);
|
||||||
|
Route::get('/{schedule}', [Client\Servers\ScheduleController::class, 'view']);
|
||||||
|
Route::post('/{schedule}', [Client\Servers\ScheduleController::class, 'update']);
|
||||||
|
Route::post('/{schedule}/execute', [Client\Servers\ScheduleController::class, 'execute']);
|
||||||
|
Route::delete('/{schedule}', [Client\Servers\ScheduleController::class, 'delete']);
|
||||||
|
|
||||||
|
Route::post('/{schedule}/tasks', [Client\Servers\ScheduleTaskController::class, 'store']);
|
||||||
|
Route::post('/{schedule}/tasks/{task}', [Client\Servers\ScheduleTaskController::class, 'update']);
|
||||||
|
Route::delete('/{schedule}/tasks/{task}', [Client\Servers\ScheduleTaskController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/network'], function () {
|
||||||
|
Route::get('/allocations', [Client\Servers\NetworkAllocationController::class, 'index']);
|
||||||
|
Route::post('/allocations', [Client\Servers\NetworkAllocationController::class, 'store']);
|
||||||
|
Route::post('/allocations/{allocation}', [Client\Servers\NetworkAllocationController::class, 'update']);
|
||||||
|
Route::post('/allocations/{allocation}/primary', [Client\Servers\NetworkAllocationController::class, 'setPrimary']);
|
||||||
|
Route::delete('/allocations/{allocation}', [Client\Servers\NetworkAllocationController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/users'], function () {
|
||||||
|
Route::get('/', [Client\Servers\SubuserController::class, 'index']);
|
||||||
|
Route::post('/', [Client\Servers\SubuserController::class, 'store']);
|
||||||
|
Route::get('/{user}', [Client\Servers\SubuserController::class, 'view']);
|
||||||
|
Route::post('/{user}', [Client\Servers\SubuserController::class, 'update']);
|
||||||
|
Route::delete('/{user}', [Client\Servers\SubuserController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/backups'], function () {
|
||||||
|
Route::get('/', [Client\Servers\BackupController::class, 'index']);
|
||||||
|
Route::post('/', [Client\Servers\BackupController::class, 'store']);
|
||||||
|
Route::get('/{backup}', [Client\Servers\BackupController::class, 'view']);
|
||||||
|
Route::get('/{backup}/download', [Client\Servers\BackupController::class, 'download']);
|
||||||
|
Route::post('/{backup}/lock', [Client\Servers\BackupController::class, 'toggleLock']);
|
||||||
|
Route::post('/{backup}/restore', [Client\Servers\BackupController::class, 'restore']);
|
||||||
|
Route::delete('/{backup}', [Client\Servers\BackupController::class, 'delete']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/startup'], function () {
|
||||||
|
Route::get('/', [Client\Servers\StartupController::class, 'index']);
|
||||||
|
Route::put('/variable', [Client\Servers\StartupController::class, 'update']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => '/settings'], function () {
|
||||||
|
Route::post('/rename', [Client\Servers\SettingsController::class, 'rename']);
|
||||||
|
Route::post('/reinstall', [Client\Servers\SettingsController::class, 'reinstall']);
|
||||||
|
Route::put('/docker-image', [Client\Servers\SettingsController::class, 'dockerImage']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue