Update
This commit is contained in:
1 parent
2105a0c5f7
commit
c89d4825e2
30 files changed
+5435
-627
No files matched your search
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/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"
|
||||
Reference in new issue
Block a user