diff options
| author | UMTS at Teleco <crt@teleco.ch> | 2025-12-13 02:59:39 +0100 |
|---|---|---|
| committer | UMTS at Teleco <crt@teleco.ch> | 2025-12-13 02:59:39 +0100 |
| commit | b51d33cb373e591d16892bde492616655ac9ec51 (patch) | |
| tree | 465d110a023857309806da5fc821de52573e2593 /beepzone-helper.sh | |
committing to insanit
Diffstat (limited to 'beepzone-helper.sh')
| -rwxr-xr-x | beepzone-helper.sh | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/beepzone-helper.sh b/beepzone-helper.sh new file mode 100755 index 0000000..38735c4 --- /dev/null +++ b/beepzone-helper.sh @@ -0,0 +1,720 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Simple TUI-based BeepZone setup helper using `dialog`. +# Targets macOS + Debian-ish Linux (podman, rustup mysql-client already installed). + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WORK_DIR="${SCRIPT_DIR}" + +: "${DIALOG:=dialog}" + +if ! command -v "$DIALOG" >/dev/null 2>&1; then + echo "\n[ERROR] 'dialog' is not installed or not in PATH." >&2 + echo "On macOS: brew install dialog" >&2 + echo "On Debian: sudo apt-get install dialog" >&2 + exit 1 +fi + +if ! command -v podman >/dev/null 2>&1; then + "$DIALOG" --title "BeepZone Setup" --msgbox "podman is required but not found in PATH.\nPlease install and configure podman (podman-desktop recommended)." 10 60 + exit 1 +fi + +# Check for MariaDB/MySQL client - try common brew locations on macOS +MYSQL_CLIENT="" +if command -v mariadb >/dev/null 2>&1; then + MYSQL_CLIENT="mariadb" +elif command -v mysql >/dev/null 2>&1; then + MYSQL_CLIENT="mysql" +elif [[ -x /opt/homebrew/opt/mysql-client/bin/mysql ]]; then + MYSQL_CLIENT="/opt/homebrew/opt/mysql-client/bin/mysql" + export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH" +elif [[ -x /opt/homebrew/opt/mariadb/bin/mariadb ]]; then + MYSQL_CLIENT="/opt/homebrew/opt/mariadb/bin/mariadb" + export PATH="/opt/homebrew/opt/mariadb/bin:$PATH" +elif [[ -x /opt/homebrew/bin/mariadb ]]; then + MYSQL_CLIENT="/opt/homebrew/bin/mariadb" + export PATH="/opt/homebrew/bin:$PATH" +elif [[ -x /opt/homebrew/bin/mysql ]]; then + MYSQL_CLIENT="/opt/homebrew/bin/mysql" + export PATH="/opt/homebrew/bin:$PATH" +elif [[ -x /usr/local/opt/mysql-client/bin/mysql ]]; then + MYSQL_CLIENT="/usr/local/opt/mysql-client/bin/mysql" + export PATH="/usr/local/opt/mysql-client/bin:$PATH" +elif [[ -x /usr/local/bin/mariadb ]]; then + MYSQL_CLIENT="/usr/local/bin/mariadb" + export PATH="/usr/local/bin:$PATH" +elif [[ -x /usr/local/bin/mysql ]]; then + MYSQL_CLIENT="/usr/local/bin/mysql" + export PATH="/usr/local/bin:$PATH" +else + "$DIALOG" --title "BeepZone Setup" --msgbox "MariaDB/MySQL client is required but not found.\n\nSearched locations:\n- System PATH\n- /opt/homebrew/opt/mysql-client/bin/\n- /opt/homebrew/opt/mariadb/bin/\n- /opt/homebrew/bin/\n- /usr/local/opt/mysql-client/bin/\n- /usr/local/bin/\n\nOn macOS: brew install mysql-client\nOn Debian: sudo apt-get install mariadb-client" 18 70 + exit 1 +fi + +TMP_FILE="$(mktemp)" +CHOICE_FILE="$(mktemp)" +trap 'rm -f "$TMP_FILE" "$CHOICE_FILE"' EXIT + +LOG_FILE="/tmp/beepzone-helper.log" +> "$LOG_FILE" + +ENV_FILE="$SCRIPT_DIR/.env" + +# Load existing settings from .env if present +if [[ -f "$ENV_FILE" ]]; then + source "$ENV_FILE" +fi + +# Set defaults if not loaded from .env +: "${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}" + +save_env() { + cat > "$ENV_FILE" << EOF +# BeepZone Setup Configuration +# Auto-generated by beepzone-helper.sh + +BEEPZONE_DB_CONTAINER_NAME="$BEEPZONE_DB_CONTAINER_NAME" +BEEPZONE_DB_IMAGE="$BEEPZONE_DB_IMAGE" +DB_HOST="$DB_HOST" +DB_PORT="$DB_PORT" +DB_NAME="$DB_NAME" +DB_USER="$DB_USER" +DB_PASS="$DB_PASS" +DB_ROOT_PASSWORD="$DB_ROOT_PASSWORD" +SECKELAPI_REPO="$SECKELAPI_REPO" +CLIENT_REPO="$CLIENT_REPO" +DEPLOYMENT_TYPE="$DEPLOYMENT_TYPE" +EOF +} + +ask_main_menu() { + while true; do + $DIALOG --clear \ + --title "BeepZone Setup" \ + --menu "Choose an action" 16 76 6 \ + 1 "Configure & run MariaDB (podman)" \ + 2 "Import DB schema & data" \ + 3 "Manage users & roles" \ + 4 "Configure & setup SeckelAPI" \ + 5 "Build desktop client" \ + 6 "Quit" 2>"$CHOICE_FILE" + + choice=$(<"$CHOICE_FILE") + case $choice in + 1) configure_and_run_db ;; + 2) import_schema_and_seed ;; + 3) manage_users_and_roles ;; + 4) setup_seckelapi ;; + 5) build_desktop_client ;; + 6) exit 0 ;; + esac + done +} + +configure_and_run_db() { + $DIALOG --form "MariaDB container configuration" 18 70 8 \ + "DB Host" 1 1 "$DB_HOST" 1 18 30 30 \ + "DB Port" 2 1 "$DB_PORT" 2 18 30 30 \ + "DB Name" 3 1 "$DB_NAME" 3 18 30 30 \ + "DB User" 4 1 "$DB_USER" 4 18 30 30 \ + "DB Password" 5 1 "$DB_PASS" 5 18 30 30 \ + "Root Password" 6 1 "$DB_ROOT_PASSWORD" 6 18 30 30 \ + "Container Name" 7 1 "$BEEPZONE_DB_CONTAINER_NAME" 7 18 30 30 \ + "Image" 8 1 "$BEEPZONE_DB_IMAGE" 8 18 30 30 2>"$TMP_FILE" || return + + # Parse dialog output (8 lines, one per field) + { + read -r DB_HOST + read -r DB_PORT + read -r DB_NAME + read -r DB_USER + read -r DB_PASS + read -r DB_ROOT_PASSWORD + read -r BEEPZONE_DB_CONTAINER_NAME + read -r BEEPZONE_DB_IMAGE + } < "$TMP_FILE" + + save_env + + if podman ps -a --format '{{.Names}}' | grep -q "^${BEEPZONE_DB_CONTAINER_NAME}$"; then + $DIALOG --yesno "Container '$BEEPZONE_DB_CONTAINER_NAME' already exists.\n\nStart (or restart) it now?" 10 60 + if [[ $? -eq 0 ]]; then + podman start "$BEEPZONE_DB_CONTAINER_NAME" >/dev/null 2>&1 || podman restart "$BEEPZONE_DB_CONTAINER_NAME" >/dev/null 2>&1 || true + $DIALOG --msgbox "Container '$BEEPZONE_DB_CONTAINER_NAME' started (or already running)." 7 60 + fi + return + fi + + run_cmd=( + podman run -d + --name "${BEEPZONE_DB_CONTAINER_NAME}" + -e "MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}" + -e "MARIADB_DATABASE=${DB_NAME}" + -e "MARIADB_USER=${DB_USER}" + -e "MARIADB_PASSWORD=${DB_PASS}" + -p "${DB_PORT}:3306" + "${BEEPZONE_DB_IMAGE}" + ) + + pretty_cmd="podman run -d \\ +--name ${BEEPZONE_DB_CONTAINER_NAME} \\ +-e MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD} \\ +-e MARIADB_DATABASE=${DB_NAME} \\ +-e MARIADB_USER=${DB_USER} \\ +-e MARIADB_PASSWORD=${DB_PASS} \\ +-p ${DB_PORT}:3306 ${BEEPZONE_DB_IMAGE}" + + if $DIALOG --yesno "About to run:\n\n${pretty_cmd}\n\nProceed?" 17 76; then + if "${run_cmd[@]}" >>"$LOG_FILE" 2>&1; then + $DIALOG --msgbox "MariaDB container '${BEEPZONE_DB_CONTAINER_NAME}' started successfully." 8 70 + else + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to start MariaDB container.\n\nError:\n${error_log}" 20 76 + fi + fi +} + +import_schema_and_seed() { + local import_type schema_file full_dump_file + schema_file="$WORK_DIR/backend/database/schema/beepzone-schema-dump.sql" + full_dump_file="$WORK_DIR/backend/database/dev/beepzone-full-dump.sql" + + # Ask what type of import + $DIALOG --clear \ + --title "Database Import" \ + --menu "Select import type" 12 70 2 \ + 1 "Full dump (schema + data in one file)" \ + 2 "Clean schema only (no data)" 2>"$CHOICE_FILE" || return + + import_type=$(<"$CHOICE_FILE") + + if [[ "$import_type" == "1" ]]; then + # Full dump import + if [[ ! -f "$full_dump_file" ]]; then + $DIALOG --msgbox "full dump file not found at:\n$full_dump_file" 10 70 + return + fi + + $DIALOG --yesno "import full database dump from:\n$full_dump_file\n\nThis will DROP and recreate the database.\n\nProceed?" 12 70 || return + + { + echo "DROP DATABASE IF EXISTS \`$DB_NAME\`;" + echo "CREATE DATABASE \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci;" + echo "USE \`$DB_NAME\`;" + echo "SET FOREIGN_KEY_CHECKS=0;" + cat "$full_dump_file" + echo "SET FOREIGN_KEY_CHECKS=1;" + } | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -30 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "full dump import failed.\n\nError:\n${error_log}" 22 76 + return + } + + DEPLOYMENT_TYPE="dev" + save_env + $DIALOG --msgbox "full database dump imported successfully!" 8 70 + + else + # Clean schema import + if [[ ! -f "$schema_file" ]]; then + $DIALOG --msgbox "schema file not found at:\n$schema_file" 10 60 + return + fi + + $DIALOG --yesno "import clean schema from:\n$schema_file\n\nThis will DROP and recreate the database.\n\nProceed?" 12 70 || return + + { + echo "DROP DATABASE IF EXISTS \`$DB_NAME\`;" + echo "CREATE DATABASE \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci;" + echo "USE \`$DB_NAME\`;" + echo "SET FOREIGN_KEY_CHECKS=0;" + cat "$schema_file" + echo "SET FOREIGN_KEY_CHECKS=1;" + } | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -30 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "schema import failed.\n\nError:\n${error_log}" 22 76 + return + } + + DEPLOYMENT_TYPE="clean" + save_env + $DIALOG --msgbox "schema imported successfully!\n\nI recommend you make an Admin role with power 100 and and Admin user as the next step." 8 70 + fi +} + +manage_users_and_roles() { + while true; do + $DIALOG --clear \ + --title "Manage Users & Roles" \ + --menu "Choose an action:" 17 60 6 \ + 1 "Create a role" \ + 2 "Create a user" \ + 3 "Delete a role" \ + 4 "Delete a user" \ + 5 "Back to main menu" 2>"$CHOICE_FILE" + + [[ ! -s "$CHOICE_FILE" ]] && return 0 + choice=$(<"$CHOICE_FILE") + + case $choice in + 1) create_role ;; + 2) create_user ;; + 3) delete_role ;; + 4) delete_user ;; + 5) return 0 ;; + esac + done +} + +create_role() { + $DIALOG --title "Create Role" \ + --form "Enter role details:" 12 60 2 \ + "Role name:" 1 1 "" 1 20 30 0 \ + "Power (1-100):" 2 1 "" 2 20 10 0 \ + 2>"$TMP_FILE" + + [[ ! -s "$TMP_FILE" ]] && return 1 + + local name power + { + read -r name + read -r power + } < "$TMP_FILE" + + [[ -z "$name" || -z "$power" ]] && { + $DIALOG --msgbox "Role name and power are required." 8 50 + return 1 + } + + # Validate power is a number between 1-100 + if ! [[ "$power" =~ ^[0-9]+$ ]] || [[ "$power" -lt 1 || "$power" -gt 100 ]]; then + $DIALOG --msgbox "Power must be a number between 1 and 100." 8 50 + return 1 + fi + + local sql="INSERT INTO roles (name, power) VALUES ('$name', $power);" + + echo "$sql" | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to create role.\n\nError:\n${error_log}" 20 76 + return 1 + } + + $DIALOG --msgbox "Role '$name' created successfully!" 8 50 +} + +delete_role() { + # Fetch roles from the database + local roles_list + roles_list=$(podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" \ + -e "SELECT id, name, power FROM roles ORDER BY power DESC;" -s -N 2>>"$LOG_FILE") || { + $DIALOG --msgbox "Failed to fetch roles from database." 10 60 + return + } + + # Build role selection menu + local role_options=() + while IFS=$'\t' read -r role_id role_name role_power; do + role_options+=("$role_id" "$role_name (power: $role_power)") + done <<< "$roles_list" + + if [[ ${#role_options[@]} -eq 0 ]]; then + $DIALOG --msgbox "No roles found in database." 10 60 + return + fi + + # Select role to delete + $DIALOG --menu "Select role to delete:" 20 70 10 "${role_options[@]}" 2>"$TMP_FILE" || return + local selected_role_id + selected_role_id=$(<"$TMP_FILE") + + # Get role name for confirmation + local selected_role_name + selected_role_name=$(echo "$roles_list" | awk -v id="$selected_role_id" -F'\t' '$1 == id {print $2}') + + # Check if any users are using this role + local user_count + user_count=$(podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" \ + -e "SELECT COUNT(*) FROM users WHERE role_id = $selected_role_id;" -s -N 2>>"$LOG_FILE") + + if [[ "$user_count" -gt 0 ]]; then + $DIALOG --msgbox "Cannot delete role '$selected_role_name'.\n$user_count user(s) are currently assigned this role." 10 60 + return + fi + + # Confirm deletion + $DIALOG --yesno "Are you sure you want to delete role '$selected_role_name' (ID: $selected_role_id)?\n\nThis action cannot be undone." 10 60 || return + + # Delete role + local sql="DELETE FROM roles WHERE id = $selected_role_id;" + + echo "$sql" | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to delete role.\n\nError:\n${error_log}" 20 76 + return + } + + $DIALOG --msgbox "Role '$selected_role_name' deleted successfully!" 8 60 +} + +create_user() { + # Get available roles + local roles_list + roles_list=$(podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" \ + -e "SELECT id, name, power FROM roles ORDER BY power DESC;" -s -N 2>>"$LOG_FILE") || { + $DIALOG --msgbox "Failed to fetch roles from database.\nEnsure schema is imported and roles exist." 10 60 + return + } + + # Build role selection menu + local role_options=() + while IFS=$'\t' read -r role_id role_name role_power; do + role_options+=("$role_id" "$role_name (power: $role_power)") + done <<< "$roles_list" + + if [[ ${#role_options[@]} -eq 0 ]]; then + $DIALOG --msgbox "No roles found in database.\nPlease create a role first." 10 60 + return + fi + + # Select role + $DIALOG --menu "Select user role" 15 60 5 "${role_options[@]}" 2>"$TMP_FILE" || return + local selected_role_id + selected_role_id=$(<"$TMP_FILE") + + # Get user details + $DIALOG --form "Create BeepZone user" 14 70 5 \ + "Name (full name)" 1 1 "" 1 20 40 40 \ + "Username" 2 1 "" 2 20 40 40 \ + "Password" 3 1 "" 3 20 40 40 \ + "Email" 4 1 "" 4 20 40 40 \ + "Phone" 5 1 "" 5 20 40 40 2>"$TMP_FILE" || return + + local name username password email phone + { + read -r name + read -r username + read -r password + read -r email + read -r phone + } < "$TMP_FILE" + + if [[ -z "$name" || -z "$username" || -z "$password" ]]; then + $DIALOG --msgbox "Name, username, and password are required." 8 60 + return + fi + + # Hash password with bcrypt (cost 12) + local password_hash + + # Try htpasswd first (native Unix tool) + if command -v htpasswd >/dev/null 2>&1; then + password_hash=$(htpasswd -nbB -C 12 "$username" "$password" 2>>"$LOG_FILE" | cut -d: -f2) + # Fall back to Python bcrypt + elif command -v python3 >/dev/null 2>&1; then + password_hash=$(python3 -c "import bcrypt; print(bcrypt.hashpw('$password'.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8'))" 2>>"$LOG_FILE") + fi + + if [[ -z "$password_hash" ]]; then + $DIALOG --msgbox "Error: Failed to hash password. No bcrypt tool found.\n\nInstall options:\n- htpasswd: brew install httpd (macOS) or apt install apache2-utils (Linux)\n- Python bcrypt: pip3 install bcrypt" 12 70 + return + fi + + # Insert user with hashed password + local sql + sql="INSERT INTO users (name, username, password, role_id, email, phone, active) VALUES + ('$name', '$username', '$password_hash', $selected_role_id, " + [[ -n "$email" ]] && sql+="'$email'" || sql+="NULL" + sql+=", " + [[ -n "$phone" ]] && sql+="'$phone'" || sql+="NULL" + sql+=", 1);" + + echo "$sql" | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to create user.\n\nError:\n${error_log}" 20 76 + return + } + + $DIALOG --msgbox "User '$username' created successfully!" 8 60 +} + +delete_user() { + # Fetch users from the database + local users_list + users_list=$(podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" \ + -e "SELECT id, username, name FROM users ORDER BY id;" -s -N 2>>"$LOG_FILE") || { + $DIALOG --msgbox "Failed to fetch users from database." 10 60 + return + } + + # Build user selection menu + local user_options=() + while IFS=$'\t' read -r user_id username name; do + user_options+=("$user_id" "$username - $name") + done <<< "$users_list" + + if [[ ${#user_options[@]} -eq 0 ]]; then + $DIALOG --msgbox "No users found in database." 10 60 + return + fi + + # Select user to delete + $DIALOG --menu "Select user to delete:" 20 70 10 "${user_options[@]}" 2>"$TMP_FILE" || return + local selected_user_id + selected_user_id=$(<"$TMP_FILE") + + # Get username for confirmation + local selected_username + selected_username=$(echo "$users_list" | awk -v id="$selected_user_id" -F'\t' '$1 == id {print $2}') + + # Confirm deletion + $DIALOG --yesno "Are you sure you want to delete user '$selected_username' (ID: $selected_user_id)?\n\nThis action cannot be undone." 10 60 || return + + # Delete user + local sql="DELETE FROM users WHERE id = $selected_user_id;" + + echo "$sql" | podman exec -i "$BEEPZONE_DB_CONTAINER_NAME" \ + mariadb -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_ROOT_PASSWORD" "$DB_NAME" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to delete user.\n\nError:\n${error_log}" 20 76 + return + } + + $DIALOG --msgbox "User '$selected_username' deleted successfully!" 8 60 +} + +clone_if_missing() { + local repo_url="$1" dest_dir="$2" + if [[ -d "$dest_dir/.git" ]]; then + return + fi + git clone "$repo_url" "$dest_dir" >>"$LOG_FILE" 2>&1 || { + error_log=$(tail -20 "$LOG_FILE") + $DIALOG --title "Error" --msgbox "Failed to clone $repo_url.\n\nError:\n${error_log}" 20 76 + return 1 + } +} + +setup_seckelapi() { + local sources_dir="$WORK_DIR/backend/seckelapi/sources" + local config_dir="$WORK_DIR/backend/seckelapi/config" + local sources_basics_config="$sources_dir/config/basics.toml" + + # Check if sources are already cloned + if [[ ! -d "$sources_dir/.git" ]]; then + mkdir -p "$sources_dir" + clone_if_missing "$SECKELAPI_REPO" "$sources_dir" || return + fi + + # Ask about config update + $DIALOG --clear \ + --title "SeckelAPI Configuration" \ + --menu "How do you want to handle the config?" 12 70 2 \ + 1 "Auto-update from database settings" \ + 2 "Manually edit config file" 2>"$CHOICE_FILE" + + [[ ! -s "$CHOICE_FILE" ]] && return 0 + config_choice=$(<"$CHOICE_FILE") + + # Ensure sources config directory exists and copy all template configs + mkdir -p "$sources_dir/config" + + # Always copy all template configs from config/ to sources/config/ + for conf_file in "$config_dir"/*.toml; do + conf_name=$(basename "$conf_file") + cp "$conf_file" "$sources_dir/config/$conf_name" 2>>"$LOG_FILE" + done + + if [[ "$config_choice" == "1" ]]; then + # Auto-update basics.toml in sources with database settings (only [database] section) + if [[ -f "$sources_basics_config" ]]; then + # Determine database host - use host.containers.internal for container deployments + local db_host_value="$DB_HOST" + + sed -i.bak \ + -e '/^\[database\]/,/^\[/ { + /^host = /s|= .*|= "'"$db_host_value"'"| + /^port = /s|= .*|= '"$DB_PORT"'| + /^database = /s|= .*|= "'"$DB_NAME"'"| + /^username = /s|= .*|= "'"$DB_USER"'"| + /^password = /s|= .*|= "'"$DB_PASS"'"| + }' \ + "$sources_basics_config" + $DIALOG --msgbox "Config updated with database settings from .env" 8 60 + else + $DIALOG --msgbox "Error: basics.toml not found at $sources_basics_config" 8 60 + return 1 + fi + else + # Open config file for manual editing (in sources/config/) + if [[ -f "$sources_basics_config" ]]; then + ${EDITOR:-nano} "$sources_basics_config" + else + $DIALOG --msgbox "Error: basics.toml not found at $sources_basics_config" 8 60 + return 1 + fi + fi + + # Ask about build and deployment + $DIALOG --clear \ + --title "Build & Deploy SeckelAPI" \ + --menu "Choose an action:" 12 70 2 \ + 1 "Build and deploy to podman container" \ + 2 "Build natively on host" 2>"$CHOICE_FILE" + + [[ ! -s "$CHOICE_FILE" ]] && return 0 + build_choice=$(<"$CHOICE_FILE") + + if [[ "$build_choice" == "2" ]]; then + # Native host build with live output + clear + echo "Building SeckelAPI..." + echo "====================" + echo "" + + if (cd "$sources_dir" && cargo build --release); then + # Copy config files to the build output directory + local target_dir="$sources_dir/target/release" + mkdir -p "$target_dir/config" + cp "$sources_dir/config"/*.toml "$target_dir/config/" 2>>"$LOG_FILE" + + echo "" + echo "Build completed successfully!" + echo "Binary location: $target_dir/seckelapi" + echo "Config location: $target_dir/config/" + read -p "Press Enter to continue..." + else + echo "" + echo "Build failed! Check the output above for errors." + read -p "Press Enter to continue..." + return 1 + fi + elif [[ "$build_choice" == "1" ]]; then + # Build and deploy to podman container + clear + echo "Building SeckelAPI container..." + echo "================================" + echo "" + + # Get the host gateway IP for container to access host services + # For Podman, we'll use the gateway IP from the default bridge network + local host_gateway="host.containers.internal" + + # Update database host for container networking + if [[ -f "$sources_basics_config" ]]; then + echo "Updating database host to: $host_gateway" + sed -i.container-bak \ + -e '/^\[database\]/,/^\[/ { + /^host = /s|= .*|= "'"$host_gateway"'"| + }' \ + "$sources_basics_config" + fi + + local container_name="beepzone-seckelapi" + local image_name="beepzone-seckelapi:latest" + local containerfile="$WORK_DIR/backend/seckelapi/Containerfile" + + # Stop and remove existing container if running + if podman ps -a --format "{{.Names}}" | grep -q "^${container_name}$"; then + echo "Stopping and removing existing container..." + podman stop "$container_name" 2>/dev/null || true + podman rm "$container_name" 2>/dev/null || true + fi + + # Build container image + echo "Building container image..." + if podman build -t "$image_name" -f "$containerfile" "$WORK_DIR/backend/seckelapi"; then + echo "" + echo "Container image built successfully!" + echo "" + + # Ask to run the container + if $DIALOG --yesno "Start the SeckelAPI container now?" 8 50; then + echo "Starting container..." + + # Run container with port mapping and host gateway + if podman run -d \ + --name "$container_name" \ + --add-host host.containers.internal:host-gateway \ + -p 5777:5777 \ + "$image_name"; then + + echo "" + echo "Container started successfully!" + echo "Container name: $container_name" + echo "API listening on: http://0.0.0.0:5777" + echo "" + echo "Useful commands:" + echo " podman logs $container_name - View logs" + echo " podman stop $container_name - Stop container" + echo " podman start $container_name - Start container" + echo " podman restart $container_name - Restart container" + read -p "Press Enter to continue..." + else + echo "" + echo "Failed to start container!" + read -p "Press Enter to continue..." + return 1 + fi + fi + else + echo "" + echo "Container build failed! Check the output above for errors." + read -p "Press Enter to continue..." + return 1 + fi + fi +} + +build_desktop_client() { + local sources_dir="$WORK_DIR/frontend/desktop-client/sources" + + # Check if sources are already cloned + if [[ ! -d "$sources_dir/.git" ]]; then + mkdir -p "$sources_dir" + clone_if_missing "$CLIENT_REPO" "$sources_dir" || return + fi + + if $DIALOG --yesno "Build BeepZone desktop client in release mode now?" 8 70; then + clear + echo "Building BeepZone Desktop Client..." + echo "====================================" + echo "" + + if (cd "$sources_dir" && cargo build --release); then + echo "" + echo "Build completed successfully!" + echo "Binary location: $sources_dir/target/release/" + read -p "Press Enter to continue..." + else + echo "" + echo "Build failed! Check the output above for errors." + read -p "Press Enter to continue..." + return 1 + fi + fi +} + +ask_main_menu |
