arthur.bebou

Le site arthur.bebou.netlib.re - retour accueil

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

index.sh (13885B)


      1 #! page
      2 title: Comment faire un sondage simple ?
      3 author: Arthur Pons
      4 description: Fabriquons de quoi faire un sondage simple avec de l\'htlm et du shell
      5 publication: 2023-06-02
      6 sectionmd: main
      7 
      8 
      9 J'ai eu besoin à plusieurs reprises de construire des sondages très simples
     10 pour des associations. Si l'on souhaite minimiser le recours au numérique il
     11 est toujours bon de se rappeler qu'il existe des moyens analogiques de sonder
     12 un groupe de personne. D'expérience il est considéré utile voir nécessaire
     13 d'avoir recours au numérique quand les personnes à sonder sont dispersées
     14 géographiquement et temporellement.
     15 
     16 Explorons la possibilité de faire des sondages à l'implémentation et
     17 l'utilisation plus simple que google forms, framaforms etc.
     18 
     19 ## Par mail
     20 
     21 Il est possible de créer des sondages par mail. L'idée est décrite en détail
     22 dans l'article sur [kun](http://katzele.netlib.re/articles/kun). Ce système a
     23 des avantages et des désavantages.
     24 
     25 Parmi les désavantages on peut noter un potentiel souci d'intégrité des données
     26 si les personnes répondant au sondage modifient (par accident ou par
     27 malveillance) les propositions de réponses envoyées dans le mail.
     28 
     29 Second désavantage, il est délicat de créer des types de questions
     30 autres qu'à choix multiples autrement qu'en écrivant dans le corps du mail
     31 quelque chose du type
     32 
     33 	Quel est votre couleur préférée ?
     34 	ne retenir qu'une seule des deux propositions suivantes
     35 	
     36 	bleu
     37 	rouge
     38 
     39 ce qui, à moins de sonder des personnes particulièrement attentives et
     40 disciplinées, conduira forcément à des soucis d'intégrité. Ces soucis pourraient
     41 être assez facilement identifiés en vérifiant si une réponse contient à la fois
     42 la réponse bleu et rouge mais cela ne dit rien sur la façon de corriger
     43 l'ambigüité. Il serait nécessaire de resonder la personne. C'est pourquoi cette
     44 solution via mail fonctionne pour des choix de dates mais pas pour la plupart
     45 des types de sondages.
     46 
     47 ## Par greppage de logs de serveurs web
     48 
     49 Oui oui vous avez bien lu le titre, on peut sonder des personnes en leur
     50 faisant construire une url précise. On récolte ensuite les informations en
     51 parsant les logs du serveur.
     52 
     53 Marc Chantreux avait pratiqué cette technique en septembre 2022 en envoyant
     54 ce mail à la liste devlog.
     55 
     56 > D'après vous donc quelle est la tendance majoritaire au sein de votre
     57 > organisation? Merci de bien vouloir me répondre sous la forme N,P,D,F,H,X,O,E
     58 > décrite ci après. la réponse peut être multiple. par exemple dans mon
     59 > cas:
     60 > 
     61 > 	debian,tech,desktop,5,5,,u-strasbourg-dnum,mc@unistra.fr
     62 > 	scientific-linux,chercheur,cluster,0,,+500,u-strasbourg
     63 > 
     64 > que j'interprète tel que:
     65 > 
     66 > * les techniciens de la DNUM utilisent principalement du debian (ou derrivatif)
     67 >   sur leurs desktops. Ils sont libres d'installer ce qu'ils veulent et
     68 >   sont heureux avec debian
     69 > * sur notre cluster HPC, les chercheurs utilisent tous scientific-linux.
     70 >   ils n'ont pas participé au choix de l'OS et je ne sais pas si ils sont
     71 >   contents. on a + de 500 comptes.
     72 > 
     73 > les critères sont:
     74 > 
     75 > N: nom de l'OS
     76 > 	les distros linux comptent pour OS
     77 > P: population
     78 > 	exemples: dev, tech, chercheur, étudiant,
     79 > 	admin (personnels administratifs)
     80 > D: device (
     81 > 	exemples: cluster (hpc), desktop, tablette, smartphone
     82 > F: free (de 1 à 5)
     83 > 	à quel point ce choix a été consenti par les usagers (5 étant un choix
     84 > 	total de sa part).
     85 > H: happy (de 1 à 5)
     86 > 	à quel point l'usager témoigne sa satisfaction par rapport à la dis
     87 > X: nombre approximatif d'utilisateurs (si connu)
     88 > O: votre organisation
     89 > E: votre adresse de contact si vous souhaitez être recontacté
     90 > 
     91 > N'ayant pas le temps de créer ou utiliser un outils de sondage, je vous
     92 > propose un "sondage par log": merci de construire (dans votre navigateur
     93 > ou avec curl) l'adresse suivante (qui répondra 404 et c'est normal).
     94 > 
     95 > https://people.u-strasbg.fr/surveydistro/devlog2209/N,P,D,F,H,X,O,E
     96 > 
     97 > par exemple: j'aurais tendance à répondre au sondage comme suit:
     98 > 
     99 > set https://people.u-strasbg.fr/surveydistro/devlog2209
    100 > <<. xargs -d"\n" -IX curl -k $1/X
    101 > debian,tech,desktop,5,5,,u-strasbourg-dnum,mc@unistra.fr
    102 > scientific-linux,chercheur,cluster,0,,+500,u-strasbourg
    103 > 
    104 > Au pire n'hésitez pas à m'envoyer votre retour par mail (tsv, csv,
    105 > attachement: je m'en débrouillerais et vous remercie par avance pour
    106 > toute réponse).
    107 
    108 Le code écrit dans le mail construit les deux commandes suivantes :
    109 
    110 	curl -k https://people.u-strasbg.fr/surveydistro/devlog2209/debian,tech,desktop,5,5,,u-strasbourg-dnum,mc@unistra.fr
    111 	curl -k https://people.u-strasbg.fr/surveydistro/devlog2209/scientific-linux,chercheur,cluster,0,,+500,u-strasbourg
    112 
    113 L'accès à ces urls ne feront strictement rien d'autre sur le serveur web que
    114 d'ajouter une ligne dans les logs. On peut ensuite parser les logs comme on le
    115 souhaite pour générer un fichier csv ne content que les réponses sous la forme :
    116 
    117 	debian,tech,desktop,5,5,,u-strasbourg-dnum,mc@unistra.fr
    118 	scientific-linux,chercheur,cluster,0,,+500,u-strasbourg
    119 
    120 Le gros désavantage de cette technique est qu'il est très facile pour quelqu'un
    121 de spammer les réponses. Si la personne le fait derrière la même ip on peut le
    122 filtrer assez rapidement mais si elle possède plusieurs ip différentes elle
    123 peut influencer le sondage.
    124 
    125 Ce genre de soucis sont relativement anecdotiques quand on sonde une cohorte
    126 limitée et connue de personnes[^1]. C'est pourquoi il n'est pas forcément nécessaire
    127 d'avoir recours à des outils compliqués dans un bon nombre de cas.
    128 
    129 ## Via formulaire html et CGI
    130 
    131 Pour partiellement remédier aux problèmes précedemment évoqués nous pouvons
    132 avoir recours à un formulaire web et un cgi pour parser les réponses.
    133 
    134 Si l'on reprend l'exemple précédent, la question "A quel point ce choix a été
    135 consenti par les usagers ?" prend pour valeur un entier entre 1 et 5 mais il
    136 n'y a aucun moyen de vérifier si c'est bien le cas de la donnée insérée dans
    137 l'url. En utilisant des formulaires html et des balises d'input on peut
    138 contrôler l'intégrité des données à la saisie[^2].
    139 
    140 ### La collecte de données
    141 
    142 Prenons pour exemple le formulaire html suivant :
    143 
    144 	<form action="/cgi-bin/parse.cgi" method=post enctype=multipart/form-data>
    145 		<fieldset>
    146 			<legend>Récolte</legend>
    147 			<label for="daterecolte">Date</label>
    148 			<input type="datetime-local" name="daterecolte" id="date" required/>
    149 			</br>
    150 			<label for="emplacement">Emplacement</label>
    151 			<select name="emplacement" id="emplacement" required/>
    152 				<option value='grand-brezouard'>Grand Brézouard</option>
    153 				<option value='champ-du-diable'>Champ du Diable</option>
    154 				<option value='abris-fuste'>Abris Fuste</option>
    155 				<option value='petit-brezouard'>Petit Brézouard</option>
    156 			</select>
    157 		</fieldset>
    158 		<fieldset>
    159 			<legend>Neige</legend>
    160 			<label for="hauteur">hauteur (cm)</label>
    161 			<input type="number" name="hauteur" id="hauteur" min="0" max="100" step="0.1" value="0" size="3" required/>
    162 			<span>cm</span>
    163 		</fieldset>
    164 		<fieldset>
    165 			<legend>Météo</legend>
    166 			<label for="tempmoy">température moyenne</label>
    167 			<input type="number" name="moyenne" id="tempmoy" min="-30" max="50" step="0.1" value="15" size="3" required/>
    168 			<span>°C</span>
    169 			<label for="pression">Pression atmosphérique (hPa)</label>
    170 			<input type="number" name="pression" id="pression" min="800" max="1500" step="0.01" value="1013.25" required/>
    171 			<span class="validity"></span>
    172 		</fieldset>
    173 		<fieldset>
    174 			<legend>Remarques</legend>
    175 			<textarea id="commentaire" name="commentaire" rows="4" cols="50" placeholder="Comentaire..."></textarea>
    176 		</fieldset>
    177 		<p>
    178 		<button type="submit">Soumettre les informations</button>
    179 		</p>
    180 		<input type="reset" value="Réinitialiser">
    181 	</form>
    182 
    183 On y retrouve quelques exemples d'input. On peut par exemple contrôler les
    184 valeurs possibles pour la hauteur de neige avec les directives `min`, `max` et
    185 `step`. On peut aussi noter certains input comme nécessaires avec `required`.
    186 
    187 Quand la personne sondée appuie sur le bouton soumettre, le script qui se trouve
    188 à `/cgi-bin/parse.cgi` sera exécuté et recevra dans `stdin` les données du
    189 formulaire. Si l'on veut récupérer les données sous la forme d'un csv il faut
    190 faire tourner quelques moulinettes. J'ai découvert avec beaucoup d'étonnement
    191 que le texte généré par le formulaire post varie d'un navigateur à un autre.
    192 Je sais donc uniquement que mon code fonctionne avec ma version de Firefox et
    193 de Chromium.
    194 
    195 Les grandes étapes du script sont de récupérer le contenu :
    196 
    197 	POST_STRING=$(cat)
    198 
    199 La commande pour récupérer la valeur d'une question en se basant sur l'id de la
    200 balise html correspondante :
    201 
    202 	recuperervaleur() {
    203 		echo $POST_STRING | sed -n "/name=\"$1\"/,/------/ p" | grep -v "Contennt-\|------\|^ \|^$"
    204 	}
    205 
    206 La boucle pour aller toutes les chercher
    207 
    208 	for i in  daterecolte emplacement hauteur moyenne pression commentaire
    209 	do
    210 		if [ $i = "commentaire" ]
    211 		then
    212 			if [ ! $(echo $data | grep -q "commentaire") ]
    213 			then
    214 				recuperervaleur $i | sed -z 's/\n/\\n/g;s/	/    /g' | sed 's/\\n$/\n/' >> $temp
    215 			else
    216 				echo "" >> $temp
    217 			fi
    218 		else
    219 			recuperervaleur $i >> $temp
    220 		fi
    221 	done
    222 
    223 La boucle traite différemment le champ commentaire pour remplacer les retours à
    224 la ligne par `\n` histoire de pouvoir les stocker en TSV sur une seule ligne.
    225 Elle ajoute les valeurs dans un fichier temporaire `temp`. On traite ensuite
    226 ce fichier pour en faire un TSV dans un fichier nommé `res` :
    227 
    228 	cat $temp | tr '\n' '	' | sed 's/	$/\n/' >> res
    229 
    230 Vous devriez pouvoir assez facilement adapter ce code pour vos besoins. Par
    231 exemple, si le fichier `res` est gité, on peut finir le script en faisant un
    232 commit et ainsi enregistrer l'historique de toutes les réponses au sondage.
    233 
    234 ### Présenter les résultats
    235 
    236 Un avantage d'avoir un serveur web est que l'on peut publier les résultats
    237 assez facilement, y compris en temps réel. Si l'on a dans un fichier TSV les
    238 données suivantes :
    239 
    240 	a	b	d	g	h	e	q
    241 	a	c	d	g	e	r	t	f
    242 	r	t	c	d	a	f	b
    243 	e	a	c	g	e	d	f	v	b
    244 
    245 On peut avoir des statistiques de base sur l'occurence de chaque réponse en faisant
    246 
    247 	tr '	' '\n' data | sort | uniq -c | sort -nr
    248 	  4 e
    249 	  4 d
    250 	  4 a
    251 	  3 g
    252 	  3 f
    253 	  3 c
    254 	  3 b
    255 	  2 t
    256 	  2 r
    257 	  1 v
    258 	  1 q
    259 	  1 h
    260 
    261 Si la première colonne est une question donnée et que l'on veut étudier les réponses sur
    262 cette question en particulier on peut remplacer le `tr` par un simple `cut`
    263 
    264 	<<. cut -f1 | sort | uniq -c | sort -nr
    265 	  2 a
    266 	  1 r
    267 	  1 e
    268 
    269 Pour tout ce qui est des inputs radio et checkbox si vous voulez
    270 qu'apparaissent non pas les identifiants des balises mais le contenu mis dans
    271 la balise `<label>` vous pouvez utiliser la fonction suivante :
    272 
    273 	idtolabel() {
    274 		xargs -d'\n' -n1 sh -c 'grep "\"$1\"" 'fichier.html'' -- |
    275 		grep "label" |
    276 		sed -E 's:<[^>]*>::g;s:^	*::g' |
    277 		tr -d '<>
    278 	}
    279 
    280 à laquelle il faut passer les identifiants en argument.
    281 
    282 Pour afficher les sorties de toutes ces commandes le plus simplement possible
    283 vous pouvez ajouter en début de script
    284 
    285 	<<% cat
    286 	<meta charset="utf-8">
    287 	<pre>
    288 	%
    289 
    290 et à la fin fermer la balise `pre`
    291 
    292 	echo "</pre>"
    293 
    294 ### Commentaires divers
    295 
    296 L'esprit de ce système combiné à Kun et respl est en cours de développement
    297 pour avoir une interface web simple[^4]. Il faut noter qu'utiliser ce genre de
    298 systèmes avec alimentation d'un fichier texte contenant les résultats sur un
    299 serveur a l'avantage d'être très flexible. Si l'on créé une interface web, elle
    300 n'empêche pas "d'attaquer" le fichier texte autrement[^3]. Si à Katzele nous
    301 privilégions certaines interfaces pour des raisons mille fois évoquées, nous
    302 souhaitons avant tout faire en sorte que les services soient les plus inclusifs
    303 possible en utilisant des dénominateurs techniques sobres mais extensibles.
    304 
    305 Trois formulaires ont déja été créés et utilisés avec ce système avec succès.
    306 Il sera utilisé dans le cadre d'un projet de recherche participatif mené
    307 conjointement par l'EOST et la Jardin des Sciences de l'Université de
    308 Strasbourg. Il semble assez fiable et assez robuste pour des usages légers ne
    309 nécessitant pas des sondages complexes[^5] ou des fonctionnalités avancées type
    310 sauvegarde d'une réponse en cours de remplissage etc. Il est tout de même possible
    311 de conditionner l'accès au formulaire via un système d'authentification type
    312 HTTP_BASIC et éventuellement un petit contrôle si la personne authentifiée a
    313 déjà soumis une réponse.
    314 
    315 Dans les sondages menés à bien les formulaire n'avaient pas de css et il n'y a pas
    316 eu de soucis particulier à leurs remplissages. Les personnes sondées étaient de
    317 niveaux techniques très divers mais toutes relativement jeunes.
    318 
    319 Le plus ennuyant est d'écrire le formulaire html. Peut-être que cela pourrait
    320 être amélioré en produisant un petit moteur de génération de formulaire. Il est
    321 possible que ce soit un problème bien plus complexe qu'il n'y paraît et que ce
    322 soit du temps perdu ou le première marche vers une complexification abusive du
    323 système. Je pense tout de même faire un petit test un jour. Dans tous les cas
    324 si le moteur n'est pas satisfaisant cela n'empêche pas d'écrire de l'html à
    325 la main.
    326 
    327 [^1]: typiquement une association dans laquelle on connait les personnes et la quantité de réponses attendues.
    328 [^2]: côté client uniquement donc cela reste assez limité
    329 [^3]: en ssh directement, via un mail + une nouvelle moulinette, via un dépôt git sur le fichier est gité etc.
    330 [^4]: l'implémentation sera certainement très différente mais ce n'est pas bien important, il y a tellement peu de code derrière tout cela. L'esprit compte, le texte moins.
    331 [^5]: je pense notamment à l'idée de conditionner l'apparition de questions aux réponses données à d'autres questions. Remarque ça doit être possible avec du css, à tester.