napi/scripts/python-upload-watcher.sh

214 lines
6.7 KiB
Bash

#!/bin/bash
# /usr/local/bin/python-upload-watcher.sh
# Watcher para entregas de Programación ASIR1 via SFTP
# v7 — Nombre completo en notificaciones ([María Jara] en vez de [jara])
#
# - Batching por carpeta: UN mensaje XMPP con listado completo
# - Re-entregas: detecta delete+recreate (<120s)
# - Windows-safe: ignora Thumbs.db, desktop.ini, .DS_Store, *.tmp, __pycache__, *.pyc
WATCH_DIR="/home"
# --- Mapa usuario → nombre completo ---
fullname() {
case "$1" in
barja) echo "Alex Barja" ;;
barrios) echo "Andrés Barrios" ;;
cayo) echo "Jared Cayo" ;;
contrera) echo "Luciano Contrera" ;;
duque) echo "Jorge Duque" ;;
florea) echo "Alejandro Florea" ;;
gomes) echo "Gabriel Gomes" ;;
izquierdo) echo "Daniel Izquierdo" ;;
jara) echo "María Jara" ;;
lillo) echo "Fernando Lillo" ;;
linares) echo "Christopher Linares" ;;
macedo) echo "Eduardo Macedo" ;;
martinez) echo "Daniel Martínez" ;;
munoz) echo "Jordy Muñoz" ;;
olcina) echo "Jorge Olcina" ;;
ponce) echo "Francisco Ponce" ;;
posada) echo "Santiago Posada" ;;
quiroz) echo "Alexander Quiroz" ;;
reynoso) echo "Jorge Reynoso" ;;
sierra) echo "Leonel Sierra" ;;
torrero) echo "Mario Torrero" ;;
*) echo "$1" ;; # fallback: username tal cual
esac
}
LOG="/var/log/python-upload-watcher.log"
BATCH_DIR="/tmp/python-watcher-batches"
DELETE_DIR="/tmp/python-watcher-deletes"
QUIET_SECONDS=10
mkdir -p "$BATCH_DIR" "$DELETE_DIR"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG"
}
notify_xmpp() {
/usr/local/bin/xmpp-notify.py "$1" >/dev/null 2>&1 &
}
is_junk() {
case "${1,,}" in
thumbs.db|desktop.ini|.ds_store|*.tmp|~\$*|~*.tmp) return 0 ;;
__pycache__|*.pyc|*.pyo) return 0 ;;
.git|.venv|.env|node_modules|.idea|.vscode) return 0 ;;
*) return 1 ;;
esac
}
# Filtrar paths que contengan directorios basura
is_junk_path() {
case "$1" in
*/__pycache__/*|*/.git/*|*/.venv/*|*/node_modules/*|*/.idea/*|*/.vscode/*) return 0 ;;
*) return 1 ;;
esac
}
file_icon() {
case "${1,,}" in
*.py) echo "🐍" ;;
*.zip|*.rar|*.tar*|*.gz|*.bz2|*.7z) echo "📦" ;;
*.md) echo "📝" ;;
*.txt) echo "📄" ;;
*.pdf) echo "📕" ;;
*.docx|*.doc) echo "📘" ;;
*.png|*.jpg|*.jpeg|*.gif) echo "🖼️" ;;
*) echo "📎" ;;
esac
}
batch_key() {
echo "${1}_${2}" | tr '/ ' '__'
}
flush_batch() {
local batchfile="$1"
[[ ! -f "$batchfile" ]] && return
local user dir tag file_count file_list label msg
user=$(sed -n '1p' "$batchfile")
dir=$(sed -n '2p' "$batchfile")
tag=$(sed -n '3p' "$batchfile")
file_count=$(tail -n +4 "$batchfile" | wc -l)
[[ "$file_count" -eq 0 ]] && { rm -f "$batchfile"; return; }
file_list=$(tail -n +4 "$batchfile")
label="Entrega"
[[ "$tag" == "re-entrega" ]] && label="♻️ Re-entrega"
local display_name
display_name=$(fullname "$user")
msg="📁 [$display_name] $label ASIR1: $dir/ ($file_count ficheros)
$file_list"
log "[$user] BATCH FLUSH ($tag): $dir/ → $file_count ficheros"
notify_xmpp "$msg"
rm -f "$batchfile"
}
flush_daemon() {
while true; do
sleep 3
for batchfile in "$BATCH_DIR"/*.batch; do
[[ ! -f "$batchfile" ]] && continue
local last_mod now age
last_mod=$(stat -c%Y "$batchfile" 2>/dev/null) || continue
now=$(date +%s)
age=$(( now - last_mod ))
(( age >= QUIET_SECONDS )) && flush_batch "$batchfile"
done
done
}
flush_daemon &
FLUSH_PID=$!
trap "kill $FLUSH_PID 2>/dev/null" EXIT
log "=== Python Upload Watcher v7 iniciado ==="
notify_xmpp "🚀 [zzz] Python Upload Watcher v7 iniciado (ASIR1)"
# ---------------------------------------------------------
# Bucle principal — sin 'local', todo variables globales
# ---------------------------------------------------------
inotifywait -m -r \
-e close_write -e moved_to -e create -e delete -e moved_from \
--format "%e %w%f" "$WATCH_DIR" 2>/dev/null | \
while IFS= read -r line; do
_event="${line%% /*}"
_filepath="/${line#* /}"
[[ ! "$_filepath" =~ ^/home/([^/]+)/python/(.+)$ ]] && continue
_user="${BASH_REMATCH[1]}"
_relpath="${BASH_REMATCH[2]}"
_filename=$(basename "$_relpath")
is_junk "$_filename" && continue
is_junk_path "$_relpath" && continue
# --- DELETE / MOVED_FROM ---
if [[ "$_event" == *DELETE* || "$_event" == *MOVED_FROM* ]]; then
if [[ "$_relpath" != */* ]]; then
_bk=$(batch_key "$_user" "$_relpath")
echo "$(date +%s)" > "$DELETE_DIR/$_bk"
rm -f "$BATCH_DIR/${_bk}.batch"
log "[$_user] BORRADA: $_relpath/"
fi
continue
fi
# --- CREATE directorio ---
if [[ "$_event" == *CREATE* && -d "$_filepath" ]]; then
# Solo carpetas de primer nivel bajo python/
if [[ "$_relpath" != */* ]]; then
_bk=$(batch_key "$_user" "$_relpath")
_tag="new"
if [[ -f "$DELETE_DIR/$_bk" ]]; then
_del_ts=$(cat "$DELETE_DIR/$_bk")
_now=$(date +%s)
(( _now - _del_ts < 120 )) && _tag="re-entrega"
rm -f "$DELETE_DIR/$_bk"
fi
printf '%s\n%s\n%s\n' "$(fullname "$_user")" "$_relpath" "$_tag" > "$BATCH_DIR/${_bk}.batch"
log "[$_user] CARPETA ($_tag): $_relpath/ — batch abierto en $BATCH_DIR/${_bk}.batch"
fi
continue
fi
# --- CREATE fichero → skip (close_write viene después) ---
[[ "$_event" == *CREATE* ]] && continue
# --- close_write / moved_to → fichero completado ---
_size=$(stat -c%s "$_filepath" 2>/dev/null || echo "?")
_icon=$(file_icon "$_filename")
if [[ "$_relpath" == */* ]]; then
_topdir="${_relpath%%/*}"
_bk=$(batch_key "$_user" "$_topdir")
_batchfile="$BATCH_DIR/${_bk}.batch"
if [[ -f "$_batchfile" ]]; then
_subpath="${_relpath#*/}"
echo " $_icon $_subpath ($_size bytes)" >> "$_batchfile"
log "[$_user] +BATCH: $_relpath ($_size bytes)"
continue
fi
# Sin batch → individual
log "[$_user] Subido: $_relpath ($_size bytes)"
notify_xmpp "$_icon [$(fullname "$_user")] Entrega ASIR1: $_relpath ($_size bytes)"
else
log "[$_user] Subido: $_relpath ($_size bytes)"
notify_xmpp "$_icon [$(fullname "$_user")] Entrega ASIR1: $_relpath ($_size bytes)"
fi
done