From bc05337cf4e0cf1da875a543fd05bf230a94cc5e Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 21 Dec 2024 20:22:07 +0100 Subject: [PATCH] feat: make some changes in database and blueprint settings --- .../Admin/BlueprintAdminLibrary.php | 4 +- .../Client/BlueprintClientLibrary.php | 4 +- .../BlueprintFramework/DeveloperCommand.php | 3 +- .../Version/VersionCacheCommand.php | 2 +- .../Version/VersionLatestCommand.php | 4 +- app/Console/Kernel.php | 4 +- .../BlueprintExtensionController.php | 46 +--- .../Admin/ExtensionsController.php | 3 + .../BlueprintTelemetryCollectionService.php | 6 +- .../Telemetry/RegisterBlueprintTelemetry.php | 4 +- blueprint.sh | 11 +- blueprint/design/schema.txt | 26 ++ database/Seeders/BlueprintSeeder.php | 226 ++++++++++++++++++ resources/views/admin/extensions.blade.php | 6 +- routes/blueprint.php | 1 - 15 files changed, 283 insertions(+), 67 deletions(-) create mode 100644 blueprint/design/schema.txt create mode 100644 database/Seeders/BlueprintSeeder.php diff --git a/app/BlueprintFramework/Libraries/ExtensionLibrary/Admin/BlueprintAdminLibrary.php b/app/BlueprintFramework/Libraries/ExtensionLibrary/Admin/BlueprintAdminLibrary.php index c5cb64b2..1b17cf59 100644 --- a/app/BlueprintFramework/Libraries/ExtensionLibrary/Admin/BlueprintAdminLibrary.php +++ b/app/BlueprintFramework/Libraries/ExtensionLibrary/Admin/BlueprintAdminLibrary.php @@ -66,7 +66,7 @@ public function notifyNow($text): void */ public function importStylesheet(string $url): string { - $cache = $this->dbGet('blueprint', 'cache', 0); + $cache = $this->dbGet('blueprint', 'internal:cache', 0); return ""; } @@ -81,7 +81,7 @@ public function importStylesheet(string $url): string */ public function importScript(string $url): string { - $cache = $this->dbGet('blueprint', 'cache', 0); + $cache = $this->dbGet('blueprint', 'internal:cache', 0); return ""; } diff --git a/app/BlueprintFramework/Libraries/ExtensionLibrary/Client/BlueprintClientLibrary.php b/app/BlueprintFramework/Libraries/ExtensionLibrary/Client/BlueprintClientLibrary.php index 4e0864d2..482d15ba 100644 --- a/app/BlueprintFramework/Libraries/ExtensionLibrary/Client/BlueprintClientLibrary.php +++ b/app/BlueprintFramework/Libraries/ExtensionLibrary/Client/BlueprintClientLibrary.php @@ -28,7 +28,7 @@ class BlueprintClientLibrary extends BlueprintBaseLibrary */ public function importStylesheet(string $url): string { - $cache = $this->dbGet('blueprint', 'cache', 0); + $cache = $this->dbGet('blueprint', 'internal:cache', 0); return ""; } @@ -43,7 +43,7 @@ public function importStylesheet(string $url): string */ public function importScript(string $url): string { - $cache = $this->dbGet('blueprint', 'cache', 0); + $cache = $this->dbGet('blueprint', 'internal:cache', 0); return ""; } diff --git a/app/Console/Commands/BlueprintFramework/DeveloperCommand.php b/app/Console/Commands/BlueprintFramework/DeveloperCommand.php index 5159e14e..32209f65 100644 --- a/app/Console/Commands/BlueprintFramework/DeveloperCommand.php +++ b/app/Console/Commands/BlueprintFramework/DeveloperCommand.php @@ -24,8 +24,7 @@ public function __construct( */ public function handle() { - $developer = $this->blueprint->dbGet('blueprint', 'developer', 'false') === 'true'; - if ($developer) { + if ($this->blueprint->dbGet('blueprint', 'flags:is_developer', 0)) { echo ("true"); return; } diff --git a/app/Console/Commands/BlueprintFramework/Version/VersionCacheCommand.php b/app/Console/Commands/BlueprintFramework/Version/VersionCacheCommand.php index 08756de1..665a6a6a 100644 --- a/app/Console/Commands/BlueprintFramework/Version/VersionCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/Version/VersionCacheCommand.php @@ -39,7 +39,7 @@ public function handle() $data = json_decode($cleaned_response, true); if (isset($data['name'])) { $latest_version = $data['name']; - $this->blueprint->dbSet('blueprint', 'version:latest', $latest_version); + $this->blueprint->dbSet('blueprint', 'internal:version:latest', $latest_version); return true; } else { echo "Error: Unable to fetch the latest release version."; diff --git a/app/Console/Commands/BlueprintFramework/Version/VersionLatestCommand.php b/app/Console/Commands/BlueprintFramework/Version/VersionLatestCommand.php index 6402c633..a5a32894 100644 --- a/app/Console/Commands/BlueprintFramework/Version/VersionLatestCommand.php +++ b/app/Console/Commands/BlueprintFramework/Version/VersionLatestCommand.php @@ -28,10 +28,10 @@ public function __construct( */ public function handle() { - $latest = $this->blueprint->dbGet('blueprint', 'version:latest'); + $latest = $this->blueprint->dbGet('blueprint', 'internal:version:latest'); if ($latest == "") { $this->call('bp:version:cache'); - $latest = $this->blueprint->dbGet('blueprint', 'version:latest'); + $latest = $this->blueprint->dbGet('blueprint', 'internal:version:latest'); } echo ($latest); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index d157bedb..a626e616 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,6 +14,7 @@ use Pterodactyl\Console\Commands\Maintenance\PruneOrphanedBackupsCommand; use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand; use Pterodactyl\Services\Telemetry\RegisterBlueprintTelemetry; +use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Console\BlueprintConsoleLibrary as BlueprintExtensionLibrary; class Kernel extends ConsoleKernel { @@ -52,7 +53,8 @@ protected function schedule(Schedule $schedule): void } // Blueprint telemetry - if (config('blueprint.telemetry')) { + $blueprint = app()->make(BlueprintExtensionLibrary::class); + if ($blueprint->dbGet('blueprint', 'flags:telemetry_enabled', 0)) { $registerBlueprintTelemetry = app()->make(RegisterBlueprintTelemetry::class); $registerBlueprintTelemetry->register($schedule); } diff --git a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php index 32fb9011..c7b13b3a 100644 --- a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php +++ b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php @@ -2,11 +2,7 @@ namespace Pterodactyl\Http\Controllers\Admin\Extensions\Blueprint; -use Illuminate\View\View; -use Illuminate\View\Factory as ViewFactory; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\BlueprintFramework\Services\PlaceholderService\BlueprintPlaceholderService; -use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Admin\BlueprintAdminLibrary as BlueprintExtensionLibrary; use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface; use Illuminate\Http\RedirectResponse; use Pterodactyl\Http\Requests\Admin\AdminFormRequest; @@ -18,32 +14,10 @@ class BlueprintExtensionController extends Controller * BlueprintExtensionController constructor. */ public function __construct( - private BlueprintExtensionLibrary $ExtensionLibrary, - private BlueprintPlaceholderService $PlaceholderService, - - private ViewFactory $view, private SettingsRepositoryInterface $settings, ) { } - /** - * Return the admin index view. - */ - public function index(): View - { - $LatestVersion = $this->ExtensionLibrary->dbGet('blueprint', 'version:latest'); - return $this->view->make( - 'admin.extensions.blueprint.index', - [ - 'ExtensionLibrary' => $this->ExtensionLibrary, - 'PlaceholderService' => $this->PlaceholderService, - 'LatestVersion' => $LatestVersion, - - 'root' => "/admin/extensions/blueprint", - ] - ); - } - /** * @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException @@ -54,31 +28,17 @@ public function update(BlueprintAdminFormRequest $request): RedirectResponse $this->settings->set('blueprint::' . $key, $value); } - // Confirm that the database value changes have been applied. - $this->ExtensionLibrary->notify("Your changes have been saved."); - // Redirect back to the page the user was on. - return redirect()->route('admin.extensions.blueprint.index'); + return redirect()->route('admin.extensions'); } } class BlueprintAdminFormRequest extends AdminFormRequest { - // Form validation for settings on the Blueprint admin page. - // This is included in the controller directly as that - // simplifies my work. public function rules(): array { return [ - 'placeholder' => 'string', - 'developer' => 'string|in:true,false', - ]; - } - - public function attributes(): array - { - return [ - 'placeholder' => 'Placeholder Value', - 'developer' => 'Developer Mode', + 'flags:is_developer' => 'boolean', + 'flags:telemetry_enabled' => 'boolean', ]; } } diff --git a/app/Http/Controllers/Admin/ExtensionsController.php b/app/Http/Controllers/Admin/ExtensionsController.php index c93594d1..219aed50 100644 --- a/app/Http/Controllers/Admin/ExtensionsController.php +++ b/app/Http/Controllers/Admin/ExtensionsController.php @@ -27,9 +27,12 @@ public function __construct( */ public function index(): View { + $configuration = $this->blueprint->dbGetMany('blueprint'); + return $this->view->make('admin.extensions', [ 'blueprint' => $this->blueprint, 'PlaceholderService' => $this->PlaceholderService, + 'configuration' => $configuration, 'version' => $this->version, 'root' => "/admin/extensions", diff --git a/app/Services/Telemetry/BlueprintTelemetryCollectionService.php b/app/Services/Telemetry/BlueprintTelemetryCollectionService.php index 60e92a2b..6cf757d4 100644 --- a/app/Services/Telemetry/BlueprintTelemetryCollectionService.php +++ b/app/Services/Telemetry/BlueprintTelemetryCollectionService.php @@ -40,10 +40,10 @@ public function __invoke(): void */ public function collect(): array { - $uuid = $this->blueprint->dbGet('blueprint', 'uuid'); + $uuid = $this->blueprint->dbGet('blueprint', 'internal:uuid'); if (is_null($uuid)) { $uuid = Uuid::uuid4()->toString(); - $this->blueprint->dbSet('blueprint', 'uuid', $uuid); + $this->blueprint->dbSet('blueprint', 'internal:uuid', $uuid); } return [ @@ -53,7 +53,7 @@ public function collect(): array 'blueprint' => [ 'version' => $this->placeholderService->version(), 'extensions' => $this->blueprint->extensions()->toArray(), - 'developer' => $this->blueprint->dbGet('blueprint', 'developer', 'false') === "true", + 'developer' => $this->blueprint->dbGet('blueprint', 'flags:is_developer', 'false') === "true", 'docker' => file_exists('/.dockerenv'), ], diff --git a/app/Services/Telemetry/RegisterBlueprintTelemetry.php b/app/Services/Telemetry/RegisterBlueprintTelemetry.php index 1c035611..ad449ec9 100644 --- a/app/Services/Telemetry/RegisterBlueprintTelemetry.php +++ b/app/Services/Telemetry/RegisterBlueprintTelemetry.php @@ -19,10 +19,10 @@ public function register(Schedule $schedule): void { $blueprint = app()->make(BlueprintExtensionLibrary::class); - $uuid = $blueprint->dbGet('blueprint', 'uuid'); + $uuid = $blueprint->dbGet('blueprint', 'internal:uuid'); if (is_null($uuid)) { $uuid = Uuid::uuid4()->toString(); - $blueprint->dbSet('blueprint', 'uuid', $uuid); + $blueprint->dbSet('blueprint', 'internal:uuid', $uuid); } // Calculate a fixed time to run the data push at, this will be the same time every day. diff --git a/blueprint.sh b/blueprint.sh index 5c950af6..179501f4 100644 --- a/blueprint.sh +++ b/blueprint.sh @@ -228,7 +228,7 @@ if [[ $1 != "-bash" ]]; then exit 2 else # Only run if Blueprint is not in the process of upgrading. - if [[ $BLUEPRINT_ENVIRONMENT != "upgrade" ]]; then + if [[ ( $BLUEPRINT_ENVIRONMENT != "upgrade" ) && ( $1 != "--post-upgrade" ) ]]; then # Print Blueprint icon with ascii characters. C0="\x1b[0m" C1="\x1b[31;43;1m" @@ -303,14 +303,15 @@ if [[ $1 != "-bash" ]]; then php artisan up &>> "$BLUEPRINT__DEBUG" fi + # Let the panel know the user has finished installation. + dbAdd "blueprint.setupFinished" + sed -i "s~NOTINSTALLED~INSTALLED~g" "$FOLDER/app/BlueprintFramework/Services/PlaceholderService/BlueprintPlaceholderService.php" + # Finish installation - if [[ $BLUEPRINT_ENVIRONMENT != "upgrade" ]]; then + if [[ ( $BLUEPRINT_ENVIRONMENT != "upgrade" ) && ( $1 != "--post-upgrade" ) ]]; then PRINT SUCCESS "Blueprint has completed its installation process." fi - # Let the panel know the user has finished installation. - dbAdd "blueprint.setupFinished" - sed -i "s~NOTINSTALLED~INSTALLED~g" "$FOLDER/app/BlueprintFramework/Services/PlaceholderService/BlueprintPlaceholderService.php" exit 0 fi fi diff --git a/blueprint/design/schema.txt b/blueprint/design/schema.txt new file mode 100644 index 00000000..6b6f4644 --- /dev/null +++ b/blueprint/design/schema.txt @@ -0,0 +1,26 @@ +blueprint + internal + seed true boolean + uuid * string + cache * integer + version + latest * string + flags + is_developer false boolean + telemetry_enabled true boolean + notification + text - string + + + + +* indicates a value is dynamically changed and + isn't a static value +- indicates an empty value + +structure: + record | default | type + +purpose of this file: + internal overview of database records managed + and used for blueprint \ No newline at end of file diff --git a/database/Seeders/BlueprintSeeder.php b/database/Seeders/BlueprintSeeder.php new file mode 100644 index 00000000..f8f663fe --- /dev/null +++ b/database/Seeders/BlueprintSeeder.php @@ -0,0 +1,226 @@ + [ + 'seed' => [ + 'default' => true, + 'type' => 'boolean' + ], + 'uuid' => [ + 'default' => null, + 'type' => 'string' + ], + 'version' => [ + 'latest' => [ + 'default' => null, // Dynamic value + 'type' => 'string' + ] + ] + ], + 'flags' => [ + 'is_developer' => [ + 'default' => false, + 'type' => 'boolean' + ], + 'telemetry_enabled' => [ + 'default' => true, + 'type' => 'boolean' + ] + ], + 'notification' => [ + 'text' => [ + 'default' => null, + 'type' => 'string' + ] + ] + ]; + + /** + * @var BlueprintExtensionLibrary + */ + private BlueprintExtensionLibrary $blueprint; + + /** + * BlueprintSeeder constructor. + */ + public function __construct(BlueprintExtensionLibrary $blueprint) + { + $this->blueprint = $blueprint; + } + + /** + * Run the database seeds. + */ + public function run(): void + { + $this->info('Seeding Blueprint...'); + + $isSeeded = $this->blueprint->dbGet('blueprint', 'internal:seed', false); + + if ($isSeeded) { + $this->info('Database already seeded - updating records'); + $this->updateRecords(); + } else { + $this->info('Fresh database detected - seeding records'); + $this->createRecords(); + } + + $this->info('Blueprint seeding completed successfully.'); + } + + /** + * Create initial records in the database. + */ + private function createRecords(): void + { + $records = []; + + foreach ($this->schema as $category => $values) { + $this->info("Processing category: {$category}"); + $categoryRecords = $this->buildCategoryRecords($category, $values); + $records = array_merge($records, $categoryRecords); + } + + if (!empty($records)) { + $this->info("Setting " . count($records) . " initial records..."); + $this->blueprint->dbSetMany('blueprint', $records); + $this->info("Initial records created successfully"); + } + + // Mark as seeded after successful creation + $this->blueprint->dbSet('blueprint', 'internal:seed', true); + $this->info("Database marked as seeded"); + } + + /** + * Update existing records in the database. + */ + private function updateRecords(): void + { + // First, get all existing records + $existingPaths = $this->getAllSchemaPaths(); + $this->info("Fetching " . count($existingPaths) . " existing records..."); + $existingRecords = $this->blueprint->dbGetMany('blueprint', $existingPaths); + + $recordsToUpdate = []; + + foreach ($this->schema as $category => $values) { + $this->info("Checking category: {$category} for missing records"); + $categoryRecords = $this->buildUpdateRecords($category, $values, $existingRecords); + $recordsToUpdate = array_merge($recordsToUpdate, $categoryRecords); + } + + if (!empty($recordsToUpdate)) { + $this->info("Updating " . count($recordsToUpdate) . " missing records..."); + $this->blueprint->dbSetMany('blueprint', $recordsToUpdate); + $this->info("Missing records updated successfully"); + } else { + $this->info("No missing records found - database is up to date"); + } + } + + /** + * Build records array for a category recursively. + */ + private function buildCategoryRecords(string $category, array $values, string $prefix = ''): array + { + $records = []; + + foreach ($values as $key => $config) { + $path = $prefix ? "{$prefix}:{$key}" : "{$category}:{$key}"; + + if (is_array($config) && isset($config['type'])) { + // This is a leaf node with a value to seed + if ($config['default'] !== null) { + $records[$path] = $config['default']; + } + } else { + // This is a nested category + $records = array_merge($records, $this->buildCategoryRecords($category, $config, $path)); + } + } + + return $records; + } + + /** + * Build update records array for a category recursively. + */ + private function buildUpdateRecords(string $category, array $values, array $existingRecords, string $prefix = ''): array + { + $records = []; + + foreach ($values as $key => $config) { + $path = $prefix ? "{$prefix}:{$key}" : "{$category}:{$key}"; + + if (is_array($config) && isset($config['type'])) { + // This is a leaf node - check if it exists + if (!isset($existingRecords[$path]) && $config['default'] !== null) { + $records[$path] = $config['default']; + $this->info("Found missing record: {$path}"); + } + } else { + // This is a nested category + $records = array_merge($records, $this->buildUpdateRecords($category, $config, $existingRecords, $path)); + } + } + + return $records; + } + + /** + * Get all possible paths from the schema. + */ + private function getAllSchemaPaths(): array + { + $paths = []; + + foreach ($this->schema as $category => $values) { + $paths = array_merge($paths, $this->extractPaths($category, $values)); + } + + return $paths; + } + + /** + * Extract all possible paths from a category recursively. + */ + private function extractPaths(string $category, array $values, string $prefix = ''): array + { + $paths = []; + + foreach ($values as $key => $config) { + $path = $prefix ? "{$prefix}:{$key}" : "{$category}:{$key}"; + + if (is_array($config) && isset($config['type'])) { + $paths[] = $path; + } else { + $paths = array_merge($paths, $this->extractPaths($category, $config, $path)); + } + } + + return $paths; + } + + /** + * Output an info message. + */ + private function info(string $message): void + { + if (app()->runningInConsole()) { + $this->command->info($message); + } + } +} \ No newline at end of file diff --git a/resources/views/admin/extensions.blade.php b/resources/views/admin/extensions.blade.php index 232297d7..db1dbe60 100644 --- a/resources/views/admin/extensions.blade.php +++ b/resources/views/admin/extensions.blade.php @@ -100,7 +100,7 @@