Fix - test unitaires OK - bug saisie notes persistant

This commit is contained in:
Emmanuel Viennet 2021-08-21 12:23:00 +02:00
parent 3254093b95
commit 29b44ad5a4
7 changed files with 64 additions and 35 deletions

View File

@ -26,6 +26,8 @@ from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import sco_etud # a deplacer dans scu from app.scodoc import sco_etud # a deplacer dans scu
VALID_LOGIN_EXP = re.compile(r"^[a-zA-Z0-9@\\\-_\\\.]+$")
class User(UserMixin, db.Model): class User(UserMixin, db.Model):
"""ScoDoc users, handled by Flask / SQLAlchemy""" """ScoDoc users, handled by Flask / SQLAlchemy"""
@ -55,6 +57,9 @@ class User(UserMixin, db.Model):
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.roles = [] self.roles = []
self.user_roles = [] self.user_roles = []
# check login:
if kwargs.get("user_name") and not VALID_LOGIN_EXP.match(kwargs["user_name"]):
raise ValueError(f"invalid user_name: {kwargs['user_name']}")
super(User, self).__init__(**kwargs) super(User, self).__init__(**kwargs)
# Ajoute roles: # Ajoute roles:
if ( if (
@ -167,6 +172,8 @@ class User(UserMixin, db.Model):
self.user_name = data["user_name"] self.user_name = data["user_name"]
if "password" in data: if "password" in data:
self.set_password(data["password"]) self.set_password(data["password"])
if not VALID_LOGIN_EXP.match(self.user_name):
raise ValueError(f"invalid user_name: {self.user_name}")
# Roles: roles_string is "Ens_RT, Secr_RT, ..." # Roles: roles_string is "Ens_RT, Secr_RT, ..."
if "roles_string" in data: if "roles_string" in data:
self.user_roles = [] self.user_roles = []

View File

@ -35,6 +35,7 @@ import datetime
import psycopg2 import psycopg2
import flask import flask
from flask import g, url_for
from flask_login import current_user from flask_login import current_user
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -251,7 +252,11 @@ def do_evaluation_upload_xls(REQUEST):
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0] M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0] mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
mod["moduleimpl_id"] = M["moduleimpl_id"] mod["moduleimpl_id"] = M["moduleimpl_id"]
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod mod["url"] = url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=mod["moduleimpl_id"],
)
sco_news.add( sco_news.add(
typ=sco_news.NEWS_NOTE, typ=sco_news.NEWS_NOTE,
object=M["moduleimpl_id"], object=M["moduleimpl_id"],
@ -335,7 +340,11 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0] M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0] mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
mod["moduleimpl_id"] = M["moduleimpl_id"] mod["moduleimpl_id"] = M["moduleimpl_id"]
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod mod["url"] = url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=mod["moduleimpl_id"],
)
sco_news.add( sco_news.add(
typ=sco_news.NEWS_NOTE, typ=sco_news.NEWS_NOTE,
object=M["moduleimpl_id"], object=M["moduleimpl_id"],
@ -344,15 +353,23 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
) )
return ( return (
html_sco_header.sco_header() html_sco_header.sco_header()
+ """<h2>%d notes changées</h2> + f"""
<ul> <h2>{nb_changed} notes changées</h2>
<li><a class="stdlink" href="saisie_notes?evaluation_id=%s"> <ul>
Revenir au formulaire de saisie des notes</a></li> <li><a class="stdlink" href="{url_for("notes.saisie_notes",
<li><a class="stdlink" href="moduleimpl_status?moduleimpl_id=%s"> scodoc_dept=g.scodoc_dept, evaluation_id=evaluation_id)
Tableau de bord du module</a></li> }">
</ul> Revenir au formulaire de saisie des notes</a>
""" </li>
% (nb_changed, evaluation_id, M["moduleimpl_id"]) <li><a class="stdlink" href="{
url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=M["moduleimpl_id"],
)}">Tableau de bord du module</a>
</li>
</ul>
"""
+ html_sco_header.sco_footer() + html_sco_header.sco_footer()
) )
@ -930,14 +947,18 @@ def saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
H.append("""</td></tr></table></div>""") H.append("""</td></tr></table></div>""")
# Le formulaire de saisie des notes: # Le formulaire de saisie des notes:
destination = "%s/Notes/moduleimpl_status?moduleimpl_id=%s" % ( destination = url_for(
scu.ScoURL(), "notes.moduleimpl_status",
E["moduleimpl_id"], scodoc_dept=g.scodoc_dept,
moduleimpl_id=E["moduleimpl_id"],
) )
form = _form_saisie_notes( form = _form_saisie_notes(
E, M, groups_infos.group_ids, destination=destination, REQUEST=REQUEST E, M, groups_infos.group_ids, destination=destination, REQUEST=REQUEST
) )
if form is None: if form is None:
log(f"redirecting to {destination}")
stop
return flask.redirect(destination) return flask.redirect(destination)
H.append(form) H.append(form)
# #
@ -1044,9 +1065,8 @@ def _form_saisie_notes(E, M, group_ids, destination="", REQUEST=None):
# Decisions de jury existantes ? # Decisions de jury existantes ?
decisions_jury = {etudid: has_existing_decision(M, E, etudid) for etudid in etudids} decisions_jury = {etudid: has_existing_decision(M, E, etudid) for etudid in etudids}
nb_decisions = sum( # Nb de decisions de jury (pour les inscrits à l'évaluation):
decisions_jury.values() nb_decisions = sum(decisions_jury.values())
) # Nb de decisions de jury (pour les inscrits à l'évaluation)
etuds = _get_sorted_etuds(E, etudids, formsemestre_id) etuds = _get_sorted_etuds(E, etudids, formsemestre_id)
@ -1155,6 +1175,7 @@ def _form_saisie_notes(E, M, group_ids, destination="", REQUEST=None):
) )
) )
# #
breakpoint()
H = [] H = []
if nb_decisions > 0: if nb_decisions > 0:
H.append( H.append(
@ -1212,7 +1233,11 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment="", REQUEST=N
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0] E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0] M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0] Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
Mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % M Mod["url"] = url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=M["moduleimpl_id"],
)
result = {"nbchanged": 0} # JSON result = {"nbchanged": 0} # JSON
# Check access: admin, respformation, or responsable_id # Check access: admin, respformation, or responsable_id
if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]): if not sco_permissions_check.can_edit_notes(authuser, E["moduleimpl_id"]):

View File

@ -116,7 +116,7 @@ def create_user_form(REQUEST, user_name=None, edit=0):
is_super_admin = True is_super_admin = True
# Les rôles standards créés à l'initialisation de ScoDoc: # Les rôles standards créés à l'initialisation de ScoDoc:
standard_roles = [Role.get_named_role(r) for r in (u"Ens", u"Secr", u"Admin")] standard_roles = [Role.get_named_role(r) for r in ("Ens", "Secr", "Admin")]
# Rôles pouvant etre attribués aux utilisateurs via ce dialogue: # Rôles pouvant etre attribués aux utilisateurs via ce dialogue:
# si SuperAdmin, tous les rôles standards dans tous les départements # si SuperAdmin, tous les rôles standards dans tous les départements
# sinon, les départements dans lesquels l'utilisateur a le droit # sinon, les départements dans lesquels l'utilisateur a le droit

View File

@ -34,7 +34,6 @@ from app.scodoc import sco_moduleimpl
from app.scodoc import sco_saisie_notes from app.scodoc import sco_saisie_notes
from app.scodoc import sco_synchro_etuds from app.scodoc import sco_synchro_etuds
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc.debug import REQUEST
from app.scodoc.notes_log import log from app.scodoc.notes_log import log
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
@ -94,6 +93,7 @@ class ScoFake(object):
@logging_meth @logging_meth
def create_etud( def create_etud(
self,
cnx=None, cnx=None,
code_nip="", code_nip="",
nom="", nom="",
@ -128,7 +128,7 @@ 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(cnx, args=locals(), REQUEST=REQUEST) etud = sco_etud.create_etud(cnx, args=locals())
inscription = "2020" # pylint: disable=possibly-unused-variable inscription = "2020" # pylint: disable=possibly-unused-variable
sco_synchro_etuds.do_import_etud_admission(cnx, etud["etudid"], locals()) sco_synchro_etuds.do_import_etud_admission(cnx, etud["etudid"], locals())
return etud return etud
@ -262,7 +262,6 @@ class ScoFake(object):
etud["etudid"], etud["etudid"],
etat="I", etat="I",
etape=etud.get("etape", None), etape=etud.get("etape", None),
REQUEST=REQUEST,
method="test_inscrit_etudiant", method="test_inscrit_etudiant",
) )
@ -280,7 +279,6 @@ class ScoFake(object):
publish_incomplete=None, publish_incomplete=None,
evaluation_type=None, evaluation_type=None,
numero=None, numero=None,
REQUEST=REQUEST,
): ):
args = locals() args = locals()
del args["self"] del args["self"]
@ -423,5 +421,4 @@ class ScoFake(object):
code_etat=code_etat, code_etat=code_etat,
devenir=devenir, devenir=devenir,
assidu=assidu, assidu=assidu,
REQUEST=REQUEST,
) )

View File

@ -309,7 +309,7 @@ def test_abs_basic(test_client):
# --- Création de billets # --- Création de billets
b1 = absences.AddBilletAbsence( b1 = absences.AddBilletAbsence(
s begin="2021-01-22 00:00", begin="2021-01-22 00:00",
end="2021-01-22 23:59", end="2021-01-22 23:59",
etudid=etudid, etudid=etudid,
description="abs du 22", description="abs du 22",
@ -327,7 +327,7 @@ s begin="2021-01-22 00:00",
code_ine=etuds[0]["code_ine"], code_ine=etuds[0]["code_ine"],
) )
li_bi = absences.listeBilletsEtud( etudid=etudid, format="json") li_bi = absences.listeBilletsEtud(etudid=etudid, format="json")
assert isinstance(li_bi, str) assert isinstance(li_bi, str)
load_li_bi = json.loads(li_bi) load_li_bi = json.loads(li_bi)

View File

@ -59,7 +59,7 @@ def test_preferences(test_client):
.value .value
) )
# Compare valeurs # Compare valeurs
sco_val = prefs.get("abs_notification_mail_tmpl") sco_val = prefs.get(None, "abs_notification_mail_tmpl")
assert orm_val.strip() == sco_val.strip() assert orm_val.strip() == sco_val.strip()
# nb: I don't understand why SQLAlchemy strips the string ?! # nb: I don't understand why SQLAlchemy strips the string ?!
@ -71,9 +71,9 @@ def test_preferences(test_client):
app.set_sco_dept("D2") app.set_sco_dept("D2")
prefs2 = sco_preferences.get_base_preferences() prefs2 = sco_preferences.get_base_preferences()
assert len(prefs2) == len(prefs) assert len(prefs2) == len(prefs)
prefs2.set("abs_notification_mail_tmpl", "toto") prefs2.set(None, "abs_notification_mail_tmpl", "toto")
assert prefs2.get("abs_notification_mail_tmpl") == "toto" assert prefs2.get(None, "abs_notification_mail_tmpl") == "toto"
assert prefs.get("abs_notification_mail_tmpl") != "toto" assert prefs.get(None, "abs_notification_mail_tmpl") != "toto"
orm_val = ( orm_val = (
ScoPreference.query.filter_by(dept_id=d.id, name="abs_notification_mail_tmpl") ScoPreference.query.filter_by(dept_id=d.id, name="abs_notification_mail_tmpl")
.first() .first()
@ -81,7 +81,7 @@ def test_preferences(test_client):
) )
assert orm_val == "toto" assert orm_val == "toto"
# --- Preferences d'un semestre # --- Preferences d'un semestre
# rejoure ce test pour avoir un semestre créé # rejoue ce test pour avoir un semestre créé
test_sco_basic.run_sco_basic() test_sco_basic.run_sco_basic()
sem = sco_formsemestre.do_formsemestre_list()[0] sem = sco_formsemestre.do_formsemestre_list()[0]
formsemestre_id = sem["formsemestre_id"] formsemestre_id = sem["formsemestre_id"]

View File

@ -65,7 +65,7 @@ def test_users_roles(test_client):
dept = "XX" dept = "XX"
perm = Permission.ScoAbsChange perm = Permission.ScoAbsChange
perm2 = Permission.ScoView perm2 = Permission.ScoView
u = User(user_name="un enseignant") u = User(user_name="un_enseignant")
db.session.add(u) db.session.add(u)
assert not u.has_permission(perm, dept) assert not u.has_permission(perm, dept)
r = Role.get_named_role("Ens") r = Role.get_named_role("Ens")
@ -73,7 +73,7 @@ def test_users_roles(test_client):
r = Role(name="Ens", permissions=perm) r = Role(name="Ens", permissions=perm)
u.add_role(r, dept) u.add_role(r, dept)
assert u.has_permission(perm, dept) assert u.has_permission(perm, dept)
u = User(user_name="un autre") u = User(user_name="un_autre")
u.add_role(r, dept) u.add_role(r, dept)
db.session.add(u) db.session.add(u)
db.session.commit() db.session.commit()
@ -83,7 +83,7 @@ def test_users_roles(test_client):
r2 = Role(name="Secr", dept=dept, permissions=perm2) r2 = Role(name="Secr", dept=dept, permissions=perm2)
u.add_roles([r, r2], dept) u.add_roles([r, r2], dept)
assert len(u.roles) == 2 assert len(u.roles) == 2
u = User(user_name="encore un") u = User(user_name="encore_un")
db.session.add(u) db.session.add(u)
db.session.commit() db.session.commit()
u.set_roles([r, r2], dept) u.set_roles([r, r2], dept)
@ -99,7 +99,7 @@ def test_users_roles(test_client):
def test_user_admin(test_client): def test_user_admin(test_client):
dept = "XX" dept = "XX"
perm = 0x1234 # a random perm perm = 0x1234 # a random perm
u = User(user_name="un admin", email=current_app.config["SCODOC_ADMIN_MAIL"]) u = User(user_name="un_admin", email=current_app.config["SCODOC_ADMIN_MAIL"])
db.session.add(u) db.session.add(u)
assert len(u.roles) == 1 assert len(u.roles) == 1
assert u.has_permission(perm, dept) assert u.has_permission(perm, dept)