Files
Calbook/scripts/export-backup.sh

119 lines
4.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# export-backup.sh Standalone-Export für CalBook (braucht nur Docker + .env)
# Funktioniert mit jeder CalBook-Version, auch ohne die Backup-API.
# Output: calbook-backup-YYYY-MM-DD.json
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_FILE="${ROOT_DIR}/.env"
if [[ ! -f "${ENV_FILE}" ]]; then
echo "Fehler: .env nicht gefunden in ${ROOT_DIR}"
exit 1
fi
get_env() {
local key="$1"
local line val
line="$(grep -E "^${key}=" "${ENV_FILE}" | head -n1 || true)"
[[ -z "${line}" ]] && { echo ""; return; }
val="${line#*=}"
val="${val#\"}"; val="${val%\"}"
val="${val#\'}"; val="${val%\'}"
echo "${val}"
}
if ! command -v docker >/dev/null 2>&1; then
echo "Fehler: Docker wird benötigt."
exit 1
fi
STACK_NAME="$(get_env STACK_NAME)"
[[ -z "${STACK_NAME}" ]] && STACK_NAME="calbook"
CONTAINER="${STACK_NAME}-db"
if ! docker ps --format '{{.Names}}' | grep -qx "${CONTAINER}"; then
echo "Fehler: DB-Container '${CONTAINER}' läuft nicht."
exit 1
fi
OUTPUT_FILE="calbook-backup-$(date '+%Y-%m-%d').json"
TEMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TEMP_DIR}"' EXIT
echo "Exportiere Datenbank via Container '${CONTAINER}'..."
run_query() {
docker exec "${CONTAINER}" psql -U calbook -d calbook -t -A -F $'\t' -c "$1" > "$2"
}
# ── Settings ─────────────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT key, value FROM \"Setting\" WHERE key NOT IN ('PUBLIC_URL', 'NEXTAUTH_URL', 'APP_BASE_URL') ORDER BY key) t;" \
"${TEMP_DIR}/settings.json"
# ── Users ────────────────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT id, name, email, \"hashedPassword\", role, slug, bio, \"avatarUrl\", timezone, \"isActive\", \"createdAt\", \"updatedAt\" FROM \"User\" ORDER BY email) t;" \
"${TEMP_DIR}/users.json"
# ── Calendar connections ─────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT id, \"userId\", name, \"bookingAllowedWeekdays\", \"bookingDayStartTime\", \"bookingDayEndTime\", \"bookingDayRangesJson\", url, username, \"notificationEmail\", \"encryptedPassword\", color, \"syncEnabled\", \"lastSyncedAt\", \"createdAt\", \"updatedAt\" FROM \"CalendarConn\" ORDER BY \"createdAt\") t;" \
"${TEMP_DIR}/calendars.json"
# ── Appointments ─────────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT * FROM \"Appointment\" ORDER BY \"startAt\") t;" \
"${TEMP_DIR}/appointments.json"
# ── Busy blocks ──────────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT * FROM \"BusyBlock\" ORDER BY \"startAt\") t;" \
"${TEMP_DIR}/busyblocks.json"
# ── Delivery issues ──────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT * FROM \"DeliveryIssue\" ORDER BY \"firstSeenAt\") t;" \
"${TEMP_DIR}/delivery.json"
# ── Sync runs + logs ─────────────────────────────────
run_query "SELECT json_agg(t) FROM (SELECT r.*, (SELECT json_agg(e) FROM (SELECT * FROM \"CalendarSyncLogEntry\" e WHERE e.\"syncRunId\" = r.id ORDER BY e.\"createdAt\") e) AS entries FROM \"CalendarSyncRun\" r ORDER BY r.\"startedAt\") t;" \
"${TEMP_DIR}/syncruns.json"
# ── Assemble via node (keine externen Dependencies) ──
echo "Erstelle Backup-Datei..."
EXPORTED_AT="$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"
CALDAV_KEY="$(get_env CALDAV_ENCRYPTION_KEY)"
node - "$CALDAV_KEY" "$EXPORTED_AT" "$OUTPUT_FILE" "$TEMP_DIR" << 'NODEEOF'
const fs = require('fs');
const caldavKey = process.argv[2] || "";
const exportedAt = process.argv[3];
const outputFile = process.argv[4];
const tempDir = process.argv[5];
const files = ['settings','users','calendars','appointments','busyblocks','delivery','syncruns'];
const data = {};
for (const f of files) {
const raw = fs.readFileSync(tempDir + '/' + f + '.json', 'utf8').trim();
data[f] = raw ? JSON.parse(raw) : [];
}
const backup = {
version: 1,
exportedAt: exportedAt,
caldavEncryptionKey: caldavKey || undefined,
settings: data.settings || [],
users: data.users || [],
calendarConns: data.calendars || [],
appointments: data.appointments || [],
busyBlocks: data.busyblocks || [],
deliveryIssues: data.delivery || [],
syncRuns: data.syncruns || []
};
fs.writeFileSync(outputFile, JSON.stringify(backup, null, 2));
NODEEOF
echo
echo "Backup erstellt: ${OUTPUT_FILE}"
echo "Größe: $(du -h "${OUTPUT_FILE}" | cut -f1)"
echo
echo "Import auf neuer Instanz:"
echo " Admin → Backup → Datei auswählen → Importieren"