70 lines
2.2 KiB
Bash
70 lines
2.2 KiB
Bash
#!/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: { pw: { "@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"
|