forked from ScoDoc/ScoDoc
Fix creation/deletion scripts + more unit tests
This commit is contained in:
parent
31288efb73
commit
b0a77fba66
17
README.md
17
README.md
@ -95,7 +95,7 @@ Lancer le script:
|
|||||||
|
|
||||||
su postgres
|
su postgres
|
||||||
cd /opt/scodoc/tools
|
cd /opt/scodoc/tools
|
||||||
./create_database.sh
|
./create_users_database.sh
|
||||||
|
|
||||||
Ce script crée une base nommée `SCO8USERS`, appartenant à l'utilisateur (role) postgres `scodoc`.
|
Ce script crée une base nommée `SCO8USERS`, appartenant à l'utilisateur (role) postgres `scodoc`.
|
||||||
Cet utilisateur est automatiquement créé si nécessaire.
|
Cet utilisateur est automatiquement créé si nécessaire.
|
||||||
@ -146,6 +146,21 @@ de votre installation ScoDoc 7 pour passer à ScoDoc 8 (*ne pas utiliser en prod
|
|||||||
cd /opt/scodoc/tools
|
cd /opt/scodoc/tools
|
||||||
./migrate_from_scodoc7.sh
|
./migrate_from_scodoc7.sh
|
||||||
|
|
||||||
|
## Création d'un département
|
||||||
|
|
||||||
|
sudo su
|
||||||
|
cd /opt/scodoc
|
||||||
|
source venv/bin/activate
|
||||||
|
flask sco-create-dept DEPT
|
||||||
|
|
||||||
|
où `DEPT` est le nom du département (un acronyme en majuscule, comme "RT", "GEA", ...).
|
||||||
|
|
||||||
|
### Suppression d'un département
|
||||||
|
|
||||||
|
sudo su
|
||||||
|
cd /opt/scodoc
|
||||||
|
source venv/bin/activate
|
||||||
|
flask sco-delete-dept DEPT
|
||||||
|
|
||||||
## Lancement serveur (développement, sur VM Linux)
|
## Lancement serveur (développement, sur VM Linux)
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ def DBInsertDict(cnx, table, vals, commit=0, convert_empty_to_nulls=1):
|
|||||||
cnx.commit() # get rid of this transaction
|
cnx.commit() # get rid of this transaction
|
||||||
raise # and re-raise exception
|
raise # and re-raise exception
|
||||||
if commit:
|
if commit:
|
||||||
log("DBInsertDict: commit (requested)")
|
# log("DBInsertDict: commit (requested)")
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
return oid
|
return oid
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ def do_import_etud_admission(
|
|||||||
"codelycee": get_opt_str(etud, "lycee"),
|
"codelycee": get_opt_str(etud, "lycee"),
|
||||||
"boursier": get_opt_str(etud, "bourse"),
|
"boursier": get_opt_str(etud, "bourse"),
|
||||||
}
|
}
|
||||||
log("do_import_etud_admission: etud=%s" % pprint.pformat(etud))
|
# log("do_import_etud_admission: etud=%s" % pprint.pformat(etud))
|
||||||
al = sco_etud.admission_list(cnx, args={"etudid": etudid})
|
al = sco_etud.admission_list(cnx, args={"etudid": etudid})
|
||||||
if not al:
|
if not al:
|
||||||
sco_etud.admission_create(cnx, args) # -> adm_id
|
sco_etud.admission_create(cnx, args) # -> adm_id
|
||||||
|
@ -133,7 +133,7 @@ def user_password(username, password=None): # user-password
|
|||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@click.argument("dept")
|
@click.argument("dept")
|
||||||
def sco_delete_dept(dept):
|
def sco_delete_dept(dept): # sco-delete-dept
|
||||||
"Delete existing departement"
|
"Delete existing departement"
|
||||||
if os.getuid() != 0:
|
if os.getuid() != 0:
|
||||||
sys.stderr.write("sco_delete_dept: must be run by root\n")
|
sys.stderr.write("sco_delete_dept: must be run by root\n")
|
||||||
@ -146,13 +146,13 @@ def sco_delete_dept(dept):
|
|||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@click.argument("dept")
|
@click.argument("dept")
|
||||||
def sco_create_dept(dept):
|
def sco_create_dept(dept): # sco-create-dept
|
||||||
"Create new departement"
|
"Create new departement"
|
||||||
if os.getuid() != 0:
|
if os.getuid() != 0:
|
||||||
sys.stderr.write("sco_create_dept: must be run by root\n")
|
sys.stderr.write("sco_create_dept: must be run by root\n")
|
||||||
return 1
|
return 1
|
||||||
if os.system('cd tools && ./create_dept.sh -n "{}"'.format(dept)):
|
if os.system(f'cd tools && ./create_dept.sh -n "{dept}"'):
|
||||||
sys.stderr.write("error deleting dept " + dept)
|
sys.stderr.write(f"error creating dept {dept}\n")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import sys
|
|||||||
import random
|
import random
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
from gen_nomprenoms import nomprenom
|
from .gen_nomprenoms import nomprenom
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Lancement d'un python scodoc interactif
|
|
||||||
# dans l'environnement d'un département
|
|
||||||
# et avec chargement des scripts indiqués
|
|
||||||
# via from ... import *
|
|
||||||
#
|
|
||||||
# Si -r est utilisé, veiller à créer au préalable
|
|
||||||
# le département via l'interface web (Zope)
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 [-h] [-r] [-x] dept [script...]"
|
|
||||||
echo "Lance un environnement interactif python/ScoDoc"
|
|
||||||
echo " -r: supprime et recrée le département (attention: efface la base !)"
|
|
||||||
echo " -x: exit après exécution des scripts, donc mode non interactif"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
cd /opt/scodoc/Products/ScoDoc || exit 2
|
|
||||||
source config/config.sh
|
|
||||||
source config/utils.sh
|
|
||||||
|
|
||||||
RECREATE_DEPT=0
|
|
||||||
PYTHON_INTERACTIVE="-i"
|
|
||||||
|
|
||||||
while [ -n "$1" ]; do
|
|
||||||
PARAM="$1"
|
|
||||||
[ "${PARAM::1}" != "-" ] && break
|
|
||||||
case $PARAM in
|
|
||||||
-h | --help)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-r)
|
|
||||||
RECREATE_DEPT=1
|
|
||||||
;;
|
|
||||||
-x)
|
|
||||||
PYTHON_INTERACTIVE=""
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: unknown parameter \"$PARAM\""
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DEPT="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [ "$RECREATE_DEPT" = 1 ]
|
|
||||||
then
|
|
||||||
cfg_pathname="${SCODOC_VAR_DIR}/config/depts/$DEPT".cfg
|
|
||||||
if [ -e "$cfg_pathname" ]
|
|
||||||
then
|
|
||||||
(cd config || terminate "no config directory"; ./delete_dept.sh -n "$DEPT") || terminate "error deleting dept $DEPT"
|
|
||||||
fi
|
|
||||||
(cd config || terminate "no config directory"; ./create_dept.sh -n "$DEPT") || terminate "error creating dept $DEPT"
|
|
||||||
# systemctl start scodoc
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmd="from __future__ import print_function;from Zope2 import configure;configure('/opt/scodoc/etc/zope.conf');import Zope2; app=Zope2.app();from debug import *;context = go_dept(app, '""$DEPT""', verbose=False);"
|
|
||||||
|
|
||||||
for f in "$@"
|
|
||||||
do
|
|
||||||
cmd="${cmd}exec(open(\"${f}\").read());"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z "$PYTHON_INTERACTIVE" ]
|
|
||||||
then
|
|
||||||
/opt/zope213/bin/python -c "$cmd"
|
|
||||||
else
|
|
||||||
/opt/zope213/bin/python "$PYTHON_INTERACTIVE" -c "$cmd"
|
|
||||||
fi
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
|||||||
|
|
||||||
# Tests avec splinter (expérimental)
|
|
||||||
|
|
||||||
<http://splinter.cobrateam.info/docs/tutorial.html>
|
|
||||||
|
|
||||||
## Installation de Splinter
|
|
||||||
|
|
||||||
```
|
|
||||||
apt-get install python-dev
|
|
||||||
apt-get install libxslt-dev
|
|
||||||
apt-get install libxml2-dev
|
|
||||||
apt-get install python-lxml python-cssselect
|
|
||||||
|
|
||||||
|
|
||||||
/opt/zope213/bin/easy_install zope.testbrowser
|
|
||||||
/opt/zope213/bin/easy_install cssselect
|
|
||||||
/opt/zope213/bin/easy_install splinter
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
J'ai du hacker `_mechanize.py`, ligne 218
|
|
||||||
|
|
||||||
```
|
|
||||||
vi +218 /opt/zope213/lib/python2.7/site-packages/mechanize-0.2.5-py2.7.egg/mechanize/_mechanize.py
|
|
||||||
|
|
||||||
url = _rfc3986.urljoin(self._response.geturl()+'/', url)
|
|
||||||
```
|
|
||||||
|
|
||||||
(ajouter le + '/')
|
|
||||||
|
|
||||||
### Essais:
|
|
||||||
/opt/zope213/bin/python common.py
|
|
||||||
|
|
||||||
ne doit pas déclencher d'erreur.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Partie commune:
|
|
||||||
|
|
||||||
se connecte et accede a la page d'accueil du premier departement
|
|
||||||
"""
|
|
||||||
from splinter import Browser
|
|
||||||
import re, sys, time
|
|
||||||
import urlparse
|
|
||||||
import pdb
|
|
||||||
from optparse import OptionParser
|
|
||||||
|
|
||||||
from conn_info import *
|
|
||||||
|
|
||||||
parser = OptionParser()
|
|
||||||
parser.add_option("-d", "--dept", dest="dept_index", default=0, help="indice du departement")
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
|
|
||||||
dept_index = int(options.dept_index)
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
browser = Browser('zope.testbrowser')
|
|
||||||
browser._browser.mech_browser.set_handle_robots(False) # must ignore ScoDoc robots.txt
|
|
||||||
browser.visit(SCODOC)
|
|
||||||
print 'Start: title:', browser.title
|
|
||||||
print 'URL: ', browser.url
|
|
||||||
# print browser.html
|
|
||||||
|
|
||||||
links = browser.find_link_by_partial_text('Scolarit')
|
|
||||||
print '%d departements' % len(links)
|
|
||||||
|
|
||||||
links[dept_index].click() # va sur le premier departement
|
|
||||||
|
|
||||||
# ---- Formulaire authentification
|
|
||||||
print 'Authentification: ', browser.url
|
|
||||||
|
|
||||||
browser.fill('__ac_name', USER)
|
|
||||||
browser.fill('__ac_password', PASSWD)
|
|
||||||
button = browser.find_by_id('submit')
|
|
||||||
button[0].click()
|
|
||||||
|
|
||||||
# ---- Page accueil Dept
|
|
||||||
print browser.url
|
|
||||||
|
|
||||||
links = browser.find_link_by_partial_text('DUT')
|
|
||||||
links[0].click()
|
|
||||||
print 'Starting test from %s' % browser.url
|
|
||||||
print browser.title
|
|
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
"""Put here the informations neeede to connect to your development test user
|
|
||||||
"""
|
|
||||||
|
|
||||||
#SCODOC='https://scodoc.example.com/'
|
|
||||||
SCODOC='https://scodoc.viennet.net/'
|
|
||||||
USER = 'tester'
|
|
||||||
#PASSWD = 'XXXXXXXXXXXX'
|
|
||||||
PASSWD = '67un^:653'
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Essais de base:
|
|
||||||
|
|
||||||
se connecte, accede a un semestre puis a un module,
|
|
||||||
et modifie les notes existantes dans la premiere evaluation
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from common import *
|
|
||||||
# ici on est sur la page d'accueil du departement !
|
|
||||||
|
|
||||||
links = browser.find_link_by_partial_text('DUT informatique en FI')
|
|
||||||
links[0].click()
|
|
||||||
|
|
||||||
# ---- Tableau bord semestre
|
|
||||||
print browser.url
|
|
||||||
# va dans module AP2 saisir des notes (dans la p1ere evaluation):
|
|
||||||
browser.find_link_by_partial_text('AP1').first.click()
|
|
||||||
browser.find_link_by_partial_text('Saisir notes').first.click()
|
|
||||||
|
|
||||||
# ---- Ici c'est complique car le bouton submit est disabled
|
|
||||||
# on construit l'url a la main:
|
|
||||||
url = browser.find_by_id('gr')[0]["action"]
|
|
||||||
evaluation_id = browser.find_by_name('evaluation_id').value
|
|
||||||
group_id = re.search( r'value="(.*?)".*?tous', browser.html ).group(1)
|
|
||||||
dest = urlparse.urljoin(url, 'notes_evaluation_formnotes?evaluation_id='+evaluation_id+'&group_ids:list='+group_id+'¬e_method=form')
|
|
||||||
browser.visit(dest)
|
|
||||||
|
|
||||||
# ---- Change une note:
|
|
||||||
# browser.fill('note_EID3835', '15')
|
|
||||||
etudids = re.findall( r'name="note_(.*?)"', browser.html )[1:]
|
|
||||||
note_max = float(re.search( r'notes sur ([0-9]+?)</span>\)', browser.html ).group(1))
|
|
||||||
for etudid in etudids:
|
|
||||||
# essaie d'ajouter 1 à la note !
|
|
||||||
old_val = browser.find_by_name('note_%s' % etudid).value
|
|
||||||
try:
|
|
||||||
val = min(float(old_val) + 1, note_max)
|
|
||||||
browser.fill('note_%s'%etudid, str(val))
|
|
||||||
print etudid, old_val, '->', val
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ... et met la derniere au max (pour tester)
|
|
||||||
browser.fill('note_%s'%etudids[-1], str(note_max))
|
|
||||||
print etudids[-1], '->', note_max
|
|
||||||
|
|
||||||
# ---- Validation formulaire saisie notes:
|
|
||||||
browser.find_by_id('tf_submit').click()
|
|
||||||
browser.find_by_id('tf_submit').click()
|
|
@ -1,66 +0,0 @@
|
|||||||
#!/opt/zope213/bin/python
|
|
||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Essais de changements intensifs des notes
|
|
||||||
(pour faire des tests en parallele)
|
|
||||||
|
|
||||||
se connecte, accede a un semestre puis a un module,
|
|
||||||
et modifie les notes existantes dans la premiere evaluation
|
|
||||||
|
|
||||||
ajoute puis soustrait 1 aux notes valides, N fois
|
|
||||||
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
|
|
||||||
from common import *
|
|
||||||
# -> ici on est sur la page d'accueil du departement !
|
|
||||||
|
|
||||||
links = browser.find_link_by_partial_text('DUT')
|
|
||||||
links[0].click() # va sur le 1er semestre de DUT trouve
|
|
||||||
|
|
||||||
# ---- Tableau bord semestre
|
|
||||||
print browser.url
|
|
||||||
# va dans module M1101 saisir des notes (dans la p1ere evaluation):
|
|
||||||
browser.find_link_by_partial_text('M1101').first.click()
|
|
||||||
browser.find_link_by_partial_text('Saisir notes').first.click()
|
|
||||||
|
|
||||||
# ---- Ici c'est complique car le bouton submit est disabled
|
|
||||||
# on construit l'url a la main:
|
|
||||||
url = browser.find_by_id('gr')[0]["action"]
|
|
||||||
evaluation_id = browser.find_by_name('evaluation_id').value
|
|
||||||
group_id = re.search( r'value="(.*?)".*?tous', browser.html ).group(1)
|
|
||||||
url_form = urlparse.urljoin(url, 'notes_evaluation_formnotes?evaluation_id='+evaluation_id+'&group_ids:list='+group_id+'¬e_method=form')
|
|
||||||
|
|
||||||
|
|
||||||
# ---- Ajoute une constante aux notes valides:
|
|
||||||
# le browser doit etre sur le formulaire saisie note
|
|
||||||
def add_to_notes(increment):
|
|
||||||
etudids = re.findall( r'name="note_(.*?)"', browser.html )[1:]
|
|
||||||
note_max = float(re.search( r'notes sur ([0-9]+?)</span>\)', browser.html ).group(1))
|
|
||||||
print 'add_to_notes: %d etudiants' % len(etudids)
|
|
||||||
for etudid in etudids:
|
|
||||||
# essaie d'ajouter 1 a la note !
|
|
||||||
old_val = browser.find_by_name('note_%s' % etudid).value
|
|
||||||
try:
|
|
||||||
val = max(0,min(float(old_val) + increment, note_max))
|
|
||||||
browser.fill('note_%s'%etudid, str(val))
|
|
||||||
print etudid, old_val, '->', val
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ---- Validation formulaire saisie notes:
|
|
||||||
browser.find_by_id('tf_submit').click()
|
|
||||||
browser.find_by_id('tf_submit').click()
|
|
||||||
|
|
||||||
|
|
||||||
for i in range(10):
|
|
||||||
browser.visit(url_form) # va sur form saisie notes
|
|
||||||
add_to_notes(1)
|
|
||||||
#time.sleep(1)
|
|
||||||
browser.visit(url_form) # va sur form saisie notes
|
|
||||||
add_to_notes(-1)
|
|
||||||
#time.sleep(1)
|
|
||||||
|
|
||||||
t1 = time.time()
|
|
||||||
print 'done in %gs' % (t1-t0)
|
|
@ -1,44 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Modification decision de jury
|
|
||||||
"""
|
|
||||||
from common import *
|
|
||||||
# -> ici on est sur la page d'accueil du departement !
|
|
||||||
DeptURL = browser.url
|
|
||||||
|
|
||||||
# Cherche un formsemestre_id:
|
|
||||||
links = browser.find_link_by_partial_text('DUT')
|
|
||||||
u = links[0]['href']
|
|
||||||
formsemestre_id = re.search( r'formsemestre_id=(SEM[0-9]*)', u ).group(1)
|
|
||||||
|
|
||||||
# Cherche les etudids
|
|
||||||
browser.visit( urlparse.urljoin(DeptURL, 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + formsemestre_id) )
|
|
||||||
|
|
||||||
#u = browser.find_link_by_partial_href('formsemestre_bulletinetud')[0]['href']
|
|
||||||
#etudid = re.search( r'etudid=([A-Za-z0-9]*)', u ).group(1)
|
|
||||||
|
|
||||||
L = browser.find_link_by_partial_href('formsemestre_bulletinetud')
|
|
||||||
etudids = [ re.search(r'etudid=([A-Za-z0-9_]*)', x['href']).group(1) for x in L ]
|
|
||||||
|
|
||||||
def suppress_then_set( etudid, formsemestre_id, code='ADM' ):
|
|
||||||
"""Supprime decision de jury pour cet étudiant dans ce semestre
|
|
||||||
puis saisie de la decision (manuelle) indiquée par code
|
|
||||||
"""
|
|
||||||
# Suppression décision existante
|
|
||||||
browser.visit( urlparse.urljoin(DeptURL, 'formsemestre_validation_suppress_etud?etudid=%s&formsemestre_id=%s&dialog_confirmed=1' % (etudid, formsemestre_id)))
|
|
||||||
|
|
||||||
# Saisie décision
|
|
||||||
browser.visit( urlparse.urljoin(DeptURL, 'formsemestre_validation_etud_form?etudid=%s&formsemestre_id=%s' % (etudid, formsemestre_id)))
|
|
||||||
browser.fill('code_etat', [code])
|
|
||||||
browser.find_by_name('formvalidmanu_submit').first.click()
|
|
||||||
# pas de verification de la page résultat
|
|
||||||
|
|
||||||
# Change decisions de jury de tous les étudiants:
|
|
||||||
for etudid in etudids:
|
|
||||||
print 'decision pour %s' % etudid
|
|
||||||
suppress_then_set( etudid, formsemestre_id, code='ADM')
|
|
||||||
|
|
||||||
t1 = time.time()
|
|
||||||
print '%d etudiants traites en %gs' % (len(etudids),t1-t0)
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Enregistre les moyennes générales de tous les étudiants de tous les
|
|
||||||
semestres.
|
|
||||||
A utiliser avec debug.py (côté serveur).
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from debug import go_dept
|
|
||||||
import time
|
|
||||||
|
|
||||||
from app.scodoc import sco_cache
|
|
||||||
|
|
||||||
DeptName = "CJ"
|
|
||||||
context = go_dept(app, DeptName)
|
|
||||||
|
|
||||||
sems = context.Notes.formsemestre_list()
|
|
||||||
|
|
||||||
print("%d semestres" % len(sems))
|
|
||||||
|
|
||||||
L = []
|
|
||||||
n = 0
|
|
||||||
for sem in sems:
|
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
etudids = nt.get_etudids()
|
|
||||||
use_ue_coef = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
|
||||||
n += 1
|
|
||||||
print("%d %s (%d) use_ue_coef=%s" % (n, formsemestre_id, len(etudids), use_ue_coef))
|
|
||||||
for etudid in etudids:
|
|
||||||
mg = nt.get_etud_moy_gen(etudid)
|
|
||||||
L.append((formsemestre_id, str(use_ue_coef), etudid, str(mg)))
|
|
||||||
|
|
||||||
print("Done: %s moys computed" % len(L))
|
|
||||||
|
|
||||||
filename = "/opt/tests/%s-%s" % (DeptName, time.strftime("%Y-%m-%dT%H:%M:%S"))
|
|
||||||
print("Writing file '%s'..." % filename)
|
|
||||||
f = open(filename, "w")
|
|
||||||
for l in L:
|
|
||||||
f.write("\t".join(l) + "\n")
|
|
||||||
|
|
||||||
f.close()
|
|
@ -1,64 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Petits essais sur les fichiers CSV Apogée
|
|
||||||
|
|
||||||
Utiliser avec
|
|
||||||
/opt/scodoc/bin/zopectl debug
|
|
||||||
|
|
||||||
"""
|
|
||||||
from __future__ import print_function
|
|
||||||
from debug import *
|
|
||||||
|
|
||||||
import sco_apogee_csv
|
|
||||||
import sco_apogee_compare
|
|
||||||
|
|
||||||
#data = open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2018-2/2019-09-23-15-46-40/V2RT2!116.csv', 'r').read()
|
|
||||||
#data = open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2018-1/2019-02-20-11-53-05/V2RT!116.csv', 'r').read()
|
|
||||||
data = open('/tmp/V2RT116.csv', 'r').read()
|
|
||||||
A = sco_apogee_csv.ApoData(data)
|
|
||||||
data = open('/tmp/V2RT116-modif.csv', 'r').read()
|
|
||||||
B = sco_apogee_csv.ApoData(data)
|
|
||||||
sco_apogee_compare.compare_etuds_res(A, B)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
A.col_ids
|
|
||||||
# -> ['apoL_a01_code', 'apoL_a02_nom', 'apoL_a03_prenom', 'apoL_a04_naissance', 'apoL_c0001', 'apoL_c0002', 'apoL_c0003', 'apoL_c0004']
|
|
||||||
|
|
||||||
e = A.etuds[0]
|
|
||||||
pp(e.cols)
|
|
||||||
# {'apoL_a01_code': '11809768',
|
|
||||||
# 'apoL_a02_nom': 'AKYOL',
|
|
||||||
# 'apoL_a03_prenom': 'OLIVIER',
|
|
||||||
# 'apoL_a04_naissance': ' 31/01/1999',
|
|
||||||
# 'apoL_c0001': '',
|
|
||||||
# 'apoL_c0002': '',
|
|
||||||
# ... }
|
|
||||||
|
|
||||||
A.apo_elts.keys()
|
|
||||||
# ['VRTW4', 'VRTW3', 'VRTU42', 'VRTU41', 'VRTU32', ... ]
|
|
||||||
elt = A.apo_elts['VRT3101']
|
|
||||||
|
|
||||||
elt.code # 'VRT3102'
|
|
||||||
|
|
||||||
B = sco_apogee_csv.ApoData( open('/opt/tests/V2RT-modif.csv').read() )
|
|
||||||
|
|
||||||
# les colonnes de l'élément
|
|
||||||
col_ids = [ ec['apoL_a01_code'] for ec in elt.cols ]
|
|
||||||
e.cols['apoL_c0033']
|
|
||||||
|
|
||||||
common_nips = set([e["nip"] for e in A.etuds])
|
|
||||||
A.etud_by_nip.keys()
|
|
||||||
|
|
||||||
B_etud_by_nip = { e["nip"] : e for e in B.etuds }
|
|
||||||
|
|
||||||
d = build_etud_res(B.etuds[0], B)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Essai export des semestres impairs avec VET seulement pour les diplômés
|
|
||||||
|
|
||||||
Utiliser avec
|
|
||||||
/opt/scodoc/bin/zopectl debug
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from debug import *
|
|
||||||
|
|
||||||
import sco_apogee_csv
|
|
||||||
import sco_parcours_dut
|
|
||||||
|
|
||||||
context = go_dept(app, 'RT').Notes
|
|
||||||
|
|
||||||
etudid='EID33751'
|
|
||||||
formsemestre_id='SEM37099'
|
|
||||||
|
|
||||||
etud = context.getEtudInfo(etudid=etudid, filled=True)[0]
|
|
||||||
Se = sco_parcours_dut.SituationEtudParcours(context, etud, formsemestre_id)
|
|
||||||
|
|
||||||
print(Se.all_other_validated())
|
|
||||||
|
|
||||||
|
|
||||||
data = open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2019-1/2020-07-07-17-24-18/V2RT!117.csv', 'r').read()
|
|
||||||
|
|
||||||
apo_data = sco_apogee_csv.ApoData(data, periode=1, export_res_etape=False)
|
|
||||||
|
|
||||||
apo_data.setup(context)
|
|
||||||
|
|
||||||
ix = [ x['nom'] for x in apo_data.etuds ].index('HAMILA')
|
|
||||||
|
|
||||||
e = apo_data.etuds[ix]
|
|
||||||
e.lookup_scodoc(context, apo_data.etape_formsemestre_ids)
|
|
||||||
|
|
||||||
e.associate_sco(context, apo_data)
|
|
||||||
|
|
||||||
pp({ k : e.new_cols[k] for k in e.new_cols if e.new_cols[k] != '' })
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Test de base de ScoDoc
|
|
||||||
|
|
||||||
Création 10 étudiants, formation, semestre, inscription etudiant, creation 1 evaluation, saisie 10 notes.
|
|
||||||
|
|
||||||
Utiliser comme:
|
|
||||||
flask test-interactive scotests/test_basic.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
import random
|
|
||||||
|
|
||||||
from flask import g
|
|
||||||
|
|
||||||
from app import decorators
|
|
||||||
import scotests.sco_fake_gen as sco_fake_gen # pylint: disable=import-error
|
|
||||||
from app.scodoc import sco_utils as scu
|
|
||||||
from app.scodoc import sco_abs
|
|
||||||
from app.scodoc import sco_abs_views
|
|
||||||
from app.scodoc import sco_bulletins
|
|
||||||
from app.scodoc import sco_evaluations
|
|
||||||
from app.scodoc import sco_codes_parcours
|
|
||||||
from app.scodoc import sco_parcours_dut
|
|
||||||
from app.scodoc import sco_formsemestre_validation
|
|
||||||
|
|
||||||
|
|
||||||
context = sco_fake_gen.Sco8Context()
|
|
||||||
g.scodoc_dept = "TEST00"
|
|
||||||
|
|
||||||
G = sco_fake_gen.ScoFake(context)
|
|
||||||
G.verbose = False
|
|
||||||
|
|
||||||
# --- Création d'étudiants
|
|
||||||
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
|
||||||
|
|
||||||
# --- Création d'une formation
|
|
||||||
f = G.create_formation(acronyme="")
|
|
||||||
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
|
||||||
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
|
||||||
mod = G.create_module(
|
|
||||||
matiere_id=mat["matiere_id"],
|
|
||||||
code="TSM1",
|
|
||||||
coefficient=1.0,
|
|
||||||
titre="module test",
|
|
||||||
ue_id=ue["ue_id"], # faiblesse de l'API
|
|
||||||
formation_id=f["formation_id"], # faiblesse de l'API
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Mise place d'un semestre
|
|
||||||
sem = G.create_formsemestre(
|
|
||||||
formation_id=f["formation_id"],
|
|
||||||
semestre_id=1,
|
|
||||||
date_debut="01/01/2020",
|
|
||||||
date_fin="30/06/2020",
|
|
||||||
)
|
|
||||||
|
|
||||||
mi = G.create_moduleimpl(
|
|
||||||
module_id=mod["module_id"],
|
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
responsable_id="bach",
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Inscription des étudiants
|
|
||||||
for etud in etuds:
|
|
||||||
G.inscrit_etudiant(sem, etud)
|
|
||||||
|
|
||||||
# --- Creation évaluation
|
|
||||||
e = G.create_evaluation(
|
|
||||||
moduleimpl_id=mi["moduleimpl_id"],
|
|
||||||
jour="01/01/2020",
|
|
||||||
description="evaluation test",
|
|
||||||
coefficient=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Saisie toutes les notes de l'évaluation
|
|
||||||
for etud in etuds:
|
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
|
||||||
evaluation=e, etud=etud, note=float(random.randint(0, 20))
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Vérifie que les notes sont prises en compte:
|
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
|
||||||
context, sem["formsemestre_id"], etud["etudid"], REQUEST=REQUEST
|
|
||||||
)
|
|
||||||
# Toute les notes sont saisies, donc eval complète
|
|
||||||
etat = sco_evaluations.do_evaluation_etat(context, e["evaluation_id"])
|
|
||||||
assert etat["evalcomplete"]
|
|
||||||
# Un seul module, donc moy gen == note module
|
|
||||||
assert b["ues"][0]["cur_moy_ue_txt"] == b["ues"][0]["modules"][0]["mod_moy_txt"]
|
|
||||||
# Note au module égale à celle de l'éval
|
|
||||||
assert (
|
|
||||||
b["ues"][0]["modules"][0]["mod_moy_txt"]
|
|
||||||
== b["ues"][0]["modules"][0]["evaluations"][0]["note_txt"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Une autre évaluation
|
|
||||||
e2 = G.create_evaluation(
|
|
||||||
moduleimpl_id=mi["moduleimpl_id"],
|
|
||||||
jour="02/01/2020",
|
|
||||||
description="evaluation test 2",
|
|
||||||
coefficient=1.0,
|
|
||||||
)
|
|
||||||
# Saisie les notes des 5 premiers étudiants:
|
|
||||||
for etud in etuds[:5]:
|
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
|
||||||
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
|
||||||
)
|
|
||||||
# Cette éval n'est pas complète
|
|
||||||
etat = sco_evaluations.do_evaluation_etat(context, e2["evaluation_id"])
|
|
||||||
assert etat["evalcomplete"] == False
|
|
||||||
# la première éval est toujours complète:
|
|
||||||
etat = sco_evaluations.do_evaluation_etat(context, e["evaluation_id"])
|
|
||||||
assert etat["evalcomplete"]
|
|
||||||
|
|
||||||
# Modifie l'évaluation 2 pour "prise en compte immédiate"
|
|
||||||
e2["publish_incomplete"] = "1"
|
|
||||||
sco_evaluations.do_evaluation_edit(context, REQUEST, e2)
|
|
||||||
etat = sco_evaluations.do_evaluation_etat(context, e2["evaluation_id"])
|
|
||||||
assert etat["evalcomplete"] == False
|
|
||||||
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
|
||||||
assert etat["evalattente"] # mais l'eval est en attente (prise en compte immédiate)
|
|
||||||
|
|
||||||
# Saisie des notes qui manquent:
|
|
||||||
for etud in etuds[5:]:
|
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
|
||||||
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
|
||||||
)
|
|
||||||
etat = sco_evaluations.do_evaluation_etat(context, e2["evaluation_id"])
|
|
||||||
assert etat["evalcomplete"]
|
|
||||||
assert etat["nb_att"] == 0
|
|
||||||
assert not etat["evalattente"] # toutes les notes sont présentes
|
|
||||||
|
|
||||||
# --- Saisie absences
|
|
||||||
etudid = etuds[0]["etudid"]
|
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
|
||||||
context,
|
|
||||||
"15/01/2020",
|
|
||||||
"18/01/2020",
|
|
||||||
demijournee=2,
|
|
||||||
etudid=etudid,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
|
||||||
|
|
||||||
_ = sco_abs_views.doJustifAbsence(
|
|
||||||
context,
|
|
||||||
"17/01/2020",
|
|
||||||
"18/01/2020",
|
|
||||||
demijournee=2,
|
|
||||||
etudid=etudid,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
|
||||||
|
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
|
||||||
assert nbabs == 6, "incorrect nbabs (%d)" % nbabs
|
|
||||||
assert nbabsjust == 2, "incorrect nbabsjust (%s)" % nbabsjust
|
|
||||||
|
|
||||||
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
|
|
||||||
# on n'a pas encore saisi de décisions
|
|
||||||
assert not sco_parcours_dut.formsemestre_has_decisions(context, sem["formsemestre_id"])
|
|
||||||
# Saisie d'un décision AJ, non assidu
|
|
||||||
etudid = etuds[-1]["etudid"]
|
|
||||||
sco_parcours_dut.formsemestre_validate_ues(
|
|
||||||
context,
|
|
||||||
sem["formsemestre_id"],
|
|
||||||
etudid,
|
|
||||||
sco_codes_parcours.AJ,
|
|
||||||
False,
|
|
||||||
REQUEST=REQUEST,
|
|
||||||
)
|
|
||||||
assert sco_parcours_dut.formsemestre_has_decisions(
|
|
||||||
context, sem["formsemestre_id"]
|
|
||||||
), "décisions manquantes"
|
|
||||||
# Suppression de la décision
|
|
||||||
sco_formsemestre_validation.formsemestre_validation_suppress_etud(
|
|
||||||
context, sem["formsemestre_id"], etudid
|
|
||||||
)
|
|
||||||
assert not sco_parcours_dut.formsemestre_has_decisions(
|
|
||||||
context, sem["formsemestre_id"]
|
|
||||||
), "décisions non effacées"
|
|
@ -1,19 +0,0 @@
|
|||||||
# -*- mode: python -*-
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from pyExcelerator import *
|
|
||||||
|
|
||||||
#UnicodeUtils.DEFAULT_ENCODING = 'utf-8'
|
|
||||||
|
|
||||||
wb = Workbook()
|
|
||||||
|
|
||||||
title = "Essai"
|
|
||||||
|
|
||||||
ws = wb.add_sheet(u"çelé")
|
|
||||||
|
|
||||||
ws.write(1,1, "çeci où".decode('utf-8'))
|
|
||||||
ws.write(2,2, "Hélène".decode('utf-8'))
|
|
||||||
|
|
||||||
wb.save("toto.xls")
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flask import g
|
from flask import g
|
||||||
|
from flask_login import login_user, logout_user, current_user
|
||||||
|
|
||||||
import app as myapp
|
import app as myapp
|
||||||
from app import db, create_app
|
from app import db, create_app
|
||||||
@ -14,16 +15,25 @@ def test_client():
|
|||||||
# Setup
|
# Setup
|
||||||
myapp.Config.TESTING = True
|
myapp.Config.TESTING = True
|
||||||
myapp.Config.SQLALCHEMY_DATABASE_URI = "sqlite://"
|
myapp.Config.SQLALCHEMY_DATABASE_URI = "sqlite://"
|
||||||
|
myapp.Config.SERVER_NAME = "test.gr"
|
||||||
apptest = create_app()
|
apptest = create_app()
|
||||||
# Run tests:
|
# Run tests:
|
||||||
with apptest.test_client() as client:
|
with apptest.test_client() as client:
|
||||||
with apptest.app_context():
|
with apptest.app_context():
|
||||||
db.create_all()
|
with apptest.test_request_context():
|
||||||
Role.insert_roles()
|
db.create_all()
|
||||||
g.scodoc_dept = "RT"
|
Role.insert_roles()
|
||||||
g.db_conn = ndb.open_dept_connection()
|
u = User(user_name="admin")
|
||||||
yield client
|
admin_role = Role.query.filter_by(name="Admin").first()
|
||||||
ndb.close_dept_connection()
|
u.add_role(admin_role, "TEST00")
|
||||||
# Teardown:
|
# u.set_password("admin")
|
||||||
db.session.remove()
|
login_user(u)
|
||||||
db.drop_all()
|
# db.session.add(u)
|
||||||
|
|
||||||
|
g.scodoc_dept = "RT"
|
||||||
|
g.db_conn = ndb.open_dept_connection()
|
||||||
|
yield client
|
||||||
|
# ndb.close_dept_connection()
|
||||||
|
# Teardown:
|
||||||
|
db.session.remove()
|
||||||
|
db.drop_all()
|
||||||
|
1
tests/unit/__init__.py
Normal file
1
tests/unit/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Unit tests
|
@ -8,7 +8,6 @@ La classe ScoFake offre un ensemble de raccourcis permettant d'écrire
|
|||||||
facilement des tests ou de reproduire des bugs.
|
facilement des tests ou de reproduire des bugs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
@ -47,7 +46,9 @@ PRENOMS_H = [x.strip() for x in open(DEMO_DIR + "/prenoms-h.txt").readlines()]
|
|||||||
PRENOMS_F = [x.strip() for x in open(DEMO_DIR + "/prenoms-f.txt").readlines()]
|
PRENOMS_F = [x.strip() for x in open(DEMO_DIR + "/prenoms-f.txt").readlines()]
|
||||||
PRENOMS_X = [x.strip() for x in open(DEMO_DIR + "/prenoms-x.txt").readlines()]
|
PRENOMS_X = [x.strip() for x in open(DEMO_DIR + "/prenoms-x.txt").readlines()]
|
||||||
|
|
||||||
# nb: en python2, les chaines ci-dessus sont en utf8
|
# En ScoDoc 8 le "context" ne sert plus (remplacé par les contextes de Flask)
|
||||||
|
# Laisse cette globale pendant la transition du code #sco8 #context
|
||||||
|
context = None
|
||||||
|
|
||||||
|
|
||||||
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
||||||
@ -58,15 +59,16 @@ def logging_meth(func):
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper_logging_meth(self, *args, **kwargs):
|
def wrapper_logging_meth(self, *args, **kwargs):
|
||||||
r = func(self, *args, **kwargs)
|
r = func(self, *args, **kwargs)
|
||||||
self.log("%s(%s) -> \n%s" % (func.__name__, kwargs, pprint.pformat(r)))
|
# self.log("%s(%s) -> \n%s" % (func.__name__, kwargs, pprint.pformat(r)))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
return wrapper_logging_meth
|
return wrapper_logging_meth
|
||||||
|
|
||||||
|
|
||||||
class ScoFake(object):
|
class ScoFake(object):
|
||||||
def __init__(self, context, verbose=True):
|
"""Helper for ScoSoc tests"""
|
||||||
self.context = context
|
|
||||||
|
def __init__(self, verbose=True):
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
|
||||||
def log(self, msg):
|
def log(self, msg):
|
||||||
@ -127,10 +129,10 @@ class ScoFake(object):
|
|||||||
nom = r_nom
|
nom = r_nom
|
||||||
if not prenom:
|
if not prenom:
|
||||||
prenom = r_prenom
|
prenom = r_prenom
|
||||||
etud = sco_etud.create_etud(self.context, cnx, args=locals(), REQUEST=REQUEST)
|
etud = sco_etud.create_etud(context, cnx, args=locals(), REQUEST=REQUEST)
|
||||||
inscription = "2020" # pylint: disable=unused-variable
|
inscription = "2020" # pylint: disable=possibly-unused-variable
|
||||||
sco_synchro_etuds.do_import_etud_admission(
|
sco_synchro_etuds.do_import_etud_admission(
|
||||||
self.context, cnx, etud["etudid"], locals()
|
context, cnx, etud["etudid"], locals()
|
||||||
)
|
)
|
||||||
return etud
|
return etud
|
||||||
|
|
||||||
@ -147,10 +149,8 @@ class ScoFake(object):
|
|||||||
"""Crée une formation"""
|
"""Crée une formation"""
|
||||||
if not acronyme:
|
if not acronyme:
|
||||||
acronyme = "TEST" + str(random.randint(100000, 999999))
|
acronyme = "TEST" + str(random.randint(100000, 999999))
|
||||||
oid = sco_edit_formation.do_formation_create(
|
oid = sco_edit_formation.do_formation_create(context, locals(), REQUEST=REQUEST)
|
||||||
self.context, locals(), REQUEST=REQUEST
|
oids = sco_formations.formation_list(context, formation_id=oid)
|
||||||
)
|
|
||||||
oids = sco_formations.formation_list(self.context, formation_id=oid)
|
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("formation not created !")
|
raise ScoValueError("formation not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
@ -171,17 +171,17 @@ class ScoFake(object):
|
|||||||
):
|
):
|
||||||
"""Crée une UE"""
|
"""Crée une UE"""
|
||||||
if numero is None:
|
if numero is None:
|
||||||
numero = sco_edit_ue.next_ue_numero(self.context, formation_id, 0)
|
numero = sco_edit_ue.next_ue_numero(context, formation_id, 0)
|
||||||
oid = sco_edit_ue.do_ue_create(self.context, locals(), REQUEST)
|
oid = sco_edit_ue.do_ue_create(context, locals(), REQUEST)
|
||||||
oids = sco_edit_ue.do_ue_list(self.context, args={"ue_id": oid})
|
oids = sco_edit_ue.do_ue_list(context, args={"ue_id": oid})
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("ue not created !")
|
raise ScoValueError("ue not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
|
|
||||||
@logging_meth
|
@logging_meth
|
||||||
def create_matiere(self, ue_id=None, titre=None, numero=None):
|
def create_matiere(self, ue_id=None, titre=None, numero=None):
|
||||||
oid = sco_edit_matiere.do_matiere_create(self.context, locals(), REQUEST)
|
oid = sco_edit_matiere.do_matiere_create(context, locals(), REQUEST)
|
||||||
oids = sco_edit_matiere.do_matiere_list(self.context, args={"matiere_id": oid})
|
oids = sco_edit_matiere.do_matiere_list(context, args={"matiere_id": oid})
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("matiere not created !")
|
raise ScoValueError("matiere not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
@ -205,8 +205,8 @@ class ScoFake(object):
|
|||||||
code_apogee=None,
|
code_apogee=None,
|
||||||
module_type=None,
|
module_type=None,
|
||||||
):
|
):
|
||||||
oid = sco_edit_module.do_module_create(self.context, locals(), REQUEST)
|
oid = sco_edit_module.do_module_create(context, locals(), REQUEST)
|
||||||
oids = sco_edit_module.do_module_list(self.context, args={"module_id": oid})
|
oids = sco_edit_module.do_module_list(context, args={"module_id": oid})
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("module not created ! (oid=%s)" % oid)
|
raise ScoValueError("module not created ! (oid=%s)" % oid)
|
||||||
return oids[0]
|
return oids[0]
|
||||||
@ -231,12 +231,11 @@ class ScoFake(object):
|
|||||||
elt_sem_apo=None,
|
elt_sem_apo=None,
|
||||||
elt_annee_apo=None,
|
elt_annee_apo=None,
|
||||||
etapes=None,
|
etapes=None,
|
||||||
responsables=["bach"],
|
responsables=("bach",),
|
||||||
):
|
):
|
||||||
oid = sco_formsemestre.do_formsemestre_create(locals())
|
oid = sco_formsemestre.do_formsemestre_create(locals())
|
||||||
# oids = self.context.do_formsemestre_list(args={"formsemestre_id": oid})
|
|
||||||
oids = sco_formsemestre.do_formsemestre_list(
|
oids = sco_formsemestre.do_formsemestre_list(
|
||||||
self.context, args={"formsemestre_id": oid}
|
context, args={"formsemestre_id": oid}
|
||||||
) # API inconsistency
|
) # API inconsistency
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("formsemestre not created !")
|
raise ScoValueError("formsemestre not created !")
|
||||||
@ -249,9 +248,9 @@ class ScoFake(object):
|
|||||||
formsemestre_id=None,
|
formsemestre_id=None,
|
||||||
responsable_id=None,
|
responsable_id=None,
|
||||||
):
|
):
|
||||||
oid = sco_moduleimpl.do_moduleimpl_create(self.context, locals())
|
oid = sco_moduleimpl.do_moduleimpl_create(context, locals())
|
||||||
oids = sco_moduleimpl.do_moduleimpl_list(
|
oids = sco_moduleimpl.do_moduleimpl_list(
|
||||||
self.context, moduleimpl_id=oid
|
context, moduleimpl_id=oid
|
||||||
) # API inconsistency
|
) # API inconsistency
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("moduleimpl not created !")
|
raise ScoValueError("moduleimpl not created !")
|
||||||
@ -260,7 +259,7 @@ class ScoFake(object):
|
|||||||
@logging_meth
|
@logging_meth
|
||||||
def inscrit_etudiant(self, sem, etud):
|
def inscrit_etudiant(self, sem, etud):
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
||||||
self.context,
|
context,
|
||||||
sem["formsemestre_id"],
|
sem["formsemestre_id"],
|
||||||
etud["etudid"],
|
etud["etudid"],
|
||||||
etat="I",
|
etat="I",
|
||||||
@ -287,10 +286,8 @@ class ScoFake(object):
|
|||||||
):
|
):
|
||||||
args = locals()
|
args = locals()
|
||||||
del args["self"]
|
del args["self"]
|
||||||
oid = sco_evaluations.do_evaluation_create(self.context, **args)
|
oid = sco_evaluations.do_evaluation_create(**args)
|
||||||
oids = sco_evaluations.do_evaluation_list(
|
oids = sco_evaluations.do_evaluation_list(args={"evaluation_id": oid})
|
||||||
self.context, args={"evaluation_id": oid}
|
|
||||||
)
|
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("evaluation not created !")
|
raise ScoValueError("evaluation not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
@ -305,7 +302,7 @@ class ScoFake(object):
|
|||||||
uid="bach",
|
uid="bach",
|
||||||
):
|
):
|
||||||
return sco_saisie_notes._notes_add(
|
return sco_saisie_notes._notes_add(
|
||||||
self.context,
|
context,
|
||||||
uid,
|
uid,
|
||||||
evaluation["evaluation_id"],
|
evaluation["evaluation_id"],
|
||||||
[(etud["etudid"], note)],
|
[(etud["etudid"], note)],
|
||||||
@ -422,7 +419,7 @@ class ScoFake(object):
|
|||||||
):
|
):
|
||||||
"""Affecte décision de jury"""
|
"""Affecte décision de jury"""
|
||||||
sco_formsemestre_validation.formsemestre_validation_etud_manu(
|
sco_formsemestre_validation.formsemestre_validation_etud_manu(
|
||||||
self.context,
|
context,
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
code_etat=code_etat,
|
code_etat=code_etat,
|
@ -17,11 +17,12 @@ from app.scodoc import sco_evaluations
|
|||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
|
|
||||||
DEPT = "RT" # ce département (BD) doit exister
|
DEPT = "RT" # ce département (BD) doit exister
|
||||||
|
context = None # #context
|
||||||
|
|
||||||
|
|
||||||
def test_notes_table(test_client):
|
def test_notes_table(test_client):
|
||||||
"""Test construction et cache de NotesTable"""
|
"""Test construction et cache de NotesTable"""
|
||||||
sems = sco_formsemestre.do_formsemestre_list(None)
|
sems = sco_formsemestre.do_formsemestre_list(context)
|
||||||
assert len(sems)
|
assert len(sems)
|
||||||
sem = sems[0]
|
sem = sems[0]
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
|
178
tests/unit/test_sco_basic.py
Normal file
178
tests/unit/test_sco_basic.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Test de base de ScoDoc
|
||||||
|
|
||||||
|
|
||||||
|
Utiliser comme:
|
||||||
|
pytest tests/unit/test_sco_basic.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
import random
|
||||||
|
|
||||||
|
from flask import g
|
||||||
|
|
||||||
|
from tests.unit import sco_fake_gen
|
||||||
|
|
||||||
|
from app import decorators
|
||||||
|
from app.scodoc import notesdb as ndb
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
from app.scodoc import sco_abs
|
||||||
|
from app.scodoc import sco_abs_views
|
||||||
|
from app.scodoc import sco_bulletins
|
||||||
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_codes_parcours
|
||||||
|
from app.scodoc import sco_parcours_dut
|
||||||
|
from app.scodoc import sco_formsemestre_validation
|
||||||
|
|
||||||
|
context = None # #context
|
||||||
|
|
||||||
|
|
||||||
|
def test_sco_basic(test_client):
|
||||||
|
"""Test quelques opérations élémentaires de ScoDoc
|
||||||
|
Création 10 étudiants, formation, semestre, inscription etudiant,
|
||||||
|
creation 1 evaluation, saisie 10 notes.
|
||||||
|
"""
|
||||||
|
ndb.set_sco_dept("TEST00") # ce département doit exister !
|
||||||
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
G.verbose = True
|
||||||
|
|
||||||
|
# --- Création d'étudiants
|
||||||
|
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
|
||||||
|
|
||||||
|
# --- Création d'une formation
|
||||||
|
f = G.create_formation(acronyme="")
|
||||||
|
ue = G.create_ue(formation_id=f["formation_id"], acronyme="TST1", titre="ue test")
|
||||||
|
mat = G.create_matiere(ue_id=ue["ue_id"], titre="matière test")
|
||||||
|
mod = G.create_module(
|
||||||
|
matiere_id=mat["matiere_id"],
|
||||||
|
code="TSM1",
|
||||||
|
coefficient=1.0,
|
||||||
|
titre="module test",
|
||||||
|
ue_id=ue["ue_id"], # faiblesse de l'API
|
||||||
|
formation_id=f["formation_id"], # faiblesse de l'API
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Mise place d'un semestre
|
||||||
|
sem = G.create_formsemestre(
|
||||||
|
formation_id=f["formation_id"],
|
||||||
|
semestre_id=1,
|
||||||
|
date_debut="01/01/2020",
|
||||||
|
date_fin="30/06/2020",
|
||||||
|
)
|
||||||
|
|
||||||
|
mi = G.create_moduleimpl(
|
||||||
|
module_id=mod["module_id"],
|
||||||
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
|
responsable_id="bach",
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Inscription des étudiants
|
||||||
|
for etud in etuds:
|
||||||
|
G.inscrit_etudiant(sem, etud)
|
||||||
|
|
||||||
|
# --- Creation évaluation
|
||||||
|
e = G.create_evaluation(
|
||||||
|
moduleimpl_id=mi["moduleimpl_id"],
|
||||||
|
jour="01/01/2020",
|
||||||
|
description="evaluation test",
|
||||||
|
coefficient=1.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Saisie toutes les notes de l'évaluation
|
||||||
|
for etud in etuds:
|
||||||
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
|
evaluation=e, etud=etud, note=float(random.randint(0, 20))
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Vérifie que les notes sont prises en compte:
|
||||||
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
|
context, sem["formsemestre_id"], etud["etudid"]
|
||||||
|
)
|
||||||
|
# Toute les notes sont saisies, donc eval complète
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||||
|
assert etat["evalcomplete"]
|
||||||
|
# Un seul module, donc moy gen == note module
|
||||||
|
assert b["ues"][0]["cur_moy_ue_txt"] == b["ues"][0]["modules"][0]["mod_moy_txt"]
|
||||||
|
# Note au module égale à celle de l'éval
|
||||||
|
assert (
|
||||||
|
b["ues"][0]["modules"][0]["mod_moy_txt"]
|
||||||
|
== b["ues"][0]["modules"][0]["evaluations"][0]["note_txt"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Une autre évaluation
|
||||||
|
e2 = G.create_evaluation(
|
||||||
|
moduleimpl_id=mi["moduleimpl_id"],
|
||||||
|
jour="02/01/2020",
|
||||||
|
description="evaluation test 2",
|
||||||
|
coefficient=1.0,
|
||||||
|
)
|
||||||
|
# Saisie les notes des 5 premiers étudiants:
|
||||||
|
for etud in etuds[:5]:
|
||||||
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
|
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
||||||
|
)
|
||||||
|
# Cette éval n'est pas complète
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
|
assert etat["evalcomplete"] == False
|
||||||
|
# la première éval est toujours complète:
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||||
|
assert etat["evalcomplete"]
|
||||||
|
|
||||||
|
# Modifie l'évaluation 2 pour "prise en compte immédiate"
|
||||||
|
e2["publish_incomplete"] = "1"
|
||||||
|
sco_evaluations.do_evaluation_edit(e2)
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
|
assert etat["evalcomplete"] == False
|
||||||
|
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
||||||
|
assert etat["evalattente"] # mais l'eval est en attente (prise en compte immédiate)
|
||||||
|
|
||||||
|
# Saisie des notes qui manquent:
|
||||||
|
for etud in etuds[5:]:
|
||||||
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
|
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
||||||
|
)
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
|
assert etat["evalcomplete"]
|
||||||
|
assert etat["nb_att"] == 0
|
||||||
|
assert not etat["evalattente"] # toutes les notes sont présentes
|
||||||
|
|
||||||
|
# --- Saisie absences
|
||||||
|
etudid = etuds[0]["etudid"]
|
||||||
|
|
||||||
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
|
context, "15/01/2020", "18/01/2020", demijournee=2, etudid=etudid
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = sco_abs_views.doJustifAbsence(
|
||||||
|
context,
|
||||||
|
"17/01/2020",
|
||||||
|
"18/01/2020",
|
||||||
|
demijournee=2,
|
||||||
|
etudid=etudid,
|
||||||
|
)
|
||||||
|
|
||||||
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
|
assert nbabs == 6, "incorrect nbabs (%d)" % nbabs
|
||||||
|
assert nbabsjust == 2, "incorrect nbabsjust (%s)" % nbabsjust
|
||||||
|
|
||||||
|
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
|
||||||
|
# on n'a pas encore saisi de décisions
|
||||||
|
assert not sco_parcours_dut.formsemestre_has_decisions(
|
||||||
|
context, sem["formsemestre_id"]
|
||||||
|
)
|
||||||
|
# Saisie d'un décision AJ, non assidu
|
||||||
|
etudid = etuds[-1]["etudid"]
|
||||||
|
sco_parcours_dut.formsemestre_validate_ues(
|
||||||
|
context, sem["formsemestre_id"], etudid, sco_codes_parcours.AJ, False
|
||||||
|
)
|
||||||
|
assert sco_parcours_dut.formsemestre_has_decisions(
|
||||||
|
context, sem["formsemestre_id"]
|
||||||
|
), "décisions manquantes"
|
||||||
|
# Suppression de la décision
|
||||||
|
sco_formsemestre_validation.formsemestre_validation_suppress_etud(
|
||||||
|
context, sem["formsemestre_id"], etudid
|
||||||
|
)
|
||||||
|
assert not sco_parcours_dut.formsemestre_has_decisions(
|
||||||
|
context, sem["formsemestre_id"]
|
||||||
|
), "décisions non effacées"
|
@ -1,20 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Create database for a ScoDoc instance
|
# Create database for a ScoDoc departement
|
||||||
# This script must be executed as root
|
# This script must be executed as postgres super user
|
||||||
#
|
#
|
||||||
# $db_name is passed as an environment variable
|
# $db_name is passed as an environment variable
|
||||||
|
|
||||||
source config.sh
|
source config.sh
|
||||||
source utils.sh
|
source utils.sh
|
||||||
|
|
||||||
check_uid_root "$0"
|
echo 'Creating postgresql database'
|
||||||
|
|
||||||
# 1--- CREATION UTILISATEUR POSTGRESQL
|
|
||||||
init_postgres_user
|
|
||||||
|
|
||||||
# 2--- CREATION BASE UTILISATEURS
|
|
||||||
echo 'Creating postgresql database for users:' "$SCODOC_USER_DB"
|
|
||||||
su -c "createdb -E UTF-8 -p $POSTGRES_PORT -O $SCODOC_USER $SCODOC_USER_DB" $POSTGRES_SUPERUSER
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
echo 'Creating postgresql database ' $db_name
|
||||||
|
createdb -E UTF-8 -p $POSTGRES_PORT -O $POSTGRES_USER $db_name
|
||||||
|
|
||||||
|
@ -56,13 +56,13 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Ensure postgres user scodoc exists
|
# --- Ensure postgres user "scodoc" ($POSTGRES_USER) exists
|
||||||
init_postgres_user
|
init_postgres_user
|
||||||
|
|
||||||
# ----------------------- Create database
|
# ----------------------- Create Dept database
|
||||||
su -c ./create_database.sh "$POSTGRES_SUPERUSER"
|
su -c ./create_database.sh "$POSTGRES_SUPERUSER"
|
||||||
|
|
||||||
# ----------------------- Create tables
|
# ----------------------- Initialize table database
|
||||||
# POSTGRES_USER == regular unix user (scodoc)
|
# POSTGRES_USER == regular unix user (scodoc)
|
||||||
if [ "$interactive" = 1 ]
|
if [ "$interactive" = 1 ]
|
||||||
then
|
then
|
||||||
@ -92,7 +92,4 @@ then
|
|||||||
echo
|
echo
|
||||||
echo " Attention: la base de donnees n'a pas de copies de sauvegarde"
|
echo " Attention: la base de donnees n'a pas de copies de sauvegarde"
|
||||||
echo
|
echo
|
||||||
echo " Maintenant, vous pouvez ajouter le departement via l'application web"
|
|
||||||
echo " en suivant le lien \"Administration de ScoDoc\" sur la page d'accueil."
|
|
||||||
echo
|
|
||||||
fi
|
fi
|
||||||
|
18
tools/create_users_database.sh
Normal file
18
tools/create_users_database.sh
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Create USERS database for ScoDoc 8
|
||||||
|
# This script must be executed as root
|
||||||
|
#
|
||||||
|
# $db_name is passed as an environment variable
|
||||||
|
|
||||||
|
source config.sh
|
||||||
|
source utils.sh
|
||||||
|
|
||||||
|
check_uid_root "$0"
|
||||||
|
|
||||||
|
# 1--- CREATION UTILISATEUR POSTGRESQL
|
||||||
|
init_postgres_user
|
||||||
|
|
||||||
|
# 2--- CREATION BASE UTILISATEURS
|
||||||
|
echo 'Creating postgresql database for users:' "$SCODOC_USER_DB"
|
||||||
|
su -c "createdb -E UTF-8 -p $POSTGRES_PORT -O $SCODOC_USER $SCODOC_USER_DB" "$POSTGRES_SUPERUSER"
|
Loading…
Reference in New Issue
Block a user