diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml new file mode 100644 index 0000000..a3057a5 --- /dev/null +++ b/.github/workflows/deploy-demo.yml @@ -0,0 +1,90 @@ +name: Deploy Demo Instance + +on: + push: + branches: + - main + - dev + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install Frontend Dependencies & Build + env: + VITE_API_BASE_URL: "https://nester-demo.philip.ps/backend/api" + run: | + echo "Building with VITE_API_BASE_URL=$VITE_API_BASE_URL" + npm ci + npm run build + echo "Verifying compiled output does not contain tabit:" + grep -r "tabit" dist/ || echo "OK: no 'tabit' found in build output" + # Move compiled frontend to root so rsync uploads it to the base path + rsync -a dist/ ./ + + - name: Deploy via rsync + uses: easingthemes/ssh-deploy@v5.0.3 + with: + SSH_PRIVATE_KEY: ${{ secrets.DEMO_SSH_KEY }} + ARGS: "-avzr --delete" + SOURCE: "/" + TARGET: "/home/philippsnesterdemo/web/nester-demo/" + REMOTE_HOST: ${{ secrets.DEMO_HOST }} + REMOTE_USER: ${{ secrets.DEMO_USERNAME }} + EXCLUDE: "/node_modules/, /.git/, /.github/, /src/, /public/, /vite.config.js, /package.json, /package-lock.json, /README.md, /eslint.config.js, /docs/, /CONTRIBUTING.md, /sync_www.command, /backend/uploads/, /backend/create_admin.php, /.DS_Store, /.env, /dist/, /INSTALLATION.md, /LICENSE, /.gitignore, /.env.example" + + - name: Redeploy Database & Set Permissions + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.DEMO_HOST }} + username: ${{ secrets.DEMO_USERNAME }} + key: ${{ secrets.DEMO_SSH_KEY }} + script: | + cd /home/philippsnesterdemo/web/nester-demo/backend + + # Since you wanted the database redeployed on every deployment, + # we run a PHP script to clean it, apply schema, and create users. + php -r " + require 'api/db.php'; + try { + \$pdo->query('SET FOREIGN_KEY_CHECKS = 0'); + \$tables = \$pdo->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN); + foreach (\$tables as \$table) { + \$pdo->query('DROP TABLE IF EXISTS \`' . \$table . '\`'); + } + + \$sql = file_get_contents('schema.sql'); + // Strip statements that might cause permission errors on shared hosting + \$sql = preg_replace('/\bCREATE\s+DATABASE\b[^;]+;/i', '', \$sql); + \$sql = preg_replace('/\bUSE\b\s+[^;]+;/i', '', \$sql); + \$pdo->exec(\$sql); + + \$pdo->query('SET FOREIGN_KEY_CHECKS = 1'); + + \$adminHash = password_hash('admin123', PASSWORD_DEFAULT); + \$demoHash = password_hash('demo123', PASSWORD_DEFAULT); + + \$stmt = \$pdo->prepare('INSERT INTO users (id, username, email, password_hash, is_admin) VALUES (?, ?, ?, ?, ?)'); + \$stmt->execute([bin2hex(random_bytes(18)), 'admin', 'admin@example.com', \$adminHash, 1]); + \$stmt->execute([bin2hex(random_bytes(18)), 'demo', 'demo@example.com', \$demoHash, 0]); + + echo \"Database successfully cleaned, schema imported, and users created!\n\"; + } catch (Exception \$e) { + echo \"DB Error: \" . \$e->getMessage() . \"\n\"; + exit(1); + } + " + + # Fix permissions for the webserver (assuming the usual www-data or client user) + # chown -R web21:client1 /home/philippsnesterdemo/web/nester-demo/ || true + # find /home/philippsnesterdemo/web/nester-demo/ -type d -exec chmod 755 {} \; + # find /home/philippsnesterdemo/web/nester-demo/ -type f -exec chmod 644 {} \; diff --git a/README.md b/README.md index 319073a..49b1bb5 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,17 @@ NesterApp ist eine Open-Source-Webanwendung zur Erfassung und Verwaltung von Tau - **Standortverfolgung**: Automatische Benennung basierend auf OpenStreetMap-Einrichtungen oder Straßenadressen. - **PWA-fähig**: Kann auf Mobilgeräten für die Berichterstattung von unterwegs installiert werden. +## Demo + +Eine Live-Demo ist verfügbar unter: **[nester-demo.philip.ps](https://nester-demo.philip.ps)** + +> **Hinweis:** Die Demo-Datenbank wird bei jedem Deployment automatisch zurückgesetzt. + +| Konto | Benutzername | Passwort | Rolle | +|-------|-------------|----------|-------| +| Admin | `admin` | `admin123` | Administrator | +| Demo | `demo` | `demo123` | Standardbenutzer | + ## Erste Schritte Siehe [INSTALLATION.md](INSTALLATION.md) für Anweisungen zur Einrichtung der lokalen Entwicklungsumgebung und zur Bereitstellung in der Produktion. diff --git a/backend/api/db.php b/backend/api/db.php index 03c1a52..07c4f1a 100644 --- a/backend/api/db.php +++ b/backend/api/db.php @@ -3,6 +3,28 @@ require_once dirname(__DIR__) . '/config.php'; +// Function to handle CORS so the React app can communicate with this API +function set_cors_headers() +{ + // Allow any localhost origin (like frontend on 5173) + if (isset($_SERVER['HTTP_ORIGIN']) && strpos($_SERVER['HTTP_ORIGIN'], 'localhost') !== false) { + header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); + } else { + header("Access-Control-Allow-Origin: *"); + } + header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); + header("Access-Control-Allow-Headers: Content-Type, Authorization"); + + // Handle preflight requests + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS') { + exit(0); + } +} + +// Set JSON header and CORS for all API endpoints including this file +header('Content-Type: application/json'); +set_cors_headers(); + $host = get_config('DB_HOST', 'localhost'); $db = get_config('DB_NAME', 'nester_db'); $user = get_config('DB_USER', 'root'); @@ -26,25 +48,4 @@ exit; } -// Function to handle CORS so the React app (port 5173) can communicate with this API -function set_cors_headers() -{ - // Allow any localhost origin (like frontend on 5173) - if (isset($_SERVER['HTTP_ORIGIN']) && strpos($_SERVER['HTTP_ORIGIN'], 'localhost') !== false) { - header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); - } else { - header("Access-Control-Allow-Origin: *"); - } - header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); - header("Access-Control-Allow-Headers: Content-Type, Authorization"); - - // Handle preflight requests - if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { - exit(0); - } -} - -// Set JSON header and CORS for all API endpoints including this file -header('Content-Type: application/json'); -set_cors_headers(); ?> \ No newline at end of file diff --git a/backend/schema.sql b/backend/schema.sql index 7fe0614..799dd8b 100644 --- a/backend/schema.sql +++ b/backend/schema.sql @@ -48,13 +48,6 @@ ALTER TABLE `taubennest_logs` ADD KEY `nest_id` (`nest_id`), ADD KEY `user_id` (`user_id`); --- --- Constraints --- -ALTER TABLE `taubennest_logs` - ADD CONSTRAINT `taubennest_logs_ibfk_1` FOREIGN KEY (`nest_id`) REFERENCES `taubennester` (`id`) ON DELETE CASCADE, - ADD CONSTRAINT `taubennest_logs_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL; - -- -------------------------------------------------------- -- @@ -119,6 +112,10 @@ ALTER TABLE `password_resets` ALTER TABLE `user_tokens` ADD CONSTRAINT `user_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; +ALTER TABLE `taubennest_logs` + ADD CONSTRAINT `taubennest_logs_ibfk_1` FOREIGN KEY (`nest_id`) REFERENCES `taubennester` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `taubennest_logs_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL; + -- -------------------------------------------------------- --