qcm

Faire des qcm simplement - retour accueil

git clone git://bebou.netlib.re/qcm
Log | Files | Refs | README |

qcm.sh (6128B)


      1 #! /bin/sh
      2 
      3 usage() {
      4 <<-. cat
      5 	Faire des sondages simples en parsant les logs d'un serveur web
      6 
      7 	Usage : qcm [-h] [-e] [-u url] [-l logs] [-g] [-i identifiant] [-d dossier]
      8 
      9 	url par défaut                : http://bebou.netlib.re    (modifiable dans le code)
     10 	log par défaut                : /var/log/nginx/access.log (modifiable dans le code)
     11 	dossier avec html des rés     : /var/www/bebou.netlib.re  (modifiable dans le code)
     12 	nombre d'options par défaut   : 4 (ABCD)
     13 	identifiant par défaut        : match la regex [a-zA-Z0-9]{3}
     14 
     15 	Exemples :
     16 
     17 	qcm                        # écrire le questionnaire sur le moment avec tous les défauts
     18 	qcm -u http://monsite.com  # modifier l'affichage de l'url
     19 	qcm -l /var/log/httpd/logs # changer le chemin du log parcouru
     20 	qcm -e                     # masquer les réponses quand elles arrivent, mode "examen"
     21 	qcm -i fraise              # lancer un questionnaire avec l'identifiant fraise
     22 	qcm -d /var/www/monsite    # changer le dossier par défaut dans lequel afficher les résultats
     23 	cat mon-questionnaire.qcm | qcm # lancer le questionnaire .qcm
     24 	cat mon-questionnaire.qcm | ssh compte@serveur qcm # le lancer à distance mais ne fonctionne pas encore !
     25 
     26 	Pour une explication plus détaillée voir le README ou
     27 	http://arthur.bebou.netlib.re/qcm
     28 .
     29 }
     30 
     31 show() {
     32 <<-.  tee "$webdir/index.html" | grep -Ev "(<pre>|</pre>)" | cat
     33 	<pre>
     34 	exemple de réponse                            : $url/$id/A
     35 	url des résultats (à rafraichir manuellement) : $url/$id
     36 
     37 	$question
     38 
     39 	$context
     40 
     41 	$groupedanswers
     42 
     43 	total   : $tot
     44 	</pre>
     45 .
     46 }
     47 
     48 gplot() {
     49 gnuplot -e "
     50 	set term dumb 75,13;
     51 	set border 1+2;
     52 	set ytics scale 0 nomirror autofreq 1;
     53 	set xtics nomirror;
     54 	set yrange [0:*];
     55 	plot '-' u 1:xtic(2) w histo not;
     56 " | sed 's/-/━/g; s/|/┃/g; s/ \* / ┃ /g; s/ \*\*/ ┏━/g; s/━+/━━/g; s/+━/┗━/g;
     57 		 s/\([0-9]\) +/\1 ┃/g; s/\(┃ \+\)+/\1 /g; s/\*\* /━┓ /g; s/\*\*\*/━━━/g;
     58 		 s/\*\*/━━/g;s/━\*━/━━━/g'
     59 }
     60 
     61 
     62 calcandshow() {
     63 	plotcmd="$1";hide="$2"
     64 	if [ -z "$uniqueanswers" ];then tot=0
     65 	else
     66 		if [ -n "$hide" ];then
     67 			groupedanswers=
     68 		else
     69 			if [ "$type" = "qcm" ];then
     70 				 sortanswers='while read line;do echo "$line" | grep -o . | sort -u | tr -d "\n";printf "\n";done'
     71 			elif [ "$type" = "vote" ];then
     72 				sortanswers='grep -o .'
     73 			else
     74 				sortanswers='cat'
     75 			fi
     76 			groupedanswers=$(echo "$uniqueanswers" |
     77 				grep -Eo "/$id/[^ ]+ " | cut -d'/' -f3- | # PARSAGE DE LOG
     78 				eval $sortanswers |
     79 				sed 's,%\([0-9A-F][0-9A-F]\),\\\\\x\1,g' | xargs printf "%b\n" |
     80 				grep -v "^$" |
     81 				sort | uniq -c | sort -rn | $qplotcmd )
     82 		fi
     83 		tot=$(echo "$uniqueanswers" | wc -l)
     84 	fi
     85 
     86 	context=$(case "$type" in
     87 		( "ouverte" ) : ;;
     88 		( "regex" )   printf "format autorisé : %s" "$options" ;;
     89 		( * )
     90 			[ "$choix" = "+" ] \
     91 				&& printf "%s\n" "plusieurs choix possibles" \
     92 				|| printf "%s\n" "un seul choix possible"
     93 			[ -n "$options" ] \
     94 				&& printf "%s" "$(echo "$options" | tr '~' '\n' | paste "$tmpd/o" -)" \
     95 				|| printf "options : %s" "$(< "$tmpd/o" paste -d '\0' -s -)"
     96 			;;
     97 	esac)
     98 
     99 	clear
    100 	show
    101 }
    102 
    103 demander() {
    104 	case "$type" in
    105 		( "ouverte" ) pattern=;                       qplotcmd="cat";;
    106 		( "regex" )   pattern="${options:-[ABCD] } "; qplotcmd="cat";;
    107 		( * )
    108 			possibleanswers="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    109 			[ -n "$options" ] && nbq=$(( $(echo "$options" | grep -o '~' | wc -l) + 1 ))
    110 			echo "$possibleanswers" | grep -o '.' | head -n"$nbq" > "$tmpd/o"
    111 			answers=$(< "$tmpd/o" tr -d '\n')
    112 			pattern="[$answers]$choix "
    113 			qplotcmd="$plotcmd";;
    114 	esac
    115 	pattern="GET /$id/$pattern"
    116 
    117 	[ -p "$tmpd/notif" ] || mkfifo "$tmpd/notif"
    118 	tail -fn0 "$logs" | grep --line-buffered -E "$pattern" >> "$tmpd/in" & # PARSAGE DE LOG
    119 	tail1pid=$!
    120 	tail -fn0 "$logs" | grep --line-buffered -E "$pattern" > "$tmpd/notif" & # PARSAGE DE LOG
    121 	tail2pid=$!
    122 
    123 	calcandshow "$qplotcmd" "$hide"
    124 	cat "$tmpd/notif" | while read newanswer ;do
    125 		uniqueanswers=$(< "$tmpd/in" sort $uopt -k1,1)
    126 		[ "$olduniqueanswers" != "$uniqueanswers" ] && calcandshow "$qplotcmd" "$hide"
    127 		olduniqueanswers="$uniqueanswers"
    128 	done &
    129 	disppid=$!
    130 
    131 	read _ < /dev/tty
    132 	kill "$disppid" "$tail1pid" "$tail2pid"
    133 
    134 	if [ -n "$hide" ];then
    135 		uniqueanswers=$(< "$tmpd/in" sort $uopt -k1,1)
    136 		calcandshow "$qplotcmd"
    137 		read _ < /dev/tty
    138 		uniqueanswers=;groupedanswers=;tot=0
    139 	fi
    140 
    141 	rm "$tmpd/in"
    142 }
    143 
    144 nbq=4
    145 uopt="-u"
    146 plotcmd="cat"
    147 
    148 while getopts "hegl:u:i:d:" opt; do
    149 	case $opt in
    150 		( l | u | i | d ) [ -n "$OPTARG" ] && eval "$opt='$OPTARG'" ;;
    151 		( g )     command -v gnuplot > /dev/null && plotcmd="gplot" ;;
    152 		( h )     usage; exit ;;
    153 		( e )     hide="yes";;
    154 		( * )     echo "Option inconnue, voir l'aide en lançant qcm -h";exit 1;;
    155   esac
    156 done
    157 
    158 url="${u:-http://bebou.netlib.re}"
    159 logs="${l:-/var/log/nginx/access.log}"
    160 
    161 
    162 [ ! -e "$logs" ] && { echo "fichier de log '$logs' n'existe pas" >&2;exit 1; }
    163 
    164 tmpd=$(mktemp -d "${TMPDIR:-/tmp}/qcm.XXXXXX")
    165 if [ -n "$i" ];then
    166 	existingids=$(ps -A -l -f | grep "[ /]qcm " |
    167 	              grep -o -- '-i [^ ]\+' |
    168 				  cut -d' ' -f2 | sort | uniq -c)
    169 	while echo "$existingids" | grep -q " \+[3-9] \+$i";do
    170 		if [ ! -t 0 ];then echo "id existe déjà"; exit 1;
    171 		else               printf "id existe déjà, nouvel id : "; read i < /dev/tty
    172 		fi
    173 	done
    174 	id="$i"
    175 else
    176 	id=$(basename "$tmpd" | cut -d'.' -f2)
    177 fi
    178 
    179 webdir="${d:-/var/www/bebou.netlib.re}"/$id
    180 mkdir "$webdir" || { echo "Impossible de créer le dossier '$webdir'" >&2;exit 1; }
    181 
    182 alias question:=question; question() { question="$*"; }
    183 alias type:=type;         type()     { type="$*"; }
    184 alias options:=options;   options()  { options="$*"; }
    185 alias choix:=choix;       choix()    { [ "$*" = "multiple" ] && choix="+" || choix=; }
    186 alias unique:=unique;     unique()   { [ "$*" = "non" ] && uopt= || uopt="-u"; }
    187 
    188 trap 'rm -rf "$tmpd" "$webdir";exit' INT TERM QUIT
    189 trap 'kill 0'            EXIT
    190 
    191 if [ -t 0 ];then
    192 	<<-. cat
    193 	Ecrivez le questionnaire puis ctrl+d sur une ligne vide pour le soumettre
    194 	syntaxe du questionnaire :
    195 	http://arthur.bebou.netlib.re/qcm/#le-format-du-fichier-de-questionnaire
    196 	.
    197 fi
    198 
    199 cat > "$tmpd/questions"
    200 file="$tmpd/questions"
    201 . "$file"