#!/usr/bin/env bash # Generates a stalwart-cli apply NDJSON plan (Domain + Account/User + aliases) # from a migration accounts.csv file. Requires jq. set -euo pipefail usage() { echo "Usage: $0 -c accounts.csv -d domain.tld -o accounts-plan.ndjson" >&2; exit 1; } while getopts "c:d:o:" opt; do case "$opt" in c) CSV="$OPTARG" ;; d) DOMAIN="$OPTARG" ;; o) OUT="$OPTARG" ;; *) usage ;; esac done [[ -z "${CSV:-}" || -z "${DOMAIN:-}" || -z "${OUT:-}" ]] && usage command -v jq >/dev/null || { echo "jq is required" >&2; exit 1; } : > "$OUT" jq -nc --arg domain "$DOMAIN" \ '{"@type":"upsert","object":"Domain","matchOn":["name"],"value":{"dom":{"name":$domain}}}' >> "$OUT" accounts_file=$(mktemp) trap 'rm -f "$accounts_file"' EXIT # Process substitution keeps the loop in the current shell, so a missing # password can abort the whole script instead of just a pipeline subshell. while IFS=',' read -r email new_password old_password aliases quota_mb; do [[ -z "$email" ]] && continue if [[ -z "$new_password" ]]; then echo "Missing new_password for $email" >&2 exit 1 fi local_part="${email%%@*}" aliases_json=$(jq -n --arg aliases "$aliases" ' ($aliases | split(";") | map(select(length > 0))) as $names | reduce $names[] as $n ({}; . + {("alias-" + $n): {name: $n, domainId: "#dom"}})') quotas_json="{}" if [[ -n "$quota_mb" ]]; then quotas_json=$(jq -n --argjson mb "$quota_mb" '{"maxDiskQuota": ($mb * 1048576)}') fi jq -n --arg id "acct-$local_part" --arg name "$local_part" --arg secret "$new_password" \ --argjson aliases "$aliases_json" --argjson quotas "$quotas_json" ' { ($id): { "@type": "User", name: $name, domainId: "#dom", credentials: { "0": { "@type": "Password", secret: $secret } }, memberGroupIds: {}, roles: { "@type": "User" }, permissions: { "@type": "Inherit" }, quotas: $quotas, aliases: $aliases, encryptionAtRest: { "@type": "Disabled" } } }' >> "$accounts_file" done < <(tail -n +2 "$CSV") accounts_value=$(jq -s 'add' "$accounts_file") jq -nc --argjson value "$accounts_value" \ '{"@type":"upsert","object":"Account","matchOn":["name"],"value":$value}' >> "$OUT" echo "Wrote plan to $OUT"