92 lines
3.0 KiB
Bash
Executable File
92 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Holt alle Zammad-Articles der letzten X Tage, gefiltert nach type_id und created_by_id.
|
|
#
|
|
# Aufruf: ZAMMAD_TOKEN=xxx ./zammad_articles.sh [TAGE] [CREATED_BY_ID] [TYPE_ID]
|
|
# Beispiel: ZAMMAD_TOKEN=xxx ./zammad_articles.sh 2 1764 1 > mails.json
|
|
#
|
|
# Voraussetzungen: curl, jq, API-Token mit Admin-Rechten (für /ticket_articles)
|
|
|
|
set -euo pipefail
|
|
|
|
BASE_URL="${ZAMMAD_URL:-https://aikava.zammad.com}"
|
|
TOKEN="${ZAMMAD_TOKEN:?Bitte ZAMMAD_TOKEN setzen}"
|
|
DAYS="${1:-2}"
|
|
CREATED_BY="${2:-1764}"
|
|
TYPE_ID="${3:-1}"
|
|
PER_PAGE=1000
|
|
MAX_PAGE=1000000 # Schutz gegen Endlosschleifen
|
|
|
|
# Call-Zähler über eine Temp-Datei, da fetch_page oft in $(...) läuft
|
|
CALLS_FILE=$(mktemp)
|
|
trap 'rm -f "$CALLS_FILE"' EXIT
|
|
calls() { wc -l < "$CALLS_FILE" | tr -d ' '; }
|
|
|
|
# Stichtag in UTC (GNU date oder BSD/macOS date)
|
|
# CALENDAR=1: ab lokaler Mitternacht vor (TAGE-1) Tagen, also TAGE=2 -> gestern 00:00 bis jetzt
|
|
# sonst: rollierend, jetzt minus TAGE*24h
|
|
if date -u -d "now" >/dev/null 2>&1; then
|
|
if [ "${CALENDAR:-0}" = "1" ]; then
|
|
TS=$(date -d "$((DAYS - 1)) days ago 00:00" +%s)
|
|
else
|
|
TS=$(date -d "${DAYS} days ago" +%s)
|
|
fi
|
|
CUTOFF=$(date -u -d "@${TS}" +%Y-%m-%dT%H:%M:%S)
|
|
else
|
|
if [ "${CALENDAR:-0}" = "1" ]; then
|
|
TS=$(date -v-"$((DAYS - 1))"d -v0H -v0M -v0S +%s)
|
|
else
|
|
TS=$(date -v-"${DAYS}"d +%s)
|
|
fi
|
|
CUTOFF=$(date -u -r "${TS}" +%Y-%m-%dT%H:%M:%S)
|
|
fi
|
|
|
|
log() { echo "$*" >&2; }
|
|
|
|
fetch_page() {
|
|
echo "$1" >> "$CALLS_FILE"
|
|
curl -sf -H "Authorization: Token token=${TOKEN}" \
|
|
"${BASE_URL}/api/v1/ticket_articles?page=$1&per_page=${PER_PAGE}"
|
|
}
|
|
|
|
page_len() { fetch_page "$1" | jq 'length'; }
|
|
|
|
log "Stichtag: ${CUTOFF}Z | created_by_id=${CREATED_BY} | type_id=${TYPE_ID}"
|
|
|
|
# 1) Letzte nicht-leere Seite per Binärsuche finden
|
|
if [ "$(page_len 1)" -eq 0 ]; then
|
|
log "Keine Articles gefunden. (API-Calls: $(calls))"
|
|
echo "[]"
|
|
exit 0
|
|
fi
|
|
|
|
lo=1; hi=2
|
|
while [ "$hi" -le "$MAX_PAGE" ] && [ "$(page_len "$hi")" -gt 0 ]; do
|
|
lo=$hi; hi=$((hi * 2))
|
|
done
|
|
while [ $((hi - lo)) -gt 1 ]; do
|
|
mid=$(( (lo + hi) / 2 ))
|
|
if [ "$(page_len "$mid")" -gt 0 ]; then lo=$mid; else hi=$mid; fi
|
|
done
|
|
SEARCH_CALLS=$(calls)
|
|
log "Letzte Seite: ${lo} (Binärsuche: ${SEARCH_CALLS} Calls)"
|
|
|
|
# 2) Rückwärts lesen bis zum Stichtag und filtern
|
|
results="[]"
|
|
p=$lo
|
|
while [ "$p" -ge 1 ]; do
|
|
batch=$(fetch_page "$p")
|
|
matches=$(jq --arg c "$CUTOFF" --argjson u "$CREATED_BY" --argjson t "$TYPE_ID" \
|
|
'[.[] | select(.created_at >= $c and .type_id == $t and .created_by_id == $u)]' <<<"$batch")
|
|
results=$(jq -s 'add' <(echo "$results") <(echo "$matches"))
|
|
|
|
oldest=$(jq -r '.[0].created_at // empty' <<<"$batch")
|
|
log "Seite ${p}: $(jq 'length' <<<"$matches") Treffer (ältester Article: ${oldest})"
|
|
[[ -z "$oldest" || "$oldest" < "$CUTOFF" ]] && break
|
|
p=$((p - 1))
|
|
done
|
|
|
|
TOTAL_CALLS=$(calls)
|
|
log "Gesamt: $(jq 'length' <<<"$results") Articles"
|
|
log "API-Calls: ${TOTAL_CALLS} (Binärsuche: ${SEARCH_CALLS}, Rückwärts lesen: $((TOTAL_CALLS - SEARCH_CALLS)))"
|
|
jq 'sort_by(.id)' <<<"$results"
|