From 07407e4db170eb0fe19e00a960e31d3cba6d6614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Sun, 6 Jul 2025 22:26:23 +0200 Subject: [PATCH] remove un-needed stuff --- .github/workflows/deploy.yml | 233 ----------- .../002_migrate_servers_to_uuid.sql | 168 -------- scripts/run_migrations.go | 148 ------- scripts/test_migrations.go | 392 ------------------ 4 files changed, 941 deletions(-) delete mode 100644 .github/workflows/deploy.yml delete mode 100644 scripts/migrations/002_migrate_servers_to_uuid.sql delete mode 100644 scripts/run_migrations.go delete mode 100644 scripts/test_migrations.go diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index f418268..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,233 +0,0 @@ -name: Deploy to Windows Server - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - workflow_dispatch: - -env: - GO_VERSION: '1.23' - SERVICE_NAME: 'ACC Server Manager' - BINARY_NAME: 'acc-server-manager' - MIGRATE_BINARY_NAME: 'acc-migrate' - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Cache Go modules - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - name: Run tests - run: go test -v ./... - - - name: Build API for Windows - env: - GOOS: windows - GOARCH: amd64 - run: | - go build -o ${{ env.BINARY_NAME }}.exe ./cmd/api - - - name: Build Migration tool for Windows - env: - GOOS: windows - GOARCH: amd64 - run: | - go build -o ${{ env.MIGRATE_BINARY_NAME }}.exe ./cmd/migrate - - - name: Upload build artifacts - uses: actions/upload-artifact@v3 - with: - name: windows-binaries - path: | - ${{ env.BINARY_NAME }}.exe - ${{ env.MIGRATE_BINARY_NAME }}.exe - retention-days: 5 - - deploy: - needs: build - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' - - steps: - - uses: actions/checkout@v4 - - - name: Download build artifacts - uses: actions/download-artifact@v3 - with: - name: windows-binaries - path: ./build - - - name: Setup SSH key - uses: webfactory/ssh-agent@v0.7.0 - with: - ssh-private-key: ${{ secrets.WINDOWS_SERVER_SSH_KEY }} - - - name: Deploy to Windows Server - env: - SERVER_HOST: ${{ secrets.WINDOWS_SERVER_HOST }} - SERVER_USER: ${{ secrets.WINDOWS_SERVER_USER }} - SERVER_PASSWORD: ${{ secrets.WINDOWS_SERVER_PASSWORD }} - DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} - run: | - # Install PowerShell Core if not available - if ! command -v pwsh &> /dev/null; then - echo "Installing PowerShell Core..." - wget -q https://github.com/PowerShell/PowerShell/releases/download/v7.4.0/powershell_7.4.0-1.deb_amd64.deb - sudo dpkg -i powershell_7.4.0-1.deb_amd64.deb - sudo apt-get install -f - fi - - # Create deployment script - cat > deploy_script.ps1 << 'EOF' - param( - [string]$ServiceName = "${{ env.SERVICE_NAME }}", - [string]$BinaryName = "${{ env.BINARY_NAME }}", - [string]$MigrateBinaryName = "${{ env.MIGRATE_BINARY_NAME }}", - [string]$DeployPath = "$env:DEPLOY_PATH" - ) - - Write-Host "Starting deployment process..." -ForegroundColor Green - - # Check if service exists and stop it - $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue - if ($service) { - Write-Host "Stopping service: $ServiceName" -ForegroundColor Yellow - Stop-Service -Name $ServiceName -Force - - # Wait for service to stop - $timeout = 30 - $elapsed = 0 - while ($service.Status -ne 'Stopped' -and $elapsed -lt $timeout) { - Start-Sleep -Seconds 1 - $elapsed++ - $service.Refresh() - } - - if ($service.Status -ne 'Stopped') { - Write-Error "Failed to stop service within timeout" - exit 1 - } - Write-Host "Service stopped successfully" -ForegroundColor Green - } else { - Write-Host "Service not found: $ServiceName" -ForegroundColor Yellow - } - - # Create backup of current deployment - $backupPath = "$DeployPath\backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" - if (Test-Path "$DeployPath\$BinaryName.exe") { - Write-Host "Creating backup at: $backupPath" -ForegroundColor Yellow - New-Item -ItemType Directory -Path $backupPath -Force | Out-Null - Copy-Item "$DeployPath\*" -Destination $backupPath -Recurse -Force - } - - # Copy new binaries - Write-Host "Copying new binaries to: $DeployPath" -ForegroundColor Yellow - Copy-Item "C:\temp\$BinaryName.exe" -Destination "$DeployPath\$BinaryName.exe" -Force - Copy-Item "C:\temp\$MigrateBinaryName.exe" -Destination "$DeployPath\$MigrateBinaryName.exe" -Force - - # Run migrations - Write-Host "Running database migrations..." -ForegroundColor Yellow - $migrateResult = & "$DeployPath\$MigrateBinaryName.exe" 2>&1 - Write-Host "Migration output: $migrateResult" -ForegroundColor Cyan - - # Start service - if ($service) { - Write-Host "Starting service: $ServiceName" -ForegroundColor Yellow - Start-Service -Name $ServiceName - - # Wait for service to start - $timeout = 30 - $elapsed = 0 - while ($service.Status -ne 'Running' -and $elapsed -lt $timeout) { - Start-Sleep -Seconds 1 - $elapsed++ - $service.Refresh() - } - - if ($service.Status -ne 'Running') { - Write-Error "Failed to start service within timeout" - # Rollback - Write-Host "Rolling back deployment..." -ForegroundColor Red - if (Test-Path $backupPath) { - Copy-Item "$backupPath\*" -Destination $DeployPath -Recurse -Force - Start-Service -Name $ServiceName - } - exit 1 - } - Write-Host "Service started successfully" -ForegroundColor Green - } else { - Write-Host "Service not configured. Manual start required." -ForegroundColor Yellow - } - - # Cleanup old backups (keep last 5) - $backupDir = Split-Path $DeployPath -Parent - Get-ChildItem -Path $backupDir -Directory -Name "backup_*" | - Sort-Object -Descending | - Select-Object -Skip 5 | - ForEach-Object { Remove-Item -Path "$backupDir\$_" -Recurse -Force } - - Write-Host "Deployment completed successfully!" -ForegroundColor Green - EOF - - # Copy files to Windows server using SCP - echo "Copying files to Windows server..." - scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - ./build/${{ env.BINARY_NAME }}.exe \ - ./build/${{ env.MIGRATE_BINARY_NAME }}.exe \ - deploy_script.ps1 \ - ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}:C:/temp/ - - # Execute deployment script on Windows server - echo "Executing deployment script on Windows server..." - ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }} \ - "powershell.exe -ExecutionPolicy Bypass -File C:/temp/deploy_script.ps1" - - # Cleanup temp files - ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }} \ - "del C:/temp/${{ env.BINARY_NAME }}.exe C:/temp/${{ env.MIGRATE_BINARY_NAME }}.exe C:/temp/deploy_script.ps1" - - echo "Deployment completed successfully!" - - notify: - needs: [build, deploy] - runs-on: ubuntu-latest - if: always() - - steps: - - name: Notify deployment status - env: - WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - run: | - if [ "${{ needs.deploy.result }}" == "success" ]; then - STATUS="✅ SUCCESS" - COLOR="good" - else - STATUS="❌ FAILED" - COLOR="danger" - fi - - if [ -n "$WEBHOOK_URL" ]; then - curl -X POST -H 'Content-type: application/json' \ - --data "{\"text\":\"ACC Server Manager Deployment $STATUS\",\"attachments\":[{\"color\":\"$COLOR\",\"fields\":[{\"title\":\"Branch\",\"value\":\"${{ github.ref_name }}\",\"short\":true},{\"title\":\"Commit\",\"value\":\"${{ github.sha }}\",\"short\":true}]}]}" \ - $WEBHOOK_URL - fi diff --git a/scripts/migrations/002_migrate_servers_to_uuid.sql b/scripts/migrations/002_migrate_servers_to_uuid.sql deleted file mode 100644 index 826fad2..0000000 --- a/scripts/migrations/002_migrate_servers_to_uuid.sql +++ /dev/null @@ -1,168 +0,0 @@ --- Migration 002: Migrate servers and related tables from integer IDs to UUIDs --- This migration handles: servers, configs, state_histories, steam_credentials, system_configs - -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; - --- Step 1: Create new servers table with UUID primary key -CREATE TABLE servers_new ( - id TEXT PRIMARY KEY, -- UUID stored as TEXT in SQLite - name TEXT NOT NULL, - ip TEXT NOT NULL, - port INTEGER NOT NULL, - path TEXT NOT NULL, -- Updated from config_path to path to match Go model - service_name TEXT NOT NULL, - date_created DATETIME, - from_steam_cmd BOOLEAN NOT NULL DEFAULT 1 -- Added to match Go model -); - --- Step 2: Generate UUIDs for existing servers and migrate data -INSERT INTO servers_new (id, name, ip, port, path, service_name, from_steam_cmd) -SELECT - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as id, - name, - COALESCE(ip, '') as ip, - COALESCE(port, 0) as port, - COALESCE(path, '') as path, - service_name, - 1 as from_steam_cmd -FROM servers; - --- Step 3: Create mapping table to track old ID to new UUID mapping -CREATE TEMP TABLE server_id_mapping AS -SELECT - s_old.id as old_id, - s_new.id as new_id -FROM servers s_old -JOIN servers_new s_new ON s_old.name = s_new.name AND s_old.service_name = s_new.service_name; - --- Step 4: Drop old servers table and rename new one -DROP TABLE servers; -ALTER TABLE servers_new RENAME TO servers; - --- Step 5: Create new configs table with UUID references -CREATE TABLE configs_new ( - id TEXT PRIMARY KEY, -- UUID for configs - server_id TEXT NOT NULL, -- UUID reference to servers (GORM expects snake_case) - config_file TEXT NOT NULL, - old_config TEXT, - new_config TEXT, - changed_at DATETIME DEFAULT CURRENT_TIMESTAMP -); - --- Step 6: Migrate configs data with UUID references -INSERT INTO configs_new (id, server_id, config_file, old_config, new_config, changed_at) -SELECT - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as id, - sim.new_id as server_id, - c.config_file, - c.old_config, - c.new_config, - c.changed_at -FROM configs c -JOIN server_id_mapping sim ON c.server_id = sim.old_id; - --- Step 7: Drop old configs table and rename new one -DROP TABLE configs; -ALTER TABLE configs_new RENAME TO configs; - --- Step 8: Create new state_histories table with UUID references -CREATE TABLE state_histories_new ( - id TEXT PRIMARY KEY, -- UUID for state_histories records - server_id TEXT NOT NULL, -- UUID reference to servers (GORM expects snake_case) - session TEXT, - track TEXT, - player_count INTEGER, - date_created DATETIME, - session_start DATETIME, - session_duration_minutes INTEGER, - session_id TEXT NOT NULL -- Changed to TEXT to store UUID -); - --- Step 9: Migrate state_histories data with UUID references -INSERT INTO state_histories_new (id, server_id, session, track, player_count, date_created, session_start, session_duration_minutes, session_id) -SELECT - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as id, - sim.new_id as server_id, - sh.session, - sh.track, - sh.player_count, - sh.date_created, - sh.session_start, - sh.session_duration_minutes, - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as session_id -FROM state_histories sh -JOIN server_id_mapping sim ON sh.server_id = sim.old_id; - --- Step 10: Drop old state_histories table and rename new one -DROP TABLE state_histories; -ALTER TABLE state_histories_new RENAME TO state_histories; - --- Step 11: Create new steam_credentials table with UUID primary key -CREATE TABLE steam_credentials_new ( - id TEXT PRIMARY KEY, -- UUID for steam_credentials - username TEXT NOT NULL, - password TEXT NOT NULL, - date_created DATETIME, - last_updated DATETIME -); - --- Step 12: Migrate steam_credentials data -INSERT INTO steam_credentials_new (id, username, password, date_created, last_updated) -SELECT - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as id, - username, - password, - date_created, - last_updated -FROM steam_credentials; - --- Step 13: Drop old steam_credentials table and rename new one -DROP TABLE steam_credentials; -ALTER TABLE steam_credentials_new RENAME TO steam_credentials; - --- Step 14: Create new system_configs table with UUID primary key -CREATE TABLE system_configs_new ( - id TEXT PRIMARY KEY, -- UUID for system_configs - key TEXT, - value TEXT, - default_value TEXT, - description TEXT, - date_modified TEXT -); - --- Step 15: Migrate system_configs data -INSERT INTO system_configs_new (id, key, value, default_value, description, date_modified) -SELECT - LOWER(HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-' || '4' || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || - SUBSTR('89AB', ABS(RANDOM()) % 4 + 1, 1) || SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))) as id, - key, - value, - default_value, - description, - date_modified -FROM system_configs; - --- Step 16: Drop old system_configs table and rename new one -DROP TABLE system_configs; -ALTER TABLE system_configs_new RENAME TO system_configs; - --- Step 17: Create migration record -CREATE TABLE IF NOT EXISTS migration_records ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - migration_name TEXT UNIQUE NOT NULL, - applied_at TEXT NOT NULL, - success BOOLEAN NOT NULL, - notes TEXT -); - -INSERT INTO migration_records (migration_name, applied_at, success, notes) -VALUES ('002_migrate_servers_to_uuid', datetime('now'), 1, 'Migrated servers, configs, state_histories, steam_credentials, and system_configs to UUID primary keys'); - -COMMIT; -PRAGMA foreign_keys=ON; diff --git a/scripts/run_migrations.go b/scripts/run_migrations.go deleted file mode 100644 index 1e3b986..0000000 --- a/scripts/run_migrations.go +++ /dev/null @@ -1,148 +0,0 @@ -package main - -import ( - "acc-server-manager/local/migrations" - "acc-server-manager/local/utl/logging" - "fmt" - "log" - "os" - "path/filepath" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -func main() { - // Initialize logging - logging.Init(true) // Enable debug logging - - // Get database path from command line args or use default - dbPath := "acc.db" - if len(os.Args) > 1 { - dbPath = os.Args[1] - } - - // Make sure we're running from the correct directory - if !fileExists(dbPath) { - // Try to find the database in common locations - possiblePaths := []string{ - "acc.db", - "../acc.db", - "../../acc.db", - "cmd/api/acc.db", - "../cmd/api/acc.db", - } - - found := false - for _, path := range possiblePaths { - if fileExists(path) { - dbPath = path - found = true - break - } - } - - if !found { - log.Fatalf("Database file not found. Please run from the project root or specify the correct path.") - } - } - - // Get absolute path for database - absDbPath, err := filepath.Abs(dbPath) - if err != nil { - log.Fatalf("Failed to get absolute path for database: %v", err) - } - - logging.Info("Using database: %s", absDbPath) - - // Open database connection - db, err := gorm.Open(sqlite.Open(absDbPath), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Info), - }) - if err != nil { - log.Fatalf("Failed to connect to database: %v", err) - } - - sqlDB, err := db.DB() - if err != nil { - log.Fatalf("Failed to get underlying sql.DB: %v", err) - } - defer sqlDB.Close() - - // Run migrations in order - logging.Info("Starting database migrations...") - - // Migration 001: Password security upgrade (if it exists and hasn't run) - logging.Info("Checking Migration 001: Password Security Upgrade...") - if err := migrations.RunPasswordSecurityMigration(db); err != nil { - log.Fatalf("Migration 001 failed: %v", err) - } - - // Migration 002: UUID migration - logging.Info("Checking Migration 002: UUID Migration...") - if err := migrations.RunUUIDMigration(db); err != nil { - log.Fatalf("Migration 002 failed: %v", err) - } - - logging.Info("All migrations completed successfully!") - - // Print summary of migration status - printMigrationStatus(db) -} - -// fileExists checks if a file exists and is not a directory -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} - -// printMigrationStatus prints a summary of applied migrations -func printMigrationStatus(db *gorm.DB) { - logging.Info("Migration Status Summary:") - logging.Info("========================") - - // Check if migration_records table exists - var tableExists int - err := db.Raw("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='migration_records'").Scan(&tableExists).Error - if err != nil || tableExists == 0 { - logging.Info("No migration tracking table found - this may be a fresh database") - return - } - - // Get all migration records - var records []struct { - MigrationName string `gorm:"column:migration_name"` - AppliedAt string `gorm:"column:applied_at"` - Success bool `gorm:"column:success"` - Notes string `gorm:"column:notes"` - } - - err = db.Table("migration_records").Find(&records).Error - if err != nil { - logging.Error("Failed to fetch migration records: %v", err) - return - } - - if len(records) == 0 { - logging.Info("No migrations have been applied yet") - return - } - - for _, record := range records { - status := "✓ SUCCESS" - if !record.Success { - status = "✗ FAILED" - } - - logging.Info(" %s - %s (%s)", record.MigrationName, status, record.AppliedAt) - if record.Notes != "" { - logging.Info(" Notes: %s", record.Notes) - } - } - - fmt.Printf("\nTotal migrations applied: %d\n", len(records)) -} diff --git a/scripts/test_migrations.go b/scripts/test_migrations.go deleted file mode 100644 index b0e44dd..0000000 --- a/scripts/test_migrations.go +++ /dev/null @@ -1,392 +0,0 @@ -package main - -import ( - "acc-server-manager/local/migrations" - "acc-server-manager/local/model" - "acc-server-manager/local/repository" - "acc-server-manager/local/service" - "acc-server-manager/local/utl/logging" - "context" - "fmt" - "log" - "os" - - "github.com/google/uuid" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -func main() { - // Initialize logging - logging.Init(true) // Enable debug logging - - // Create a test database - testDbPath := "test_migrations.db" - - // Remove existing test database if it exists - if fileExists(testDbPath) { - os.Remove(testDbPath) - } - - logging.Info("Creating test database: %s", testDbPath) - - // Open database connection - db, err := gorm.Open(sqlite.Open(testDbPath), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Info), - }) - if err != nil { - log.Fatalf("Failed to connect to test database: %v", err) - } - - sqlDB, err := db.DB() - if err != nil { - log.Fatalf("Failed to get underlying sql.DB: %v", err) - } - defer sqlDB.Close() - - // Create initial schema with integer IDs to simulate old database - logging.Info("Creating initial schema with integer IDs...") - createOldSchema(db) - - // Insert test data with integer IDs - logging.Info("Inserting test data...") - insertTestData(db) - - // Run UUID migration - logging.Info("Running UUID migration...") - if err := migrations.RunUUIDMigration(db); err != nil { - log.Fatalf("UUID migration failed: %v", err) - } - - // Verify migration worked - logging.Info("Verifying migration results...") - if err := verifyMigration(db); err != nil { - log.Fatalf("Migration verification failed: %v", err) - } - - // Test role system - logging.Info("Testing role system...") - if err := testRoleSystem(db); err != nil { - log.Fatalf("Role system test failed: %v", err) - } - - // Test Super Admin deletion prevention - logging.Info("Testing Super Admin deletion prevention...") - if err := testSuperAdminDeletionPrevention(db); err != nil { - log.Fatalf("Super Admin deletion prevention test failed: %v", err) - } - - logging.Info("All tests passed successfully!") - - // Clean up - os.Remove(testDbPath) - logging.Info("Test database cleaned up") -} - -func createOldSchema(db *gorm.DB) { - // Create tables with integer primary keys to simulate old schema - db.Exec(` - CREATE TABLE IF NOT EXISTS servers ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - ip TEXT NOT NULL, - port INTEGER NOT NULL, - config_path TEXT NOT NULL, - service_name TEXT NOT NULL, - date_created DATETIME, - from_steam_cmd BOOLEAN NOT NULL DEFAULT 1 - ) - `) - - db.Exec(` - CREATE TABLE IF NOT EXISTS configs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - server_id INTEGER NOT NULL, - config_file TEXT NOT NULL, - old_config TEXT, - new_config TEXT, - changed_at DATETIME DEFAULT CURRENT_TIMESTAMP - ) - `) - - db.Exec(` - CREATE TABLE IF NOT EXISTS state_histories ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - server_id INTEGER NOT NULL, - session TEXT, - track TEXT, - player_count INTEGER, - date_created DATETIME, - session_start DATETIME, - session_duration_minutes INTEGER, - session_id INTEGER NOT NULL DEFAULT 0 - ) - `) - - db.Exec(` - CREATE TABLE IF NOT EXISTS steam_credentials ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT NOT NULL, - password TEXT NOT NULL, - date_created DATETIME, - last_updated DATETIME - ) - `) - - db.Exec(` - CREATE TABLE IF NOT EXISTS system_configs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - key TEXT, - value TEXT, - default_value TEXT, - description TEXT, - date_modified TEXT - ) - `) -} - -func insertTestData(db *gorm.DB) { - // Insert test server - db.Exec(` - INSERT INTO servers (name, ip, port, config_path, service_name, date_created, from_steam_cmd) - VALUES ('Test Server', '127.0.0.1', 9600, '/test/path', 'TestService', datetime('now'), 1) - `) - - // Insert test config - db.Exec(` - INSERT INTO configs (server_id, config_file, old_config, new_config) - VALUES (1, 'test.json', '{"old": true}', '{"new": true}') - `) - - // Insert test state history - db.Exec(` - INSERT INTO state_histories (server_id, session, track, player_count, date_created, session_duration_minutes, session_id) - VALUES (1, 'Practice', 'monza', 5, datetime('now'), 60, 1) - `) - - // Insert test steam credentials - db.Exec(` - INSERT INTO steam_credentials (username, password, date_created, last_updated) - VALUES ('testuser', 'testpass', datetime('now'), datetime('now')) - `) - - // Insert test system config - db.Exec(` - INSERT INTO system_configs (key, value, default_value, description, date_modified) - VALUES ('test_key', 'test_value', 'default_value', 'Test config', datetime('now')) - `) -} - -func verifyMigration(db *gorm.DB) error { - // Check that all tables now have UUID primary keys - - // Check servers table - var serverID string - err := db.Raw("SELECT id FROM servers LIMIT 1").Scan(&serverID).Error - if err != nil { - return fmt.Errorf("failed to query servers table: %v", err) - } - if _, err := uuid.Parse(serverID); err != nil { - return fmt.Errorf("servers table ID is not a valid UUID: %s", serverID) - } - - // Check configs table - var configID, configServerID string - err = db.Raw("SELECT id, server_id FROM configs LIMIT 1").Row().Scan(&configID, &configServerID) - if err != nil { - return fmt.Errorf("failed to query configs table: %v", err) - } - if _, err := uuid.Parse(configID); err != nil { - return fmt.Errorf("configs table ID is not a valid UUID: %s", configID) - } - if _, err := uuid.Parse(configServerID); err != nil { - return fmt.Errorf("configs table server_id is not a valid UUID: %s", configServerID) - } - - // Check state_histories table - var stateID, stateServerID string - err = db.Raw("SELECT id, server_id FROM state_histories LIMIT 1").Row().Scan(&stateID, &stateServerID) - if err != nil { - return fmt.Errorf("failed to query state_histories table: %v", err) - } - if _, err := uuid.Parse(stateID); err != nil { - return fmt.Errorf("state_histories table ID is not a valid UUID: %s", stateID) - } - if _, err := uuid.Parse(stateServerID); err != nil { - return fmt.Errorf("state_histories table server_id is not a valid UUID: %s", stateServerID) - } - - // Check steam_credentials table - var steamID string - err = db.Raw("SELECT id FROM steam_credentials LIMIT 1").Scan(&steamID).Error - if err != nil { - return fmt.Errorf("failed to query steam_credentials table: %v", err) - } - if _, err := uuid.Parse(steamID); err != nil { - return fmt.Errorf("steam_credentials table ID is not a valid UUID: %s", steamID) - } - - // Check system_configs table - var systemID string - err = db.Raw("SELECT id FROM system_configs LIMIT 1").Scan(&systemID).Error - if err != nil { - return fmt.Errorf("failed to query system_configs table: %v", err) - } - if _, err := uuid.Parse(systemID); err != nil { - return fmt.Errorf("system_configs table ID is not a valid UUID: %s", systemID) - } - - logging.Info("✓ All tables successfully migrated to UUID primary keys") - return nil -} - -func testRoleSystem(db *gorm.DB) error { - // Auto-migrate the models for role system - db.AutoMigrate(&model.Role{}, &model.Permission{}, &model.User{}) - - // Create repository and service - repo := repository.NewMembershipRepository(db) - service := service.NewMembershipService(repo) - - ctx := context.Background() - - // Setup initial data (this should create Super Admin, Admin, and Manager roles) - if err := service.SetupInitialData(ctx); err != nil { - return fmt.Errorf("failed to setup initial data: %v", err) - } - - // Test that all three roles were created - roles, err := service.GetAllRoles(ctx) - if err != nil { - return fmt.Errorf("failed to get roles: %v", err) - } - - expectedRoles := map[string]bool{ - "Super Admin": false, - "Admin": false, - "Manager": false, - } - - for _, role := range roles { - if _, exists := expectedRoles[role.Name]; exists { - expectedRoles[role.Name] = true - } - } - - for roleName, found := range expectedRoles { - if !found { - return fmt.Errorf("role '%s' was not created", roleName) - } - } - - // Test permissions for each role - superAdminRole, err := repo.FindRoleByName(ctx, "Super Admin") - if err != nil { - return fmt.Errorf("failed to find Super Admin role: %v", err) - } - - adminRole, err := repo.FindRoleByName(ctx, "Admin") - if err != nil { - return fmt.Errorf("failed to find Admin role: %v", err) - } - - managerRole, err := repo.FindRoleByName(ctx, "Manager") - if err != nil { - return fmt.Errorf("failed to find Manager role: %v", err) - } - - // Load permissions for roles - db.Preload("Permissions").Find(superAdminRole) - db.Preload("Permissions").Find(adminRole) - db.Preload("Permissions").Find(managerRole) - - // Super Admin and Admin should have all permissions - allPermissions := model.AllPermissions() - if len(superAdminRole.Permissions) != len(allPermissions) { - return fmt.Errorf("Super Admin should have all %d permissions, but has %d", len(allPermissions), len(superAdminRole.Permissions)) - } - - if len(adminRole.Permissions) != len(allPermissions) { - return fmt.Errorf("Admin should have all %d permissions, but has %d", len(allPermissions), len(adminRole.Permissions)) - } - - // Manager should have limited permissions (no create/delete for membership, role, user, server) - expectedManagerPermissions := []string{ - model.ServerView, - model.ServerUpdate, - model.ServerStart, - model.ServerStop, - model.ConfigView, - model.ConfigUpdate, - model.UserView, - model.RoleView, - model.MembershipView, - } - - if len(managerRole.Permissions) != len(expectedManagerPermissions) { - return fmt.Errorf("Manager should have %d permissions, but has %d", len(expectedManagerPermissions), len(managerRole.Permissions)) - } - - // Verify Manager doesn't have restricted permissions - restrictedPermissions := []string{ - model.ServerCreate, - model.ServerDelete, - model.UserCreate, - model.UserDelete, - model.RoleCreate, - model.RoleDelete, - model.MembershipCreate, - } - - for _, restrictedPerm := range restrictedPermissions { - for _, managerPerm := range managerRole.Permissions { - if managerPerm.Name == restrictedPerm { - return fmt.Errorf("Manager should not have permission '%s'", restrictedPerm) - } - } - } - - logging.Info("✓ Role system working correctly") - logging.Info(" - Super Admin role: %d permissions", len(superAdminRole.Permissions)) - logging.Info(" - Admin role: %d permissions", len(adminRole.Permissions)) - logging.Info(" - Manager role: %d permissions", len(managerRole.Permissions)) - - return nil -} - -func testSuperAdminDeletionPrevention(db *gorm.DB) error { - // Create repository and service - repo := repository.NewMembershipRepository(db) - service := service.NewMembershipService(repo) - - ctx := context.Background() - - // Find the default admin user (should be Super Admin) - adminUser, err := repo.FindUserByUsername(ctx, "admin") - if err != nil { - return fmt.Errorf("failed to find admin user: %v", err) - } - - // Try to delete the Super Admin user (should fail) - err = service.DeleteUser(ctx, adminUser.ID) - if err == nil { - return fmt.Errorf("deleting Super Admin user should have failed, but it succeeded") - } - - if err.Error() != "cannot delete Super Admin user" { - return fmt.Errorf("expected 'cannot delete Super Admin user' error, got: %v", err) - } - - logging.Info("✓ Super Admin deletion prevention working correctly") - return nil -} - -// fileExists checks if a file exists and is not a directory -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -}