Compare commits
10 Commits
2ff413efd3
...
6095bd26ce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6095bd26ce | ||
|
|
34154c7c4d | ||
|
|
23d5368f40 | ||
| 8d011bd818 | |||
| c718ddfd7c | |||
| 6a2ccb5d2b | |||
| ad09c3ec72 | |||
| 8d65ab03cf | |||
| 9159d2a082 | |||
| faedb4c80c |
11
LISEZMOI.md
11
LISEZMOI.md
@@ -29,7 +29,7 @@ C'est la description de wikipedia https://fr.wikipedia.org/wiki/Jugement_majorit
|
|||||||
|
|
||||||
(https://en.wikipedia.org/wiki/Majority_judgment)
|
(https://en.wikipedia.org/wiki/Majority_judgment)
|
||||||
|
|
||||||
L'implémentaion est très basique et miminale :
|
L'implémentation est très basique et miminale :
|
||||||
|
|
||||||
|langage|code|
|
|langage|code|
|
||||||
|-----|---------------------|
|
|-----|---------------------|
|
||||||
@@ -170,3 +170,12 @@ https://framagit.org/framasoft/framadate
|
|||||||
|
|
||||||
C'est un intégration de framadate dans yunohost.
|
C'est un intégration de framadate dans yunohost.
|
||||||
|
|
||||||
|
## Mieux Voter
|
||||||
|
|
||||||
|
https://app.mieuxvoter.fr/
|
||||||
|
|
||||||
|
Il est possible d'importer un csv.
|
||||||
|
|
||||||
|
https://github.com/MieuxVoter/majority-judgment-web-app
|
||||||
|
|
||||||
|
exemples sous samples/mieuxvoter
|
||||||
10
README.md
10
README.md
@@ -1,4 +1,4 @@
|
|||||||
# Glue to use majortiy judgement algorithm in various polls applications
|
# Glue to use majority judgement algorithm in various polls applications
|
||||||
|
|
||||||
Initial trigger of this project is implementation of this in Nextcloud poll app https://github.com/nextcloud/polls/issues/3472, project pushed by https://www.astrolabe.coop/
|
Initial trigger of this project is implementation of this in Nextcloud poll app https://github.com/nextcloud/polls/issues/3472, project pushed by https://www.astrolabe.coop/
|
||||||
|
|
||||||
@@ -14,7 +14,6 @@ https://en.wikipedia.org/wiki/Majority_judgment
|
|||||||
|
|
||||||
After some research most of implementation is done in https://github.com/MieuxVoter
|
After some research most of implementation is done in https://github.com/MieuxVoter
|
||||||
|
|
||||||
|
|
||||||
Sorry for inconvenience but currently only french version is available.
|
Sorry for inconvenience but currently only french version is available.
|
||||||
|
|
||||||
LISEZMOI.md
|
LISEZMOI.md
|
||||||
@@ -51,3 +50,10 @@ dev done on Ubuntu 24.04.2 LTS
|
|||||||
cd code
|
cd code
|
||||||
./check_csv.sh ../samples/nextcloud_poll_export/poll1.csv
|
./check_csv.sh ../samples/nextcloud_poll_export/poll1.csv
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
./check_csv.sh ../samples/nextcloud_poll_export/poll1.csv >../samples/0.json
|
||||||
|
```
|
||||||
|
|
||||||
|
et tester
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,37 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# SPDX-FileCopyrightText: 2025 artlog@l0g.eu
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
|
|
||||||
|
toolsdir=../lib
|
||||||
|
pushd $toolsdir >/dev/null
|
||||||
|
toolsdir=$(pwd)
|
||||||
|
source metascript.sh
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
while [[ $# > 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
*)
|
||||||
|
if [[ -z $csv_file ]]
|
||||||
|
then
|
||||||
csv_file="$1"
|
csv_file="$1"
|
||||||
python3 convert_nextcloud_poll_csv.py "$csv_file" 'Très Bien' 'Bien' 'Assez Bien' 'Passable' 'Insuffisant' 'A Rejeter'
|
else
|
||||||
|
parsemetaarg "$1"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
metarun=metarun
|
||||||
|
|
||||||
|
if [[ -z $csv_file ]]
|
||||||
|
then
|
||||||
|
log_error "Missing csv_file argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
enforcefile "$csv_file" exists
|
||||||
|
|
||||||
|
$metarun python3 convert_nextcloud_poll_csv.py "$csv_file" 'Très Bien' 'Bien' 'Assez Bien' 'Passable' 'Insuffisant' 'A Rejeter'
|
||||||
|
|||||||
@@ -3,41 +3,41 @@ import sys
|
|||||||
import csv
|
import csv
|
||||||
|
|
||||||
# using non modified nextcloud standard text poll
|
# using non modified nextcloud standard text poll
|
||||||
nom_mentions=['yes','maybe','','no']
|
mentions_name=['yes','maybe','','no']
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
csv_file=sys.argv[1]
|
csv_file=sys.argv[1]
|
||||||
if len(sys.argv) > 2:
|
if len(sys.argv) > 2:
|
||||||
nom_mentions=[]
|
mentions_name=[]
|
||||||
for i in range(2,len(sys.argv)):
|
for i in range(2,len(sys.argv)):
|
||||||
nom_mentions.append(sys.argv[i])
|
mentions_name.append(sys.argv[i])
|
||||||
else:
|
else:
|
||||||
print('missing file argument')
|
print('missing file argument')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
def mention_index(mention):
|
def mention_index(mention):
|
||||||
return nom_mentions.index(mention)
|
return mentions_name.index(mention)
|
||||||
|
|
||||||
verbose=False
|
verbose=False
|
||||||
|
|
||||||
mentions=len(nom_mentions)
|
mentions=len(mentions_name)
|
||||||
default_mention=mentions-1
|
default_mention=mentions-1
|
||||||
|
|
||||||
warnings=[]
|
warnings=[]
|
||||||
candidats={}
|
candidates={}
|
||||||
candidats_alias=[]
|
candidates_alias=[]
|
||||||
a_vote={}
|
a_vote={}
|
||||||
votes=[]
|
votes=[]
|
||||||
with open(csv_file,'r') as csv_fd:
|
with open(csv_file,'r') as csv_fd:
|
||||||
vote_reader = csv.reader(csv_fd, delimiter=',')
|
vote_reader = csv.reader(csv_fd, delimiter=',')
|
||||||
for row in vote_reader:
|
for row in vote_reader:
|
||||||
if len(candidats_alias) == 0:
|
if len(candidates_alias) == 0:
|
||||||
for i in range(2,len(row)):
|
for i in range(2,len(row)):
|
||||||
candidat_alias=row[i]
|
candidate_alias=row[i]
|
||||||
candidats_alias.append(candidat_alias)
|
candidates_alias.append(candidate_alias)
|
||||||
# no other name given
|
# no other name given
|
||||||
if not candidat_alias in candidats:
|
if not candidate_alias in candidates:
|
||||||
candidats[candidat_alias]=candidat_alias
|
candidates[candidate_alias]=candidate_alias
|
||||||
else:
|
else:
|
||||||
# check if not duplicated
|
# check if not duplicated
|
||||||
participant=row[0]
|
participant=row[0]
|
||||||
@@ -47,20 +47,20 @@ with open(csv_file,'r') as csv_fd:
|
|||||||
a_vote[participant]=row[1]
|
a_vote[participant]=row[1]
|
||||||
vote={}
|
vote={}
|
||||||
for i in range(2,len(row)):
|
for i in range(2,len(row)):
|
||||||
candidat_index=i-2
|
candidate_index=i-2
|
||||||
candidat_alias=candidats_alias[candidat_index]
|
candidate_alias=candidates_alias[candidate_index]
|
||||||
mention=row[i]
|
mention=row[i]
|
||||||
vote[candidat_alias]=mention_index(mention)
|
vote[candidate_alias]=mention_index(mention)
|
||||||
votes.append(vote)
|
votes.append(vote)
|
||||||
|
|
||||||
|
|
||||||
default_vote={}
|
default_vote={}
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print(','.join(candidats))
|
print(','.join(candidates))
|
||||||
print(','.join(nom_mentions))
|
print(','.join(mentions_name))
|
||||||
|
|
||||||
result = {'candidats':candidats,'votants':{'decompte':len(a_vote)},'mentions':nom_mentions,'votation':{'votes':votes}}
|
result = {'candidates':candidates,'voters':{'count':len(a_vote)},'mentions':mentions_name,'votation':{'votes':votes}}
|
||||||
print(json.dumps(result))
|
print(json.dumps(result))
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
import json
|
|
||||||
import sys
|
|
||||||
from majority_judgment import majority_judgment
|
|
||||||
|
|
||||||
verbose=False
|
|
||||||
|
|
||||||
def collect_votes(votes,candidats,default_mention,warnings):
|
|
||||||
collect={}
|
|
||||||
for vote in votes:
|
|
||||||
# missing candidat in vote picks the worse one
|
|
||||||
for candidat in candidats:
|
|
||||||
if not candidat in vote:
|
|
||||||
vote[candidat]=default_mention
|
|
||||||
|
|
||||||
for candidat,mention in vote.items():
|
|
||||||
if mention > default_mention or mention < 0:
|
|
||||||
mention = default_mention
|
|
||||||
warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée")
|
|
||||||
if candidat in collect:
|
|
||||||
if mention in collect[candidat]:
|
|
||||||
collect[candidat][mention]=collect[candidat][mention]+1
|
|
||||||
else:
|
|
||||||
collect[candidat][mention]=1
|
|
||||||
else:
|
|
||||||
collect[candidat]={mention:1}
|
|
||||||
return collect
|
|
||||||
|
|
||||||
def arrange_votes_par_candidat(votes,candidats,default_mention):
|
|
||||||
vpc={}
|
|
||||||
for candidat in candidats:
|
|
||||||
vpc[candidat]=[vote[candidat] if candidat in vote else default_mention for vote in votes]
|
|
||||||
return vpc
|
|
||||||
|
|
||||||
def jugement_majoritaire(poll):
|
|
||||||
|
|
||||||
verbose=False
|
|
||||||
crosscheck=True
|
|
||||||
|
|
||||||
votants=poll['votants']['decompte']
|
|
||||||
candidats=poll['candidats']
|
|
||||||
nombre_candidats=len(candidats)
|
|
||||||
|
|
||||||
# l'ordre des mentions est de la meilleure à la pire (reject)
|
|
||||||
nom_mentions=poll['mentions']
|
|
||||||
mentions=len(nom_mentions)
|
|
||||||
default_mention=mentions-1
|
|
||||||
|
|
||||||
votes=poll["votation"]["votes"]
|
|
||||||
if verbose:
|
|
||||||
print('candidats:' + str(candidats))
|
|
||||||
print(votes)
|
|
||||||
|
|
||||||
warnings=[]
|
|
||||||
|
|
||||||
collect=collect_votes(votes,list(candidats),default_mention,warnings)
|
|
||||||
if verbose:
|
|
||||||
print(collect)
|
|
||||||
|
|
||||||
votant_median_check= votants / 2 if votants % 2 == 0 else ((votants-1) / 2) +1
|
|
||||||
|
|
||||||
votant_median=votants // 2 + votants % 2
|
|
||||||
|
|
||||||
if votant_median_check != votant_median:
|
|
||||||
print('[ERROR] le nombre median de votants semble erroné. contactez le developpeur de ce code.' + str(votant_median_check))
|
|
||||||
|
|
||||||
merite={}
|
|
||||||
mention_mediane={}
|
|
||||||
merite_pourcent={}
|
|
||||||
|
|
||||||
votes_par_candidat=arrange_votes_par_candidat(votes,candidats,mentions-1)
|
|
||||||
|
|
||||||
# cumul : du meilleur au pire
|
|
||||||
# range_mentions = range(len(mentions))
|
|
||||||
# cumul du pire au meilleur
|
|
||||||
range_mentions = range(mentions-1,-1,-1)
|
|
||||||
|
|
||||||
for candidat in list(candidats):
|
|
||||||
vote=collect[candidat]
|
|
||||||
cumul=0
|
|
||||||
m=[0 for i in range(mentions)]
|
|
||||||
mention_m=None
|
|
||||||
pourcent=[0 for i in range(mentions)]
|
|
||||||
for mention in range_mentions:
|
|
||||||
if mention in vote:
|
|
||||||
cumul=cumul+vote[mention]
|
|
||||||
pourcent[mention]= ( 100 * vote[mention] ) / votants
|
|
||||||
if cumul >= votant_median and mention_m is None:
|
|
||||||
mention_m=mention
|
|
||||||
m[mention]=cumul
|
|
||||||
if cumul < votants:
|
|
||||||
print('[ERROR] le cumul des votes doit correspondre au nombre de votants. contactez le developpeur de ce code.')
|
|
||||||
mention_mediane[candidat]=mention_m
|
|
||||||
merite[candidat]=m
|
|
||||||
merite_pourcent[candidat]=pourcent
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
print(merite)
|
|
||||||
print(mention_mediane)
|
|
||||||
|
|
||||||
# les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure )
|
|
||||||
found=[]
|
|
||||||
for mention in range(0,mentions):
|
|
||||||
for candidat,merite_median in mention_mediane.items():
|
|
||||||
if merite_median == mention:
|
|
||||||
found.append({candidat:candidats[candidat]})
|
|
||||||
if len(found) > 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
print(found)
|
|
||||||
print(nom_mentions[mention])
|
|
||||||
|
|
||||||
# expanded=expand_collect(collect,list(candidats),mentions)
|
|
||||||
if verbose:
|
|
||||||
print(votes_par_candidat)
|
|
||||||
|
|
||||||
result = {'resultat':{'mention':nom_mentions[mention],'candidats':found},'merite':merite,'profil':merite_pourcent,"warnings":warnings}
|
|
||||||
|
|
||||||
if crosscheck:
|
|
||||||
# cross check with a well known implementation
|
|
||||||
result["crosscheck"]=majority_judgment(votes_par_candidat, reverse=True)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
124
code/majority_judgment_method/__init__.py
Normal file
124
code/majority_judgment_method/__init__.py
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from majority_judgment import majority_judgment
|
||||||
|
|
||||||
|
verbose=False
|
||||||
|
|
||||||
|
def collect_votes(votes,candidates,default_mention,warnings):
|
||||||
|
collect={}
|
||||||
|
for vote in votes:
|
||||||
|
# missing candidate in vote picks the worse one
|
||||||
|
for candidate in candidates:
|
||||||
|
if not candidate in vote:
|
||||||
|
vote[candidate]=default_mention
|
||||||
|
|
||||||
|
for candidate,mention in vote.items():
|
||||||
|
if mention > default_mention or mention < 0:
|
||||||
|
mention = default_mention
|
||||||
|
warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée")
|
||||||
|
if candidate in collect:
|
||||||
|
if mention in collect[candidate]:
|
||||||
|
collect[candidate][mention]=collect[candidate][mention]+1
|
||||||
|
else:
|
||||||
|
collect[candidate][mention]=1
|
||||||
|
else:
|
||||||
|
collect[candidate]={mention:1}
|
||||||
|
return collect
|
||||||
|
|
||||||
|
def arrange_votes_by_candidate(votes,candidates,default_mention):
|
||||||
|
vpc={}
|
||||||
|
for candidate in candidates:
|
||||||
|
vpc[candidate]=[vote[candidate] if candidate in vote else default_mention for vote in votes]
|
||||||
|
return vpc
|
||||||
|
|
||||||
|
def majority_judgment_run(poll):
|
||||||
|
|
||||||
|
verbose=False
|
||||||
|
crosscheck=True
|
||||||
|
|
||||||
|
voters=poll['voters']['count']
|
||||||
|
candidates=poll['candidates']
|
||||||
|
nombre_candidates=len(candidates)
|
||||||
|
|
||||||
|
# l'ordre des mentions est de la meilleure à la pire (reject)
|
||||||
|
nom_mentions=poll['mentions']
|
||||||
|
mentions=len(nom_mentions)
|
||||||
|
default_mention=mentions-1
|
||||||
|
|
||||||
|
votes=poll["votation"]["votes"]
|
||||||
|
if verbose:
|
||||||
|
print('candidates:' + str(candidates))
|
||||||
|
print(votes)
|
||||||
|
|
||||||
|
warnings=[]
|
||||||
|
|
||||||
|
collect=collect_votes(votes,list(candidates),default_mention,warnings)
|
||||||
|
if verbose:
|
||||||
|
print(collect)
|
||||||
|
|
||||||
|
voter_median_check= voters / 2 if voters % 2 == 0 else ((voters-1) / 2) +1
|
||||||
|
|
||||||
|
voter_median=voters // 2 + voters % 2
|
||||||
|
|
||||||
|
if voter_median_check != voter_median:
|
||||||
|
print('[ERROR] le nombre median de voters semble erroné. contactez le developpeur de ce code.' + str(voter_median_check))
|
||||||
|
|
||||||
|
merit={}
|
||||||
|
mention_mediane={}
|
||||||
|
merit_pourcent={}
|
||||||
|
|
||||||
|
votes_by_candidate=arrange_votes_by_candidate(votes,candidates,mentions-1)
|
||||||
|
|
||||||
|
# cumul : du meilleur au pire
|
||||||
|
# range_mentions = range(len(mentions))
|
||||||
|
# cumul du pire au meilleur
|
||||||
|
range_mentions = range(mentions-1,-1,-1)
|
||||||
|
|
||||||
|
for candidate in list(candidates):
|
||||||
|
vote=collect[candidate]
|
||||||
|
cumul=0
|
||||||
|
m=[0 for i in range(mentions)]
|
||||||
|
mention_m=None
|
||||||
|
pourcent=[0 for i in range(mentions)]
|
||||||
|
for mention in range_mentions:
|
||||||
|
if mention in vote:
|
||||||
|
cumul=cumul+vote[mention]
|
||||||
|
pourcent[mention]= ( 100 * vote[mention] ) / voters
|
||||||
|
if cumul >= voter_median and mention_m is None:
|
||||||
|
mention_m=mention
|
||||||
|
m[mention]=cumul
|
||||||
|
if cumul < voters:
|
||||||
|
print('[ERROR] cumulated votes should match voters. Contact this code developer.')
|
||||||
|
mention_mediane[candidate]=mention_m
|
||||||
|
merit[candidate]=m
|
||||||
|
merit_pourcent[candidate]=pourcent
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print(merit)
|
||||||
|
print(mention_mediane)
|
||||||
|
|
||||||
|
# les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure )
|
||||||
|
found=[]
|
||||||
|
for mention in range(0,mentions):
|
||||||
|
for candidate,merit_median in mention_mediane.items():
|
||||||
|
if merit_median == mention:
|
||||||
|
found.append({candidate:candidates[candidate]})
|
||||||
|
if len(found) > 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print(found)
|
||||||
|
print(nom_mentions[mention])
|
||||||
|
|
||||||
|
# expanded=expand_collect(collect,list(candidates),mentions)
|
||||||
|
if verbose:
|
||||||
|
print(votes_by_candidatee)
|
||||||
|
|
||||||
|
result = {'result':{'mention':nom_mentions[mention],'candidates':found},'merit':merit,'profil':merit_pourcent,"warnings":warnings}
|
||||||
|
|
||||||
|
if crosscheck:
|
||||||
|
# cross check with a well known implementation
|
||||||
|
result["crosscheck"]=majority_judgment(votes_by_candidate, reverse=True)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
@@ -21,9 +21,9 @@ if ($verbose) {
|
|||||||
var_dump($poll);
|
var_dump($poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
$votants=$poll['votants']['decompte'];
|
$voters=$poll['voters']['count'];
|
||||||
$candidats=$poll['candidats'];
|
$candidates=$poll['candidates'];
|
||||||
$nombre_candidats=count($candidats);
|
$nombre_candidates=count($candidates);
|
||||||
|
|
||||||
# l'ordre des mentions est de la meilleure à la pire (reject)
|
# l'ordre des mentions est de la meilleure à la pire (reject)
|
||||||
$nom_mentions=$poll['mentions'];
|
$nom_mentions=$poll['mentions'];
|
||||||
@@ -33,22 +33,22 @@ $default_mention=$mentions-1;
|
|||||||
|
|
||||||
$votes=$poll["votation"]["votes"];
|
$votes=$poll["votation"]["votes"];
|
||||||
if ($verbose) {
|
if ($verbose) {
|
||||||
print("candidats\n");
|
print("candidates\n");
|
||||||
var_dump($candidats);
|
var_dump($candidates);
|
||||||
print("votes:\n");
|
print("votes:\n");
|
||||||
var_dump($votes);
|
var_dump($votes);
|
||||||
}
|
}
|
||||||
|
|
||||||
$warnings=[];
|
$warnings=[];
|
||||||
$default_vote=[];
|
$default_vote=[];
|
||||||
foreach ($candidats as $candidat => $nom_candidat ) {
|
foreach ($candidates as $candidat => $nom_candidat ) {
|
||||||
$default_vote[$candidat]=$default_mention;
|
$default_vote[$candidat]=$default_mention;
|
||||||
}
|
}
|
||||||
|
|
||||||
$collect=[];
|
$collect=[];
|
||||||
foreach ($votes as $vote) {
|
foreach ($votes as $vote) {
|
||||||
# missing candidat in vote is the worts one
|
# missing candidat in vote is the worts one
|
||||||
foreach ($candidats as $candidat => $nom_candidat ) {
|
foreach ($candidates as $candidat => $nom_candidat ) {
|
||||||
if (! array_key_exists($candidat,$vote)) {
|
if (! array_key_exists($candidat,$vote)) {
|
||||||
$vote[$candidat]=$default_mention;
|
$vote[$candidat]=$default_mention;
|
||||||
}
|
}
|
||||||
@@ -78,24 +78,24 @@ if ($verbose) {
|
|||||||
print(json_encode($collect));
|
print(json_encode($collect));
|
||||||
}
|
}
|
||||||
|
|
||||||
$votant_median_check= ($votants % 2 == 0) ? intdiv($votants,2) : intdiv(($votants-1),2) + 1;
|
$voter_median_check= ($voters % 2 == 0) ? intdiv($voters,2) : intdiv(($voters-1),2) + 1;
|
||||||
|
|
||||||
$votant_median=intdiv($votants, 2) + $votants % 2;
|
$voter_median=intdiv($voters, 2) + $voters % 2;
|
||||||
|
|
||||||
if ( $votant_median_check != $votant_median ) {
|
if ( $voter_median_check != $voter_median ) {
|
||||||
print('[ERROR] le nombre median de votants (' . $votant_median_check . '/' . $votant_median . ') semble erroné. contactez le developpeur de ce code.');
|
print('[ERROR] le nombre median de voters (' . $voter_median_check . '/' . $voter_median . ') semble erroné. contactez le developpeur de ce code.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$merite=[];
|
$merit=[];
|
||||||
$mention_mediane=[];
|
$mention_mediane=[];
|
||||||
$merite_pourcent=[];
|
$merit_pourcent=[];
|
||||||
|
|
||||||
# cumul : du meilleur au pire
|
# cumul : du meilleur au pire
|
||||||
# range_mentions = range(count(mentions))
|
# range_mentions = range(count(mentions))
|
||||||
# cumul du pire au meilleur
|
# cumul du pire au meilleur
|
||||||
$range_mentions = $mentions;
|
$range_mentions = $mentions;
|
||||||
|
|
||||||
foreach ($candidats as $candidat => $nom_candidat) {
|
foreach ($candidates as $candidat => $nom_candidat) {
|
||||||
$vote=$collect[$candidat];
|
$vote=$collect[$candidat];
|
||||||
$cumul=0;
|
$cumul=0;
|
||||||
for ($i=0; $i < $range_mentions; $i ++) {
|
for ($i=0; $i < $range_mentions; $i ++) {
|
||||||
@@ -106,24 +106,24 @@ foreach ($candidats as $candidat => $nom_candidat) {
|
|||||||
for ($mention=$range_mentions -1; $mention >=0; $mention --) {
|
for ($mention=$range_mentions -1; $mention >=0; $mention --) {
|
||||||
if ( array_key_exists($mention,$vote) ) {
|
if ( array_key_exists($mention,$vote) ) {
|
||||||
$cumul=$cumul+$vote[$mention];
|
$cumul=$cumul+$vote[$mention];
|
||||||
$pourcent[$mention]= ( 100 * $vote[$mention] ) / $votants;
|
$pourcent[$mention]= ( 100 * $vote[$mention] ) / $voters;
|
||||||
}
|
}
|
||||||
if ($cumul >= $votant_median and $mention_m == null ) {
|
if ($cumul >= $voter_median and $mention_m == null ) {
|
||||||
$mention_m=$mention;
|
$mention_m=$mention;
|
||||||
}
|
}
|
||||||
$m[$mention]=$cumul;
|
$m[$mention]=$cumul;
|
||||||
}
|
}
|
||||||
if ($cumul < $votants) {
|
if ($cumul < $voters) {
|
||||||
print("[ERROR] le cumul des votes " . $cumul . " doit correspondre au nombre de votants. contactez le developpeur de ce code.");
|
print("[ERROR] votes cumulated " . $cumul . " should match voters. Contact this code developer.");
|
||||||
}
|
}
|
||||||
$mention_mediane[$candidat]=$mention_m;
|
$mention_mediane[$candidat]=$mention_m;
|
||||||
$merite[$candidat]=$m;
|
$merit[$candidat]=$m;
|
||||||
$merite_pourcent[$candidat]=$pourcent;
|
$merit_pourcent[$candidat]=$pourcent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($verbose) {
|
if ($verbose) {
|
||||||
print("\nmerite:\n");
|
print("\nmerit:\n");
|
||||||
print(json_encode($merite));
|
print(json_encode($merit));
|
||||||
print("\nmention_mediane:\n");
|
print("\nmention_mediane:\n");
|
||||||
print(json_encode($mention_mediane));
|
print(json_encode($mention_mediane));
|
||||||
}
|
}
|
||||||
@@ -132,10 +132,10 @@ if ($verbose) {
|
|||||||
$found=[];
|
$found=[];
|
||||||
|
|
||||||
for ($mention = 0; $mention < $mentions; $mention ++) {
|
for ($mention = 0; $mention < $mentions; $mention ++) {
|
||||||
foreach ($mention_mediane as $candidat => $merite_median)
|
foreach ($mention_mediane as $candidat => $merit_median)
|
||||||
if ($merite_median == $mention) {
|
if ($merit_median == $mention) {
|
||||||
$item=[];
|
$item=[];
|
||||||
$item[$candidat]=$candidats[$candidat];
|
$item[$candidat]=$candidates[$candidat];
|
||||||
array_push($found,$item);
|
array_push($found,$item);
|
||||||
}
|
}
|
||||||
if (count($found) > 0) {
|
if (count($found) > 0) {
|
||||||
@@ -148,7 +148,7 @@ if ($verbose) {
|
|||||||
print($nom_mentions[$mention]);
|
print($nom_mentions[$mention]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = ['resultat'=> ['mention'=>$nom_mentions[$mention],'candidats' => $found],'merite' => $merite,'profil' => $merite_pourcent,"warnings" => $warnings];
|
$result = ['result'=> ['mention'=>$nom_mentions[$mention],'candidates' => $found],'merit' => $merit,'profil' => $merit_pourcent,"warnings" => $warnings];
|
||||||
|
|
||||||
print(json_encode($result));
|
print(json_encode($result));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from jugement_majoritaire import jugement_majoritaire
|
from majority_judgment_method import majority_judgment_run
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
poll_file=sys.argv[1]
|
poll_file=sys.argv[1]
|
||||||
@@ -16,6 +16,6 @@ with open(poll_file,'r') as poll_fd:
|
|||||||
if verbose:
|
if verbose:
|
||||||
print(poll)
|
print(poll)
|
||||||
|
|
||||||
result = jugement_majoritaire(poll)
|
result = majority_judgment_run(poll)
|
||||||
|
|
||||||
print(json.dumps(result))
|
print(json.dumps(result))
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
# contexte
|
# contexte
|
||||||
|
|
||||||
Choix des noms de mentions
|
Choix des noms de mentions
|
||||||
|
|
||||||
|
|
||||||
https://fr.wikipedia.org/wiki/Jugement_majoritaire
|
https://fr.wikipedia.org/wiki/Jugement_majoritaire
|
||||||
vs
|
vs
|
||||||
https://en.wikipedia.org/wiki/Jugement_majoritaire
|
https://en.wikipedia.org/wiki/Jugement_majoritaire
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
# Nextcloud Dev En
|
# Nextcloud Dev En
|
||||||
|
|
||||||
|
two options
|
||||||
|
|
||||||
|
one created manualy with a simple podman and a local database
|
||||||
|
|
||||||
|
one fully under podman, done on nextcloud conference
|
||||||
|
|
||||||
|
# Option 1 / simple podman
|
||||||
|
|
||||||
Create a dev env for nextcloud
|
Create a dev env for nextcloud
|
||||||
|
|
||||||
setup databse :
|
setup database :
|
||||||
|
|
||||||
```
|
```
|
||||||
./setupdatabase.sh
|
./setupdatabase.sh
|
||||||
@@ -63,3 +71,50 @@ utiliser la base de donnee postgres et non le SQLLite ?
|
|||||||
|
|
||||||
./migrate_db_sqlite2postgres.sh
|
./migrate_db_sqlite2postgres.sh
|
||||||
|
|
||||||
|
|
||||||
|
# NEW PLAIN nextcloud dev
|
||||||
|
|
||||||
|
setup
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@github.com:juliusknorr/nextcloud-docker-dev.git
|
||||||
|
git git@github.com:nextcloud/server.git
|
||||||
|
```
|
||||||
|
|
||||||
|
check nextcloud-docker-dev.env then
|
||||||
|
|
||||||
|
```
|
||||||
|
cp nextcloud-docker-dev.env nextcloud-docker-dev.git/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
https setup, local private PKI.
|
||||||
|
|
||||||
|
missing setup cert and setupcert host ... mkcert compilation + install
|
||||||
|
|
||||||
|
update-certs update-hosts
|
||||||
|
|
||||||
|
https://nextcloud-dev.l0g.eu
|
||||||
|
|
||||||
|
|
||||||
|
then will be done as sudo ( RootLess or podman limitation ? )
|
||||||
|
|
||||||
|
```
|
||||||
|
./runit.sh dryrun up
|
||||||
|
```
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
```
|
||||||
|
./runit.sh up
|
||||||
|
```
|
||||||
|
|
||||||
|
stop
|
||||||
|
|
||||||
|
```
|
||||||
|
./runit.sh down
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Pour les mails : https://mail-dev.l0g.eu/#
|
||||||
|
|
||||||
|
un MailHog est installé !
|
||||||
@@ -11,5 +11,13 @@ flavor=dev
|
|||||||
|
|
||||||
database_name=nextcloud_$flavor
|
database_name=nextcloud_$flavor
|
||||||
username=nextcloud_$flavor
|
username=nextcloud_$flavor
|
||||||
|
|
||||||
|
# postgres
|
||||||
db_port=5432
|
db_port=5432
|
||||||
db_hostname=127.0.0.1
|
db_hostname=127.0.0.1
|
||||||
|
dbtype_nextcloude=pgsql
|
||||||
|
|
||||||
|
# mariadb/mysql
|
||||||
|
db_port=3306
|
||||||
|
db_hostname=127.0.0.1
|
||||||
|
dbtype_nextcloud=mysql
|
||||||
|
|||||||
@@ -1,30 +1,72 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# SPDX-FileCopyrightText: 2025 artlog@l0g.eu
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
# metascript to include
|
# metascript to include
|
||||||
#
|
#
|
||||||
# usual way if no parameters used by outer script :
|
# to generate file header for caller script do :
|
||||||
#
|
# bash <relative_path_to>/metascript.sh header
|
||||||
# source $(dirname "$0")/metascript.sh
|
# ex:
|
||||||
#
|
# bash lib/metascript.sh header
|
||||||
# defaultmetainit $@
|
|
||||||
|
# if called directly
|
||||||
|
if [[ "$0" =~ ^(.*)/metascript.sh$ ]]
|
||||||
|
then
|
||||||
|
prefix=${BASH_REMATCH[1]}
|
||||||
|
if [[ $1 == header ]]
|
||||||
|
then
|
||||||
|
cat <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
# SPDX-FileCopyrightText: 2025 artlog@l0g.eu
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
#
|
#
|
||||||
|
# sample to include this script.
|
||||||
|
toolsdir=$prefix
|
||||||
|
pushd \$toolsdir >/dev/null
|
||||||
|
toolsdir=\$(pwd)
|
||||||
|
source metascript.sh
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
while [[ \$# > 0 ]]
|
||||||
|
do
|
||||||
|
case "\$1" in
|
||||||
|
*)
|
||||||
|
parsemetaarg "\$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo "[WARNING] only header argument is supported. (prefix=$prefix)" >&2
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$metascript_included" == "yes" ]]
|
||||||
|
then
|
||||||
|
log_warn "metascript already included ($0)"
|
||||||
|
else
|
||||||
|
|
||||||
metascript_included=yes
|
metascript_included=yes
|
||||||
|
|
||||||
|
|
||||||
|
# at this step $(pwd) should be this of metascript.sh
|
||||||
|
# while $0 is this of caller script using metascript
|
||||||
|
|
||||||
|
if [[ -z $toolsdir ]]
|
||||||
|
then
|
||||||
# assume all tools are in lib/
|
# assume all tools are in lib/
|
||||||
toolsdir=$(dirname $(readlink -f $0))/lib
|
toolsdir=$(dirname $(readlink -f $0))/lib
|
||||||
# all tools resources are relative to this directory
|
# all tools resources are relative to this directory
|
||||||
|
fi
|
||||||
# project directory
|
|
||||||
# relative
|
|
||||||
# toolsparentdir=$(realpath --relative-to "$(pwd)" $(readlink -f $0))/
|
|
||||||
# absolute
|
|
||||||
toolsparentdir=$(realpath $(readlink -f $0))/
|
|
||||||
|
|
||||||
if [[ -z $log_functions ]]
|
if [[ -z $log_functions ]]
|
||||||
then
|
then
|
||||||
log_functions=$toolsdir/log_functions.sh
|
log_functions=$toolsdir/log_functions.sh
|
||||||
[[ -f $log_functions ]] || { echo "[FATAL] Missing $log_functions" >&2 ; exit 1 ;}
|
[[ -f $log_functions ]] || { echo "[FATAL] Missing $log_functions , toolsdir=$toolsdir script=$0" >&2 ; exit 1 ;}
|
||||||
source $log_functions
|
source $log_functions
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -36,7 +78,7 @@ metascript commands :
|
|||||||
help|usage help or usage of this {$0} tool
|
help|usage help or usage of this {$0} tool
|
||||||
dryrun|show|showdoc display what should/will be done
|
dryrun|show|showdoc display what should/will be done
|
||||||
|
|
||||||
defersource= script file defining defer() non sandard function
|
defersource= script file defining defer() non standard function
|
||||||
defer= defer function to use, default is showdoc
|
defer= defer function to use, default is showdoc
|
||||||
toolsresourcesdir= where to pick resource
|
toolsresourcesdir= where to pick resource
|
||||||
default to parent of script $toolsresourcesdir
|
default to parent of script $toolsresourcesdir
|
||||||
@@ -54,7 +96,12 @@ usage()
|
|||||||
|
|
||||||
showinfo()
|
showinfo()
|
||||||
{
|
{
|
||||||
echo $@
|
echo "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
metarun()
|
||||||
|
{
|
||||||
|
$defer $metasudo "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
showdoc()
|
showdoc()
|
||||||
@@ -62,10 +109,10 @@ showdoc()
|
|||||||
if [[ $1 =~ ^tools/ ]]
|
if [[ $1 =~ ^tools/ ]]
|
||||||
then
|
then
|
||||||
# assumes it handles ENV_METASCRIPT_DEFER
|
# assumes it handles ENV_METASCRIPT_DEFER
|
||||||
$@
|
"$@"
|
||||||
else
|
else
|
||||||
echo '```'
|
echo '```'
|
||||||
autoquoteargs $@
|
autoquoteargs "$@"
|
||||||
echo
|
echo
|
||||||
echo '```'
|
echo '```'
|
||||||
fi
|
fi
|
||||||
@@ -92,11 +139,11 @@ execredirectfrom()
|
|||||||
if [[ -n $defer ]]
|
if [[ -n $defer ]]
|
||||||
then
|
then
|
||||||
echo '```'
|
echo '```'
|
||||||
autoquoteargs $@
|
autoquoteargs "$@"
|
||||||
echo ' < '"$tofile"
|
echo ' < '"$tofile"
|
||||||
echo '```'
|
echo '```'
|
||||||
else
|
else
|
||||||
$@ < $tofile
|
"$@" < $tofile
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +154,7 @@ execredirectto()
|
|||||||
if [[ -n $defer ]]
|
if [[ -n $defer ]]
|
||||||
then
|
then
|
||||||
echo '```'
|
echo '```'
|
||||||
autoquoteargs $@
|
autoquoteargs "$@"
|
||||||
echo ' > '"$tofile"
|
echo ' > '"$tofile"
|
||||||
echo '```'
|
echo '```'
|
||||||
else
|
else
|
||||||
@@ -115,19 +162,34 @@ execredirectto()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
execredirecttoroot()
|
||||||
|
{
|
||||||
|
tofile=$1
|
||||||
|
shift
|
||||||
|
if [[ -n $defer ]]
|
||||||
|
then
|
||||||
|
echo '```'
|
||||||
|
autoquoteargs "$@"
|
||||||
|
echo ' | sudo tee '"$tofile"
|
||||||
|
echo '```'
|
||||||
|
else
|
||||||
|
"$@" | sudo tee $tofile
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
pipeto()
|
pipeto()
|
||||||
{
|
{
|
||||||
if [[ -n $defer ]]
|
if [[ -n $defer ]]
|
||||||
then
|
then
|
||||||
echo '```'
|
echo '```'
|
||||||
echo -n 'cat << EOF| '
|
echo -n 'cat << EOF| '
|
||||||
autoquoteargs $@
|
autoquoteargs "$@"
|
||||||
echo
|
echo
|
||||||
cat
|
cat
|
||||||
echo "EOF"
|
echo "EOF"
|
||||||
echo '```'
|
echo '```'
|
||||||
else
|
else
|
||||||
cat | $@
|
cat | "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +417,9 @@ parsemetaarg()
|
|||||||
dryrun|show|showdoc)
|
dryrun|show|showdoc)
|
||||||
defer=showdoc
|
defer=showdoc
|
||||||
;;
|
;;
|
||||||
|
metasudo=*)
|
||||||
|
metasudo=${1/metasudo=}
|
||||||
|
;;
|
||||||
help|usage)
|
help|usage)
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
@@ -528,7 +593,7 @@ check_variable_in()
|
|||||||
shift 2
|
shift 2
|
||||||
|
|
||||||
local value=""
|
local value=""
|
||||||
local values=$@
|
local values="$@"
|
||||||
|
|
||||||
eval value='$'"$var"
|
eval value='$'"$var"
|
||||||
|
|
||||||
@@ -570,17 +635,148 @@ get_timestamp_second()
|
|||||||
echo "$(date +"%Y%m%d%H%M%S")"
|
echo "$(date +"%Y%m%d%H%M%S")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
todo()
|
||||||
|
{
|
||||||
|
log_any TODO "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_resource_var() {
|
||||||
|
local varname="$1"
|
||||||
|
local default_value="$2"
|
||||||
|
|
||||||
|
eval value='$'"$varname"
|
||||||
|
if [[ -z $value ]]
|
||||||
|
then
|
||||||
|
echo "# ($0:metascript.sh:$LINENO) $(date)" >>$collect_context
|
||||||
|
if [[ -z $default_value ]]
|
||||||
|
then
|
||||||
|
log_error "resource $varname does not exists and no non empty default provided"
|
||||||
|
echo "# $varname=<MISSING>" >>$collect_context
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log_warn "($0) Using default value '$varname'='$default_value' HARDCODED in script : should be fixed with proper default file .resources.var, see traces in $collect_context"
|
||||||
|
read "$varname" <<<"$default_value"
|
||||||
|
echo "$varname=$default_value" >>$collect_context
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_resources_var()
|
||||||
|
{
|
||||||
|
local resource_var="$1"
|
||||||
|
enforcefile "$resource_var" exists
|
||||||
|
while read line
|
||||||
|
do
|
||||||
|
if [[ $line =~ ^([a-zA-Z0-9_]+)=(.+)$ ]]
|
||||||
|
then
|
||||||
|
varname=${BASH_REMATCH[1]}
|
||||||
|
value=${BASH_REMATCH[2]}
|
||||||
|
read "$varname" <<<"$value"
|
||||||
|
elif [[ $line =~ ^# ]]
|
||||||
|
then
|
||||||
|
echo "$line"
|
||||||
|
else
|
||||||
|
log_warn "Invalid syntax in $resource_var '$line' does not match any expected expression"
|
||||||
|
fi
|
||||||
|
done <"$resource_var"
|
||||||
|
}
|
||||||
|
|
||||||
|
# allow to check mounted points
|
||||||
|
mountpoint_get_device()
|
||||||
|
{
|
||||||
|
local mount_point="$1"
|
||||||
|
$defer awk "{ if (\$2 == \""$mount_point"\") print \$1 ;}" /proc/mounts
|
||||||
|
}
|
||||||
|
|
||||||
|
device_get_mountpoints()
|
||||||
|
{
|
||||||
|
local device="$1"
|
||||||
|
$defer awk "{ if (\$1 == \""$device"\") print \$2 ;}" /proc/mounts
|
||||||
|
}
|
||||||
|
|
||||||
|
mount_if_needed()
|
||||||
|
{
|
||||||
|
local mountpoint="$1"
|
||||||
|
local mountdevice="$2"
|
||||||
|
local param="$3"
|
||||||
|
device=$(mountpoint_get_device "$mountpoint")
|
||||||
|
|
||||||
|
enforcedir "$mountpoint" exists
|
||||||
|
# device is a device ...
|
||||||
|
# enforcefile "$mountdevice" exists
|
||||||
|
|
||||||
|
if [[ -z $device ]]
|
||||||
|
then
|
||||||
|
$metarun mount $param "$mountdevice" "$device"
|
||||||
|
elif [[ "$device" == "$mountdevice" ]]
|
||||||
|
then
|
||||||
|
log_info "$device already mounted on $mountdevice"
|
||||||
|
else
|
||||||
|
log_warn "Another device $device is mounted on $mountdevice, not $mountdevice"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
umount_if_needed()
|
||||||
|
{
|
||||||
|
local mountpoint="$1"
|
||||||
|
local mountdevice="$2"
|
||||||
|
device=$(mountpoint_get_device "$mountpoint")
|
||||||
|
if [[ -n "$device" ]]
|
||||||
|
then
|
||||||
|
if [[ "$device" == "$mountpoint" ]]
|
||||||
|
then
|
||||||
|
$metarun umount "$mountpoint"
|
||||||
|
else
|
||||||
|
log_warn "Another device $device is mounted on $mountdevice, not $mountdevice"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# collect all hardcoded values.
|
||||||
|
mkdir -p ~/.artlog
|
||||||
|
collect_context=~/.artlog/collect_context.var
|
||||||
|
|
||||||
|
if [[ -z $toolsresourcesdir ]]
|
||||||
|
then
|
||||||
|
# project directory
|
||||||
|
|
||||||
|
# from current $(pwd) will follow parent dir hierarchy to find .resources.var
|
||||||
|
dir="$(pwd)"
|
||||||
|
while [[ -n $dir ]] && [[ -d $dir ]] && [[ ! -f $dir/.resources.var ]]
|
||||||
|
do
|
||||||
|
new_dir=$(dirname "$dir")
|
||||||
|
if [[ $new_dir == $dir ]]
|
||||||
|
then
|
||||||
|
# protect against infinite loop
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
dir="$new_dir"
|
||||||
|
done
|
||||||
|
if [[ -f $dir/.resources.var ]]
|
||||||
|
then
|
||||||
|
toolsresourcesdir=$dir
|
||||||
|
else
|
||||||
if [[ -z $ENV_METASCRIPT_RESOURCESDIR ]]
|
if [[ -z $ENV_METASCRIPT_RESOURCESDIR ]]
|
||||||
then
|
then
|
||||||
toolsresourcesdir=$toolsparentdir
|
toolsresourcesdir=$toolsparentdir
|
||||||
else
|
else
|
||||||
toolsresourcesdir=$ENV_METASCRIPT_RESOURCESDIR
|
toolsresourcesdir=$ENV_METASCRIPT_RESOURCESDIR
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
resources_var=$toolsresourcesdir/.resources.var
|
||||||
|
if [[ -f $resources_var ]]
|
||||||
|
then
|
||||||
|
setup_resources_var "$resources_var"
|
||||||
|
else
|
||||||
|
log_warn "No $resources_var found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# quick way to give scl patches to fill scl_arg array
|
# quick way to give scl patches to fill scl_arg array
|
||||||
if [[ -f $toolsparentdir/.scl_env ]]
|
if [[ -f $toolsresourcesdir/.scl_env ]]
|
||||||
then
|
then
|
||||||
source $toolsparentdir/.scl_env
|
source $toolsresourcesdir/.scl_env
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# empty defer means doit
|
# empty defer means doit
|
||||||
@@ -588,6 +784,11 @@ defer=$ENV_METASCRIPT_DEFER
|
|||||||
|
|
||||||
showinfo=showinfo
|
showinfo=showinfo
|
||||||
|
|
||||||
allparms=$@
|
allparms="$@"
|
||||||
|
|
||||||
applymetaargs=applymetaargs
|
applymetaargs=applymetaargs
|
||||||
|
|
||||||
|
metarun=$defer
|
||||||
|
|
||||||
|
# metascript included
|
||||||
|
fi
|
||||||
|
|||||||
4
nextcloud_devenv/logs.sh
Normal file
4
nextcloud_devenv/logs.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
nextcloud_storage=/var/wwww/http/data
|
||||||
|
sudo -u www-data tail -f $nextcloud_storage/nextcloud.log
|
||||||
@@ -15,10 +15,16 @@ log_info "See https://docs.nextcloud.com/server/latest/admin_manual/configuratio
|
|||||||
|
|
||||||
source ./config_db_query.sh
|
source ./config_db_query.sh
|
||||||
|
|
||||||
# convert localhost of host into container virtual brdige hostname mapping
|
# convert localhost of host into container virtual bridge hostname mapping
|
||||||
#db_hostname=host.docker.internal
|
#db_hostname=host.docker.internal
|
||||||
#db_hostname=host.containers.internal
|
#db_hostname=host.containers.internal
|
||||||
# host loopback mapped address
|
# host loopback mapped address
|
||||||
db_hostname=10.1.1.13
|
db_hostname=10.1.1.13
|
||||||
|
# dbtype_nextcloud inherited from config_db_query
|
||||||
|
|
||||||
$defer ./run_occ.sh db:convert-type --password="$password" --port="$db_port" --all-apps pgsql "$username" "$db_hostname" "$database_name"
|
$defer ./run_occ.sh db:convert-type --password="$password" --port="$db_port" --all-apps "$dbtype_nextcloud" "$username" "$db_hostname" "$database_name"
|
||||||
|
|
||||||
|
if [[ $dbtype_nextcloud == mysql ]]
|
||||||
|
then
|
||||||
|
$defer ./run_occ.sh config:system:set mysql.utf8mb4 --type boolean --value="true"
|
||||||
|
fi
|
||||||
|
|||||||
72
nextcloud_devenv/nextcloud-docker-dev.env
Normal file
72
nextcloud_devenv/nextcloud-docker-dev.env
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
COMPOSE_PROJECT_NAME=master
|
||||||
|
|
||||||
|
# Default protocol to use for Nextcloud and other containers
|
||||||
|
# check the readme for details how to setup https
|
||||||
|
PROTOCOL=https
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
REPO_PATH_SERVER=/home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/nextcloud_devenv/server
|
||||||
|
|
||||||
|
# Specify a path to apps which will be shared between all containers. Useful for apps that support multiple nextcloud versions
|
||||||
|
# ADDITIONAL_APPS_PATH=/home/alice/nextcloud-docker-dev/workspace/server/apps-shared
|
||||||
|
|
||||||
|
# Stable releases root directory
|
||||||
|
# STABLE_ROOT_PATH=/home/alice/nextcloud-docker-dev/workspace
|
||||||
|
|
||||||
|
# Install Nextcloud apps per default
|
||||||
|
# NEXTCLOUD_AUTOINSTALL_APPS="viewer activity"
|
||||||
|
# Retry enabling apps for a provided amount of time (can be useful when using the containers in CI)
|
||||||
|
# NEXTCLOUD_AUTOINSTALL_APPS_WAIT_TIME=0
|
||||||
|
|
||||||
|
# Blackfire configuration
|
||||||
|
# BLACKFIRE_CLIENT_ID=
|
||||||
|
# BLACKFIRE_CLIENT_TOKEN=
|
||||||
|
# BLACKFIRE_SERVER_ID=
|
||||||
|
# BLACKFIRE_SERVER_TOKEN=
|
||||||
|
|
||||||
|
# By default the published ports are only accessible at 127.0.0.1 (your localhost).
|
||||||
|
# Set this to '0.0.0.0' to make them accessible from your whole local network.
|
||||||
|
# IP_BIND=127.0.0.1
|
||||||
|
|
||||||
|
# can be used to run separate setups besides each other
|
||||||
|
# DOCKER_SUBNET=192.168.15.0/24
|
||||||
|
# PORTBASE=815
|
||||||
|
|
||||||
|
|
||||||
|
# Main dns names for ssl proxy
|
||||||
|
# This can be used to append a custom domain name to the container names
|
||||||
|
DOMAIN_SUFFIX=-dev.l0g.eu
|
||||||
|
|
||||||
|
# May be used to set the PHP version. Defaults to 7.2.
|
||||||
|
# PHP_VERSION=71
|
||||||
|
# PHP_VERSION=72
|
||||||
|
# PHP_VERSION=73
|
||||||
|
# PHP_VERSION=74
|
||||||
|
# PHP_VERSION=80
|
||||||
|
PHP_VERSION=81
|
||||||
|
|
||||||
|
# May be used to choose database (sqlite, pgsql, mysql)
|
||||||
|
SQL=mysql
|
||||||
|
|
||||||
|
# The mode of the xdebuger extention. This can be a comma separated list of
|
||||||
|
# the entries none, develop, debug, trace, and profile.
|
||||||
|
PHP_XDEBUG_MODE=develop
|
||||||
|
|
||||||
|
# Docker socket location, use it when you run rootless Docker
|
||||||
|
# Replace "1000" with the uid used by your Docker engine (default $(id -u))
|
||||||
|
# DOCKER_SOCKET=/run/user/1000/docker.sock
|
||||||
|
DOCKER_SOCKET=/var/run/podman/podman.sock
|
||||||
|
|
||||||
|
# Nextcloud AppAPI Docker Socket Proxy
|
||||||
|
# ------------------------------------
|
||||||
|
# NC_HAPROXY_PASSWORD=some_secure_password
|
||||||
|
# BIND_ADDRESS=172.17.0.1
|
||||||
|
# CERT_PATH=./data/ssl/app_api/app_api.pem
|
||||||
|
# NETWORK_MODE=host
|
||||||
|
# HAPROXY_PORT=2375
|
||||||
|
# TIMEOUT_CONNECT=10s
|
||||||
|
# TIMEOUT_CLIENT=30s
|
||||||
|
# TIMEOUT_SERVER=30s
|
||||||
|
# EX_APPS_NET=ipv4@localhost
|
||||||
|
# EX_APPS_COUNT=50
|
||||||
|
# ------------------------------------
|
||||||
6
nextcloud_devenv/reset_polls.sh
Executable file
6
nextcloud_devenv/reset_polls.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./get_dbcontent.sh
|
||||||
|
./run_occ.sh polls:db:purge
|
||||||
|
./run_occ.sh app:enable polls
|
||||||
|
./run_occ.sh polls:db:rebuild
|
||||||
43
nextcloud_devenv/runit.sh
Executable file
43
nextcloud_devenv/runit.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SPDX-FileCopyrightText: 2025 artlog@l0g.eu
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
|
toolsdir=lib
|
||||||
|
pushd $toolsdir >/dev/null
|
||||||
|
toolsdir=$(pwd)
|
||||||
|
source metascript.sh
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
while [[ $# > 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
up|down)
|
||||||
|
action=$1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
parsemetaarg "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
metarun=metarun
|
||||||
|
metasudo=sudo
|
||||||
|
|
||||||
|
enforcedir nextcloud-docker-dev exists
|
||||||
|
|
||||||
|
pushd nextcloud-docker-dev
|
||||||
|
|
||||||
|
if [[ $action = down ]]
|
||||||
|
then
|
||||||
|
$metarun podman-compose down
|
||||||
|
fi
|
||||||
|
|
||||||
|
services=(nextcloud proxy database-mysql)
|
||||||
|
|
||||||
|
if [[ $action == up ]]
|
||||||
|
then
|
||||||
|
$metarun podman-compose --env-file $(pwd)/.env $action "${services[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
popd
|
||||||
@@ -20,4 +20,14 @@ GRANT ALL PRIVILEGES ON SCHEMA public TO $username;
|
|||||||
EOF
|
EOF
|
||||||
} | pipeto sudo -u postgres psql -f -
|
} | pipeto sudo -u postgres psql -f -
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
cat <<EOF
|
||||||
|
CREATE USER '$username'@'localhost' IDENTIFIED BY '$password';
|
||||||
|
CREATE DATABASE IF NOT EXISTS ${database_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||||
|
GRANT ALL PRIVILEGES on ${database_name}.* to '$username'@'localhost';
|
||||||
|
EOF
|
||||||
|
} | pipeto sudo mariadb -uroot -p
|
||||||
|
|
||||||
|
|
||||||
log_info "created database ${database_name} with user $username"
|
log_info "created database ${database_name} with user $username"
|
||||||
|
|||||||
1
samples/0.json
Normal file
1
samples/0.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"candidates": {"A": "A", "B": "B", "C": "C"}, "voters": {"count": 4}, "mentions": ["Tr\u00e8s Bien", "Bien", "Assez Bien", "Passable", "Insuffisant", "A Rejeter"], "votation": {"votes": [{"A": 0, "B": 1, "C": 2}, {"A": 0, "B": 1, "C": 2}, {"A": 0, "B": 1, "C": 2}, {"A": 0, "B": 1, "C": 2}]}}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"candidats":{
|
"candidates":{
|
||||||
"A":"albert",
|
"A":"albert",
|
||||||
"B":"Beatrice",
|
"B":"Beatrice",
|
||||||
"C":"Chloé",
|
"C":"Chloé",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"G":"Gisèle",
|
"G":"Gisèle",
|
||||||
"H":"Hugo"
|
"H":"Hugo"
|
||||||
},
|
},
|
||||||
"votants":{
|
"voters":{
|
||||||
"decompte":10
|
"count":10
|
||||||
},
|
},
|
||||||
"mentions":[
|
"mentions":[
|
||||||
"Très Bien",
|
"Très Bien",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"candidats":{
|
"candidates":{
|
||||||
"A":"albert",
|
"A":"albert",
|
||||||
"B":"Beatrice",
|
"B":"Beatrice",
|
||||||
"C":"Chloé",
|
"C":"Chloé",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"G":"Gisèle",
|
"G":"Gisèle",
|
||||||
"H":"Hugo"
|
"H":"Hugo"
|
||||||
},
|
},
|
||||||
"votants":{
|
"voters":{
|
||||||
"decompte":10
|
"count":10
|
||||||
},
|
},
|
||||||
"mentions":[
|
"mentions":[
|
||||||
"Très Bien",
|
"Très Bien",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"candidats":{
|
"candidates":{
|
||||||
"A":"albert",
|
"A":"albert",
|
||||||
"B":"Beatrice",
|
"B":"Beatrice",
|
||||||
"C":"Chloé",
|
"C":"Chloé",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"G":"Gisèle",
|
"G":"Gisèle",
|
||||||
"H":"Hugo"
|
"H":"Hugo"
|
||||||
},
|
},
|
||||||
"votants":{
|
"voters":{
|
||||||
"decompte":11
|
"count":11
|
||||||
},
|
},
|
||||||
"mentions":[
|
"mentions":[
|
||||||
"Très Bien",
|
"Très Bien",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"candidats":{
|
"candidates":{
|
||||||
"A":"albert",
|
"A":"albert",
|
||||||
"B":"Beatrice",
|
"B":"Beatrice",
|
||||||
"C":"Chloé",
|
"C":"Chloé",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"G":"Gisèle",
|
"G":"Gisèle",
|
||||||
"H":"Hugo"
|
"H":"Hugo"
|
||||||
},
|
},
|
||||||
"votants":{
|
"voters":{
|
||||||
"decompte":11
|
"count":11
|
||||||
},
|
},
|
||||||
"mentions":[
|
"mentions":[
|
||||||
"Très Bien",
|
"Très Bien",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"candidats":{
|
"candidates":{
|
||||||
"A":"albert",
|
"A":"albert",
|
||||||
"B":"Beatrice",
|
"B":"Beatrice",
|
||||||
"C":"Chloé",
|
"C":"Chloé",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"G":"Gisèle",
|
"G":"Gisèle",
|
||||||
"H":"Hugo"
|
"H":"Hugo"
|
||||||
},
|
},
|
||||||
"votants":{
|
"voters":{
|
||||||
"decompte":11
|
"count":11
|
||||||
},
|
},
|
||||||
"mentions":[
|
"mentions":[
|
||||||
"Très Bien",
|
"Très Bien",
|
||||||
|
|||||||
@@ -1,25 +1,53 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# SPDX-FileCopyrightText: 2025 artlog@l0g.eu
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
#
|
||||||
|
|
||||||
if [[ $# > 0 ]]
|
toolsdir=../lib
|
||||||
|
pushd $toolsdir >/dev/null
|
||||||
|
toolsdir=$(pwd)
|
||||||
|
source metascript.sh
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
while [[ $# > 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
*.json)
|
||||||
|
json_file=$1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ $1 =~ [0-9]+ ]]
|
||||||
then
|
then
|
||||||
vote=$1
|
vote=$1
|
||||||
|
else
|
||||||
|
parsemetaarg "$1"
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -z $vote ]]
|
if [[ -z $vote ]] && [[ -z $json_file ]]
|
||||||
then
|
then
|
||||||
echo "[ERROR] numéro de vote manquant ( ex 1 pour 1.json )"
|
log_error "numéro de vote manquant ( ex 1 pour 1.json )"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -z $json_file ]]
|
||||||
|
then
|
||||||
json_file=$vote.json
|
json_file=$vote.json
|
||||||
json=~/clients/artlog/artisanlogiciel.code/artlog_jsontools/build/json
|
fi
|
||||||
|
|
||||||
|
enforcefile $json_file exists
|
||||||
|
|
||||||
|
json=json
|
||||||
if [[ -x $json ]]
|
if [[ -x $json ]]
|
||||||
then
|
then
|
||||||
json_indent_file=$vote.indent.json
|
json_indent_file=$vote.indent.json
|
||||||
echo "generating $json_indent_file"
|
echo "generating $json_indent_file"
|
||||||
$json indent=spaces:2 -- $json_file > $json_indent_file
|
$json indent=spaces:2 -- $json_file > $json_indent_file
|
||||||
json=$json_file
|
json_file=$json_indent_file
|
||||||
|
enforcefile $json_file exists
|
||||||
fi
|
fi
|
||||||
|
|
||||||
code_dir=../code/
|
code_dir=../code/
|
||||||
|
|||||||
16
samples/expected/6.stderr
Normal file
16
samples/expected/6.stderr
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[WARN] No /.resources.var found
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/samples/../code/parse_sample.py", line 19, in <module>
|
||||||
|
result = majority_judgment_run(poll)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/majority_judgment_method/__init__.py", line 39, in majority_judgment_run
|
||||||
|
voters=poll['voters']['count']
|
||||||
|
~~~~^^^^^^^^^^
|
||||||
|
KeyError: 'voters'
|
||||||
|
PHP Warning: Undefined array key "voters" in /home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/parse_sample.php on line 24
|
||||||
|
PHP Warning: Trying to access array offset on null in /home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/parse_sample.php on line 24
|
||||||
|
PHP Warning: Undefined array key "candidates" in /home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/parse_sample.php on line 25
|
||||||
|
PHP Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in /home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/parse_sample.php:26
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in /home/plhardy/clients/astrolabe/nextcloud/poll/jugement_majoritaire/code/parse_sample.php on line 26
|
||||||
58
samples/mieuxvoter/cloture.indent.json
Normal file
58
samples/mieuxvoter/cloture.indent.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"ref":"zdslqbbzvk",
|
||||||
|
"name":"Quel sont les mérites respectifs des participants",
|
||||||
|
"description":"{\"description\":\"\",\"randomOrder\":true}",
|
||||||
|
"candidates":[
|
||||||
|
{
|
||||||
|
"name":"A",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"id":61445
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"B",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"id":61446
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"C",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"id":61447
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grades":[
|
||||||
|
{
|
||||||
|
"name":"Excellent",
|
||||||
|
"value":4,
|
||||||
|
"id":47253
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Très bien",
|
||||||
|
"value":3,
|
||||||
|
"id":47254
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Bien",
|
||||||
|
"value":2,
|
||||||
|
"id":47255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Passable",
|
||||||
|
"value":1,
|
||||||
|
"id":47256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Insuffisant",
|
||||||
|
"value":0,
|
||||||
|
"id":47257
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"num_voters":0,
|
||||||
|
"hide_results":false,
|
||||||
|
"force_close":true,
|
||||||
|
"date_end":"2025-10-08T08:00:00Z",
|
||||||
|
"auth_for_result":false,
|
||||||
|
"restricted":false
|
||||||
|
}
|
||||||
1
samples/mieuxvoter/cloture.json
Normal file
1
samples/mieuxvoter/cloture.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"ref":"zdslqbbzvk","name":"Quel sont les mérites respectifs des participants","description":"{\"description\":\"\",\"randomOrder\":true}","candidates":[{"name":"A","description":"","image":"","id":61445},{"name":"B","description":"","image":"","id":61446},{"name":"C","description":"","image":"","id":61447}],"grades":[{"name":"Excellent","value":4,"id":47253},{"name":"Très bien","value":3,"id":47254},{"name":"Bien","value":2,"id":47255},{"name":"Passable","value":1,"id":47256},{"name":"Insuffisant","value":0,"id":47257}],"num_voters":0,"hide_results":false,"force_close":true,"date_end":"2025-10-08T08:00:00Z","auth_for_result":false,"restricted":false}
|
||||||
72
samples/mieuxvoter/cloture.response.indent.json
Normal file
72
samples/mieuxvoter/cloture.response.indent.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"name":"Quel sont les mérites respectifs des participants",
|
||||||
|
"description":"{\"description\":\"\",\"randomOrder\":true}",
|
||||||
|
"ref":"zdslqbbzvk",
|
||||||
|
"date_start":"2025-10-07T09:41:24.294727Z",
|
||||||
|
"date_end":"2025-10-08T08:00:00Z",
|
||||||
|
"hide_results":false,
|
||||||
|
"restricted":false,
|
||||||
|
"auth_for_result":false,
|
||||||
|
"force_close":true,
|
||||||
|
"grades":[
|
||||||
|
{
|
||||||
|
"name":"Excellent",
|
||||||
|
"value":4,
|
||||||
|
"description":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":47253
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Très bien",
|
||||||
|
"value":3,
|
||||||
|
"description":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":47254
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Bien",
|
||||||
|
"value":2,
|
||||||
|
"description":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":47255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Passable",
|
||||||
|
"value":1,
|
||||||
|
"description":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":47256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Insuffisant",
|
||||||
|
"value":0,
|
||||||
|
"description":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":47257
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"candidates":[
|
||||||
|
{
|
||||||
|
"name":"A",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":61445
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"B",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":61446
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"C",
|
||||||
|
"description":"",
|
||||||
|
"image":"",
|
||||||
|
"election_ref":"zdslqbbzvk",
|
||||||
|
"id":61447
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"invites":[]
|
||||||
|
}
|
||||||
2
samples/mieuxvoter/cloture.response.json
Normal file
2
samples/mieuxvoter/cloture.response.json
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{"name":"Quel sont les mérites respectifs des participants","description":"{\"description\":\"\",\"randomOrder\":true}","ref":"zdslqbbzvk","date_start":"2025-10-07T09:41:24.294727Z","date_end":"2025-10-08T08:00:00Z","hide_results":false,"restricted":false,"auth_for_result":false,"force_close":true,"grades":[{"name":"Excellent","value":4,"description":"","election_ref":"zdslqbbzvk","id":47253},{"name":"Très bien","value":3,"description":"","election_ref":"zdslqbbzvk","id":47254},{"name":"Bien","value":2,"description":"","election_ref":"zdslqbbzvk","id":47255},{"name":"Passable","value":1,"description":"","election_ref":"zdslqbbzvk","id":47256},{"name":"Insuffisant","value":0,"description":"","election_ref":"zdslqbbzvk","id":47257}],"candidates":[{"name":"A","description":"","image":"","election_ref":"zdslqbbzvk","id":61445},{"name":"B","description":"","image":"","election_ref":"zdslqbbzvk","id":61446},{"name":"C","description":"","image":"","election_ref":"zdslqbbzvk","id":61447}],"invites":[]}
|
||||||
|
|
||||||
4
samples/mieuxvoter/results-zds-lqb-bzvk.csv
Normal file
4
samples/mieuxvoter/results-zds-lqb-bzvk.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
"name","Excellent","Très bien","Bien","Passable","Insuffisant"
|
||||||
|
"A","0","0","3","0","0"
|
||||||
|
"B","0","1","1","1","0"
|
||||||
|
"C","1","0","2","0","0"
|
||||||
|
@@ -1,2 +1,5 @@
|
|||||||
Participants,Adresse e-mail,A,B,C
|
Participants,Adresse e-mail,A,B,C
|
||||||
admin,,Très Bien,Bien,Assez Bien
|
admin,,Très Bien,Bien,Assez Bien
|
||||||
|
user1,,Très Bien,Bien,Assez Bien
|
||||||
|
user2,,Très Bien,Bien,Assez Bien
|
||||||
|
user3,,Très Bien,Bien,Assez Bien
|
||||||
|
1
samples/poll1.csv.json
Normal file
1
samples/poll1.csv.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"candidats": {"A": "A", "B": "B", "C": "C"}, "votants": {"decompte": 1}, "mentions": ["Tr\u00e8s Bien", "Bien", "Assez Bien", "Passable", "Insuffisant", "A Rejeter"], "votation": {"votes": [{"A": 0, "B": 1, "C": 2}]}}
|
||||||
@@ -2,7 +2,20 @@
|
|||||||
|
|
||||||
[[ -n $VIRTUAL_ENV ]] || source ../code/bin/activate
|
[[ -n $VIRTUAL_ENV ]] || source ../code/bin/activate
|
||||||
|
|
||||||
for (( i=0;i<7;i++ ))
|
|
||||||
|
expect_error()
|
||||||
|
{
|
||||||
|
sample=$1
|
||||||
|
# error case on purpose
|
||||||
|
resultdir=tmp
|
||||||
|
[[ -d ${resultdir} ]] || mkdir ${resultdir}
|
||||||
|
./check.sh $sample 2>${resultdir}/$sample.stderr
|
||||||
|
diff ${resultdir}/$sample.stderr expected/$sample.stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
for (( i=0;i<6;i++ ))
|
||||||
do
|
do
|
||||||
./check.sh $i
|
./check.sh $i
|
||||||
done
|
done
|
||||||
|
|
||||||
|
expect_error 6
|
||||||
|
|||||||
Reference in New Issue
Block a user