- Front controller and UI in [public/index.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/public/index.php) and [views/dashboard.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/views/dashboard.php)
R2 S3 Signature V4 client in [src/R2/R2Client.php](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/R2/R2Client.php) SQLite mirror, usage ledger, settings, local tags, permission labels, and signed URL history under [src/Repository](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/src/Repository) Simple password auth and CSRF protection Uploads, folders, sync, copy/move/delete, downloads, presigned URLs, CORS JSON management, and usage/billing-style summaries Setup docs in [README.md](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/README.md) and config template in [.env.example](/Users/tyemeclifford/Documents/GH/CloudflareR2-Manager/.env.example) Important R2 caveat: Cloudflare’s current R2 S3 compatibility docs say ACLs and object-tagging APIs are not implemented, so the app stores tags and permission labels locally in SQLite while keeping file bytes on R2. I used Cloudflare’s official docs for S3 compatibility, presigned URLs, and CORS.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use R2Manager\Repository\ObjectRepository;
|
||||
use R2Manager\Repository\SettingsRepository;
|
||||
use R2Manager\Repository\UsageRepository;
|
||||
use R2Manager\Support\Config;
|
||||
use R2Manager\Support\Database;
|
||||
use R2Manager\Support\View;
|
||||
|
||||
$_SERVER['HTTPS'] = 'off';
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SESSION = ['authenticated' => true];
|
||||
|
||||
require dirname(__DIR__) . '/src/bootstrap.php';
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(dirname(__DIR__) . '/src'));
|
||||
foreach ($iterator as $file) {
|
||||
if ($file instanceof SplFileInfo && $file->isFile() && $file->getExtension() === 'php' && $file->getFilename() !== 'bootstrap.php') {
|
||||
require_once $file->getPathname();
|
||||
}
|
||||
}
|
||||
|
||||
$config = new Config(dirname(__DIR__));
|
||||
$database = new Database($config);
|
||||
new ObjectRepository($database);
|
||||
new UsageRepository($database);
|
||||
new SettingsRepository($database);
|
||||
|
||||
ob_start();
|
||||
View::render('login', [
|
||||
'appName' => 'R2 Manager',
|
||||
'csrf' => 'token',
|
||||
'flash' => [],
|
||||
]);
|
||||
|
||||
View::render('dashboard', [
|
||||
'appName' => 'R2 Manager',
|
||||
'bucket' => 'example-bucket',
|
||||
'configured' => false,
|
||||
'missingSettings' => ['R2_ACCOUNT_ID'],
|
||||
'prefix' => '',
|
||||
'breadcrumbs' => [['label' => 'Bucket root', 'prefix' => '']],
|
||||
'search' => '',
|
||||
'tagFilter' => '',
|
||||
'tagNames' => [],
|
||||
'folders' => [],
|
||||
'objects' => [],
|
||||
'stats' => ['objects' => 0, 'folders' => 0, 'bytes' => 0, 'latest_sync' => null],
|
||||
'eventSummary' => [],
|
||||
'billingSummary' => [
|
||||
'storage_bytes' => 0,
|
||||
'class_a_requests' => 0,
|
||||
'class_b_requests' => 0,
|
||||
'local_requests' => 0,
|
||||
'uploaded_bytes' => 0,
|
||||
'downloaded_bytes' => 0,
|
||||
],
|
||||
'dailySummary' => [],
|
||||
'recentShares' => [],
|
||||
'shareCount' => 0,
|
||||
'selected' => null,
|
||||
'selectedPublicUrl' => null,
|
||||
'corsJson' => '[]',
|
||||
'csrf' => 'token',
|
||||
'flash' => [],
|
||||
]);
|
||||
$html = ob_get_clean();
|
||||
|
||||
if (!is_string($html) || !str_contains($html, 'Storage manager') || !str_contains($html, 'Objects')) {
|
||||
throw new RuntimeException('Expected smoke-render content was not produced.');
|
||||
}
|
||||
|
||||
echo "Smoke OK\n";
|
||||
Reference in New Issue
Block a user