Initial commit
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
138
admin/controller.php
Normal file
138
admin/controller.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Extensions\s3manager;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Admin\BlueprintAdminLibrary as BlueprintExtensionLibrary;
|
||||
|
||||
class s3managerExtensionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private ViewFactory $view,
|
||||
private BlueprintExtensionLibrary $blueprint,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle both GET and POST requests.
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$message = null;
|
||||
|
||||
// Handle backup driver selection
|
||||
if ($request->has('save_driver')) {
|
||||
\Artisan::call('config:clear');
|
||||
$driver = $request->input('APP_BACKUP_DRIVER');
|
||||
if (!in_array($driver, ['s3', 'wings'])) {
|
||||
// Use the 'message' variable to pass a message to the view
|
||||
$message = 'Invalid backup driver selected.';
|
||||
return $this->view->make(
|
||||
'admin.extensions.{identifier}.index', [
|
||||
'root' => "/admin/extensions/{identifier}",
|
||||
'blueprint' => $this->blueprint,
|
||||
'message' => $message, // Pass the message to the view
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$this->setEnvironmentValue([
|
||||
'APP_BACKUP_DRIVER' => $driver,
|
||||
]);
|
||||
|
||||
$message = 'Backup driver updated successfully!';
|
||||
}
|
||||
|
||||
// Only validate and save S3-related values if `save_env` was used
|
||||
if ($request->has('save_env')) {
|
||||
\Artisan::call('config:clear');
|
||||
$endpoint = rtrim($request->input('AWS_ENDPOINT'), '/');
|
||||
$validatedUrl = filter_var($endpoint, FILTER_VALIDATE_URL);
|
||||
|
||||
if (!$validatedUrl) {
|
||||
$message = 'Invalid endpoint URL.';
|
||||
return $this->view->make(
|
||||
'admin.extensions.{identifier}.index', [
|
||||
'root' => "/admin/extensions/{identifier}",
|
||||
'blueprint' => $this->blueprint,
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$allowedStorageClasses = ['STANDARD', 'STANDARD_IA', 'GLACIER'];
|
||||
$storageClass = strtoupper($request->input('AWS_BACKUPS_STORAGE_CLASS'));
|
||||
|
||||
if (!in_array($storageClass, $allowedStorageClasses)) {
|
||||
$message = 'Invalid storage class selected.';
|
||||
return $this->view->make(
|
||||
'admin.extensions.{identifier}.index', [
|
||||
'root' => "/admin/extensions/{identifier}",
|
||||
'blueprint' => $this->blueprint,
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$maxPartSizeGB = min((int) $request->input('BACKUP_MAX_PART_SIZE_GB'), 5);
|
||||
$maxPartSizeBytes = $maxPartSizeGB * 1024 * 1024 * 1024;
|
||||
|
||||
$this->setEnvironmentValue([
|
||||
'AWS_DEFAULT_REGION' => $request->input('AWS_DEFAULT_REGION'),
|
||||
'AWS_ACCESS_KEY_ID' => $request->input('AWS_ACCESS_KEY_ID'),
|
||||
'AWS_SECRET_ACCESS_KEY' => $request->input('AWS_SECRET_ACCESS_KEY'),
|
||||
'AWS_BACKUPS_BUCKET' => $request->input('AWS_BACKUPS_BUCKET'),
|
||||
'AWS_ENDPOINT' => $validatedUrl,
|
||||
'AWS_USE_PATH_STYLE_ENDPOINT' => $request->input('AWS_USE_PATH_STYLE_ENDPOINT') === 'true' ? 'true' : 'false',
|
||||
'AWS_BACKUPS_STORAGE_CLASS' => $storageClass,
|
||||
'BACKUP_MAX_PART_SIZE' => $maxPartSizeBytes,
|
||||
'BACKUP_PRESIGNED_URL_LIFESPAN' => (int) $request->input('BACKUP_PRESIGNED_URL_LIFESPAN'),
|
||||
]);
|
||||
|
||||
$message = 'Environment variables updated successfully!';
|
||||
}
|
||||
|
||||
// Return the view with the message
|
||||
return $this->view->make(
|
||||
'admin.extensions.{identifier}.index', [
|
||||
'root' => "/admin/extensions/{identifier}",
|
||||
'blueprint' => $this->blueprint,
|
||||
'message' => $message, // Pass the message to the view
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle POST requests by delegating to index().
|
||||
*/
|
||||
public function post(Request $request): View
|
||||
{
|
||||
return $this->index($request);
|
||||
}
|
||||
|
||||
protected function setEnvironmentValue(array $values)
|
||||
{
|
||||
$envPath = base_path('.env');
|
||||
$envContent = File::get($envPath);
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
// If the key already exists, replace it with the new value.
|
||||
$pattern = "/^$key=.*$/m";
|
||||
$replacement = $key . '=' . $value;
|
||||
|
||||
if (preg_match($pattern, $envContent)) {
|
||||
// If the key exists, replace the line.
|
||||
$envContent = preg_replace($pattern, $replacement, $envContent);
|
||||
} else {
|
||||
// If the key doesn't exist, append it to the end of the file.
|
||||
$envContent .= "\n$replacement";
|
||||
}
|
||||
}
|
||||
|
||||
// Write the updated content back to the .env file.
|
||||
File::put($envPath, $envContent);
|
||||
}
|
||||
}
|
||||
109
admin/view.blade.php
Normal file
109
admin/view.blade.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<!--
|
||||
Content on this page will be displayed on your extension's admin page.
|
||||
-->
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Information</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>
|
||||
An Extension For Managing <code>S3 Storage</code> Credentials.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Backup Driver</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<form method="POST" action="{{ $root }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group">
|
||||
<label for="backup_driver">Select Backup Driver</label>
|
||||
<select name="APP_BACKUP_DRIVER" id="backup_driver" class="form-control">
|
||||
<option value="s3" {{ env('APP_BACKUP_DRIVER') === 's3' ? 'selected' : '' }}>S3 (Remote)</option>
|
||||
<option value="wings" {{ env('APP_BACKUP_DRIVER') === 'wings' ? 'selected' : '' }}>Wings (Local)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" name="save_driver" value="1" class="btn btn-warning">Save Driver</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Management</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<!-- Display success or error message if available -->
|
||||
@if(isset($message) && $message)
|
||||
<div class="alert alert-success">
|
||||
{{ $message }}
|
||||
</div>
|
||||
@endif
|
||||
<form method="POST" action="{{ $root }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group">
|
||||
<label for="region">AWS Region</label>
|
||||
<input type="text" id="region" name="AWS_DEFAULT_REGION" class="form-control" value="{{ env('AWS_DEFAULT_REGION') }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="key">Access Key ID</label>
|
||||
<input type="text" id="key" name="AWS_ACCESS_KEY_ID" class="form-control" value="{{ env('AWS_ACCESS_KEY_ID') }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="secret">Secret Access Key</label>
|
||||
<input type="text" id="secret" name="AWS_SECRET_ACCESS_KEY" class="form-control" value="{{ env('AWS_SECRET_ACCESS_KEY') }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="bucket">Bucket Name</label>
|
||||
<input type="text" id="bucket" name="AWS_BACKUPS_BUCKET" class="form-control" value="{{ env('AWS_BACKUPS_BUCKET') }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="endpoint">Endpoint</label>
|
||||
<input type="url" id="endpoint" name="AWS_ENDPOINT" class="form-control" value="{{ rtrim(env('AWS_ENDPOINT'), '/') }}" placeholder="https://s3.example.com">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="path_style">Path Style Endpoint</label>
|
||||
<select name="AWS_USE_PATH_STYLE_ENDPOINT" class="form-control">
|
||||
<option value="true" {{ env('AWS_USE_PATH_STYLE_ENDPOINT') == 'true' ? 'selected' : '' }}>true</option>
|
||||
<option value="false" {{ env('AWS_USE_PATH_STYLE_ENDPOINT') == 'false' ? 'selected' : '' }}>false</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="storage_class">Storage Class</label>
|
||||
<select name="AWS_BACKUPS_STORAGE_CLASS" class="form-control">
|
||||
<option value="STANDARD" {{ env('AWS_BACKUPS_STORAGE_CLASS') == 'STANDARD' ? 'selected' : '' }}>STANDARD</option>
|
||||
<option value="STANDARD_IA" {{ env('AWS_BACKUPS_STORAGE_CLASS') == 'STANDARD_IA' ? 'selected' : '' }}>STANDARD_IA</option>
|
||||
<option value="GLACIER" {{ env('AWS_BACKUPS_STORAGE_CLASS') == 'GLACIER' ? 'selected' : '' }}>GLACIER</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="part_size">Max Part Size (GB)</label>
|
||||
<input type="number" min="1" max="5" step="1" id="part_size" name="BACKUP_MAX_PART_SIZE_GB" class="form-control" value="{{ intval(env('BACKUP_MAX_PART_SIZE')) / 1073741824 }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lifespan">Presigned URL Lifespan (seconds)</label>
|
||||
<input type="number" id="lifespan" name="BACKUP_PRESIGNED_URL_LIFESPAN" class="form-control" value="{{ env('BACKUP_PRESIGNED_URL_LIFESPAN') }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" name="save_env" value="1" class="btn btn-primary">Save Settings</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
37
conf.yml
Normal file
37
conf.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
info:
|
||||
name: "S3 Manager"
|
||||
identifier: "s3manager"
|
||||
description: "Setup S3 Bucket For Backups System"
|
||||
flags: ""
|
||||
version: "1.0.0"
|
||||
target: "beta-2024-12"
|
||||
author: "nekomonci12"
|
||||
icon: "public/S3Manager.png"
|
||||
website: ""
|
||||
|
||||
admin:
|
||||
view: "admin/view.blade.php"
|
||||
controller: "admin/controller.php"
|
||||
css: ""
|
||||
wrapper: ""
|
||||
|
||||
dashboard:
|
||||
css: ""
|
||||
wrapper: ""
|
||||
components: ""
|
||||
|
||||
data:
|
||||
directory: ""
|
||||
public: ""
|
||||
console: ""
|
||||
|
||||
requests:
|
||||
views: ""
|
||||
app: ""
|
||||
routers:
|
||||
application: ""
|
||||
client: ""
|
||||
web: ""
|
||||
|
||||
database:
|
||||
migrations: ""
|
||||
BIN
public/S3Manager.png
Normal file
BIN
public/S3Manager.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
Reference in New Issue
Block a user