ab971618d5
Schließt die Lücke „nach Import landet die ZIP nicht im Image-Default":
./factory-import.sh --save-as-builtin
→ entpackt die ZIP nach erfolgreichem DB-Import zusätzlich in
backend/factory-defaults/ (alter Inhalt vorher aufgeräumt, README.md
und .gitkeep bleiben). Beim nächsten Image-Build sind die Defaults
drin und seeden frische VMs automatisch.
README-Abschnitt „Factory-Defaults" komplett überarbeitet:
- Drei Transport-Pfade explizit erklärt (laufende DB / Drop-Box / Image)
- HTML-Standardtexte + AppSetting-Whitelist dokumentiert
- Auto-Seed-Verhalten + Berechtigungen aktualisiert
- Typische Workflows als End-zu-End-Sequenz inkl. scp-Sync
Live verifiziert: STALE_FILE.txt im backend/factory-defaults/ wurde beim
--save-as-builtin sauber entfernt, README.md blieb erhalten, Subfolder neu
befüllt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
4.8 KiB
Bash
Executable File
141 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Factory-Defaults-Import – pflegt eine ZIP in eine OpenCRM-Instanz ein.
|
||
# Idempotent (upserts pro Kategorie, nichts wird gelöscht).
|
||
#
|
||
# Aufruf:
|
||
# ./factory-import.sh # jüngste ZIP aus factory-exports/
|
||
# ./factory-import.sh ./factory-exports/foo.zip # explizite ZIP
|
||
# ./factory-import.sh --save-as-builtin # nach Import auch ins
|
||
# ./factory-import.sh --save-as-builtin ./foo.zip # backend/factory-defaults/
|
||
# # entpacken → nächster
|
||
# # Image-Build hat sie
|
||
# # als Werkseinstellung
|
||
#
|
||
# ENV (wie factory-export.sh):
|
||
# OPENCRM_URL (default http://localhost:3010)
|
||
# OPENCRM_EMAIL (default admin@admin.com)
|
||
# OPENCRM_PASSWORD (sonst interaktiv)
|
||
|
||
set -euo pipefail
|
||
|
||
URL="${OPENCRM_URL:-http://localhost:3010}"
|
||
EMAIL="${OPENCRM_EMAIL:-admin@admin.com}"
|
||
PASSWORD="${OPENCRM_PASSWORD:-}"
|
||
|
||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
EXPORT_DIR="$REPO_ROOT/factory-exports"
|
||
BUILTIN_DIR="$REPO_ROOT/backend/factory-defaults"
|
||
|
||
# Argumente parsen: erlaubt sind --save-as-builtin und 0/1 ZIP-Pfade in
|
||
# beliebiger Reihenfolge.
|
||
SAVE_AS_BUILTIN=false
|
||
ZIP_PATH=""
|
||
for arg in "$@"; do
|
||
case "$arg" in
|
||
--save-as-builtin) SAVE_AS_BUILTIN=true ;;
|
||
-h|--help)
|
||
sed -n '2,16p' "$0" | sed 's/^# \?//'
|
||
exit 0
|
||
;;
|
||
--*) echo "✗ Unbekanntes Flag: $arg"; exit 2 ;;
|
||
*)
|
||
if [ -n "$ZIP_PATH" ]; then
|
||
echo "✗ Mehrere ZIP-Pfade angegeben (nur einer erlaubt)"; exit 2
|
||
fi
|
||
ZIP_PATH="$arg"
|
||
;;
|
||
esac
|
||
done
|
||
|
||
if [ -z "$ZIP_PATH" ]; then
|
||
# Jüngste ZIP automatisch wählen
|
||
ZIP_PATH="$(ls -1t "$EXPORT_DIR"/*.zip 2>/dev/null | head -1 || true)"
|
||
if [ -z "$ZIP_PATH" ]; then
|
||
echo "✗ Keine ZIP angegeben und keine in $EXPORT_DIR/ gefunden."
|
||
echo " Aufruf: ./factory-import.sh <pfad/zur/factory-defaults.zip>"
|
||
exit 1
|
||
fi
|
||
echo "→ Keine ZIP angegeben – nehme jüngste aus $EXPORT_DIR/:"
|
||
echo " $(basename "$ZIP_PATH")"
|
||
fi
|
||
|
||
if [ ! -f "$ZIP_PATH" ]; then
|
||
echo "✗ Datei nicht gefunden: $ZIP_PATH"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$PASSWORD" ]; then
|
||
read -r -s -p "Passwort für $EMAIL @ $URL: " PASSWORD
|
||
echo
|
||
fi
|
||
|
||
echo "→ Login als $EMAIL @ $URL"
|
||
LOGIN_RESPONSE="$(curl -sS -X POST "$URL/api/auth/login" \
|
||
-H 'Content-Type: application/json' \
|
||
--data-raw "$(E="$EMAIL" P="$PASSWORD" python3 -c 'import json,os;print(json.dumps({"email":os.environ["E"],"password":os.environ["P"]}))')")"
|
||
|
||
TOKEN="$(printf '%s' "$LOGIN_RESPONSE" | python3 -c 'import json,sys;d=json.load(sys.stdin);print((d.get("data") or {}).get("token","") or d.get("token",""))')"
|
||
|
||
if [ -z "$TOKEN" ]; then
|
||
echo "✗ Login fehlgeschlagen. Antwort:"
|
||
echo "$LOGIN_RESPONSE" | head -c 500
|
||
echo
|
||
exit 1
|
||
fi
|
||
|
||
echo "→ Upload + Import: $(basename "$ZIP_PATH")"
|
||
RESPONSE="$(curl -sS -X POST "$URL/api/factory-defaults/import" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "zip=@$ZIP_PATH")"
|
||
|
||
# Hübsch ausgeben + auf success prüfen
|
||
if ! printf '%s' "$RESPONSE" | python3 -c '
|
||
import json, sys
|
||
r = json.load(sys.stdin)
|
||
if not r.get("success"):
|
||
print("✗ Import fehlgeschlagen:", r.get("error", "(unbekannt)"))
|
||
sys.exit(1)
|
||
d = r.get("data", {})
|
||
print("✓ Import erfolgreich:")
|
||
for label, key in [
|
||
("Anbieter", "providers"),
|
||
("Tarife", "tariffs"),
|
||
("Kündigungsfristen", "cancellationPeriods"),
|
||
("Laufzeiten", "contractDurations"),
|
||
("Vertragskategorien","contractCategories"),
|
||
("PDF-Vorlagen", "pdfTemplates"),
|
||
("HTML-Templates", "appSettings"),
|
||
]:
|
||
print(f" {label}: {d.get(key, 0)}")
|
||
skipped = d.get("pdfTemplatesSkipped", 0)
|
||
if skipped:
|
||
print(f" (PDF-Vorlagen übersprungen: {skipped})")
|
||
warnings = d.get("warnings", []) or []
|
||
if warnings:
|
||
print("Hinweise:")
|
||
for w in warnings:
|
||
print(f" - {w}")
|
||
'; then
|
||
exit 1
|
||
fi
|
||
|
||
# --save-as-builtin: ZIP zusätzlich in backend/factory-defaults/ entpacken,
|
||
# damit der nächste Image-Build sie als Werkseinstellung mitnimmt.
|
||
# Vorher räumen wir auf (außer README.md + .gitkeep), damit nichts Veraltetes
|
||
# liegen bleibt.
|
||
if [ "$SAVE_AS_BUILTIN" = "true" ]; then
|
||
echo
|
||
echo "→ --save-as-builtin: aktualisiere $BUILTIN_DIR/"
|
||
if [ ! -d "$BUILTIN_DIR" ]; then
|
||
mkdir -p "$BUILTIN_DIR"
|
||
fi
|
||
# Aufräumen: alles außer README.md und .gitkeep löschen
|
||
find "$BUILTIN_DIR" -mindepth 1 \
|
||
\! -name 'README.md' \! -name '.gitkeep' \
|
||
-delete
|
||
# ZIP entpacken (manifest.json kommt mit, ist aber harmlos)
|
||
unzip -q -o "$ZIP_PATH" -d "$BUILTIN_DIR"
|
||
echo "✓ Werkseinstellungen aktualisiert. Beim nächsten 'docker-compose up"
|
||
echo " --build' landen sie im Image und seeden frische DBs automatisch."
|
||
fi
|