Officially support PostgreSQL database (#1066)
* 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
This commit is contained in:
parent
bca02ced86
commit
8261184b57
@ -3,5 +3,4 @@ APP_DEBUG=false
|
||||
APP_KEY=
|
||||
APP_URL=http://panel.test
|
||||
APP_INSTALLED=false
|
||||
APP_TIMEZONE=UTC
|
||||
APP_LOCALE=en
|
||||
|
76
.github/workflows/ci.yaml
vendored
76
.github/workflows/ci.yaml
vendored
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
]);
|
||||
|
@ -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')));
|
||||
|
||||
|
@ -155,8 +155,8 @@ class AllocationSelectionService
|
||||
$query->whereIn('node_id', $nodes);
|
||||
}
|
||||
|
||||
return $query->groupBy('ip')
|
||||
->get()
|
||||
return $query
|
||||
->groupBy('ip')
|
||||
->pluck('ip')
|
||||
->toArray();
|
||||
}
|
||||
|
@ -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',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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');
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('permissions', function (Blueprint $table) {
|
||||
$table->renameColumn('permissions', 'permission');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('permissions', function (Blueprint $table) {});
|
||||
}
|
||||
};
|
@ -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();
|
||||
});
|
||||
|
@ -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');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('permissions', function (Blueprint $table) {
|
||||
$table->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');
|
||||
});
|
||||
}
|
||||
};
|
@ -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();
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Subuser;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('permissions', function (Blueprint $table) {
|
||||
$table->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');
|
||||
});
|
||||
}
|
||||
};
|
@ -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');
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$permissions = DB::table('permissions')->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]);
|
||||
}
|
||||
}
|
||||
};
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
});
|
||||
|
@ -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 () {
|
||||
|
@ -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']);
|
||||
});
|
||||
|
||||
|
@ -1,64 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Models\Permission as P;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* A list of all pre-1.0 permissions available to a user and their associated
|
||||
* casting for the new permissions system.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $permissionsMap = [
|
||||
'power-start' => 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');
|
||||
});
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
});
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
@ -11,6 +12,19 @@ return new class extends Migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (Schema::getConnection()->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();
|
||||
});
|
||||
|
@ -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]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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' => '*']);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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\')'),
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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'])) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user