diff options
| author | crt <crt@teleco.ch> | 2025-12-13 22:08:54 +0100 |
|---|---|---|
| committer | crt <crt@teleco.ch> | 2025-12-13 22:08:54 +0100 |
| commit | 8f4e7ae7e0fffa27b22c17e94a57ec6ecb28f96d (patch) | |
| tree | 94ae93079e4299d33de7b75f2e7408710b8e91b6 /beepzone-helper.ps1 | |
| parent | ff187ef944b0aacb379eb0dbec2d185633cf3b71 (diff) | |
made it somewhat run on windows kinda
Diffstat (limited to 'beepzone-helper.ps1')
| -rw-r--r-- | beepzone-helper.ps1 | 822 |
1 files changed, 822 insertions, 0 deletions
diff --git a/beepzone-helper.ps1 b/beepzone-helper.ps1 new file mode 100644 index 0000000..ffdd523 --- /dev/null +++ b/beepzone-helper.ps1 @@ -0,0 +1,822 @@ +# BeepZone Setup Helper for Windows +# PowerShell version - no WSL needed + +$ErrorActionPreference = "Stop" +$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path +$WORK_DIR = $SCRIPT_DIR +$LOG_FILE = "$env:TEMP\beepzone-helper.log" +$ENV_FILE = Join-Path $SCRIPT_DIR ".env" + +# Initialize log +"" | Out-File $LOG_FILE -Force + +# Default configuration +$config = @{ + BEEPZONE_DB_CONTAINER_NAME = "beepzone-mariadb" + BEEPZONE_DB_IMAGE = "mariadb:12" + DB_HOST = "127.0.0.1" + DB_PORT = "3306" + DB_NAME = "beepzone" + DB_USER = "beepzone" + DB_PASS = "beepzone" + DB_ROOT_PASSWORD = "root" + SECKELAPI_REPO = "https://git.teleco.ch/crt/seckelapi.git" + CLIENT_REPO = "https://git.teleco.ch/crt/beepzone-client-egui-emo.git" + DEPLOYMENT_TYPE = "clean" +} + +# Load existing .env if present +if (Test-Path $ENV_FILE) { + Get-Content $ENV_FILE | ForEach-Object { + if ($_ -match '^([^=]+)="?([^"]*)"?$') { + $config[$matches[1]] = $matches[2] + } + } +} + +function Save-Config { + @" +# BeepZone Setup Configuration +# Auto-generated by beepzone-helper.ps1 + +BEEPZONE_DB_CONTAINER_NAME="$($config.BEEPZONE_DB_CONTAINER_NAME)" +BEEPZONE_DB_IMAGE="$($config.BEEPZONE_DB_IMAGE)" +DB_HOST="$($config.DB_HOST)" +DB_PORT="$($config.DB_PORT)" +DB_NAME="$($config.DB_NAME)" +DB_USER="$($config.DB_USER)" +DB_PASS="$($config.DB_PASS)" +DB_ROOT_PASSWORD="$($config.DB_ROOT_PASSWORD)" +SECKELAPI_REPO="$($config.SECKELAPI_REPO)" +CLIENT_REPO="$($config.CLIENT_REPO)" +DEPLOYMENT_TYPE="$($config.DEPLOYMENT_TYPE)" +"@ | Out-File $ENV_FILE -Encoding UTF8 +} + +function Show-Menu { + param([string]$Title, [array]$Options) + + Write-Host "`n=== $Title ===" -ForegroundColor Cyan + for ($i = 0; $i -lt $Options.Count; $i++) { + Write-Host " [$($i+1)] $($Options[$i])" + } + Write-Host "" + $choice = Read-Host "Choose an option (1-$($Options.Count))" + return [int]$choice +} + +function Run-Command { + param( + [string]$Command, + [array]$Arguments, + [string]$SuccessMessage, + [string]$ErrorMessage, + [switch]$ShowOutput, + [switch]$LiveOutput + ) + + Write-Host "Running: $Command $($Arguments -join ' ')" -ForegroundColor DarkGray + Write-Host "" + + if ($LiveOutput) { + # Show output in real-time for long-running commands + $process = Start-Process -FilePath $Command -ArgumentList $Arguments -NoNewWindow -Wait -PassThru + $exitCode = $process.ExitCode + + # Log the command execution + "$Command $($Arguments -join ' ')" | Out-File $LOG_FILE -Append + "Exit Code: $exitCode" | Out-File $LOG_FILE -Append + + Write-Host "" + if ($exitCode -ne 0) { + Write-Host "$ErrorMessage (Exit Code: $exitCode)" -ForegroundColor Red + Write-Host "Full log: $LOG_FILE" -ForegroundColor DarkGray + return $false + } else { + if ($SuccessMessage) { + Write-Host $SuccessMessage -ForegroundColor Green + } + return $true + } + } else { + # Capture output for commands where we want to parse it + $tempOutput = New-TemporaryFile + $tempError = New-TemporaryFile + + try { + $process = Start-Process -FilePath $Command -ArgumentList $Arguments -NoNewWindow -Wait -PassThru ` + -RedirectStandardOutput $tempOutput.FullName -RedirectStandardError $tempError.FullName + + $exitCode = $process.ExitCode + $stdOut = Get-Content $tempOutput.FullName -Raw -ErrorAction SilentlyContinue + $stdErr = Get-Content $tempError.FullName -Raw -ErrorAction SilentlyContinue + + # Log everything + if ($stdOut) { $stdOut | Out-File $LOG_FILE -Append } + if ($stdErr) { $stdErr | Out-File $LOG_FILE -Append } + + # Show informational stderr messages if requested + if ($ShowOutput -and $stdErr) { + $stdErr.Split("`n") | ForEach-Object { + if ($_.Trim()) { Write-Host " $_" -ForegroundColor DarkGray } + } + } + + if ($exitCode -ne 0) { + Write-Host "`n$ErrorMessage" -ForegroundColor Red + Write-Host "Exit Code: $exitCode" -ForegroundColor Yellow + if ($stdOut) { + Write-Host "Output:" -ForegroundColor Yellow + $stdOut.Split("`n") | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } + if ($stdErr) { + Write-Host "Error:" -ForegroundColor Yellow + $stdErr.Split("`n") | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } + Write-Host "`nFull log: $LOG_FILE" -ForegroundColor DarkGray + return $false + } else { + if ($SuccessMessage) { + Write-Host $SuccessMessage -ForegroundColor Green + } + # Show stdout if it contains useful info (like container ID) + if ($stdOut -and $stdOut.Trim().Length -lt 100) { + Write-Host " → $($stdOut.Trim())" -ForegroundColor DarkGray + } + return $true + } + } finally { + Remove-Item $tempOutput -ErrorAction SilentlyContinue + Remove-Item $tempError -ErrorAction SilentlyContinue + } + } +} +function Test-Dependencies { + $missing = @() + + if (-not (Get-Command podman -ErrorAction SilentlyContinue)) { + $missing += "Podman (install Podman Desktop from podman.io)" + } + + # Check for MySQL/MariaDB client in PATH and common installation locations + $mysqlFound = $false + $script:MYSQL_CLIENT = "" + + # First check if already in PATH + foreach ($cmd in @("mysql", "mariadb")) { + if (Get-Command $cmd -ErrorAction SilentlyContinue) { + $script:MYSQL_CLIENT = $cmd + $mysqlFound = $true + break + } + } + + # If not in PATH, check common Windows installation locations + if (-not $mysqlFound) { + $searchPaths = @( + "C:\Program Files\MariaDB*\bin\mysql.exe", + "C:\Program Files\MariaDB*\bin\mariadb.exe", + "C:\Program Files\MySQL\MySQL Server*\bin\mysql.exe", + "C:\Program Files (x86)\MariaDB*\bin\mysql.exe", + "C:\Program Files (x86)\MySQL\MySQL Server*\bin\mysql.exe" + ) + + foreach ($pattern in $searchPaths) { + $found = Get-ChildItem $pattern -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($found) { + $script:MYSQL_CLIENT = $found.FullName + $mysqlFound = $true + # Add to PATH for this session + $binDir = Split-Path $found.FullName + $env:Path = "$binDir;$env:Path" + Write-Host "Found MySQL/MariaDB at: $($found.FullName)" -ForegroundColor Green + break + } + } + } + + if (-not $mysqlFound) { + $missing += "MySQL/MariaDB client (winget install Oracle.MySQL or MariaDB.MariaDB)" + } + + if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + $missing += "Git (winget install Git.Git)" + } + + if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { + $missing += "Rust/Cargo (https://rustup.rs)" + } + + if ($missing.Count -gt 0) { + Write-Host "`nMissing dependencies:" -ForegroundColor Red + $missing | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } + Write-Host "`nPlease install the missing tools and try again.`n" + exit 1 + } +} + +function Configure-Database { + Write-Host "`n=== MariaDB Container Configuration ===" -ForegroundColor Cyan + + $config.DB_HOST = Read-Host "DB Host [$($config.DB_HOST)]" + if ([string]::IsNullOrWhiteSpace($config.DB_HOST)) { $config.DB_HOST = "127.0.0.1" } + + $port = Read-Host "DB Port [$($config.DB_PORT)]" + if ($port) { $config.DB_PORT = $port } + + $name = Read-Host "DB Name [$($config.DB_NAME)]" + if ($name) { $config.DB_NAME = $name } + + $user = Read-Host "DB User [$($config.DB_USER)]" + if ($user) { $config.DB_USER = $user } + + $pass = Read-Host "DB Password [$($config.DB_PASS)]" + if ($pass) { $config.DB_PASS = $pass } + + $rootPass = Read-Host "Root Password [$($config.DB_ROOT_PASSWORD)]" + if ($rootPass) { $config.DB_ROOT_PASSWORD = $rootPass } + + Save-Config + + # Check if container exists + $exists = podman ps -a --format "{{.Names}}" | Select-String -Pattern "^$($config.BEEPZONE_DB_CONTAINER_NAME)$" -Quiet + + if ($exists) { + $restart = Read-Host "`nContainer '$($config.BEEPZONE_DB_CONTAINER_NAME)' exists. Start/restart it? (y/n)" + if ($restart -eq 'y') { + $null = Run-Command -Command "podman" -Arguments @("start", $config.BEEPZONE_DB_CONTAINER_NAME) ` + -SuccessMessage "Container started successfully!" ` + -ErrorMessage "Failed to start container" + } + return + } + + # Create new container + Write-Host "`nCreating new MariaDB container..." -ForegroundColor Yellow + + $cmd = @( + "run", "-d", + "--name", $config.BEEPZONE_DB_CONTAINER_NAME, + "-e", "MARIADB_ROOT_PASSWORD=$($config.DB_ROOT_PASSWORD)", + "-e", "MARIADB_DATABASE=$($config.DB_NAME)", + "-e", "MARIADB_USER=$($config.DB_USER)", + "-e", "MARIADB_PASSWORD=$($config.DB_PASS)", + "-p", "$($config.DB_PORT):3306", + $config.BEEPZONE_DB_IMAGE + ) + + $success = Run-Command -Command "podman" -Arguments $cmd ` + -SuccessMessage "MariaDB container started successfully!" ` + -ErrorMessage "Failed to start MariaDB container" + + if (-not $success) { + Read-Host "`nPress Enter to continue" + } +} + +function Import-Database { + $schemaFile = Join-Path $WORK_DIR "backend\database\schema\beepzone-schema-dump.sql" + $fullDumpFile = Join-Path $WORK_DIR "backend\database\dev\beepzone-full-dump.sql" + + $choice = Show-Menu "Database Import" @( + "Full dump (schema + data)", + "Clean schema only (no data)" + ) + + $file = if ($choice -eq 1) { $fullDumpFile } else { $schemaFile } + + if (-not (Test-Path $file)) { + Write-Host "File not found: $file" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + $confirm = Read-Host "`nThis will DROP and recreate the database. Continue? (y/n)" + if ($confirm -ne 'y') { return } + + Write-Host "Importing database..." -ForegroundColor Yellow + + $sql = @" +DROP DATABASE IF EXISTS ``$($config.DB_NAME)``; +CREATE DATABASE ``$($config.DB_NAME)`` CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci; +USE ``$($config.DB_NAME)``; +SET FOREIGN_KEY_CHECKS=0; +$(Get-Content $file -Raw) +SET FOREIGN_KEY_CHECKS=1; +"@ + + # Import via podman exec + Write-Host "Importing SQL..." -ForegroundColor Yellow + + $tempFile = New-TemporaryFile + $sql | Out-File $tempFile.FullName -Encoding UTF8 + + $importCmd = "podman exec -i $($config.BEEPZONE_DB_CONTAINER_NAME) mariadb -h $($config.DB_HOST) -P $($config.DB_PORT) -uroot -p`"$($config.DB_ROOT_PASSWORD)`" < `"$($tempFile.FullName)`"" + $output = cmd /c $importCmd 2`>`&1 + $exitCode = $LASTEXITCODE + + Remove-Item $tempFile -ErrorAction SilentlyContinue + $output | Out-File $LOG_FILE -Append + + if ($exitCode -ne 0) { + Write-Host "`nDatabase import failed!" -ForegroundColor Red + Write-Host "Error output:" -ForegroundColor Yellow + $output | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + Write-Host "`nFull log: $LOG_FILE" -ForegroundColor DarkGray + } else { + Write-Host "Database imported successfully!" -ForegroundColor Green + + if ($choice -eq 2) { + Write-Host "`nRecommendation: Create an Admin role (power 100) and Admin user next." -ForegroundColor Cyan + } + + $config.DEPLOYMENT_TYPE = if ($choice -eq 1) { "dev" } else { "clean" } + Save-Config + } + + Read-Host "`nPress Enter to continue" +} + +function Manage-Users { + while ($true) { + $choice = Show-Menu "Manage Users & Roles" @( + "Create a role", + "Create a user", + "Delete a role", + "Delete a user", + "Back to main menu" + ) + + switch ($choice) { + 1 { Create-Role } + 2 { Create-User } + 3 { Delete-Role } + 4 { Delete-User } + 5 { return } + } + } +} + +function Create-Role { + Write-Host "`n=== Create Role ===" -ForegroundColor Cyan + $name = Read-Host "Role name" + $power = Read-Host "Power (1-100)" + + if ([string]::IsNullOrWhiteSpace($name) -or [string]::IsNullOrWhiteSpace($power)) { + Write-Host "Name and power are required!" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + if (-not ($power -match '^\d+$') -or [int]$power -lt 1 -or [int]$power -gt 100) { + Write-Host "Power must be 1-100!" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + $sql = "INSERT INTO roles (name, power) VALUES ('$name', $power);" + + $ErrorActionPreference = 'Continue' + $output = $sql | podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + $output | Out-File $LOG_FILE -Append + + if ($LASTEXITCODE -ne 0) { + Write-Host "`nFailed to create role!" -ForegroundColor Red + Write-Host "Error output:" -ForegroundColor Yellow + $output | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } else { + Write-Host "Role '$name' created successfully!" -ForegroundColor Green + } + + Read-Host "Press Enter to continue" +} + +function Delete-Role { + Write-Host "`nFetching roles..." -ForegroundColor Yellow + $ErrorActionPreference = 'Continue' + $roles = podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME -e "SELECT id, name, power FROM roles ORDER BY power DESC;" -s -N 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + + if (-not $roles) { + Write-Host "No roles found!" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + Write-Host "`n=== Select Role to Delete ===" -ForegroundColor Cyan + $roleList = @() + $i = 1 + $roles | ForEach-Object { + $parts = $_ -split "`t" + Write-Host " [$i] $($parts[1]) (power: $($parts[2]))" + $roleList += @{ Id = $parts[0]; Name = $parts[1]; Power = $parts[2] } + $i++ + } + + $choice = Read-Host "`nSelect role (1-$($roleList.Count))" + $selected = $roleList[[int]$choice - 1] + + $confirm = Read-Host "Delete role '$($selected.Name)'? (y/n)" + if ($confirm -ne 'y') { return } + + $ErrorActionPreference = 'Continue' + $output = "DELETE FROM roles WHERE id = $($selected.Id);" | podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + $output | Out-File $LOG_FILE -Append + + if ($LASTEXITCODE -ne 0) { + Write-Host "`nFailed to delete role!" -ForegroundColor Red + Write-Host "Error output:" -ForegroundColor Yellow + $output | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } else { + Write-Host "Role deleted!" -ForegroundColor Green + } + + Read-Host "Press Enter to continue" +} + +function Create-User { + Write-Host "`nFetching roles..." -ForegroundColor Yellow + $ErrorActionPreference = 'Continue' + $roles = podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME -e "SELECT id, name, power FROM roles ORDER BY power DESC;" -s -N 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + + if (-not $roles) { + Write-Host "No roles found! Create a role first." -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + Write-Host "`n=== Select Role ===" -ForegroundColor Cyan + $roleList = @() + $i = 1 + $roles | ForEach-Object { + $parts = $_ -split "`t" + Write-Host " [$i] $($parts[1]) (power: $($parts[2]))" + $roleList += @{ Id = $parts[0]; Name = $parts[1] } + $i++ + } + + $roleChoice = Read-Host "`nSelect role (1-$($roleList.Count))" + $selectedRole = $roleList[[int]$roleChoice - 1] + + Write-Host "`n=== Create User ===" -ForegroundColor Cyan + $name = Read-Host "Full name" + $username = Read-Host "Username" + $password = Read-Host "Password" -AsSecureString + $passwordPlain = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)) + $email = Read-Host "Email (optional)" + $phone = Read-Host "Phone (optional)" + + if ([string]::IsNullOrWhiteSpace($name) -or [string]::IsNullOrWhiteSpace($username) -or [string]::IsNullOrWhiteSpace($passwordPlain)) { + Write-Host "Name, username, and password are required!" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + # Hash password with bcrypt cost 12 using Rust (since cargo is already available) + Write-Host "Hashing password..." -ForegroundColor Yellow + + $bcryptToolPath = Join-Path $env:TEMP "beepzone_bcrypt_tool.exe" + + # Build tiny bcrypt tool if not already built + if (-not (Test-Path $bcryptToolPath)) { + Write-Host "Building bcrypt tool (one-time setup)..." -ForegroundColor Yellow + + $tempDir = Join-Path $env:TEMP "bcrypt_hasher" + New-Item -ItemType Directory -Force -Path $tempDir | Out-Null + + # Create minimal Cargo.toml + @" +[package] +name = "bcrypt_hasher" +version = "0.1.0" +edition = "2021" + +[dependencies] +bcrypt = "0.15" +"@ | Out-File (Join-Path $tempDir "Cargo.toml") -Encoding UTF8 + + # Create main.rs + @" +use std::env; + +fn main() { + let args: Vec<String> = env::args().collect(); + if args.len() != 2 { + eprintln!("Usage: bcrypt_hasher <password>"); + std::process::exit(1); + } + + match bcrypt::hash(&args[1], 12) { + Ok(hash) => println!("{}", hash), + Err(e) => { + eprintln!("Error: {}", e); + std::process::exit(1); + } + } +} +"@ | Out-File (Join-Path $tempDir "main.rs") -Encoding UTF8 + + # Create src directory and move main.rs + $srcDir = Join-Path $tempDir "src" + New-Item -ItemType Directory -Force -Path $srcDir | Out-Null + Move-Item (Join-Path $tempDir "main.rs") (Join-Path $srcDir "main.rs") -Force + + # Build it + Push-Location $tempDir + Write-Host " Compiling bcrypt tool..." -ForegroundColor DarkGray + cargo build --release --quiet 2>&1 | Out-Null + Pop-Location + + # Copy to temp location + $builtExe = Join-Path $tempDir "target\release\bcrypt_hasher.exe" + if (Test-Path $builtExe) { + Copy-Item $builtExe $bcryptToolPath -Force + Write-Host " Bcrypt tool ready!" -ForegroundColor Green + } else { + Write-Host " Failed to build bcrypt tool" -ForegroundColor Red + } + + # Cleanup build directory + Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue + } + + # Hash the password + if (Test-Path $bcryptToolPath) { + try { + $passwordHash = & $bcryptToolPath $passwordPlain + if ($LASTEXITCODE -eq 0 -and $passwordHash -match '^\$2[ab]\$12\$') { + Write-Host "Password hashed successfully!" -ForegroundColor Green + } else { + Write-Host "`nError: Failed to hash password" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + } catch { + Write-Host "`nError: Failed to hash password: $_" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + } else { + Write-Host "`nError: Could not build bcrypt tool. Make sure cargo is working." -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + $emailVal = if ($email) { "'$email'" } else { "NULL" } + $phoneVal = if ($phone) { "'$phone'" } else { "NULL" } + + $sql = "INSERT INTO users (name, username, password, role_id, email, phone, active) VALUES ('$name', '$username', '$passwordHash', $($selectedRole.Id), $emailVal, $phoneVal, 1);" + + $ErrorActionPreference = 'Continue' + $output = $sql | podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + $output | Out-File $LOG_FILE -Append + + if ($LASTEXITCODE -ne 0) { + Write-Host "`nFailed to create user!" -ForegroundColor Red + Write-Host "Error output:" -ForegroundColor Yellow + $output | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } else { + Write-Host "User '$username' created successfully!" -ForegroundColor Green + } + + Read-Host "Press Enter to continue" +} + +function Delete-User { + Write-Host "`nFetching users..." -ForegroundColor Yellow + $ErrorActionPreference = 'Continue' + $users = podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME -e "SELECT id, username, name FROM users ORDER BY id;" -s -N 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + + if (-not $users) { + Write-Host "No users found!" -ForegroundColor Red + Read-Host "Press Enter to continue" + return + } + + Write-Host "`n=== Select User to Delete ===" -ForegroundColor Cyan + $userList = @() + $i = 1 + $users | ForEach-Object { + $parts = $_ -split "`t" + Write-Host " [$i] $($parts[1]) - $($parts[2])" + $userList += @{ Id = $parts[0]; Username = $parts[1] } + $i++ + } + + $choice = Read-Host "`nSelect user (1-$($userList.Count))" + $selected = $userList[[int]$choice - 1] + + $confirm = Read-Host "Delete user '$($selected.Username)'? (y/n)" + if ($confirm -ne 'y') { return } + + $ErrorActionPreference = 'Continue' + $output = "DELETE FROM users WHERE id = $($selected.Id);" | podman exec -i $config.BEEPZONE_DB_CONTAINER_NAME mariadb -h $config.DB_HOST -P $config.DB_PORT -uroot -p"$($config.DB_ROOT_PASSWORD)" $config.DB_NAME 2>&1 | Where-Object { $_ -notmatch '^(mysql:|mariadb:)' } + $ErrorActionPreference = 'Stop' + $output | Out-File $LOG_FILE -Append + + if ($LASTEXITCODE -ne 0) { + Write-Host "`nFailed to delete user!" -ForegroundColor Red + Write-Host "Error output:" -ForegroundColor Yellow + $output | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + } else { + Write-Host "User deleted!" -ForegroundColor Green + } + + Read-Host "Press Enter to continue" +} + +function Setup-SeckelAPI { + $sourcesDir = Join-Path $WORK_DIR "backend\seckelapi\sources" + $configDir = Join-Path $WORK_DIR "backend\seckelapi\config" + + if (-not (Test-Path (Join-Path $sourcesDir ".git"))) { + Write-Host "Cloning SeckelAPI repository..." -ForegroundColor Yellow + $parentDir = Split-Path $sourcesDir -Parent + New-Item -ItemType Directory -Force -Path $parentDir | Out-Null + $success = Run-Command -Command "git" -Arguments @("clone", $config.SECKELAPI_REPO, $sourcesDir) ` + -SuccessMessage "Repository cloned successfully!" ` + -ErrorMessage "Failed to clone SeckelAPI repository" ` + -ShowOutput + if (-not $success) { + Read-Host "`nPress Enter to continue" + return + } + } + + # Copy config files + New-Item -ItemType Directory -Force -Path (Join-Path $sourcesDir "config") | Out-Null + Get-ChildItem "$configDir\*.toml" | ForEach-Object { + Copy-Item $_.FullName (Join-Path $sourcesDir "config\$($_.Name)") -Force + } + + # Update config with database settings for container + $basicsConfig = Join-Path $sourcesDir "config\basics.toml" + if (Test-Path $basicsConfig) { + Write-Host "Updating config for container deployment..." -ForegroundColor Yellow + + # Read line by line and only update values in [database] section + $lines = Get-Content $basicsConfig + $inDatabaseSection = $false + $newLines = @() + + foreach ($line in $lines) { + if ($line -match '^\[database\]') { + $inDatabaseSection = $true + $newLines += $line + } + elseif ($line -match '^\[.*\]') { + # Entering a different section + $inDatabaseSection = $false + $newLines += $line + } + elseif ($inDatabaseSection) { + # We're in [database] section, update relevant values + if ($line -match '^host\s*=') { + $newLines += 'host = "host.containers.internal"' + } + elseif ($line -match '^port\s*=') { + $newLines += "port = $($config.DB_PORT)" + } + elseif ($line -match '^database\s*=') { + $newLines += "database = `"$($config.DB_NAME)`"" + } + elseif ($line -match '^username\s*=') { + $newLines += "username = `"$($config.DB_USER)`"" + } + elseif ($line -match '^password\s*=') { + $newLines += "password = `"$($config.DB_PASS)`"" + } + else { + $newLines += $line + } + } + else { + $newLines += $line + } + } + + $newLines | Out-File $basicsConfig -Encoding UTF8 + Write-Host "Config updated!" -ForegroundColor Green + } + + # Build and deploy container + $choice = Show-Menu "SeckelAPI Container Build" @( + "Build and run in podman container", + "Skip for now" + ) + + if ($choice -eq 1) { + $containerName = "beepzone-seckelapi" + $imageName = "beepzone-seckelapi:latest" + $containerfile = Join-Path $WORK_DIR "backend\seckelapi\Containerfile" + + # Stop and remove existing container + $existing = podman ps -a --format "{{.Names}}" | Select-String -Pattern "^${containerName}$" -Quiet + if ($existing) { + Write-Host "Stopping existing container..." -ForegroundColor Yellow + podman stop $containerName 2>&1 | Out-Null + podman rm $containerName 2>&1 | Out-Null + } + + # Build container + Write-Host "`nBuilding SeckelAPI container..." -ForegroundColor Yellow + $success = Run-Command -Command "podman" -Arguments @("build", "-t", $imageName, "-f", $containerfile, (Join-Path $WORK_DIR "backend\seckelapi")) ` + -SuccessMessage "Container image built successfully!" ` + -ErrorMessage "Container build failed!" ` + -LiveOutput + + if ($success) { + $run = Read-Host "`nStart the container now? (y/n)" + if ($run -eq 'y') { + Write-Host "Starting container..." -ForegroundColor Yellow + $success = Run-Command -Command "podman" -Arguments @("run", "-d", "--name", $containerName, "--add-host", "host.containers.internal:host-gateway", "-p", "5777:5777", $imageName) ` + -SuccessMessage "Container started successfully!" ` + -ErrorMessage "Failed to start container!" + + if ($success) { + Write-Host "`nSeckelAPI is running at: http://localhost:5777" -ForegroundColor Cyan + Write-Host "`nUseful commands:" -ForegroundColor DarkGray + Write-Host " podman logs $containerName - View logs" -ForegroundColor DarkGray + Write-Host " podman stop $containerName - Stop container" -ForegroundColor DarkGray + Write-Host " podman start $containerName - Start container" -ForegroundColor DarkGray + Write-Host " podman restart $containerName - Restart container" -ForegroundColor DarkGray + } + } + } + } + + Read-Host "`nPress Enter to continue" +} + +function Build-DesktopClient { + $sourcesDir = Join-Path $WORK_DIR "frontend\desktop-client\sources" + + if (-not (Test-Path (Join-Path $sourcesDir ".git"))) { + Write-Host "Cloning client repository..." -ForegroundColor Yellow + $parentDir = Split-Path $sourcesDir -Parent + New-Item -ItemType Directory -Force -Path $parentDir | Out-Null + $success = Run-Command -Command "git" -Arguments @("clone", $config.CLIENT_REPO, $sourcesDir) ` + -SuccessMessage "Repository cloned successfully!" ` + -ErrorMessage "Failed to clone client repository" ` + -ShowOutput + if (-not $success) { + Read-Host "`nPress Enter to continue" + return + } + } + + $confirm = Read-Host "`nBuild BeepZone desktop client for Windows? (y/n)" + if ($confirm -ne 'y') { return } + + Write-Host "Building desktop client..." -ForegroundColor Yellow + Push-Location $sourcesDir + + $success = Run-Command -Command "cargo" -Arguments @("build", "--release") ` + -SuccessMessage "" ` + -ErrorMessage "Build failed!" ` + -LiveOutput + + Pop-Location + + if ($success) { + Write-Host "`nBuild complete!" -ForegroundColor Green + Write-Host "Binary: $sourcesDir\target\release\" -ForegroundColor Cyan + } + + Read-Host "Press Enter to continue" +} + +# Main +Clear-Host +Write-Host @" +######################################### +# BeepZone Setup Helper (Windows) # +######################################### +"@ -ForegroundColor Cyan + +Test-Dependencies + +while ($true) { + $choice = Show-Menu "BeepZone Setup" @( + "Configure & run MariaDB (podman)", + "Import DB schema & data", + "Manage users & roles", + "Configure & setup SeckelAPI", + "Build desktop client", + "Quit" + ) + + switch ($choice) { + 1 { Configure-Database } + 2 { Import-Database } + 3 { Manage-Users } + 4 { Setup-SeckelAPI } + 5 { Build-DesktopClient } + 6 { exit 0 } + } +} |
