aboutsummaryrefslogtreecommitdiff
path: root/beepzone-helper.sh
diff options
context:
space:
mode:
Diffstat (limited to 'beepzone-helper.sh')
-rwxr-xr-xbeepzone-helper.sh720
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