214 lines
6.7 KiB
Bash
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
|