From 8261184b57dd18e3b877eea8e77a594050db6caa Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sun, 30 Mar 2025 14:44:03 -0400 Subject: [PATCH] Officially support PostgreSQL database (#1066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Just skip this table because it no longer exists * Add postgresql * This no longer needs to be there * These are the same output in mysql, but different in postgresql * Fix these migrations for postgresql * This table no longer exists * This is expected to be a json column for json operations, required for postgresql * Shoot for the stars * Fix pint * Why was this missing * Updates * Restore this * This needs to be explicit * Don’t like strings * Fix these classes * Use different method to compare dates * Apparently postgresql doesn’t like case insensitivity * Postgresql orders it backwards * Ordered different by postgresql * Unnecessary and breaking * Make sure the order is correct for postresql * Fix this with the order too * Remove this * Force email to be lowercased * Update app/Models/User.php --- .env.example | 1 - .github/workflows/ci.yaml | 76 +++++++++++++++ .../UserResource/Pages/CreateUser.php | 7 ++ app/Livewire/Installer/Steps/DatabaseStep.php | 29 ++++-- app/Models/User.php | 4 + .../Deployment/AllocationSelectionService.php | 4 +- config/database.php | 15 +++ .../2016_01_23_195851_add_api_keys.php | 2 +- .../2016_01_23_200159_add_downloads.php | 4 +- .../2016_01_23_200648_add_nodes.php | 2 +- .../2016_01_23_201748_add_servers.php | 6 +- .../2016_01_23_203150_add_subusers.php | 2 +- .../2016_01_23_203159_add_users.php | 6 +- ...01_25_234418_rename_permissions_column.php | 25 ----- ...9_04_182835_create_notifications_table.php | 2 +- ...016_09_07_163017_add_unique_identifier.php | 2 +- .../2016_10_07_152117_build_api_log_table.php | 4 +- ...6_10_23_203522_add_foreign_permissions.php | 33 ------- .../2016_11_11_220649_add_pack_support.php | 2 +- ...create_node_configuration_tokens_table.php | 2 +- .../2017_02_02_175548_UpdateColumnNames.php | 2 +- .../2017_02_03_140948_UpdateNodesTable.php | 4 +- .../2017_02_03_155554_RenameColumns.php | 4 +- .../2017_02_05_164123_AdjustColumnNames.php | 4 +- ...64516_AdjustColumnNamesForServicePacks.php | 4 +- ...2_09_174834_SetupPermissionsPivotTable.php | 81 ---------------- ...7_02_10_171858_UpdateAPIKeyColumnNames.php | 4 +- .../2017_05_01_141528_DeleteDownloadTable.php | 4 +- ...01_141559_DeleteNodeConfigurationTable.php | 2 +- ...eUserPermissionsToDeleteOnUserDeletion.php | 12 --- ...dPermissionsToPointToNewScheduleSystem.php | 43 -------- ...628_RemoveDaemonSecretFromServersTable.php | 2 +- ...22_RemoveDaemonSecretFromSubusersTable.php | 2 +- ...angeServicesToUseAMoreUniqueIdentifier.php | 2 +- ...ngeToABetterUniqueServiceConfiguration.php | 2 +- ...122708_MigratePubPrivFormatToSingleKey.php | 15 ++- ...1_13_142012_SetupTableForKeyEncryption.php | 2 +- ..._merge_permissions_table_into_subusers.php | 97 ------------------- ...2020_04_03_230614_create_backups_table.php | 2 +- ...4_store_node_tokens_as_encrypted_value.php | 4 +- .../2020_05_20_234655_add_mounts_table.php | 2 +- .../2020_09_13_110047_drop_packs_table.php | 2 +- ...ort_multiple_docker_images_and_updates.php | 8 +- ...uccessful_nullable_in_server_transfers.php | 25 +++++ ...chived_field_to_server_transfers_table.php | 2 +- ..._24_092449_make_allocation_fields_json.php | 9 ++ ...1_01_17_102401_create_audit_logs_table.php | 2 +- ...52623_add_generic_server_status_column.php | 6 +- ...n_month_field_to_have_value_if_missing.php | 4 +- ...21_07_12_013420_remove_userinteraction.php | 9 ++ ...5_28_135717_create_activity_logs_table.php | 2 +- .../2024_03_12_154408_remove_nests_table.php | 2 +- ...24_07_25_072050_convert_rules_to_array.php | 6 ++ .../Api/Application/EggControllerTest.php | 2 +- .../Users/ExternalUserControllerTest.php | 2 +- .../Application/Users/UserControllerTest.php | 2 +- .../Client/ClientApiIntegrationTestCase.php | 6 +- .../Api/Client/ClientControllerTest.php | 12 +-- .../Startup/GetStartupAndVariablesTest.php | 2 +- .../Api/Client/TwoFactorControllerTest.php | 2 +- .../Servers/ServerCreationServiceTest.php | 4 +- .../StartupModificationServiceTest.php | 12 +-- .../Servers/VariableValidatorServiceTest.php | 11 ++- 63 files changed, 270 insertions(+), 384 deletions(-) delete mode 100644 database/migrations/2016_01_25_234418_rename_permissions_column.php delete mode 100644 database/migrations/2016_10_23_203522_add_foreign_permissions.php delete mode 100644 database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php delete mode 100644 database/migrations/2017_09_13_211810_UpdateOldPermissionsToPointToNewScheduleSystem.php diff --git a/.env.example b/.env.example index f6911efe3..74f817210 100644 --- a/.env.example +++ b/.env.example @@ -3,5 +3,4 @@ APP_DEBUG=false APP_KEY= APP_URL=http://panel.test APP_INSTALLED=false -APP_TIMEZONE=UTC APP_LOCALE=en diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d1d95bafa..8ac88b97c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -213,3 +213,79 @@ jobs: - name: Integration tests run: vendor/bin/pest tests/Integration + + postgresql: + name: PostgreSQL + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [8.2, 8.3, 8.4] + database: ["postgres:14"] + services: + database: + image: ${{ matrix.database }} + env: + POSTGRES_DB: testing + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + env: + APP_ENV: testing + APP_DEBUG: "false" + APP_KEY: ThisIsARandomStringForTests12345 + APP_TIMEZONE: UTC + APP_URL: http://localhost/ + CACHE_DRIVER: array + MAIL_MAILER: array + SESSION_DRIVER: array + QUEUE_CONNECTION: sync + DB_CONNECTION: pgsql + DB_HOST: 127.0.0.1 + DB_DATABASE: testing + DB_USERNAME: postgres + DB_PASSWORD: postgres + GUZZLE_TIMEOUT: 60 + GUZZLE_CONNECT_TIMEOUT: 60 + steps: + - name: Code Checkout + uses: actions/checkout@v4 + + - name: Get cache directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip + tools: composer:v2 + coverage: none + + - name: Install dependencies + run: composer install --no-interaction --no-suggest --no-progress --no-scripts + + - name: Unit tests + run: vendor/bin/pest tests/Unit + env: + DB_HOST: UNIT_NO_DB + SKIP_MIGRATIONS: true + + - name: Integration tests + run: vendor/bin/pest tests/Integration diff --git a/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php index 44fdbdb1f..8666d31a2 100644 --- a/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php +++ b/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php @@ -33,6 +33,13 @@ class CreateUser extends CreateRecord return []; } + protected function prepareForValidation($attributes): array + { + $attributes['data']['email'] = mb_strtolower($attributes['data']['email']); + + return $attributes; + } + protected function handleRecordCreation(array $data): Model { $data['root_admin'] = false; diff --git a/app/Livewire/Installer/Steps/DatabaseStep.php b/app/Livewire/Installer/Steps/DatabaseStep.php index 2751d1a47..387a50fe2 100644 --- a/app/Livewire/Installer/Steps/DatabaseStep.php +++ b/app/Livewire/Installer/Steps/DatabaseStep.php @@ -19,6 +19,7 @@ class DatabaseStep 'sqlite' => 'SQLite', 'mariadb' => 'MariaDB', 'mysql' => 'MySQL', + 'pgsql' => 'PostgreSQL', ]; public static function make(PanelInstaller $installer): Step @@ -39,15 +40,24 @@ class DatabaseStep ->afterStateUpdated(function ($state, Set $set, Get $get) { $set('env_database.DB_DATABASE', $state === 'sqlite' ? 'database.sqlite' : 'panel'); - if ($state === 'sqlite') { - $set('env_database.DB_HOST', null); - $set('env_database.DB_PORT', null); - $set('env_database.DB_USERNAME', null); - $set('env_database.DB_PASSWORD', null); - } else { - $set('env_database.DB_HOST', $get('env_database.DB_HOST') ?? '127.0.0.1'); - $set('env_database.DB_PORT', $get('env_database.DB_PORT') ?? '3306'); - $set('env_database.DB_USERNAME', $get('env_database.DB_USERNAME') ?? 'pelican'); + switch ($state) { + case 'sqlite': + $set('env_database.DB_HOST', null); + $set('env_database.DB_PORT', null); + $set('env_database.DB_USERNAME', null); + $set('env_database.DB_PASSWORD', null); + break; + case 'mariadb': + case 'mysql': + $set('env_database.DB_HOST', $get('env_database.DB_HOST') ?? '127.0.0.1'); + $set('env_database.DB_USERNAME', $get('env_database.DB_USERNAME') ?? 'pelican'); + $set('env_database.DB_PORT', '3306'); + break; + case 'pgsql': + $set('env_database.DB_HOST', $get('env_database.DB_HOST') ?? '127.0.0.1'); + $set('env_database.DB_USERNAME', $get('env_database.DB_USERNAME') ?? 'pelican'); + $set('env_database.DB_PORT', '5432'); + break; } }), TextInput::make('env_database.DB_DATABASE') @@ -114,7 +124,6 @@ class DatabaseStep 'database' => $database, 'username' => $username, 'password' => $password, - 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'strict' => true, ]); diff --git a/app/Models/User.php b/app/Models/User.php index 8390a01f8..3fb70b70d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -178,6 +178,10 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return true; }); + static::saving(function (self $user) { + $user->email = mb_strtolower($user->email); + }); + static::deleting(function (self $user) { throw_if($user->servers()->count() > 0, new DisplayException(trans('exceptions.users.has_servers'))); diff --git a/app/Services/Deployment/AllocationSelectionService.php b/app/Services/Deployment/AllocationSelectionService.php index d589b6368..a18ceafd0 100644 --- a/app/Services/Deployment/AllocationSelectionService.php +++ b/app/Services/Deployment/AllocationSelectionService.php @@ -155,8 +155,8 @@ class AllocationSelectionService $query->whereIn('node_id', $nodes); } - return $query->groupBy('ip') - ->get() + return $query + ->groupBy('ip') ->pluck('ip') ->toArray(); } diff --git a/config/database.php b/config/database.php index 3336c3894..f866df436 100644 --- a/config/database.php +++ b/config/database.php @@ -89,6 +89,21 @@ return [ ]) : [], ], + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'panel'), + 'username' => env('DB_USERNAME', 'pelican'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + ], /* diff --git a/database/migrations/2016_01_23_195851_add_api_keys.php b/database/migrations/2016_01_23_195851_add_api_keys.php index 6dfe066f6..8c37d9cab 100644 --- a/database/migrations/2016_01_23_195851_add_api_keys.php +++ b/database/migrations/2016_01_23_195851_add_api_keys.php @@ -12,7 +12,7 @@ return new class extends Migration { Schema::create('api_keys', function (Blueprint $table) { $table->increments('id'); - $table->char('public', 16); + $table->string('public', 16)->nullable(); $table->text('secret'); $table->text('allowed_ips')->nullable(); $table->timestamps(); diff --git a/database/migrations/2016_01_23_200159_add_downloads.php b/database/migrations/2016_01_23_200159_add_downloads.php index 493e71ef9..b20ea0abe 100644 --- a/database/migrations/2016_01_23_200159_add_downloads.php +++ b/database/migrations/2016_01_23_200159_add_downloads.php @@ -12,8 +12,8 @@ return new class extends Migration { Schema::create('downloads', function (Blueprint $table) { $table->increments('id'); - $table->char('token', 36)->unique(); - $table->char('server', 36); + $table->string('token', 36)->unique(); + $table->string('server', 36); $table->text('path'); $table->timestamps(); }); diff --git a/database/migrations/2016_01_23_200648_add_nodes.php b/database/migrations/2016_01_23_200648_add_nodes.php index 2344b8f83..4bcdcc1a0 100644 --- a/database/migrations/2016_01_23_200648_add_nodes.php +++ b/database/migrations/2016_01_23_200648_add_nodes.php @@ -21,7 +21,7 @@ return new class extends Migration $table->mediumInteger('memory_overallocate')->unsigned()->nullable(); $table->integer('disk')->unsigned(); $table->mediumInteger('disk_overallocate')->unsigned()->nullable(); - $table->char('daemonSecret', 36)->unique(); + $table->string('daemonSecret', 36)->unique(); $table->smallInteger('daemonListen')->unsigned()->default(8080); $table->smallInteger('daemonSFTP')->unsgined()->default(2022); $table->string('daemonBase')->default('/home/daemon-files'); diff --git a/database/migrations/2016_01_23_201748_add_servers.php b/database/migrations/2016_01_23_201748_add_servers.php index 580339d17..cad8ded3c 100644 --- a/database/migrations/2016_01_23_201748_add_servers.php +++ b/database/migrations/2016_01_23_201748_add_servers.php @@ -12,8 +12,8 @@ return new class extends Migration { Schema::create('servers', function (Blueprint $table) { $table->increments('id'); - $table->char('uuid', 36)->unique(); - $table->char('uuidShort', 8)->unique(); + $table->string('uuid', 36)->unique(); + $table->string('uuidShort', 8)->unique(); $table->mediumInteger('node')->unsigned(); $table->string('name'); $table->tinyInteger('active')->unsigned(); @@ -29,7 +29,7 @@ return new class extends Migration $table->mediumInteger('service')->unsigned(); $table->mediumInteger('option')->unsigned(); $table->text('startup'); - $table->char('daemonSecret', 36)->unique(); + $table->string('daemonSecret', 36)->unique(); $table->string('username')->unique(); $table->tinyInteger('installed')->unsigned()->default(0); $table->timestamps(); diff --git a/database/migrations/2016_01_23_203150_add_subusers.php b/database/migrations/2016_01_23_203150_add_subusers.php index 44cb8dfc3..b4d360acf 100644 --- a/database/migrations/2016_01_23_203150_add_subusers.php +++ b/database/migrations/2016_01_23_203150_add_subusers.php @@ -14,7 +14,7 @@ return new class extends Migration $table->increments('id'); $table->integer('user_id')->unsigned(); $table->integer('server_id')->unsigned(); - $table->char('daemonSecret', 36)->unique(); + $table->string('daemonSecret', 36)->unique(); $table->timestamps(); }); } diff --git a/database/migrations/2016_01_23_203159_add_users.php b/database/migrations/2016_01_23_203159_add_users.php index 7c3e8afa1..3a4077e2e 100644 --- a/database/migrations/2016_01_23_203159_add_users.php +++ b/database/migrations/2016_01_23_203159_add_users.php @@ -12,14 +12,14 @@ return new class extends Migration { Schema::create('users', function (Blueprint $table) { $table->increments('id'); - $table->char('uuid', 36)->unique(); + $table->string('uuid', 36)->unique(); $table->string('email')->unique(); $table->text('password'); $table->string('remember_token')->nullable(); - $table->char('language', 5)->default('en'); + $table->string('language', 5)->default('en'); $table->tinyInteger('root_admin')->unsigned()->default(0); $table->tinyInteger('use_totp')->unsigned(); - $table->char('totp_secret', 16)->nullable(); + $table->string('totp_secret', 16)->nullable(); $table->timestamps(); }); } diff --git a/database/migrations/2016_01_25_234418_rename_permissions_column.php b/database/migrations/2016_01_25_234418_rename_permissions_column.php deleted file mode 100644 index 181fa1dba..000000000 --- a/database/migrations/2016_01_25_234418_rename_permissions_column.php +++ /dev/null @@ -1,25 +0,0 @@ -renameColumn('permissions', 'permission'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('permissions', function (Blueprint $table) {}); - } -}; diff --git a/database/migrations/2016_09_04_182835_create_notifications_table.php b/database/migrations/2016_09_04_182835_create_notifications_table.php index 788e37be0..604362096 100644 --- a/database/migrations/2016_09_04_182835_create_notifications_table.php +++ b/database/migrations/2016_09_04_182835_create_notifications_table.php @@ -14,7 +14,7 @@ return new class extends Migration $table->string('id')->primary(); $table->string('type'); $table->morphs('notifiable'); - $table->text('data'); + $table->json('data'); $table->timestamp('read_at')->nullable(); $table->timestamps(); }); diff --git a/database/migrations/2016_09_07_163017_add_unique_identifier.php b/database/migrations/2016_09_07_163017_add_unique_identifier.php index ad186c385..ff7fe7e04 100644 --- a/database/migrations/2016_09_07_163017_add_unique_identifier.php +++ b/database/migrations/2016_09_07_163017_add_unique_identifier.php @@ -12,7 +12,7 @@ return new class extends Migration public function up(): void { Schema::table('services', function (Blueprint $table) { - $table->char('author', 36)->after('id'); + $table->string('author', 36)->after('id'); }); } diff --git a/database/migrations/2016_10_07_152117_build_api_log_table.php b/database/migrations/2016_10_07_152117_build_api_log_table.php index 0fa86e4ed..b6001b35a 100644 --- a/database/migrations/2016_10_07_152117_build_api_log_table.php +++ b/database/migrations/2016_10_07_152117_build_api_log_table.php @@ -15,8 +15,8 @@ return new class extends Migration $table->increments('id'); $table->boolean('authorized'); $table->text('error')->nullable(); - $table->char('key', 16)->nullable(); - $table->char('method', 6); + $table->string('key', 16)->nullable(); + $table->string('method', 6); $table->text('route'); $table->text('content')->nullable(); $table->text('user_agent'); diff --git a/database/migrations/2016_10_23_203522_add_foreign_permissions.php b/database/migrations/2016_10_23_203522_add_foreign_permissions.php deleted file mode 100644 index 8af4860b4..000000000 --- a/database/migrations/2016_10_23_203522_add_foreign_permissions.php +++ /dev/null @@ -1,33 +0,0 @@ -foreign('user_id')->references('id')->on('users'); - $table->foreign('server_id')->references('id')->on('servers'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('permissions', function (Blueprint $table) { - $table->dropForeign('permissions_user_id_foreign'); - $table->dropForeign('permissions_server_id_foreign'); - - $table->dropIndex('permissions_user_id_foreign'); - $table->dropIndex('permissions_server_id_foreign'); - }); - } -}; diff --git a/database/migrations/2016_11_11_220649_add_pack_support.php b/database/migrations/2016_11_11_220649_add_pack_support.php index 07ed33861..58436dbd6 100644 --- a/database/migrations/2016_11_11_220649_add_pack_support.php +++ b/database/migrations/2016_11_11_220649_add_pack_support.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::create('service_packs', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('option'); - $table->char('uuid', 36)->unique(); + $table->string('uuid', 36)->unique(); $table->string('name'); $table->string('version'); $table->text('description')->nullable(); diff --git a/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php b/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php index 8be53ea8a..11d9fcb1f 100644 --- a/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php +++ b/database/migrations/2017_01_07_154228_create_node_configuration_tokens_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('node_configuration_tokens', function (Blueprint $table) { $table->increments('id'); - $table->char('token', 32); + $table->string('token', 32); $table->timestamp('expires_at'); $table->integer('node')->unsigned(); $table->foreign('node')->references('id')->on('nodes'); diff --git a/database/migrations/2017_02_02_175548_UpdateColumnNames.php b/database/migrations/2017_02_02_175548_UpdateColumnNames.php index 9fbae3352..be93ba61a 100644 --- a/database/migrations/2017_02_02_175548_UpdateColumnNames.php +++ b/database/migrations/2017_02_02_175548_UpdateColumnNames.php @@ -19,7 +19,7 @@ return new class extends Migration $table->dropForeign(['option']); $table->dropForeign(['pack']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('servers_node_foreign'); $table->dropIndex('servers_owner_foreign'); $table->dropIndex('servers_allocation_foreign'); diff --git a/database/migrations/2017_02_03_140948_UpdateNodesTable.php b/database/migrations/2017_02_03_140948_UpdateNodesTable.php index 07186787b..825b5a828 100644 --- a/database/migrations/2017_02_03_140948_UpdateNodesTable.php +++ b/database/migrations/2017_02_03_140948_UpdateNodesTable.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::table('nodes', function (Blueprint $table) { $table->dropForeign(['location']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('nodes_location_foreign'); } @@ -31,7 +31,7 @@ return new class extends Migration Schema::table('nodes', function (Blueprint $table) { $table->dropForeign(['location_id']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('nodes_location_id_foreign'); } diff --git a/database/migrations/2017_02_03_155554_RenameColumns.php b/database/migrations/2017_02_03_155554_RenameColumns.php index e61b72ab3..73aead0c3 100644 --- a/database/migrations/2017_02_03_155554_RenameColumns.php +++ b/database/migrations/2017_02_03_155554_RenameColumns.php @@ -15,7 +15,7 @@ return new class extends Migration $table->dropForeign(['node']); $table->dropForeign(['assigned_to']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('allocations_node_foreign'); $table->dropIndex('allocations_assigned_to_foreign'); } @@ -36,7 +36,7 @@ return new class extends Migration $table->dropForeign(['node_id']); $table->dropForeign(['server_id']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('allocations_node_id_foreign'); $table->dropIndex('allocations_server_id_foreign'); } diff --git a/database/migrations/2017_02_05_164123_AdjustColumnNames.php b/database/migrations/2017_02_05_164123_AdjustColumnNames.php index 275eccaea..c8262430f 100644 --- a/database/migrations/2017_02_05_164123_AdjustColumnNames.php +++ b/database/migrations/2017_02_05_164123_AdjustColumnNames.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::table('service_options', function (Blueprint $table) { $table->dropForeign(['parent_service']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('service_options_parent_service_foreign'); } @@ -31,7 +31,7 @@ return new class extends Migration Schema::table('service_options', function (Blueprint $table) { $table->dropForeign(['service_id']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('service_options_service_id_foreign'); } diff --git a/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php index 5369b68e7..929b3559c 100644 --- a/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php +++ b/database/migrations/2017_02_05_164516_AdjustColumnNamesForServicePacks.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::table('service_packs', function (Blueprint $table) { $table->dropForeign(['option']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('service_packs_option_foreign'); } @@ -31,7 +31,7 @@ return new class extends Migration Schema::table('service_packs', function (Blueprint $table) { $table->dropForeign(['option_id']); - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropIndex('service_packs_option_id_foreign'); } diff --git a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php b/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php deleted file mode 100644 index e1af0b0a3..000000000 --- a/database/migrations/2017_02_09_174834_SetupPermissionsPivotTable.php +++ /dev/null @@ -1,81 +0,0 @@ -unsignedInteger('subuser_id')->after('id'); - }); - - DB::transaction(function () { - foreach (Subuser::all() as &$subuser) { - Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->update([ - 'subuser_id' => $subuser->id, - ]); - } - }); - - Schema::table('permissions', function (Blueprint $table) { - - $table->dropForeign(['server_id']); - $table->dropForeign(['user_id']); - - if (Schema::getConnection()->getDriverName() !== 'sqlite') { - $table->dropIndex('permissions_server_id_foreign'); - $table->dropIndex('permissions_user_id_foreign'); - } else { - $table->dropForeign(['server_id']); - $table->dropForeign(['user_id']); - } - - $table->dropColumn('server_id'); - $table->dropColumn('user_id'); - $table->dropColumn('created_at'); - $table->dropColumn('updated_at'); - $table->foreign('subuser_id')->references('id')->on('subusers'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('permissions', function (Blueprint $table) { - $table->unsignedInteger('server_id')->after('subuser_id'); - $table->unsignedInteger('user_id')->after('server_id'); - $table->timestamps(); - }); - - DB::transaction(function () { - foreach (Subuser::all() as &$subuser) { - Permission::where('subuser_id', $subuser->id)->update([ - 'user_id' => $subuser->user_id, - 'server_id' => $subuser->server_id, - ]); - } - }); - - Schema::table('permissions', function (Blueprint $table) { - if (Schema::getConnection()->getDriverName() !== 'sqlite') { - $table->dropForeign('permissions_subuser_id_foreign'); - $table->dropIndex('permissions_subuser_id_foreign'); - } - $table->dropColumn('subuser_id'); - - $table->foreign('server_id')->references('id')->on('servers'); - $table->foreign('user_id')->references('id')->on('users'); - }); - } -}; diff --git a/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php index 177d59952..d67bc2d90 100644 --- a/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php +++ b/database/migrations/2017_02_10_171858_UpdateAPIKeyColumnNames.php @@ -12,7 +12,7 @@ return new class extends Migration public function up(): void { Schema::table('api_keys', function (Blueprint $table) { - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropForeign('api_keys_user_foreign'); $table->dropIndex('api_keys_user_foreign'); } @@ -28,7 +28,7 @@ return new class extends Migration public function down(): void { Schema::table('api_keys', function (Blueprint $table) { - if (Schema::getConnection()->getDriverName() !== 'sqlite') { + if (!in_array(Schema::getConnection()->getDriverName(), ['sqlite', 'pgsql'])) { $table->dropForeign('api_keys_user_id_foreign'); $table->dropIndex('api_keys_user_id_foreign'); } diff --git a/database/migrations/2017_05_01_141528_DeleteDownloadTable.php b/database/migrations/2017_05_01_141528_DeleteDownloadTable.php index 685fb317d..14e394eaf 100644 --- a/database/migrations/2017_05_01_141528_DeleteDownloadTable.php +++ b/database/migrations/2017_05_01_141528_DeleteDownloadTable.php @@ -21,8 +21,8 @@ return new class extends Migration { Schema::create('downloads', function (Blueprint $table) { $table->increments('id'); - $table->char('token', 36)->unique(); - $table->char('server', 36); + $table->string('token', 36)->unique(); + $table->string('server', 36); $table->text('path'); $table->timestamps(); }); diff --git a/database/migrations/2017_05_01_141559_DeleteNodeConfigurationTable.php b/database/migrations/2017_05_01_141559_DeleteNodeConfigurationTable.php index 16d17b30f..34b180879 100644 --- a/database/migrations/2017_05_01_141559_DeleteNodeConfigurationTable.php +++ b/database/migrations/2017_05_01_141559_DeleteNodeConfigurationTable.php @@ -21,7 +21,7 @@ return new class extends Migration { Schema::create('node_configuration_tokens', function (Blueprint $table) { $table->increments('id'); - $table->char('token', 32); + $table->string('token', 32); $table->unsignedInteger('node_id'); $table->timestamps(); }); diff --git a/database/migrations/2017_07_08_152806_ChangeUserPermissionsToDeleteOnUserDeletion.php b/database/migrations/2017_07_08_152806_ChangeUserPermissionsToDeleteOnUserDeletion.php index a3dc806d5..32d91b926 100644 --- a/database/migrations/2017_07_08_152806_ChangeUserPermissionsToDeleteOnUserDeletion.php +++ b/database/migrations/2017_07_08_152806_ChangeUserPermissionsToDeleteOnUserDeletion.php @@ -11,12 +11,6 @@ return new class extends Migration */ public function up(): void { - Schema::table('permissions', function (Blueprint $table) { - $table->dropForeign(['subuser_id']); - - $table->foreign('subuser_id')->references('id')->on('subusers')->onDelete('cascade'); - }); - Schema::table('subusers', function (Blueprint $table) { $table->dropForeign(['user_id']); $table->dropForeign(['server_id']); @@ -38,11 +32,5 @@ return new class extends Migration $table->foreign('user_id')->references('id')->on('users'); $table->foreign('server_id')->references('id')->on('servers'); }); - - Schema::table('permissions', function (Blueprint $table) { - $table->dropForeign(['subuser_id']); - - $table->foreign('subuser_id')->references('id')->on('subusers'); - }); } }; diff --git a/database/migrations/2017_09_13_211810_UpdateOldPermissionsToPointToNewScheduleSystem.php b/database/migrations/2017_09_13_211810_UpdateOldPermissionsToPointToNewScheduleSystem.php deleted file mode 100644 index aca8afb6c..000000000 --- a/database/migrations/2017_09_13_211810_UpdateOldPermissionsToPointToNewScheduleSystem.php +++ /dev/null @@ -1,43 +0,0 @@ -where('permission', 'like', '%-task%')->get(); - foreach ($permissions as $record) { - $parts = explode('-', $record->permission); - if (!in_array(array_get($parts, 1), ['tasks', 'task']) || count($parts) !== 2) { - continue; - } - - $newPermission = $parts[0] . '-' . str_replace('task', 'schedule', $parts[1]); - - DB::table('permissions')->where('id', '=', $record->id)->update(['permission' => $newPermission]); - } - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - $permissions = DB::table('permissions')->where('permission', 'like', '%-schedule%')->get(); - foreach ($permissions as $record) { - $parts = explode('-', $record->permission); - if (!in_array(array_get($parts, 1), ['schedules', 'schedule']) || count($parts) !== 2) { - continue; - } - - $newPermission = $parts[0] . '-' . str_replace('schedule', 'task', $parts[1]); - - DB::table('permissions')->where('id', '=', $record->id)->update(['permission' => $newPermission]); - } - } -}; diff --git a/database/migrations/2017_09_23_173628_RemoveDaemonSecretFromServersTable.php b/database/migrations/2017_09_23_173628_RemoveDaemonSecretFromServersTable.php index ab2e8056e..a26c13c9d 100644 --- a/database/migrations/2017_09_23_173628_RemoveDaemonSecretFromServersTable.php +++ b/database/migrations/2017_09_23_173628_RemoveDaemonSecretFromServersTable.php @@ -44,7 +44,7 @@ return new class extends Migration public function down(): void { Schema::table('servers', function (Blueprint $table) { - $table->char('daemonSecret', 36)->after('startup')->unique(); + $table->string('daemonSecret', 36)->after('startup')->unique(); }); DB::table('daemon_keys')->truncate(); diff --git a/database/migrations/2017_09_23_185022_RemoveDaemonSecretFromSubusersTable.php b/database/migrations/2017_09_23_185022_RemoveDaemonSecretFromSubusersTable.php index 9090be407..6216dd5d8 100644 --- a/database/migrations/2017_09_23_185022_RemoveDaemonSecretFromSubusersTable.php +++ b/database/migrations/2017_09_23_185022_RemoveDaemonSecretFromSubusersTable.php @@ -42,7 +42,7 @@ return new class extends Migration public function down(): void { Schema::table('subusers', function (Blueprint $table) { - $table->char('daemonSecret', 36)->after('server_id'); + $table->string('daemonSecret', 36)->after('server_id'); }); $subusers = DB::table('subusers')->get(); diff --git a/database/migrations/2017_10_02_202000_ChangeServicesToUseAMoreUniqueIdentifier.php b/database/migrations/2017_10_02_202000_ChangeServicesToUseAMoreUniqueIdentifier.php index 3ffe5a866..f1546eebb 100644 --- a/database/migrations/2017_10_02_202000_ChangeServicesToUseAMoreUniqueIdentifier.php +++ b/database/migrations/2017_10_02_202000_ChangeServicesToUseAMoreUniqueIdentifier.php @@ -18,7 +18,7 @@ return new class extends Migration $table->dropUnique(['file']); $table->string('author')->change(); - $table->char('uuid', 36)->after('id'); + $table->string('uuid', 36)->after('id'); $table->dropColumn('folder'); $table->dropColumn('startup'); $table->dropColumn('index_file'); diff --git a/database/migrations/2017_10_02_202007_ChangeToABetterUniqueServiceConfiguration.php b/database/migrations/2017_10_02_202007_ChangeToABetterUniqueServiceConfiguration.php index 92d86500e..f44d4594e 100644 --- a/database/migrations/2017_10_02_202007_ChangeToABetterUniqueServiceConfiguration.php +++ b/database/migrations/2017_10_02_202007_ChangeToABetterUniqueServiceConfiguration.php @@ -14,7 +14,7 @@ return new class extends Migration public function up(): void { Schema::table('service_options', function (Blueprint $table) { - $table->char('uuid', 36)->after('id'); + $table->string('uuid', 36)->after('id'); $table->string('author')->after('service_id'); $table->dropColumn('tag'); }); diff --git a/database/migrations/2017_11_19_122708_MigratePubPrivFormatToSingleKey.php b/database/migrations/2017_11_19_122708_MigratePubPrivFormatToSingleKey.php index 7cc32110a..82c25e65e 100644 --- a/database/migrations/2017_11_19_122708_MigratePubPrivFormatToSingleKey.php +++ b/database/migrations/2017_11_19_122708_MigratePubPrivFormatToSingleKey.php @@ -31,10 +31,21 @@ return new class extends Migration if (Schema::getConnection()->getDriverName() === 'sqlite') { Schema::table('api_keys', function (Blueprint $table) { $table->dropColumn('public'); - $table->char('secret', 32)->change(); + $table->string('secret', 32)->change(); $table->renameColumn('secret', 'token'); $table->string('token', 32)->unique()->change(); }); + } elseif (Schema::getConnection()->getDriverName() === 'pgsql') { + // Rename column 'secret' to 'token' + DB::statement('ALTER TABLE api_keys RENAME COLUMN secret TO token'); + + // Change data type of 'token' to CHAR(32) and set NOT NULL constraint + DB::statement('ALTER TABLE api_keys ALTER COLUMN token TYPE CHAR(32)'); + DB::statement('ALTER TABLE api_keys ALTER COLUMN token SET NOT NULL'); + + // Add unique constraint on 'token' + DB::statement('ALTER TABLE api_keys ADD CONSTRAINT api_keys_token_unique UNIQUE (token)'); + } else { DB::statement('ALTER TABLE `api_keys` CHANGE `secret` `token` CHAR(32) NOT NULL, ADD UNIQUE INDEX `api_keys_token_unique` (`token`(32))'); } @@ -49,7 +60,7 @@ return new class extends Migration DB::statement('ALTER TABLE `api_keys` CHANGE `token` `secret` TEXT, DROP INDEX `api_keys_token_unique`'); Schema::table('api_keys', function (Blueprint $table) { - $table->char('public', 16)->after('user_id'); + $table->string('public', 16)->after('user_id'); }); DB::transaction(function () { diff --git a/database/migrations/2018_01_13_142012_SetupTableForKeyEncryption.php b/database/migrations/2018_01_13_142012_SetupTableForKeyEncryption.php index fcd1a534f..946d21591 100644 --- a/database/migrations/2018_01_13_142012_SetupTableForKeyEncryption.php +++ b/database/migrations/2018_01_13_142012_SetupTableForKeyEncryption.php @@ -16,7 +16,7 @@ return new class extends Migration public function up(): void { Schema::table('api_keys', function (Blueprint $table) { - $table->char('identifier', 16)->nullable()->unique()->after('user_id'); + $table->string('identifier', 16)->nullable()->unique()->after('user_id'); $table->dropUnique(['token']); }); diff --git a/database/migrations/2020_03_22_163911_merge_permissions_table_into_subusers.php b/database/migrations/2020_03_22_163911_merge_permissions_table_into_subusers.php index 6a9280b5f..c90d485ce 100644 --- a/database/migrations/2020_03_22_163911_merge_permissions_table_into_subusers.php +++ b/database/migrations/2020_03_22_163911_merge_permissions_table_into_subusers.php @@ -1,64 +1,11 @@ P::ACTION_CONTROL_START, - 'power-stop' => P::ACTION_CONTROL_STOP, - 'power-restart' => P::ACTION_CONTROL_RESTART, - 'power-kill' => P::ACTION_CONTROL_STOP, - 'send-command' => P::ACTION_CONTROL_CONSOLE, - 'list-subusers' => P::ACTION_USER_READ, - 'view-subuser' => P::ACTION_USER_READ, - 'edit-subuser' => P::ACTION_USER_UPDATE, - 'create-subuser' => P::ACTION_USER_CREATE, - 'delete-subuser' => P::ACTION_USER_DELETE, - 'view-allocations' => P::ACTION_ALLOCATION_READ, - 'edit-allocation' => P::ACTION_ALLOCATION_UPDATE, - 'view-startup' => P::ACTION_STARTUP_READ, - 'edit-startup' => P::ACTION_STARTUP_UPDATE, - 'view-databases' => P::ACTION_DATABASE_READ, - // Better to just break this flow a bit than accidentally grant a dangerous permission. - 'reset-db-password' => P::ACTION_DATABASE_UPDATE, - 'delete-database' => P::ACTION_DATABASE_DELETE, - 'create-database' => P::ACTION_DATABASE_CREATE, - 'access-sftp' => P::ACTION_FILE_SFTP, - 'list-files' => P::ACTION_FILE_READ, - 'edit-files' => P::ACTION_FILE_READ_CONTENT, - 'save-files' => P::ACTION_FILE_UPDATE, - 'create-files' => P::ACTION_FILE_CREATE, - 'delete-files' => P::ACTION_FILE_DELETE, - 'compress-files' => P::ACTION_FILE_ARCHIVE, - 'list-schedules' => P::ACTION_SCHEDULE_READ, - 'view-schedule' => P::ACTION_SCHEDULE_READ, - 'edit-schedule' => P::ACTION_SCHEDULE_UPDATE, - 'create-schedule' => P::ACTION_SCHEDULE_CREATE, - 'delete-schedule' => P::ACTION_SCHEDULE_DELETE, - // Skipping these permissions as they are granted if you have more specific read/write permissions. - 'move-files' => null, - 'copy-files' => null, - 'decompress-files' => null, - 'upload-files' => null, - 'download-files' => null, - // These permissions do not exist in 1.0 - 'toggle-schedule' => null, - 'queue-schedule' => null, - ]; - /** * Run the migrations. */ @@ -67,31 +14,6 @@ return new class extends Migration Schema::table('subusers', function (Blueprint $table) { $table->json('permissions')->nullable()->after('server_id'); }); - - $cursor = DB::table('permissions') - ->select(['subuser_id']) - ->selectRaw('GROUP_CONCAT(permission) as permissions') - ->from('permissions') - ->groupBy(['subuser_id']) - ->cursor(); - - DB::transaction(function () use (&$cursor) { - $cursor->each(function ($datum) { - $updated = Collection::make(explode(',', $datum->permissions)) - ->map(function ($value) { - return self::$permissionsMap[$value] ?? null; - })->filter(function ($value) { - return !is_null($value) && $value !== Permission::ACTION_WEBSOCKET_CONNECT; - }) - // All subusers get this permission, so make sure it gets pushed into the array. - ->merge([Permission::ACTION_WEBSOCKET_CONNECT]) - ->unique() - ->values() - ->toJson(); - - DB::update('UPDATE subusers SET permissions = ? WHERE id = ?', [$updated, $datum->subuser_id]); - }); - }); } /** @@ -99,25 +21,6 @@ return new class extends Migration */ public function down(): void { - $flipped = array_flip(array_filter(self::$permissionsMap)); - - foreach (DB::select('SELECT id, permissions FROM subusers') as $datum) { - $values = []; - foreach (json_decode($datum->permissions, true) as $permission) { - $v = $flipped[$permission] ?? null; - if (!empty($v)) { - $values[] = $datum->id; - $values[] = $v; - } - } - - if (!empty($values)) { - $string = 'VALUES ' . implode(', ', array_fill(0, count($values) / 2, '(?, ?)')); - - DB::insert('INSERT INTO permissions(`subuser_id`, `permission`) ' . $string, $values); - } - } - Schema::table('subusers', function (Blueprint $table) { $table->dropColumn('permissions'); }); diff --git a/database/migrations/2020_04_03_230614_create_backups_table.php b/database/migrations/2020_04_03_230614_create_backups_table.php index b45e43f63..079cb4fdb 100644 --- a/database/migrations/2020_04_03_230614_create_backups_table.php +++ b/database/migrations/2020_04_03_230614_create_backups_table.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::create('backups', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedInteger('server_id'); - $table->char('uuid', 36); + $table->string('uuid', 36); $table->string('name'); $table->text('ignored_files'); $table->string('disk'); diff --git a/database/migrations/2020_04_10_141024_store_node_tokens_as_encrypted_value.php b/database/migrations/2020_04_10_141024_store_node_tokens_as_encrypted_value.php index 911461d70..2cb558970 100644 --- a/database/migrations/2020_04_10_141024_store_node_tokens_as_encrypted_value.php +++ b/database/migrations/2020_04_10_141024_store_node_tokens_as_encrypted_value.php @@ -21,8 +21,8 @@ return new class extends Migration }); Schema::table('nodes', function (Blueprint $table) { - $table->char('uuid', 36)->after('id'); - $table->char('daemon_token_id', 16)->after('upload_size'); + $table->string('uuid', 36)->after('id'); + $table->string('daemon_token_id', 16)->after('upload_size'); $table->renameColumn('daemonSecret', 'daemon_token'); }); diff --git a/database/migrations/2020_05_20_234655_add_mounts_table.php b/database/migrations/2020_05_20_234655_add_mounts_table.php index 602e1040a..c048668d6 100644 --- a/database/migrations/2020_05_20_234655_add_mounts_table.php +++ b/database/migrations/2020_05_20_234655_add_mounts_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('mounts', function (Blueprint $table) { $table->increments('id')->unique(); - $table->char('uuid', 36)->unique(); + $table->string('uuid', 36)->unique(); $table->string('name')->unique(); $table->text('description')->nullable(); $table->string('source'); diff --git a/database/migrations/2020_09_13_110047_drop_packs_table.php b/database/migrations/2020_09_13_110047_drop_packs_table.php index 2a3bf7019..7b9d8a6ca 100644 --- a/database/migrations/2020_09_13_110047_drop_packs_table.php +++ b/database/migrations/2020_09_13_110047_drop_packs_table.php @@ -22,7 +22,7 @@ return new class extends Migration Schema::create('packs', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('egg_id'); - $table->char('uuid', 36)->unique(); + $table->string('uuid', 36)->unique(); $table->string('name'); $table->string('version'); $table->text('description')->nullable(); diff --git a/database/migrations/2020_12_12_102435_support_multiple_docker_images_and_updates.php b/database/migrations/2020_12_12_102435_support_multiple_docker_images_and_updates.php index 9e84f8e1d..e503f892e 100644 --- a/database/migrations/2020_12_12_102435_support_multiple_docker_images_and_updates.php +++ b/database/migrations/2020_12_12_102435_support_multiple_docker_images_and_updates.php @@ -18,7 +18,11 @@ return new class extends Migration }); Schema::table('eggs', function (Blueprint $table) { - DB::statement('UPDATE `eggs` SET `docker_images` = JSON_ARRAY(docker_image)'); + if (Schema::getConnection()->getDriverName() === 'pgsql') { + DB::statement('UPDATE eggs SET docker_images = json_build_array(docker_image)'); + } else { + DB::statement('UPDATE eggs SET docker_images = JSON_ARRAY(docker_image)'); + } }); Schema::table('eggs', function (Blueprint $table) { @@ -36,7 +40,7 @@ return new class extends Migration }); Schema::table('eggs', function (Blueprint $table) { - DB::statement('UPDATE `eggs` SET `docker_image` = JSON_UNQUOTE(JSON_EXTRACT(docker_images, "$[0]"))'); + DB::statement('UPDATE eggs SET docker_image = JSON_UNQUOTE(JSON_EXTRACT(docker_images, "$[0]"))'); }); Schema::table('eggs', function (Blueprint $table) { diff --git a/database/migrations/2020_12_14_013707_make_successful_nullable_in_server_transfers.php b/database/migrations/2020_12_14_013707_make_successful_nullable_in_server_transfers.php index c90e6a31d..524ffab74 100644 --- a/database/migrations/2020_12_14_013707_make_successful_nullable_in_server_transfers.php +++ b/database/migrations/2020_12_14_013707_make_successful_nullable_in_server_transfers.php @@ -1,5 +1,6 @@ getDriverName() === 'pgsql') { + // Drop existing default first + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful DROP DEFAULT'); + + // Change type to boolean explicitly casting smallint values + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful TYPE BOOLEAN USING (successful <> 0)'); + + // Set column nullable if desired + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful DROP NOT NULL'); + + return; + } + Schema::table('server_transfers', function (Blueprint $table) { $table->boolean('successful')->nullable()->default(null)->change(); }); @@ -21,6 +35,17 @@ return new class extends Migration */ public function down(): void { + if (Schema::getConnection()->getDriverName() === 'pgsql') { + // Convert boolean back to smallint + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful TYPE SMALLINT USING (CASE WHEN successful THEN 1 ELSE 0 END)'); + + // Restore previous defaults and constraints + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful SET DEFAULT 0'); + DB::statement('ALTER TABLE server_transfers ALTER COLUMN successful SET NOT NULL'); + + return; + } + Schema::table('server_transfers', function (Blueprint $table) { $table->boolean('successful')->default(0)->change(); }); diff --git a/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php b/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php index e11be7d3e..a2045504f 100644 --- a/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php +++ b/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php @@ -18,7 +18,7 @@ return new class extends Migration // Update archived to all be true on existing transfers. Schema::table('server_transfers', function (Blueprint $table) { - DB::statement('UPDATE `server_transfers` SET `archived` = 1 WHERE `successful` = 1'); + DB::table('server_transfers')->where('successful', 1)->update(['archived' => 1]); }); } diff --git a/database/migrations/2020_12_24_092449_make_allocation_fields_json.php b/database/migrations/2020_12_24_092449_make_allocation_fields_json.php index 1fb88bb05..ce04aa4b4 100644 --- a/database/migrations/2020_12_24_092449_make_allocation_fields_json.php +++ b/database/migrations/2020_12_24_092449_make_allocation_fields_json.php @@ -11,6 +11,15 @@ return new class extends Migration */ public function up(): void { + if (Schema::getConnection()->getDriverName() === 'pgsql') { + Schema::table('server_transfers', function (Blueprint $table) { + DB::statement('ALTER TABLE server_transfers ALTER COLUMN old_additional_allocations TYPE JSON USING old_additional_allocations::json'); + DB::statement('ALTER TABLE server_transfers ALTER COLUMN new_additional_allocations TYPE JSON USING new_additional_allocations::json'); + }); + + return; + } + Schema::table('server_transfers', function (Blueprint $table) { $table->json('old_additional_allocations')->nullable()->change(); $table->json('new_additional_allocations')->nullable()->change(); diff --git a/database/migrations/2021_01_17_102401_create_audit_logs_table.php b/database/migrations/2021_01_17_102401_create_audit_logs_table.php index 43b02d63f..e2aed6ec7 100644 --- a/database/migrations/2021_01_17_102401_create_audit_logs_table.php +++ b/database/migrations/2021_01_17_102401_create_audit_logs_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('audit_logs', function (Blueprint $table) { $table->id(); - $table->char('uuid', 36); + $table->string('uuid', 36); $table->boolean('is_system')->default(false); $table->unsignedInteger('user_id')->nullable(); $table->unsignedInteger('server_id')->nullable(); diff --git a/database/migrations/2021_01_17_152623_add_generic_server_status_column.php b/database/migrations/2021_01_17_152623_add_generic_server_status_column.php index b864ee628..6aeac2be9 100644 --- a/database/migrations/2021_01_17_152623_add_generic_server_status_column.php +++ b/database/migrations/2021_01_17_152623_add_generic_server_status_column.php @@ -17,9 +17,9 @@ return new class extends Migration }); DB::transaction(function () { - DB::update('UPDATE servers SET `status` = \'suspended\' WHERE `suspended` = 1'); - DB::update('UPDATE servers SET `status` = \'installing\' WHERE `installed` = 0'); - DB::update('UPDATE servers SET `status` = \'install_failed\' WHERE `installed` = 2'); + DB::table('servers')->where('suspended', 1)->update(['status' => 'suspended']); + DB::table('servers')->where('suspended', 0)->update(['status' => 'installing']); + DB::table('servers')->where('suspended', 2)->update(['status' => 'install_failed']); }); Schema::table('servers', function (Blueprint $table) { diff --git a/database/migrations/2021_03_21_104718_force_cron_month_field_to_have_value_if_missing.php b/database/migrations/2021_03_21_104718_force_cron_month_field_to_have_value_if_missing.php index ada00daef..0b2e36fa7 100644 --- a/database/migrations/2021_03_21_104718_force_cron_month_field_to_have_value_if_missing.php +++ b/database/migrations/2021_03_21_104718_force_cron_month_field_to_have_value_if_missing.php @@ -13,7 +13,9 @@ return new class extends Migration public function up(): void { Schema::table('schedules', function (Blueprint $table) { - DB::update("UPDATE `schedules` SET `cron_month` = '*' WHERE `cron_month` = ''"); + DB::table('schedules') + ->where('cron_month', '') + ->update(['cron_month' => '*']); }); } diff --git a/database/migrations/2021_07_12_013420_remove_userinteraction.php b/database/migrations/2021_07_12_013420_remove_userinteraction.php index 25e0a1528..18fd072fd 100644 --- a/database/migrations/2021_07_12_013420_remove_userinteraction.php +++ b/database/migrations/2021_07_12_013420_remove_userinteraction.php @@ -2,6 +2,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Database\Migrations\Migration; +use Illuminate\Support\Facades\Schema; return new class extends Migration { @@ -10,6 +11,14 @@ return new class extends Migration */ public function up(): void { + if (Schema::getConnection()->getDriverName() === 'pgsql') { + DB::table('eggs')->update([ + 'config_startup' => DB::raw("config_startup::jsonb - 'userInteraction'"), + ]); + + return; + } + // Remove User Interaction from startup config DB::table('eggs')->update([ 'config_startup' => DB::raw('JSON_REMOVE(config_startup, \'$.userInteraction\')'), diff --git a/database/migrations/2022_05_28_135717_create_activity_logs_table.php b/database/migrations/2022_05_28_135717_create_activity_logs_table.php index 186125aa3..03c50952a 100644 --- a/database/migrations/2022_05_28_135717_create_activity_logs_table.php +++ b/database/migrations/2022_05_28_135717_create_activity_logs_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('activity_logs', function (Blueprint $table) { $table->id(); - $table->char('batch', 36)->nullable(); + $table->string('batch', 36)->nullable(); $table->string('event')->index(); $table->string('ip'); $table->text('description')->nullable(); diff --git a/database/migrations/2024_03_12_154408_remove_nests_table.php b/database/migrations/2024_03_12_154408_remove_nests_table.php index 42d1315b9..7493d87fe 100644 --- a/database/migrations/2024_03_12_154408_remove_nests_table.php +++ b/database/migrations/2024_03_12_154408_remove_nests_table.php @@ -58,7 +58,7 @@ return new class extends Migration Schema::create('nests', function (Blueprint $table) { $table->increments('id'); - $table->char('uuid', 36)->unique(); + $table->string('uuid', 36)->unique(); $table->string('author'); $table->string('name'); $table->text('description')->nullable(); diff --git a/database/migrations/2024_07_25_072050_convert_rules_to_array.php b/database/migrations/2024_07_25_072050_convert_rules_to_array.php index 6646a6661..e7db3153b 100644 --- a/database/migrations/2024_07_25_072050_convert_rules_to_array.php +++ b/database/migrations/2024_07_25_072050_convert_rules_to_array.php @@ -16,6 +16,12 @@ return new class extends Migration DB::table('egg_variables')->where('id', $eggVariable->id)->update(['rules' => explode('|', $eggVariable->rules)]); }); + if (Schema::getConnection()->getDriverName() === 'pgsql') { + DB::statement('ALTER TABLE egg_variables ALTER COLUMN rules TYPE JSON USING rules::json'); + + return; + } + Schema::table('egg_variables', function (Blueprint $table) { $table->json('rules')->change(); }); diff --git a/tests/Integration/Api/Application/EggControllerTest.php b/tests/Integration/Api/Application/EggControllerTest.php index 66548e38d..8731d9f9e 100644 --- a/tests/Integration/Api/Application/EggControllerTest.php +++ b/tests/Integration/Api/Application/EggControllerTest.php @@ -101,7 +101,7 @@ class EggControllerTest extends ApplicationApiIntegrationTestCase */ public function test_get_missing_egg(): void { - $response = $this->getJson('/api/application/eggs/nil'); + $response = $this->getJson('/api/application/eggs/12345'); $this->assertNotFoundJson($response); } diff --git a/tests/Integration/Api/Application/Users/ExternalUserControllerTest.php b/tests/Integration/Api/Application/Users/ExternalUserControllerTest.php index 80069f4bc..7606c80fd 100644 --- a/tests/Integration/Api/Application/Users/ExternalUserControllerTest.php +++ b/tests/Integration/Api/Application/Users/ExternalUserControllerTest.php @@ -50,7 +50,7 @@ class ExternalUserControllerTest extends ApplicationApiIntegrationTestCase */ public function test_get_missing_user(): void { - $response = $this->getJson('/api/application/users/external/nil'); + $response = $this->getJson('/api/application/users/external/12345'); $this->assertNotFoundJson($response); } diff --git a/tests/Integration/Api/Application/Users/UserControllerTest.php b/tests/Integration/Api/Application/Users/UserControllerTest.php index 9d83cd53f..f98d33216 100644 --- a/tests/Integration/Api/Application/Users/UserControllerTest.php +++ b/tests/Integration/Api/Application/Users/UserControllerTest.php @@ -182,7 +182,7 @@ class UserControllerTest extends ApplicationApiIntegrationTestCase */ public function test_get_missing_user(): void { - $response = $this->getJson('/api/application/users/nil'); + $response = $this->getJson('/api/application/users/12345'); $this->assertNotFoundJson($response); } diff --git a/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php b/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php index 90ff06d35..129572688 100644 --- a/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php +++ b/tests/Integration/Api/Client/ClientApiIntegrationTestCase.php @@ -3,15 +3,13 @@ namespace App\Tests\Integration\Api\Client; use App\Models\Task; -use App\Models\Model; use App\Models\Backup; use App\Models\Server; use App\Models\Schedule; use Illuminate\Support\Collection; use App\Models\Allocation; -use App\Tests\Integration\TestResponse; use App\Tests\Integration\IntegrationTestCase; -use Illuminate\Database\Eloquent\Model as EloquentModel; +use Illuminate\Database\Eloquent\Model; use App\Transformers\Api\Client\BaseClientTransformer; abstract class ClientApiIntegrationTestCase extends IntegrationTestCase @@ -57,7 +55,7 @@ abstract class ClientApiIntegrationTestCase extends IntegrationTestCase * Asserts that the data passed through matches the output of the data from the transformer. This * will remove the "relationships" key when performing the comparison. */ - protected function assertJsonTransformedWith(array $data, Model|EloquentModel $model): void + protected function assertJsonTransformedWith(array $data, Model $model): void { $reflect = new \ReflectionClass($model); $transformer = sprintf('\\App\\Transformers\\Api\\Client\\%sTransformer', $reflect->getShortName()); diff --git a/tests/Integration/Api/Client/ClientControllerTest.php b/tests/Integration/Api/Client/ClientControllerTest.php index f8f1be56e..18e11df22 100644 --- a/tests/Integration/Api/Client/ClientControllerTest.php +++ b/tests/Integration/Api/Client/ClientControllerTest.php @@ -53,13 +53,13 @@ class ClientControllerTest extends ClientApiIntegrationTestCase /** @var \App\Models\Server[] $servers */ $servers = [ - $this->createServerModel(['user_id' => $users[0]->id, 'name' => 'Julia']), - $this->createServerModel(['user_id' => $users[1]->id, 'uuid_short' => '12121212', 'name' => 'Janice']), - $this->createServerModel(['user_id' => $users[1]->id, 'uuid' => '88788878-12356789', 'external_id' => 'ext123', 'name' => 'Julia']), - $this->createServerModel(['user_id' => $users[1]->id, 'uuid' => '88788878-abcdefgh', 'name' => 'Jennifer']), + $this->createServerModel(['user_id' => $users[0]->id, 'name' => 'julia']), + $this->createServerModel(['user_id' => $users[1]->id, 'uuid_short' => '12121212', 'name' => 'janice']), + $this->createServerModel(['user_id' => $users[1]->id, 'uuid' => '88788878-12356789', 'external_id' => 'ext123', 'name' => 'julia']), + $this->createServerModel(['user_id' => $users[1]->id, 'uuid' => '88788878-abcdefgh', 'name' => 'jennifer']), ]; - $this->actingAs($users[1])->getJson('/api/client?filter[*]=Julia') + $this->actingAs($users[1])->getJson('/api/client?filter[*]=julia') ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuid_short); @@ -90,7 +90,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.attributes.identifier', $servers[3]->uuid_short); - $this->actingAs($users[0])->getJson('/api/client?filter[*]=Julia&type=admin-all') + $this->actingAs($users[0])->getJson('/api/client?filter[*]=julia&type=admin-all') ->assertOk() ->assertJsonCount(2, 'data') ->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuid_short) diff --git a/tests/Integration/Api/Client/Server/Startup/GetStartupAndVariablesTest.php b/tests/Integration/Api/Client/Server/Startup/GetStartupAndVariablesTest.php index ea8376988..590f400b2 100644 --- a/tests/Integration/Api/Client/Server/Startup/GetStartupAndVariablesTest.php +++ b/tests/Integration/Api/Client/Server/Startup/GetStartupAndVariablesTest.php @@ -42,7 +42,7 @@ class GetStartupAndVariablesTest extends ClientApiIntegrationTestCase $response->assertJsonPath('object', 'list'); $response->assertJsonCount(1, 'data'); $response->assertJsonPath('data.0.object', EggVariable::RESOURCE_NAME); - $this->assertJsonTransformedWith($response->json('data.0.attributes'), $egg->variables[1]); + $this->assertJsonTransformedWith($response->json('data.0.attributes'), $egg->variables()->where('user_viewable', true)->first()); } /** diff --git a/tests/Integration/Api/Client/TwoFactorControllerTest.php b/tests/Integration/Api/Client/TwoFactorControllerTest.php index 996762de4..a36a27ccb 100644 --- a/tests/Integration/Api/Client/TwoFactorControllerTest.php +++ b/tests/Integration/Api/Client/TwoFactorControllerTest.php @@ -142,7 +142,7 @@ class TwoFactorControllerTest extends ClientApiIntegrationTestCase $user = $user->refresh(); $this->assertFalse($user->use_totp); $this->assertNotNull($user->totp_authenticated_at); - $this->assertSame(Carbon::now()->toAtomString(), $user->totp_authenticated_at->toAtomString()); + $this->assertTrue(now()->isSameAs('Y-m-d H:i:s', $user->totp_authenticated_at)); } /** diff --git a/tests/Integration/Services/Servers/ServerCreationServiceTest.php b/tests/Integration/Services/Servers/ServerCreationServiceTest.php index 43c5c862b..e0cf4e61b 100644 --- a/tests/Integration/Services/Servers/ServerCreationServiceTest.php +++ b/tests/Integration/Services/Servers/ServerCreationServiceTest.php @@ -118,8 +118,8 @@ class ServerCreationServiceTest extends IntegrationTestCase $this->assertSame($response->uuid_short, substr($response->uuid, 0, 8)); $this->assertSame($egg->id, $response->egg_id); $this->assertCount(2, $response->variables); - $this->assertSame('123', $response->variables[0]->server_value); - $this->assertSame('server2.jar', $response->variables[1]->server_value); + $this->assertSame('123', $response->variables()->firstWhere(['env_variable' => 'BUNGEE_VERSION'])->server_value); + $this->assertSame('server2.jar', $response->variables()->firstWhere(['env_variable' => 'SERVER_JARFILE'])->server_value); foreach ($data as $key => $value) { if (in_array($key, ['allocation_additional', 'environment', 'start_on_completion'])) { diff --git a/tests/Integration/Services/Servers/StartupModificationServiceTest.php b/tests/Integration/Services/Servers/StartupModificationServiceTest.php index 5bc661452..1166eed64 100644 --- a/tests/Integration/Services/Servers/StartupModificationServiceTest.php +++ b/tests/Integration/Services/Servers/StartupModificationServiceTest.php @@ -106,7 +106,7 @@ class StartupModificationServiceTest extends IntegrationTestCase $clone = $this->cloneEggAndVariables($server->egg); // This makes the BUNGEE_VERSION variable not user editable. - $clone->variables()->first()->update([ + $clone->variables()->firstWhere(['env_variable' => 'BUNGEE_VERSION'])->update([ 'user_editable' => false, ]); @@ -115,7 +115,7 @@ class StartupModificationServiceTest extends IntegrationTestCase ServerVariable::query()->updateOrCreate([ 'server_id' => $server->id, - 'variable_id' => $server->variables[0]->id, + 'variable_id' => $server->variables()->firstWhere(['env_variable' => 'BUNGEE_VERSION'])->id, ], ['variable_value' => 'EXIST']); $response = $this->getService()->handle($server, [ @@ -126,8 +126,8 @@ class StartupModificationServiceTest extends IntegrationTestCase ]); $this->assertCount(2, $response->variables); - $this->assertSame('EXIST', $response->variables[0]->server_value); - $this->assertSame('test.jar', $response->variables[1]->server_value); + $this->assertSame('EXIST', $response->variables()->firstWhere(['env_variable' => 'BUNGEE_VERSION'])->server_value); + $this->assertSame('test.jar', $response->variables()->firstWhere(['env_variable' => 'SERVER_JARFILE'])->server_value); $response = $this->getService() ->setUserLevel(User::USER_LEVEL_ADMIN) @@ -139,8 +139,8 @@ class StartupModificationServiceTest extends IntegrationTestCase ]); $this->assertCount(2, $response->variables); - $this->assertSame('1234', $response->variables[0]->server_value); - $this->assertSame('test.jar', $response->variables[1]->server_value); + $this->assertSame('1234', $response->variables()->firstWhere(['env_variable' => 'BUNGEE_VERSION'])->server_value); + $this->assertSame('test.jar', $response->variables()->firstWhere(['env_variable' => 'SERVER_JARFILE'])->server_value); } /** diff --git a/tests/Integration/Services/Servers/VariableValidatorServiceTest.php b/tests/Integration/Services/Servers/VariableValidatorServiceTest.php index 66255bd8c..013ecea0f 100644 --- a/tests/Integration/Services/Servers/VariableValidatorServiceTest.php +++ b/tests/Integration/Services/Servers/VariableValidatorServiceTest.php @@ -107,12 +107,15 @@ class VariableValidatorServiceTest extends IntegrationTestCase 'SERVER_JARFILE' => 'server.jar', ]); + $bungeeVersion = $response->firstWhere('key', 'BUNGEE_VERSION'); + $serverJarfile = $response->firstWhere('key', 'SERVER_JARFILE'); + $this->assertInstanceOf(Collection::class, $response); $this->assertCount(2, $response); - $this->assertSame('BUNGEE_VERSION', $response->get(0)->key); - $this->assertSame('123', $response->get(0)->value); - $this->assertSame('SERVER_JARFILE', $response->get(1)->key); - $this->assertSame('server.jar', $response->get(1)->value); + $this->assertSame('BUNGEE_VERSION', $bungeeVersion->key); + $this->assertSame('123', $bungeeVersion->value); + $this->assertSame('SERVER_JARFILE', $serverJarfile->key); + $this->assertSame('server.jar', $serverJarfile->value); } public function test_nullable_environment_variables_can_be_used_correctly(): void