forked from ScoDoc/ScoDoc
maj
This commit is contained in:
commit
e249f45ce9
@ -130,12 +130,12 @@ base de données (tous les départements, et les utilisateurs) avant de commence
|
|||||||
|
|
||||||
On utilise SQLAlchemy avec Alembic et Flask-Migrate.
|
On utilise SQLAlchemy avec Alembic et Flask-Migrate.
|
||||||
|
|
||||||
flask db migrate -m "ScoDoc 9.0.x: ..." # ajuster le message !
|
flask db migrate -m "message explicatif....."
|
||||||
flask db upgrade
|
flask db upgrade
|
||||||
|
|
||||||
Ne pas oublier de commiter les migrations (`git add migrations` ...).
|
Ne pas oublier de d'ajouter le script de migration à git (`git add migrations/...`).
|
||||||
|
|
||||||
Mémo pour développeurs: séquence re-création d'une base (vérifiez votre `.env`
|
**Mémo**: séquence re-création d'une base (vérifiez votre `.env`
|
||||||
ou variables d'environnement pour interroger la bonne base !).
|
ou variables d'environnement pour interroger la bonne base !).
|
||||||
|
|
||||||
dropdb SCODOC_DEV
|
dropdb SCODOC_DEV
|
||||||
|
@ -317,6 +317,8 @@ def set_sco_dept(scodoc_dept: str):
|
|||||||
g.scodoc_dept_id = dept.id # l'id
|
g.scodoc_dept_id = dept.id # l'id
|
||||||
if not hasattr(g, "db_conn"):
|
if not hasattr(g, "db_conn"):
|
||||||
ndb.open_db_connection()
|
ndb.open_db_connection()
|
||||||
|
if not hasattr(g, "stored_get_formsemestre"):
|
||||||
|
g.stored_get_formsemestre = {}
|
||||||
|
|
||||||
|
|
||||||
def user_db_init():
|
def user_db_init():
|
||||||
|
@ -33,7 +33,7 @@ token_auth = HTTPTokenAuth()
|
|||||||
|
|
||||||
@basic_auth.verify_password
|
@basic_auth.verify_password
|
||||||
def verify_password(username, password):
|
def verify_password(username, password):
|
||||||
user = User.query.filter_by(username=username).first()
|
user = User.query.filter_by(user_name=username).first()
|
||||||
if user and user.check_password(password):
|
if user and user.check_password(password):
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
"""
|
"""
|
||||||
# PAS ENCORE IMPLEMENTEE, juste un essai
|
# PAS ENCORE IMPLEMENTEE, juste un essai
|
||||||
# Pour P. Bouron, il faudrait en priorité l'équivalent de
|
# Pour P. Bouron, il faudrait en priorité l'équivalent de
|
||||||
# Scolarite/Notes/do_moduleimpl_withmodule_list
|
# Scolarite/Notes/moduleimpl_withmodule_list (alias scodoc7 do_moduleimpl_withmodule_list)
|
||||||
# Scolarite/Notes/evaluation_create
|
# Scolarite/Notes/evaluation_create
|
||||||
# Scolarite/Notes/evaluation_delete
|
# Scolarite/Notes/evaluation_delete
|
||||||
# Scolarite/Notes/formation_list
|
# Scolarite/Notes/formation_list
|
||||||
|
@ -8,7 +8,7 @@ TODO: à revoir complètement pour reprendre ZScoUsers et les pages d'authentifi
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
||||||
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
||||||
from app.auth.models import User
|
from app.auth.models import User, is_valid_password
|
||||||
|
|
||||||
|
|
||||||
_ = lambda x: x # sans babel
|
_ = lambda x: x # sans babel
|
||||||
@ -43,8 +43,11 @@ class UserCreationForm(FlaskForm):
|
|||||||
|
|
||||||
|
|
||||||
class ResetPasswordRequestForm(FlaskForm):
|
class ResetPasswordRequestForm(FlaskForm):
|
||||||
email = StringField(_l("Email"), validators=[DataRequired(), Email()])
|
email = StringField(
|
||||||
submit = SubmitField(_l("Request Password Reset"))
|
_l("Adresse email associée à votre compte ScoDoc:"),
|
||||||
|
validators=[DataRequired(), Email()],
|
||||||
|
)
|
||||||
|
submit = SubmitField(_l("Envoyer"))
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordForm(FlaskForm):
|
class ResetPasswordForm(FlaskForm):
|
||||||
@ -52,7 +55,11 @@ class ResetPasswordForm(FlaskForm):
|
|||||||
password2 = PasswordField(
|
password2 = PasswordField(
|
||||||
_l("Répéter"), validators=[DataRequired(), EqualTo("password")]
|
_l("Répéter"), validators=[DataRequired(), EqualTo("password")]
|
||||||
)
|
)
|
||||||
submit = SubmitField(_l("Request Password Reset"))
|
submit = SubmitField(_l("Valider ce mot de passe"))
|
||||||
|
|
||||||
|
def validate_password(self, password):
|
||||||
|
if not is_valid_password(password.data):
|
||||||
|
raise ValidationError(f"Mot de passe trop simple, recommencez")
|
||||||
|
|
||||||
|
|
||||||
class DeactivateUserForm(FlaskForm):
|
class DeactivateUserForm(FlaskForm):
|
||||||
|
@ -10,6 +10,7 @@ import re
|
|||||||
from time import time
|
from time import time
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import cracklib # pylint: disable=import-error
|
||||||
from flask import current_app, url_for, g
|
from flask import current_app, url_for, g
|
||||||
from flask_login import UserMixin, AnonymousUserMixin
|
from flask_login import UserMixin, AnonymousUserMixin
|
||||||
|
|
||||||
@ -28,6 +29,23 @@ from app.scodoc import sco_etud # a deplacer dans scu
|
|||||||
VALID_LOGIN_EXP = re.compile(r"^[a-zA-Z0-9@\\\-_\.]+$")
|
VALID_LOGIN_EXP = re.compile(r"^[a-zA-Z0-9@\\\-_\.]+$")
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_password(cleartxt):
|
||||||
|
"""Check password.
|
||||||
|
returns True if OK.
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
hasattr(scu.CONFIG, "MIN_PASSWORD_LENGTH")
|
||||||
|
and scu.CONFIG.MIN_PASSWORD_LENGTH > 0
|
||||||
|
and len(cleartxt) < scu.CONFIG.MIN_PASSWORD_LENGTH
|
||||||
|
):
|
||||||
|
return False # invalid: too short
|
||||||
|
try:
|
||||||
|
_ = cracklib.FascistCheck(cleartxt)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class User(UserMixin, db.Model):
|
class User(UserMixin, db.Model):
|
||||||
"""ScoDoc users, handled by Flask / SQLAlchemy"""
|
"""ScoDoc users, handled by Flask / SQLAlchemy"""
|
||||||
|
|
||||||
|
@ -46,7 +46,10 @@ def login():
|
|||||||
if not next_page or url_parse(next_page).netloc != "":
|
if not next_page or url_parse(next_page).netloc != "":
|
||||||
next_page = url_for("scodoc.index")
|
next_page = url_for("scodoc.index")
|
||||||
return redirect(next_page)
|
return redirect(next_page)
|
||||||
return render_template("auth/login.html", title=_("Sign In"), form=form)
|
message = request.args.get("message", "")
|
||||||
|
return render_template(
|
||||||
|
"auth/login.html", title=_("Sign In"), form=form, message=message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/logout")
|
@bp.route("/logout")
|
||||||
@ -95,7 +98,9 @@ def reset_password_request():
|
|||||||
current_app.logger.info(
|
current_app.logger.info(
|
||||||
"reset_password_request: for unkown user '{}'".format(form.email.data)
|
"reset_password_request: for unkown user '{}'".format(form.email.data)
|
||||||
)
|
)
|
||||||
flash(_("Voir les instructions envoyées par mail"))
|
flash(
|
||||||
|
_("Voir les instructions envoyées par mail (pensez à regarder vos spams)")
|
||||||
|
)
|
||||||
return redirect(url_for("auth.login"))
|
return redirect(url_for("auth.login"))
|
||||||
return render_template(
|
return render_template(
|
||||||
"auth/reset_password_request.html", title=_("Reset Password"), form=form
|
"auth/reset_password_request.html", title=_("Reset Password"), form=form
|
||||||
@ -113,6 +118,6 @@ def reset_password(token):
|
|||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
user.set_password(form.password.data)
|
user.set_password(form.password.data)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(_("Your password has been reset."))
|
flash(_("Votre mot de passe a été changé."))
|
||||||
return redirect(url_for("auth.login"))
|
return redirect(url_for("auth.login"))
|
||||||
return render_template("auth/reset_password.html", form=form)
|
return render_template("auth/reset_password.html", form=form, user=user)
|
||||||
|
@ -10,12 +10,10 @@ import logging
|
|||||||
import werkzeug
|
import werkzeug
|
||||||
from werkzeug.exceptions import BadRequest
|
from werkzeug.exceptions import BadRequest
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g, current_app, request
|
||||||
from flask import abort, current_app
|
from flask import abort, url_for, redirect
|
||||||
from flask import request
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from flask import current_app
|
|
||||||
import flask_login
|
import flask_login
|
||||||
|
|
||||||
import app
|
import app
|
||||||
@ -52,6 +50,15 @@ def scodoc(func):
|
|||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def scodoc_function(*args, **kwargs):
|
def scodoc_function(*args, **kwargs):
|
||||||
|
# interdit les POST si pas loggué
|
||||||
|
if request.method == "POST" and not current_user.is_authenticated:
|
||||||
|
current_app.logger.info("POST by non authenticated user")
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"auth.login",
|
||||||
|
message="La page a expiré. Identifiez-vous et recommencez l'opération",
|
||||||
|
)
|
||||||
|
)
|
||||||
if "scodoc_dept" in kwargs:
|
if "scodoc_dept" in kwargs:
|
||||||
dept_acronym = kwargs["scodoc_dept"]
|
dept_acronym = kwargs["scodoc_dept"]
|
||||||
# current_app.logger.info("setting dept to " + dept_acronym)
|
# current_app.logger.info("setting dept to " + dept_acronym)
|
||||||
@ -81,7 +88,7 @@ def permission_required(permission):
|
|||||||
|
|
||||||
|
|
||||||
def permission_required_compat_scodoc7(permission):
|
def permission_required_compat_scodoc7(permission):
|
||||||
"""Décorateur pour les fonctions utilisée comme API dans ScoDoc 7
|
"""Décorateur pour les fonctions utilisées comme API dans ScoDoc 7
|
||||||
Comme @permission_required mais autorise de passer directement
|
Comme @permission_required mais autorise de passer directement
|
||||||
les informations d'auth en paramètres:
|
les informations d'auth en paramètres:
|
||||||
__ac_name, __ac_password
|
__ac_name, __ac_password
|
||||||
|
@ -32,6 +32,7 @@ class NotesFormation(db.Model):
|
|||||||
|
|
||||||
ues = db.relationship("NotesUE", backref="formation", lazy="dynamic")
|
ues = db.relationship("NotesUE", backref="formation", lazy="dynamic")
|
||||||
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
|
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
|
||||||
|
ues = db.relationship("NotesUE", lazy="dynamic", backref="formation")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme}')>"
|
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme}')>"
|
||||||
@ -65,6 +66,10 @@ class NotesUE(db.Model):
|
|||||||
# coef UE, utilise seulement si l'option use_ue_coefs est activée:
|
# coef UE, utilise seulement si l'option use_ue_coefs est activée:
|
||||||
coefficient = db.Column(db.Float)
|
coefficient = db.Column(db.Float)
|
||||||
|
|
||||||
|
# relations
|
||||||
|
matieres = db.relationship("NotesMatiere", lazy="dynamic", backref="ue")
|
||||||
|
modules = db.relationship("NotesModule", lazy="dynamic", backref="ue")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
||||||
|
|
||||||
@ -84,6 +89,8 @@ class NotesMatiere(db.Model):
|
|||||||
titre = db.Column(db.Text())
|
titre = db.Column(db.Text())
|
||||||
numero = db.Column(db.Integer) # ordre de présentation
|
numero = db.Column(db.Integer) # ordre de présentation
|
||||||
|
|
||||||
|
modules = db.relationship("NotesModule", lazy="dynamic", backref="matiere")
|
||||||
|
|
||||||
|
|
||||||
class NotesModule(db.Model):
|
class NotesModule(db.Model):
|
||||||
"""Module"""
|
"""Module"""
|
||||||
@ -110,6 +117,8 @@ class NotesModule(db.Model):
|
|||||||
# id de l'element pedagogique Apogee correspondant:
|
# id de l'element pedagogique Apogee correspondant:
|
||||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||||
module_type = db.Column(db.Integer) # NULL ou 0:defaut, 1: malus (NOTES_MALUS)
|
module_type = db.Column(db.Integer) # NULL ou 0:defaut, 1: malus (NOTES_MALUS)
|
||||||
|
# Relations:
|
||||||
|
modimpls = db.relationship("NotesModuleImpl", backref="module", lazy="dynamic")
|
||||||
|
|
||||||
|
|
||||||
class NotesTag(db.Model):
|
class NotesTag(db.Model):
|
||||||
|
@ -70,9 +70,14 @@ class FormSemestre(db.Model):
|
|||||||
# code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'
|
# code element annee Apogee, eg 'VRT1A' ou 'V2INLA,V2INCA,...'
|
||||||
elt_annee_apo = db.Column(db.Text())
|
elt_annee_apo = db.Column(db.Text())
|
||||||
|
|
||||||
|
# Relations:
|
||||||
etapes = db.relationship(
|
etapes = db.relationship(
|
||||||
"NotesFormsemestreEtape", cascade="all,delete", backref="notes_formsemestre"
|
"NotesFormsemestreEtape", cascade="all,delete", backref="formsemestre"
|
||||||
)
|
)
|
||||||
|
formsemestres = db.relationship(
|
||||||
|
"NotesModuleImpl", backref="formsemestre", lazy="dynamic"
|
||||||
|
)
|
||||||
|
|
||||||
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
||||||
# ne pas utiliser après migrate_scodoc7_dept_archive
|
# ne pas utiliser après migrate_scodoc7_dept_archive
|
||||||
scodoc7_id = db.Column(db.Text(), nullable=True)
|
scodoc7_id = db.Column(db.Text(), nullable=True)
|
||||||
|
@ -44,7 +44,6 @@ import unicodedata
|
|||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
import six
|
|
||||||
|
|
||||||
PE_DEBUG = 0
|
PE_DEBUG = 0
|
||||||
|
|
||||||
@ -145,7 +144,7 @@ def escape_for_latex(s):
|
|||||||
}
|
}
|
||||||
exp = re.compile(
|
exp = re.compile(
|
||||||
"|".join(
|
"|".join(
|
||||||
re.escape(six.text_type(key))
|
re.escape(key)
|
||||||
for key in sorted(list(conv.keys()), key=lambda item: -len(item))
|
for key in sorted(list(conv.keys()), key=lambda item: -len(item))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -194,7 +194,8 @@ def bonus_tours(notes_sport, coefs, infos=None):
|
|||||||
|
|
||||||
|
|
||||||
def bonus_iutr(notes_sport, coefs, infos=None):
|
def bonus_iutr(notes_sport, coefs, infos=None):
|
||||||
"""Calcul du bonus , regle de l'IUT de Roanne (contribuée par Raphael C., nov 2012)
|
"""Calcul du bonus , règle de l'IUT de Roanne
|
||||||
|
(contribuée par Raphael C., nov 2012)
|
||||||
|
|
||||||
Le bonus est compris entre 0 et 0.35 point.
|
Le bonus est compris entre 0 et 0.35 point.
|
||||||
cette procédure modifie la moyenne de chaque UE capitalisable.
|
cette procédure modifie la moyenne de chaque UE capitalisable.
|
||||||
|
@ -752,6 +752,8 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = doc.getvalue()
|
data = doc.getvalue()
|
||||||
open("/tmp/gen_table.pdf", "wb").write(data)
|
with open("/tmp/gen_table.pdf", "wb") as f:
|
||||||
|
f.write(data)
|
||||||
p = T.make_page(format="pdf")
|
p = T.make_page(format="pdf")
|
||||||
open("toto.pdf", "wb").write(p)
|
with open("toto.pdf", "wb") as f:
|
||||||
|
f.write(p)
|
||||||
|
@ -104,6 +104,8 @@ def make_menu(title, items, css_class="", alone=False):
|
|||||||
item["urlq"] = url_for(
|
item["urlq"] = url_for(
|
||||||
item["endpoint"], scodoc_dept=g.scodoc_dept, **args
|
item["endpoint"], scodoc_dept=g.scodoc_dept, **args
|
||||||
)
|
)
|
||||||
|
elif "url" in item:
|
||||||
|
item["urlq"] = item["url"]
|
||||||
else:
|
else:
|
||||||
item["urlq"] = "#"
|
item["urlq"] = "#"
|
||||||
item["attr"] = item.get("attr", "")
|
item["attr"] = item.get("attr", "")
|
||||||
|
@ -4,11 +4,8 @@
|
|||||||
|
|
||||||
# Code from http://code.activestate.com/recipes/457411/
|
# Code from http://code.activestate.com/recipes/457411/
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from bisect import bisect_left, bisect_right
|
from bisect import bisect_left, bisect_right
|
||||||
|
|
||||||
from six.moves import zip
|
|
||||||
|
|
||||||
|
|
||||||
class intervalmap(object):
|
class intervalmap(object):
|
||||||
"""
|
"""
|
||||||
|
@ -27,10 +27,7 @@
|
|||||||
|
|
||||||
"""Calculs sur les notes et cache des resultats
|
"""Calculs sur les notes et cache des resultats
|
||||||
"""
|
"""
|
||||||
import inspect
|
|
||||||
import os
|
|
||||||
import pdb
|
|
||||||
import time
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
@ -40,12 +37,8 @@ import app.scodoc.sco_utils as scu
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_formulas import NoteVector
|
from app.scodoc.sco_formulas import NoteVector
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
AccessDenied,
|
|
||||||
NoteProcessError,
|
|
||||||
ScoException,
|
|
||||||
ScoValueError,
|
|
||||||
)
|
|
||||||
from app.scodoc.sco_formsemestre import (
|
from app.scodoc.sco_formsemestre import (
|
||||||
formsemestre_uecoef_list,
|
formsemestre_uecoef_list,
|
||||||
formsemestre_uecoef_create,
|
formsemestre_uecoef_create,
|
||||||
@ -109,15 +102,13 @@ def get_sem_ues_modimpls(formsemestre_id, modimpls=None):
|
|||||||
(utilisé quand on ne peut pas construire nt et faire nt.get_ues())
|
(utilisé quand on ne peut pas construire nt et faire nt.get_ues())
|
||||||
"""
|
"""
|
||||||
if modimpls is None:
|
if modimpls is None:
|
||||||
modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
uedict = {}
|
uedict = {}
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
mod = sco_edit_module.do_module_list(args={"module_id": modimpl["module_id"]})[
|
mod = sco_edit_module.module_list(args={"module_id": modimpl["module_id"]})[0]
|
||||||
0
|
|
||||||
]
|
|
||||||
modimpl["module"] = mod
|
modimpl["module"] = mod
|
||||||
if not mod["ue_id"] in uedict:
|
if not mod["ue_id"] in uedict:
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": mod["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": mod["ue_id"]})[0]
|
||||||
uedict[ue["ue_id"]] = ue
|
uedict[ue["ue_id"]] = ue
|
||||||
ues = list(uedict.values())
|
ues = list(uedict.values())
|
||||||
ues.sort(key=lambda u: u["numero"])
|
ues.sort(key=lambda u: u["numero"])
|
||||||
@ -219,26 +210,29 @@ class NotesTable(object):
|
|||||||
valid_evals,
|
valid_evals,
|
||||||
mods_att,
|
mods_att,
|
||||||
self.expr_diagnostics,
|
self.expr_diagnostics,
|
||||||
) = sco_compute_moy.do_formsemestre_moyennes(self, formsemestre_id)
|
) = sco_compute_moy.formsemestre_compute_modimpls_moyennes(
|
||||||
|
self, formsemestre_id
|
||||||
|
)
|
||||||
self._mods_att = mods_att # liste des modules avec des notes en attente
|
self._mods_att = mods_att # liste des modules avec des notes en attente
|
||||||
self._matmoys = {} # moyennes par matieres
|
self._matmoys = {} # moyennes par matieres
|
||||||
self._valid_evals = {} # { evaluation_id : eval }
|
self._valid_evals = {} # { evaluation_id : eval }
|
||||||
for e in valid_evals:
|
for e in valid_evals:
|
||||||
self._valid_evals[e["evaluation_id"]] = e # Liste des modules et UE
|
self._valid_evals[e["evaluation_id"]] = e # Liste des modules et UE
|
||||||
uedict = {} # public member: { ue_id : ue }
|
uedict = {} # public member: { ue_id : ue }
|
||||||
self.uedict = uedict
|
self.uedict = uedict # les ues qui ont un modimpl dans ce semestre
|
||||||
for modimpl in self._modimpls:
|
for modimpl in self._modimpls:
|
||||||
mod = modimpl["module"] # has been added here by do_formsemestre_moyennes
|
# module has been added by formsemestre_compute_modimpls_moyennes
|
||||||
|
mod = modimpl["module"]
|
||||||
if not mod["ue_id"] in uedict:
|
if not mod["ue_id"] in uedict:
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": mod["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": mod["ue_id"]})[0]
|
||||||
uedict[ue["ue_id"]] = ue
|
uedict[ue["ue_id"]] = ue
|
||||||
else:
|
else:
|
||||||
ue = uedict[mod["ue_id"]]
|
ue = uedict[mod["ue_id"]]
|
||||||
modimpl["ue"] = ue # add ue dict to moduleimpl
|
modimpl["ue"] = ue # add ue dict to moduleimpl
|
||||||
self._matmoys[mod["matiere_id"]] = {}
|
self._matmoys[mod["matiere_id"]] = {}
|
||||||
mat = sco_edit_matiere.do_matiere_list(
|
mat = sco_edit_matiere.matiere_list(args={"matiere_id": mod["matiere_id"]})[
|
||||||
args={"matiere_id": mod["matiere_id"]}
|
0
|
||||||
)[0]
|
]
|
||||||
modimpl["mat"] = mat # add matiere dict to moduleimpl
|
modimpl["mat"] = mat # add matiere dict to moduleimpl
|
||||||
# calcul moyennes du module et stocke dans le module
|
# calcul moyennes du module et stocke dans le module
|
||||||
# nb_inscrits, nb_notes, nb_abs, nb_neutre, moy, median, last_modif=
|
# nb_inscrits, nb_notes, nb_abs, nb_neutre, moy, median, last_modif=
|
||||||
@ -1059,7 +1053,7 @@ class NotesTable(object):
|
|||||||
"Warning: %s capitalized an UE %s which is not part of current sem %s"
|
"Warning: %s capitalized an UE %s which is not part of current sem %s"
|
||||||
% (etudid, ue_id, self.formsemestre_id)
|
% (etudid, ue_id, self.formsemestre_id)
|
||||||
)
|
)
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||||
self.uedict[ue_id] = ue # record this UE
|
self.uedict[ue_id] = ue # record this UE
|
||||||
if ue_id not in self._uecoef:
|
if ue_id not in self._uecoef:
|
||||||
cl = formsemestre_uecoef_list(
|
cl = formsemestre_uecoef_list(
|
||||||
|
@ -96,7 +96,7 @@ def DBInsertDict(
|
|||||||
convert_empty_to_nulls=1,
|
convert_empty_to_nulls=1,
|
||||||
return_id=True,
|
return_id=True,
|
||||||
ignore_conflicts=False,
|
ignore_conflicts=False,
|
||||||
):
|
) -> int:
|
||||||
"""insert into table values in dict 'vals'
|
"""insert into table values in dict 'vals'
|
||||||
Return: id de l'object créé
|
Return: id de l'object créé
|
||||||
"""
|
"""
|
||||||
@ -327,7 +327,7 @@ class EditableTable(object):
|
|||||||
self.sql_default_values = None
|
self.sql_default_values = None
|
||||||
self.insert_ignore_conflicts = insert_ignore_conflicts
|
self.insert_ignore_conflicts = insert_ignore_conflicts
|
||||||
|
|
||||||
def create(self, cnx, args):
|
def create(self, cnx, args) -> int:
|
||||||
"create object in table"
|
"create object in table"
|
||||||
vals = dictfilter(args, self.dbfields, self.filter_nulls)
|
vals = dictfilter(args, self.dbfields, self.filter_nulls)
|
||||||
if self.id_name in vals:
|
if self.id_name in vals:
|
||||||
|
@ -474,7 +474,7 @@ def _get_abs_description(a, cursor=None):
|
|||||||
desc = a["description"]
|
desc = a["description"]
|
||||||
if a["moduleimpl_id"] and a["moduleimpl_id"] != "NULL":
|
if a["moduleimpl_id"] and a["moduleimpl_id"] != "NULL":
|
||||||
# Trouver le nom du module
|
# Trouver le nom du module
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=a["moduleimpl_id"]
|
moduleimpl_id=a["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
if Mlist:
|
if Mlist:
|
||||||
|
@ -115,7 +115,7 @@ def doSignaleAbsence(
|
|||||||
J = "NON "
|
J = "NON "
|
||||||
M = ""
|
M = ""
|
||||||
if moduleimpl_id and moduleimpl_id != "NULL":
|
if moduleimpl_id and moduleimpl_id != "NULL":
|
||||||
mod = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
formsemestre_id = mod["formsemestre_id"]
|
formsemestre_id = mod["formsemestre_id"]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||||
ues = nt.get_ues(etudid=etudid)
|
ues = nt.get_ues(etudid=etudid)
|
||||||
@ -939,7 +939,7 @@ def _tables_abs_etud(
|
|||||||
return ""
|
return ""
|
||||||
ex = []
|
ex = []
|
||||||
for ev in a["evals"]:
|
for ev in a["evals"]:
|
||||||
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
mod = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=ev["moduleimpl_id"]
|
moduleimpl_id=ev["moduleimpl_id"]
|
||||||
)[0]
|
)[0]
|
||||||
if format == "html":
|
if format == "html":
|
||||||
@ -957,7 +957,7 @@ def _tables_abs_etud(
|
|||||||
def descr_abs(a):
|
def descr_abs(a):
|
||||||
ex = []
|
ex = []
|
||||||
for ev in a.get("absent", []):
|
for ev in a.get("absent", []):
|
||||||
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
mod = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=ev["moduleimpl_id"]
|
moduleimpl_id=ev["moduleimpl_id"]
|
||||||
)[0]
|
)[0]
|
||||||
if format == "html":
|
if format == "html":
|
||||||
|
@ -203,7 +203,9 @@ class BaseArchiver(object):
|
|||||||
def get_archive_description(self, archive_id):
|
def get_archive_description(self, archive_id):
|
||||||
"""Return description of archive"""
|
"""Return description of archive"""
|
||||||
self.initialize()
|
self.initialize()
|
||||||
return open(os.path.join(archive_id, "_description.txt")).read()
|
with open(os.path.join(archive_id, "_description.txt")) as f:
|
||||||
|
descr = f.read()
|
||||||
|
return descr
|
||||||
|
|
||||||
def create_obj_archive(self, oid: int, description: str):
|
def create_obj_archive(self, oid: int, description: str):
|
||||||
"""Creates a new archive for this object and returns its id."""
|
"""Creates a new archive for this object and returns its id."""
|
||||||
@ -232,9 +234,8 @@ class BaseArchiver(object):
|
|||||||
try:
|
try:
|
||||||
scu.GSL.acquire()
|
scu.GSL.acquire()
|
||||||
fname = os.path.join(archive_id, filename)
|
fname = os.path.join(archive_id, filename)
|
||||||
f = open(fname, "wb")
|
with open(fname, "wb") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
f.close()
|
|
||||||
finally:
|
finally:
|
||||||
scu.GSL.release()
|
scu.GSL.release()
|
||||||
return filename
|
return filename
|
||||||
@ -247,7 +248,9 @@ class BaseArchiver(object):
|
|||||||
raise ValueError("invalid filename")
|
raise ValueError("invalid filename")
|
||||||
fname = os.path.join(archive_id, filename)
|
fname = os.path.join(archive_id, filename)
|
||||||
log("reading archive file %s" % fname)
|
log("reading archive file %s" % fname)
|
||||||
return open(fname, "rb").read()
|
with open(fname, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
return data
|
||||||
|
|
||||||
def get_archived_file(self, oid, archive_name, filename):
|
def get_archived_file(self, oid, archive_name, filename):
|
||||||
"""Recupere donnees du fichier indiqué et envoie au client"""
|
"""Recupere donnees du fichier indiqué et envoie au client"""
|
||||||
|
@ -360,7 +360,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
"decisions_ue"
|
"decisions_ue"
|
||||||
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||||
for ue_id in decision["decisions_ue"].keys():
|
for ue_id in decision["decisions_ue"].keys():
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
||||||
d["decision_ue"].append(
|
d["decision_ue"].append(
|
||||||
dict(
|
dict(
|
||||||
ue_id=ue["ue_id"],
|
ue_id=ue["ue_id"],
|
||||||
|
@ -385,7 +385,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
"decisions_ue"
|
"decisions_ue"
|
||||||
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||||
for ue_id in decision["decisions_ue"].keys():
|
for ue_id in decision["decisions_ue"].keys():
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
||||||
doc.append(
|
doc.append(
|
||||||
Element(
|
Element(
|
||||||
"decision_ue",
|
"decision_ue",
|
||||||
|
@ -292,7 +292,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
|
|||||||
|
|
||||||
|
|
||||||
class DefferedSemCacheManager:
|
class DefferedSemCacheManager:
|
||||||
"""Experimental: pour effectuer des opérations indépendantes dans la
|
"""Contexte pour effectuer des opérations indépendantes dans la
|
||||||
même requete qui invalident le cache. Par exemple, quand on inscrit
|
même requete qui invalident le cache. Par exemple, quand on inscrit
|
||||||
des étudiants un par un à un semestre, chaque inscription va invalider
|
des étudiants un par un à un semestre, chaque inscription va invalider
|
||||||
le cache, et la suivante va le reconstruire... pour l'invalider juste après.
|
le cache, et la suivante va le reconstruire... pour l'invalider juste après.
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
"""Semestres: Codes gestion parcours (constantes)
|
"""Semestres: Codes gestion parcours (constantes)
|
||||||
"""
|
"""
|
||||||
import collections
|
import collections
|
||||||
from six.moves import range
|
|
||||||
|
|
||||||
NOTES_TOLERANCE = 0.00499999999999 # si note >= (BARRE-TOLERANCE), considere ok
|
NOTES_TOLERANCE = 0.00499999999999 # si note >= (BARRE-TOLERANCE), considere ok
|
||||||
# (permet d'eviter d'afficher 10.00 sous barre alors que la moyenne vaut 9.999)
|
# (permet d'eviter d'afficher 10.00 sous barre alors que la moyenne vaut 9.999)
|
||||||
|
@ -27,10 +27,10 @@
|
|||||||
|
|
||||||
"""Calcul des moyennes de module
|
"""Calcul des moyennes de module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import traceback
|
|
||||||
import pprint
|
import pprint
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from flask import url_for, g
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_utils import (
|
from app.scodoc.sco_utils import (
|
||||||
@ -40,7 +40,7 @@ from app.scodoc.sco_utils import (
|
|||||||
EVALUATION_RATTRAPAGE,
|
EVALUATION_RATTRAPAGE,
|
||||||
EVALUATION_SESSION2,
|
EVALUATION_SESSION2,
|
||||||
)
|
)
|
||||||
from app.scodoc.sco_exceptions import ScoException
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
@ -65,7 +65,8 @@ def moduleimpl_has_expression(mod):
|
|||||||
|
|
||||||
def formsemestre_expressions_use_abscounts(formsemestre_id):
|
def formsemestre_expressions_use_abscounts(formsemestre_id):
|
||||||
"""True si les notes de ce semestre dépendent des compteurs d'absences.
|
"""True si les notes de ce semestre dépendent des compteurs d'absences.
|
||||||
Cela n'est normalement pas le cas, sauf si des formules utilisateur utilisent ces compteurs.
|
Cela n'est normalement pas le cas, sauf si des formules utilisateur
|
||||||
|
utilisent ces compteurs.
|
||||||
"""
|
"""
|
||||||
# check presence of 'nbabs' in expressions
|
# check presence of 'nbabs' in expressions
|
||||||
ab = "nb_abs" # chaine recherchée
|
ab = "nb_abs" # chaine recherchée
|
||||||
@ -79,7 +80,7 @@ def formsemestre_expressions_use_abscounts(formsemestre_id):
|
|||||||
if expr and expr[0] != "#" and ab in expr:
|
if expr and expr[0] != "#" and ab in expr:
|
||||||
return True
|
return True
|
||||||
# 2- moyennes de modules
|
# 2- moyennes de modules
|
||||||
for mod in sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id):
|
for mod in sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id):
|
||||||
if moduleimpl_has_expression(mod) and ab in mod["computation_expr"]:
|
if moduleimpl_has_expression(mod) and ab in mod["computation_expr"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -128,7 +129,7 @@ def compute_user_formula(
|
|||||||
coefs,
|
coefs,
|
||||||
coefs_mask,
|
coefs_mask,
|
||||||
formula,
|
formula,
|
||||||
diag_info={}, # infos supplementaires a placer ds messages d'erreur
|
diag_info=None, # infos supplementaires a placer ds messages d'erreur
|
||||||
use_abs=True,
|
use_abs=True,
|
||||||
):
|
):
|
||||||
"""Calcul moyenne a partir des notes et coefs, en utilisant la formule utilisateur (une chaine).
|
"""Calcul moyenne a partir des notes et coefs, en utilisant la formule utilisateur (une chaine).
|
||||||
@ -164,9 +165,14 @@ def compute_user_formula(
|
|||||||
if (user_moy > 20) or (user_moy < 0):
|
if (user_moy > 20) or (user_moy < 0):
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
|
|
||||||
raise ScoException(
|
raise ScoValueError(
|
||||||
"""valeur moyenne %s hors limite pour <a href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s">%s</a>"""
|
f"""
|
||||||
% (user_moy, sem["formsemestre_id"], etudid, etud["nomprenom"])
|
Valeur moyenne {user_moy} hors limite pour
|
||||||
|
<a href="{url_for('notes.formsemestre_bulletinetud',
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
|
etudid=etudid
|
||||||
|
)}">{etud["nomprenom"]}</a>"""
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
log(
|
log(
|
||||||
@ -183,7 +189,7 @@ def compute_user_formula(
|
|||||||
return user_moy
|
return user_moy
|
||||||
|
|
||||||
|
|
||||||
def do_moduleimpl_moyennes(nt, mod):
|
def compute_moduleimpl_moyennes(nt, modimpl):
|
||||||
"""Retourne dict { etudid : note_moyenne } pour tous les etuds inscrits
|
"""Retourne dict { etudid : note_moyenne } pour tous les etuds inscrits
|
||||||
au moduleimpl mod, la liste des evaluations "valides" (toutes notes entrées
|
au moduleimpl mod, la liste des evaluations "valides" (toutes notes entrées
|
||||||
ou en attente), et att (vrai s'il y a des notes en attente dans ce module).
|
ou en attente), et att (vrai s'il y a des notes en attente dans ce module).
|
||||||
@ -193,13 +199,13 @@ def do_moduleimpl_moyennes(nt, mod):
|
|||||||
S'il manque des notes et que le coef n'est pas nul,
|
S'il manque des notes et que le coef n'est pas nul,
|
||||||
la moyenne n'est pas calculée: NA
|
la moyenne n'est pas calculée: NA
|
||||||
Ne prend en compte que les evaluations où toutes les notes sont entrées.
|
Ne prend en compte que les evaluations où toutes les notes sont entrées.
|
||||||
Le résultat est une note sur 20.
|
Le résultat note_moyenne est une note sur 20.
|
||||||
"""
|
"""
|
||||||
diag_info = {} # message d'erreur formule
|
diag_info = {} # message d'erreur formule
|
||||||
moduleimpl_id = mod["moduleimpl_id"]
|
moduleimpl_id = modimpl["moduleimpl_id"]
|
||||||
is_malus = mod["module"]["module_type"] == scu.MODULE_MALUS
|
is_malus = modimpl["module"]["module_type"] == scu.MODULE_MALUS
|
||||||
sem = sco_formsemestre.get_formsemestre(mod["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(modimpl["formsemestre_id"])
|
||||||
etudids = sco_moduleimpl.do_moduleimpl_listeetuds(
|
etudids = sco_moduleimpl.moduleimpl_listeetuds(
|
||||||
moduleimpl_id
|
moduleimpl_id
|
||||||
) # tous, y compris demissions
|
) # tous, y compris demissions
|
||||||
# Inscrits au semestre (pour traiter les demissions):
|
# Inscrits au semestre (pour traiter les demissions):
|
||||||
@ -207,7 +213,7 @@ def do_moduleimpl_moyennes(nt, mod):
|
|||||||
[
|
[
|
||||||
x["etudid"]
|
x["etudid"]
|
||||||
for x in sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
for x in sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
||||||
mod["formsemestre_id"]
|
modimpl["formsemestre_id"]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -218,7 +224,7 @@ def do_moduleimpl_moyennes(nt, mod):
|
|||||||
key=lambda x: (x["numero"], x["jour"], x["heure_debut"])
|
key=lambda x: (x["numero"], x["jour"], x["heure_debut"])
|
||||||
) # la plus ancienne en tête
|
) # la plus ancienne en tête
|
||||||
|
|
||||||
user_expr = moduleimpl_has_expression(mod)
|
user_expr = moduleimpl_has_expression(modimpl)
|
||||||
attente = False
|
attente = False
|
||||||
# recupere les notes de toutes les evaluations
|
# recupere les notes de toutes les evaluations
|
||||||
eval_rattr = None
|
eval_rattr = None
|
||||||
@ -268,7 +274,7 @@ def do_moduleimpl_moyennes(nt, mod):
|
|||||||
]
|
]
|
||||||
#
|
#
|
||||||
R = {}
|
R = {}
|
||||||
formula = scu.unescape_html(mod["computation_expr"])
|
formula = scu.unescape_html(modimpl["computation_expr"])
|
||||||
formula_use_abs = "abs" in formula
|
formula_use_abs = "abs" in formula
|
||||||
|
|
||||||
for etudid in insmod_set: # inscrits au semestre et au module
|
for etudid in insmod_set: # inscrits au semestre et au module
|
||||||
@ -365,7 +371,7 @@ def do_moduleimpl_moyennes(nt, mod):
|
|||||||
return R, valid_evals, attente, diag_info
|
return R, valid_evals, attente, diag_info
|
||||||
|
|
||||||
|
|
||||||
def do_formsemestre_moyennes(nt, formsemestre_id):
|
def formsemestre_compute_modimpls_moyennes(nt, formsemestre_id):
|
||||||
"""retourne dict { moduleimpl_id : { etudid, note_moyenne_dans_ce_module } },
|
"""retourne dict { moduleimpl_id : { etudid, note_moyenne_dans_ce_module } },
|
||||||
la liste des moduleimpls, la liste des evaluations valides,
|
la liste des moduleimpls, la liste des evaluations valides,
|
||||||
liste des moduleimpls avec notes en attente.
|
liste des moduleimpls avec notes en attente.
|
||||||
@ -375,7 +381,7 @@ def do_formsemestre_moyennes(nt, formsemestre_id):
|
|||||||
# args={"formsemestre_id": formsemestre_id}
|
# args={"formsemestre_id": formsemestre_id}
|
||||||
# )
|
# )
|
||||||
# etudids = [x["etudid"] for x in inscr]
|
# etudids = [x["etudid"] for x in inscr]
|
||||||
modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
# recupere les moyennes des etudiants de tous les modules
|
# recupere les moyennes des etudiants de tous les modules
|
||||||
D = {}
|
D = {}
|
||||||
valid_evals = []
|
valid_evals = []
|
||||||
@ -383,15 +389,16 @@ def do_formsemestre_moyennes(nt, formsemestre_id):
|
|||||||
mods_att = []
|
mods_att = []
|
||||||
expr_diags = []
|
expr_diags = []
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
mod = sco_edit_module.do_module_list(args={"module_id": modimpl["module_id"]})[
|
mod = sco_edit_module.module_list(args={"module_id": modimpl["module_id"]})[0]
|
||||||
0
|
|
||||||
]
|
|
||||||
modimpl["module"] = mod # add module dict to moduleimpl (used by nt)
|
modimpl["module"] = mod # add module dict to moduleimpl (used by nt)
|
||||||
moduleimpl_id = modimpl["moduleimpl_id"]
|
moduleimpl_id = modimpl["moduleimpl_id"]
|
||||||
assert moduleimpl_id not in D
|
assert moduleimpl_id not in D
|
||||||
D[moduleimpl_id], valid_evals_mod, attente, expr_diag = do_moduleimpl_moyennes(
|
(
|
||||||
nt, modimpl
|
D[moduleimpl_id],
|
||||||
)
|
valid_evals_mod,
|
||||||
|
attente,
|
||||||
|
expr_diag,
|
||||||
|
) = compute_moduleimpl_moyennes(nt, modimpl)
|
||||||
valid_evals_per_mod[moduleimpl_id] = valid_evals_mod
|
valid_evals_per_mod[moduleimpl_id] = valid_evals_mod
|
||||||
valid_evals += valid_evals_mod
|
valid_evals += valid_evals_mod
|
||||||
if attente:
|
if attente:
|
||||||
|
@ -59,9 +59,7 @@ def formsemestre_table_estim_cost(
|
|||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
sco_formsemestre_status.fill_formsemestre(sem)
|
sco_formsemestre_status.fill_formsemestre(sem)
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
T = []
|
T = []
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
Mod = M["module"]
|
Mod = M["module"]
|
||||||
|
@ -167,7 +167,8 @@ def _anonymize_db(ano_db_name):
|
|||||||
|
|
||||||
def _get_scodoc_serial():
|
def _get_scodoc_serial():
|
||||||
try:
|
try:
|
||||||
return int(open(os.path.join(scu.SCODOC_VERSION_DIR, "scodoc.sn")).read())
|
with open(os.path.join(scu.SCODOC_VERSION_DIR, "scodoc.sn")) as f:
|
||||||
|
return int(f.read())
|
||||||
except:
|
except:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ def do_formation_delete(oid):
|
|||||||
raise ScoLockedFormError()
|
raise ScoLockedFormError()
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# delete all UE in this formation
|
# delete all UE in this formation
|
||||||
ues = sco_edit_ue.do_ue_list({"formation_id": oid})
|
ues = sco_edit_ue.ue_list({"formation_id": oid})
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
sco_edit_ue.do_ue_delete(ue["ue_id"], force=True)
|
sco_edit_ue.do_ue_delete(ue["ue_id"], force=True)
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ def formation_edit(formation_id=None, create=False):
|
|||||||
do_formation_edit(tf[2])
|
do_formation_edit(tf[2])
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -313,13 +313,13 @@ def invalidate_sems_in_formation(formation_id):
|
|||||||
|
|
||||||
def module_move(module_id, after=0, redirect=1):
|
def module_move(module_id, after=0, redirect=1):
|
||||||
"""Move before/after previous one (decrement/increment numero)"""
|
"""Move before/after previous one (decrement/increment numero)"""
|
||||||
module = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
module = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
after = int(after) # 0: deplace avant, 1 deplace apres
|
after = int(after) # 0: deplace avant, 1 deplace apres
|
||||||
if after not in (0, 1):
|
if after not in (0, 1):
|
||||||
raise ValueError('invalid value for "after"')
|
raise ValueError('invalid value for "after"')
|
||||||
formation_id = module["formation_id"]
|
formation_id = module["formation_id"]
|
||||||
others = sco_edit_module.do_module_list({"matiere_id": module["matiere_id"]})
|
others = sco_edit_module.module_list({"matiere_id": module["matiere_id"]})
|
||||||
# log('others=%s' % others)
|
# log('others=%s' % others)
|
||||||
if len(others) > 1:
|
if len(others) > 1:
|
||||||
idx = [p["module_id"] for p in others].index(module_id)
|
idx = [p["module_id"] for p in others].index(module_id)
|
||||||
@ -343,21 +343,21 @@ def module_move(module_id, after=0, redirect=1):
|
|||||||
if redirect:
|
if redirect:
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def ue_move(ue_id, after=0, redirect=1):
|
def ue_move(ue_id, after=0, redirect=1):
|
||||||
"""Move UE before/after previous one (decrement/increment numero)"""
|
"""Move UE before/after previous one (decrement/increment numero)"""
|
||||||
o = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
o = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
||||||
# log('ue_move %s (#%s) after=%s' % (ue_id, o['numero'], after))
|
# log('ue_move %s (#%s) after=%s' % (ue_id, o['numero'], after))
|
||||||
redirect = int(redirect)
|
redirect = int(redirect)
|
||||||
after = int(after) # 0: deplace avant, 1 deplace apres
|
after = int(after) # 0: deplace avant, 1 deplace apres
|
||||||
if after not in (0, 1):
|
if after not in (0, 1):
|
||||||
raise ValueError('invalid value for "after"')
|
raise ValueError('invalid value for "after"')
|
||||||
formation_id = o["formation_id"]
|
formation_id = o["formation_id"]
|
||||||
others = sco_edit_ue.do_ue_list({"formation_id": formation_id})
|
others = sco_edit_ue.ue_list({"formation_id": formation_id})
|
||||||
if len(others) > 1:
|
if len(others) > 1:
|
||||||
idx = [p["ue_id"] for p in others].index(ue_id)
|
idx = [p["ue_id"] for p in others].index(ue_id)
|
||||||
neigh = None # object to swap with
|
neigh = None # object to swap with
|
||||||
@ -378,7 +378,7 @@ def ue_move(ue_id, after=0, redirect=1):
|
|||||||
if redirect:
|
if redirect:
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=o["formation_id"],
|
formation_id=o["formation_id"],
|
||||||
)
|
)
|
||||||
|
@ -47,7 +47,7 @@ _matiereEditor = ndb.EditableTable(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_matiere_list(*args, **kw):
|
def matiere_list(*args, **kw):
|
||||||
"list matieres"
|
"list matieres"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
return _matiereEditor.list(cnx, *args, **kw)
|
return _matiereEditor.list(cnx, *args, **kw)
|
||||||
@ -60,12 +60,12 @@ def do_matiere_edit(*args, **kw):
|
|||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# check
|
# check
|
||||||
mat = do_matiere_list({"matiere_id": args[0]["matiere_id"]})[0]
|
mat = matiere_list({"matiere_id": args[0]["matiere_id"]})[0]
|
||||||
if matiere_is_locked(mat["matiere_id"]):
|
if matiere_is_locked(mat["matiere_id"]):
|
||||||
raise ScoLockedFormError()
|
raise ScoLockedFormError()
|
||||||
# edit
|
# edit
|
||||||
_matiereEditor.edit(cnx, *args, **kw)
|
_matiereEditor.edit(cnx, *args, **kw)
|
||||||
formation_id = sco_edit_ue.do_ue_list({"ue_id": mat["ue_id"]})[0]["formation_id"]
|
formation_id = sco_edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]["formation_id"]
|
||||||
sco_edit_formation.invalidate_sems_in_formation(formation_id)
|
sco_edit_formation.invalidate_sems_in_formation(formation_id)
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ def do_matiere_create(args):
|
|||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# check
|
# check
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": args["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": args["ue_id"]})[0]
|
||||||
# create matiere
|
# create matiere
|
||||||
r = _matiereEditor.create(cnx, args)
|
r = _matiereEditor.create(cnx, args)
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ def matiere_create(ue_id=None):
|
|||||||
"""Creation d'une matiere"""
|
"""Creation d'une matiere"""
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
UE = sco_edit_ue.do_ue_list(args={"ue_id": ue_id})[0]
|
UE = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Création d'une matière"),
|
html_sco_header.sco_header(page_title="Création d'une matière"),
|
||||||
"""<h2>Création d'une matière dans l'UE %(titre)s (%(acronyme)s)</h2>""" % UE,
|
"""<h2>Création d'une matière dans l'UE %(titre)s (%(acronyme)s)</h2>""" % UE,
|
||||||
@ -134,7 +134,7 @@ associé.
|
|||||||
)
|
)
|
||||||
|
|
||||||
dest_url = url_for(
|
dest_url = url_for(
|
||||||
"notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=UE["formation_id"]
|
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=UE["formation_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
@ -143,7 +143,7 @@ associé.
|
|||||||
return flask.redirect(dest_url)
|
return flask.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
# check unicity
|
# check unicity
|
||||||
mats = do_matiere_list(args={"ue_id": ue_id, "titre": tf[2]["titre"]})
|
mats = matiere_list(args={"ue_id": ue_id, "titre": tf[2]["titre"]})
|
||||||
if mats:
|
if mats:
|
||||||
return (
|
return (
|
||||||
"\n".join(H)
|
"\n".join(H)
|
||||||
@ -164,8 +164,8 @@ def do_matiere_delete(oid):
|
|||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# check
|
# check
|
||||||
mat = do_matiere_list({"matiere_id": oid})[0]
|
mat = matiere_list({"matiere_id": oid})[0]
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": mat["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]
|
||||||
locked = matiere_is_locked(mat["matiere_id"])
|
locked = matiere_is_locked(mat["matiere_id"])
|
||||||
if locked:
|
if locked:
|
||||||
log("do_matiere_delete: mat=%s" % mat)
|
log("do_matiere_delete: mat=%s" % mat)
|
||||||
@ -174,7 +174,7 @@ def do_matiere_delete(oid):
|
|||||||
raise ScoLockedFormError()
|
raise ScoLockedFormError()
|
||||||
log("do_matiere_delete: matiere_id=%s" % oid)
|
log("do_matiere_delete: matiere_id=%s" % oid)
|
||||||
# delete all modules in this matiere
|
# delete all modules in this matiere
|
||||||
mods = sco_edit_module.do_module_list({"matiere_id": oid})
|
mods = sco_edit_module.module_list({"matiere_id": oid})
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
sco_edit_module.do_module_delete(mod["module_id"])
|
sco_edit_module.do_module_delete(mod["module_id"])
|
||||||
_matiereEditor.delete(cnx, oid)
|
_matiereEditor.delete(cnx, oid)
|
||||||
@ -193,8 +193,8 @@ def matiere_delete(matiere_id=None):
|
|||||||
"""Delete an UE"""
|
"""Delete an UE"""
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
M = do_matiere_list(args={"matiere_id": matiere_id})[0]
|
M = matiere_list(args={"matiere_id": matiere_id})[0]
|
||||||
UE = sco_edit_ue.do_ue_list(args={"ue_id": M["ue_id"]})[0]
|
UE = sco_edit_ue.ue_list(args={"ue_id": M["ue_id"]})[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Suppression d'une matière"),
|
html_sco_header.sco_header(page_title="Suppression d'une matière"),
|
||||||
"<h2>Suppression de la matière %(titre)s" % M,
|
"<h2>Suppression de la matière %(titre)s" % M,
|
||||||
@ -223,17 +223,17 @@ def matiere_edit(matiere_id=None):
|
|||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
F = do_matiere_list(args={"matiere_id": matiere_id})
|
F = matiere_list(args={"matiere_id": matiere_id})
|
||||||
if not F:
|
if not F:
|
||||||
raise ScoValueError("Matière inexistante !")
|
raise ScoValueError("Matière inexistante !")
|
||||||
F = F[0]
|
F = F[0]
|
||||||
U = sco_edit_ue.do_ue_list(args={"ue_id": F["ue_id"]})
|
U = sco_edit_ue.ue_list(args={"ue_id": F["ue_id"]})
|
||||||
if not F:
|
if not F:
|
||||||
raise ScoValueError("UE inexistante !")
|
raise ScoValueError("UE inexistante !")
|
||||||
U = U[0]
|
U = U[0]
|
||||||
Fo = sco_formations.formation_list(args={"formation_id": U["formation_id"]})[0]
|
Fo = sco_formations.formation_list(args={"formation_id": U["formation_id"]})[0]
|
||||||
|
|
||||||
ues = sco_edit_ue.do_ue_list(args={"formation_id": U["formation_id"]})
|
ues = sco_edit_ue.ue_list(args={"formation_id": U["formation_id"]})
|
||||||
ue_names = ["%(acronyme)s (%(titre)s)" % u for u in ues]
|
ue_names = ["%(acronyme)s (%(titre)s)" % u for u in ues]
|
||||||
ue_ids = [u["ue_id"] for u in ues]
|
ue_ids = [u["ue_id"] for u in ues]
|
||||||
H = [
|
H = [
|
||||||
@ -286,7 +286,7 @@ associé.
|
|||||||
return flask.redirect(dest_url)
|
return flask.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
# check unicity
|
# check unicity
|
||||||
mats = do_matiere_list(args={"ue_id": tf[2]["ue_id"], "titre": tf[2]["titre"]})
|
mats = matiere_list(args={"ue_id": tf[2]["ue_id"], "titre": tf[2]["titre"]})
|
||||||
if len(mats) > 1 or (len(mats) == 1 and mats[0]["matiere_id"] != matiere_id):
|
if len(mats) > 1 or (len(mats) == 1 and mats[0]["matiere_id"] != matiere_id):
|
||||||
return (
|
return (
|
||||||
"\n".join(H)
|
"\n".join(H)
|
||||||
|
@ -94,7 +94,7 @@ _moduleEditor = ndb.EditableTable(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_module_list(*args, **kw):
|
def module_list(*args, **kw):
|
||||||
"list modules"
|
"list modules"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
return _moduleEditor.list(cnx, *args, **kw)
|
return _moduleEditor.list(cnx, *args, **kw)
|
||||||
@ -126,8 +126,8 @@ def module_create(matiere_id=None):
|
|||||||
|
|
||||||
if matiere_id is None:
|
if matiere_id is None:
|
||||||
raise ScoValueError("invalid matiere !")
|
raise ScoValueError("invalid matiere !")
|
||||||
M = sco_edit_matiere.do_matiere_list(args={"matiere_id": matiere_id})[0]
|
M = sco_edit_matiere.matiere_list(args={"matiere_id": matiere_id})[0]
|
||||||
UE = sco_edit_ue.do_ue_list(args={"ue_id": M["ue_id"]})[0]
|
UE = sco_edit_ue.ue_list(args={"ue_id": M["ue_id"]})[0]
|
||||||
Fo = sco_formations.formation_list(args={"formation_id": UE["formation_id"]})[0]
|
Fo = sco_formations.formation_list(args={"formation_id": UE["formation_id"]})[0]
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||||
@ -138,7 +138,7 @@ def module_create(matiere_id=None):
|
|||||||
_MODULE_HELP,
|
_MODULE_HELP,
|
||||||
]
|
]
|
||||||
# cherche le numero adequat (pour placer le module en fin de liste)
|
# cherche le numero adequat (pour placer le module en fin de liste)
|
||||||
Mods = do_module_list(args={"matiere_id": matiere_id})
|
Mods = module_list(args={"matiere_id": matiere_id})
|
||||||
if Mods:
|
if Mods:
|
||||||
default_num = max([m["numero"] for m in Mods]) + 10
|
default_num = max([m["numero"] for m in Mods]) + 10
|
||||||
else:
|
else:
|
||||||
@ -241,7 +241,7 @@ def module_create(matiere_id=None):
|
|||||||
do_module_create(tf[2])
|
do_module_create(tf[2])
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=UE["formation_id"],
|
formation_id=UE["formation_id"],
|
||||||
)
|
)
|
||||||
@ -252,18 +252,18 @@ def do_module_delete(oid):
|
|||||||
"delete module"
|
"delete module"
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
|
|
||||||
mod = do_module_list({"module_id": oid})[0]
|
mod = module_list({"module_id": oid})[0]
|
||||||
if module_is_locked(mod["module_id"]):
|
if module_is_locked(mod["module_id"]):
|
||||||
raise ScoLockedFormError()
|
raise ScoLockedFormError()
|
||||||
|
|
||||||
# S'il y a des moduleimpls, on ne peut pas detruire le module !
|
# S'il y a des moduleimpls, on ne peut pas detruire le module !
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(module_id=oid)
|
mods = sco_moduleimpl.moduleimpl_list(module_id=oid)
|
||||||
if mods:
|
if mods:
|
||||||
err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
|
err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
|
||||||
<p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
<p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
||||||
laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
||||||
</p>
|
</p>
|
||||||
<a href="{url_for('notes.ue_list', scodoc_dept=g.scodoc_dept,
|
<a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=mod["formation_id"])}">reprendre</a>
|
formation_id=mod["formation_id"])}">reprendre</a>
|
||||||
"""
|
"""
|
||||||
raise ScoGenError(err_page)
|
raise ScoGenError(err_page)
|
||||||
@ -285,7 +285,7 @@ def module_delete(module_id=None):
|
|||||||
"""Delete a module"""
|
"""Delete a module"""
|
||||||
if not module_id:
|
if not module_id:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
Mods = do_module_list(args={"module_id": module_id})
|
Mods = module_list(args={"module_id": module_id})
|
||||||
if not Mods:
|
if not Mods:
|
||||||
raise ScoValueError("Module inexistant !")
|
raise ScoValueError("Module inexistant !")
|
||||||
Mod = Mods[0]
|
Mod = Mods[0]
|
||||||
@ -317,7 +317,7 @@ def do_module_edit(val):
|
|||||||
from app.scodoc import sco_edit_formation
|
from app.scodoc import sco_edit_formation
|
||||||
|
|
||||||
# check
|
# check
|
||||||
mod = do_module_list({"module_id": val["module_id"]})[0]
|
mod = module_list({"module_id": val["module_id"]})[0]
|
||||||
if module_is_locked(mod["module_id"]):
|
if module_is_locked(mod["module_id"]):
|
||||||
# formation verrouillée: empeche de modifier certains champs:
|
# formation verrouillée: empeche de modifier certains champs:
|
||||||
protected_fields = ("coefficient", "ue_id", "matiere_id", "semestre_id")
|
protected_fields = ("coefficient", "ue_id", "matiere_id", "semestre_id")
|
||||||
@ -332,7 +332,7 @@ def do_module_edit(val):
|
|||||||
|
|
||||||
def check_module_code_unicity(code, field, formation_id, module_id=None):
|
def check_module_code_unicity(code, field, formation_id, module_id=None):
|
||||||
"true si code module unique dans la formation"
|
"true si code module unique dans la formation"
|
||||||
Mods = do_module_list(args={"code": code, "formation_id": formation_id})
|
Mods = module_list(args={"code": code, "formation_id": formation_id})
|
||||||
if module_id: # edition: supprime le module en cours
|
if module_id: # edition: supprime le module en cours
|
||||||
Mods = [m for m in Mods if m["module_id"] != module_id]
|
Mods = [m for m in Mods if m["module_id"] != module_id]
|
||||||
|
|
||||||
@ -346,7 +346,7 @@ def module_edit(module_id=None):
|
|||||||
|
|
||||||
if not module_id:
|
if not module_id:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
Mod = do_module_list(args={"module_id": module_id})
|
Mod = module_list(args={"module_id": module_id})
|
||||||
if not Mod:
|
if not Mod:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
Mod = Mod[0]
|
Mod = Mod[0]
|
||||||
@ -521,7 +521,7 @@ def edit_module_set_code_apogee(id=None, value=None):
|
|||||||
value = value.strip("-_ \t")
|
value = value.strip("-_ \t")
|
||||||
log("edit_module_set_code_apogee: module_id=%s code_apogee=%s" % (module_id, value))
|
log("edit_module_set_code_apogee: module_id=%s code_apogee=%s" % (module_id, value))
|
||||||
|
|
||||||
modules = do_module_list(args={"module_id": module_id})
|
modules = module_list(args={"module_id": module_id})
|
||||||
if not modules:
|
if not modules:
|
||||||
return "module invalide" # should not occur
|
return "module invalide" # should not occur
|
||||||
|
|
||||||
@ -531,7 +531,7 @@ def edit_module_set_code_apogee(id=None, value=None):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def module_list(formation_id):
|
def module_table(formation_id):
|
||||||
"""Liste des modules de la formation
|
"""Liste des modules de la formation
|
||||||
(XXX inutile ou a revoir)
|
(XXX inutile ou a revoir)
|
||||||
"""
|
"""
|
||||||
@ -548,7 +548,7 @@ def module_list(formation_id):
|
|||||||
]
|
]
|
||||||
editable = current_user.has_permission(Permission.ScoChangeFormation)
|
editable = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
|
|
||||||
for Mod in do_module_list(args={"formation_id": formation_id}):
|
for Mod in module_list(args={"formation_id": formation_id}):
|
||||||
H.append('<li class="notes_module_list">%s' % Mod)
|
H.append('<li class="notes_module_list">%s' % Mod)
|
||||||
if editable:
|
if editable:
|
||||||
H.append('<a href="module_edit?module_id=%(module_id)s">modifier</a>' % Mod)
|
H.append('<a href="module_edit?module_id=%(module_id)s">modifier</a>' % Mod)
|
||||||
@ -580,7 +580,7 @@ def module_is_locked(module_id):
|
|||||||
|
|
||||||
def module_count_moduleimpls(module_id):
|
def module_count_moduleimpls(module_id):
|
||||||
"Number of moduleimpls using this module"
|
"Number of moduleimpls using this module"
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(module_id=module_id)
|
mods = sco_moduleimpl.moduleimpl_list(module_id=module_id)
|
||||||
return len(mods)
|
return len(mods)
|
||||||
|
|
||||||
|
|
||||||
@ -588,14 +588,14 @@ def formation_add_malus_modules(formation_id, titre=None, redirect=True):
|
|||||||
"""Création d'un module de "malus" dans chaque UE d'une formation"""
|
"""Création d'un module de "malus" dans chaque UE d'une formation"""
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
ue_list = sco_edit_ue.do_ue_list(args={"formation_id": formation_id})
|
ue_list = sco_edit_ue.ue_list(args={"formation_id": formation_id})
|
||||||
|
|
||||||
for ue in ue_list:
|
for ue in ue_list:
|
||||||
# Un seul module de malus par UE:
|
# Un seul module de malus par UE:
|
||||||
nb_mod_malus = len(
|
nb_mod_malus = len(
|
||||||
[
|
[
|
||||||
mod
|
mod
|
||||||
for mod in do_module_list(args={"ue_id": ue["ue_id"]})
|
for mod in module_list(args={"ue_id": ue["ue_id"]})
|
||||||
if mod["module_type"] == scu.MODULE_MALUS
|
if mod["module_type"] == scu.MODULE_MALUS
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -610,7 +610,7 @@ def ue_add_malus_module(ue_id, titre=None, code=None):
|
|||||||
"""Add a malus module in this ue"""
|
"""Add a malus module in this ue"""
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||||
|
|
||||||
if titre is None:
|
if titre is None:
|
||||||
titre = ""
|
titre = ""
|
||||||
@ -629,7 +629,7 @@ def ue_add_malus_module(ue_id, titre=None, code=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Matiere pour placer le module malus
|
# Matiere pour placer le module malus
|
||||||
Matlist = sco_edit_matiere.do_matiere_list(args={"ue_id": ue_id})
|
Matlist = sco_edit_matiere.matiere_list(args={"ue_id": ue_id})
|
||||||
numero = max([mat["numero"] for mat in Matlist]) + 10
|
numero = max([mat["numero"] for mat in Matlist]) + 10
|
||||||
matiere_id = sco_edit_matiere.do_matiere_create(
|
matiere_id = sco_edit_matiere.do_matiere_create(
|
||||||
{"ue_id": ue_id, "titre": "Malus", "numero": numero}
|
{"ue_id": ue_id, "titre": "Malus", "numero": numero}
|
||||||
|
@ -85,7 +85,7 @@ _ueEditor = ndb.EditableTable(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_ue_list(*args, **kw):
|
def ue_list(*args, **kw):
|
||||||
"list UEs"
|
"list UEs"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
return _ueEditor.list(cnx, *args, **kw)
|
return _ueEditor.list(cnx, *args, **kw)
|
||||||
@ -97,9 +97,7 @@ def do_ue_create(args):
|
|||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# check duplicates
|
# check duplicates
|
||||||
ues = do_ue_list(
|
ues = ue_list({"formation_id": args["formation_id"], "acronyme": args["acronyme"]})
|
||||||
{"formation_id": args["formation_id"], "acronyme": args["acronyme"]}
|
|
||||||
)
|
|
||||||
if ues:
|
if ues:
|
||||||
raise ScoValueError('Acronyme d\'UE "%s" déjà utilisé !' % args["acronyme"])
|
raise ScoValueError('Acronyme d\'UE "%s" déjà utilisé !' % args["acronyme"])
|
||||||
# create
|
# create
|
||||||
@ -124,7 +122,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue_id, delete_validations))
|
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue_id, delete_validations))
|
||||||
# check
|
# check
|
||||||
ue = do_ue_list({"ue_id": ue_id})
|
ue = ue_list({"ue_id": ue_id})
|
||||||
if not ue:
|
if not ue:
|
||||||
raise ScoValueError("UE inexistante !")
|
raise ScoValueError("UE inexistante !")
|
||||||
ue = ue[0]
|
ue = ue[0]
|
||||||
@ -152,7 +150,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# delete all matiere in this UE
|
# delete all matiere in this UE
|
||||||
mats = sco_edit_matiere.do_matiere_list({"ue_id": ue_id})
|
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
|
||||||
for mat in mats:
|
for mat in mats:
|
||||||
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
|
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
|
||||||
# delete uecoef and events
|
# delete uecoef and events
|
||||||
@ -177,7 +175,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
if not force:
|
if not force:
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=ue["formation_id"],
|
formation_id=ue["formation_id"],
|
||||||
)
|
)
|
||||||
@ -197,7 +195,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
|
|||||||
|
|
||||||
create = int(create)
|
create = int(create)
|
||||||
if not create:
|
if not create:
|
||||||
U = do_ue_list(args={"ue_id": ue_id})
|
U = ue_list(args={"ue_id": ue_id})
|
||||||
if not U:
|
if not U:
|
||||||
raise ScoValueError("UE inexistante !")
|
raise ScoValueError("UE inexistante !")
|
||||||
U = U[0]
|
U = U[0]
|
||||||
@ -371,7 +369,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
|
|||||||
do_ue_edit(tf[2])
|
do_ue_edit(tf[2])
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -382,7 +380,7 @@ def _add_ue_semestre_id(ue_list):
|
|||||||
qui les place à la fin de la liste.
|
qui les place à la fin de la liste.
|
||||||
"""
|
"""
|
||||||
for ue in ue_list:
|
for ue in ue_list:
|
||||||
Modlist = sco_edit_module.do_module_list(args={"ue_id": ue["ue_id"]})
|
Modlist = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
||||||
if Modlist:
|
if Modlist:
|
||||||
ue["semestre_id"] = Modlist[0]["semestre_id"]
|
ue["semestre_id"] = Modlist[0]["semestre_id"]
|
||||||
else:
|
else:
|
||||||
@ -393,7 +391,7 @@ def next_ue_numero(formation_id, semestre_id=None):
|
|||||||
"""Numero d'une nouvelle UE dans cette formation.
|
"""Numero d'une nouvelle UE dans cette formation.
|
||||||
Si le semestre est specifie, cherche les UE ayant des modules de ce semestre
|
Si le semestre est specifie, cherche les UE ayant des modules de ce semestre
|
||||||
"""
|
"""
|
||||||
ue_list = do_ue_list(args={"formation_id": formation_id})
|
ue_list = ue_list(args={"formation_id": formation_id})
|
||||||
if not ue_list:
|
if not ue_list:
|
||||||
return 0
|
return 0
|
||||||
if semestre_id is None:
|
if semestre_id is None:
|
||||||
@ -410,7 +408,7 @@ def next_ue_numero(formation_id, semestre_id=None):
|
|||||||
|
|
||||||
def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
|
def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
|
||||||
"""Delete an UE"""
|
"""Delete an UE"""
|
||||||
ue = do_ue_list(args={"ue_id": ue_id})
|
ue = ue_list(args={"ue_id": ue_id})
|
||||||
if not ue:
|
if not ue:
|
||||||
raise ScoValueError("UE inexistante !")
|
raise ScoValueError("UE inexistante !")
|
||||||
ue = ue[0]
|
ue = ue[0]
|
||||||
@ -426,9 +424,9 @@ def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
|
|||||||
return do_ue_delete(ue_id, delete_validations=delete_validations)
|
return do_ue_delete(ue_id, delete_validations=delete_validations)
|
||||||
|
|
||||||
|
|
||||||
def ue_list(formation_id=None, msg=""):
|
def ue_table(formation_id=None, msg=""): # was ue_list
|
||||||
"""Liste des matières et modules d'une formation, avec liens pour
|
"""Liste des matières et modules d'une formation, avec liens pour
|
||||||
editer (si non verrouillée).
|
éditer (si non verrouillée).
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre_validation
|
from app.scodoc import sco_formsemestre_validation
|
||||||
@ -440,7 +438,7 @@ def ue_list(formation_id=None, msg=""):
|
|||||||
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
||||||
locked = sco_formations.formation_has_locked_sems(formation_id)
|
locked = sco_formations.formation_has_locked_sems(formation_id)
|
||||||
|
|
||||||
ue_list = do_ue_list(args={"formation_id": formation_id})
|
ue_list = ue_list(args={"formation_id": formation_id})
|
||||||
# tri par semestre et numero:
|
# tri par semestre et numero:
|
||||||
_add_ue_semestre_id(ue_list)
|
_add_ue_semestre_id(ue_list)
|
||||||
ue_list.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
ue_list.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||||
@ -461,7 +459,7 @@ def ue_list(formation_id=None, msg=""):
|
|||||||
else:
|
else:
|
||||||
lockicon = ""
|
lockicon = ""
|
||||||
|
|
||||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags()
|
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
|
||||||
delete_icon = scu.icontag(
|
delete_icon = scu.icontag(
|
||||||
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer"
|
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer"
|
||||||
)
|
)
|
||||||
@ -627,7 +625,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
H.append('<span class="locked">[verrouillé]</span>')
|
H.append('<span class="locked">[verrouillé]</span>')
|
||||||
if not parcours.UE_IS_MODULE:
|
if not parcours.UE_IS_MODULE:
|
||||||
H.append('<ul class="notes_matiere_list">')
|
H.append('<ul class="notes_matiere_list">')
|
||||||
Matlist = sco_edit_matiere.do_matiere_list(args={"ue_id": UE["ue_id"]})
|
Matlist = sco_edit_matiere.matiere_list(args={"ue_id": UE["ue_id"]})
|
||||||
for Mat in Matlist:
|
for Mat in Matlist:
|
||||||
if not parcours.UE_IS_MODULE:
|
if not parcours.UE_IS_MODULE:
|
||||||
H.append('<li class="notes_matiere_list">')
|
H.append('<li class="notes_matiere_list">')
|
||||||
@ -648,7 +646,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
H.append("</a>")
|
H.append("</a>")
|
||||||
|
|
||||||
H.append('<ul class="notes_module_list">')
|
H.append('<ul class="notes_module_list">')
|
||||||
Modlist = sco_edit_module.do_module_list(
|
Modlist = sco_edit_module.module_list(
|
||||||
args={"matiere_id": Mat["matiere_id"]}
|
args={"matiere_id": Mat["matiere_id"]}
|
||||||
)
|
)
|
||||||
im = 0
|
im = 0
|
||||||
@ -847,7 +845,7 @@ def ue_sharing_code(ue_code=None, ue_id=None, hide_ue_id=None):
|
|||||||
|
|
||||||
ue_code = str(ue_code)
|
ue_code = str(ue_code)
|
||||||
if ue_id:
|
if ue_id:
|
||||||
ue = do_ue_list(args={"ue_id": ue_id})[0]
|
ue = ue_list(args={"ue_id": ue_id})[0]
|
||||||
if not ue_code:
|
if not ue_code:
|
||||||
ue_code = ue["ue_code"]
|
ue_code = ue["ue_code"]
|
||||||
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
|
||||||
@ -884,7 +882,7 @@ def ue_sharing_code(ue_code=None, ue_id=None, hide_ue_id=None):
|
|||||||
for ue in ues:
|
for ue in ues:
|
||||||
H.append(
|
H.append(
|
||||||
f"""<li>{ue.acronyme} ({ue.titre}) dans <a class="stdlink"
|
f"""<li>{ue.acronyme} ({ue.titre}) dans <a class="stdlink"
|
||||||
href="{url_for("notes.ue_list", scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)}"
|
href="{url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)}"
|
||||||
>{ue.formation.acronyme} ({ue.formation.titre})</a>, version {ue.formation.version}
|
>{ue.formation.acronyme} ({ue.formation.titre})</a>, version {ue.formation.version}
|
||||||
</li>
|
</li>
|
||||||
"""
|
"""
|
||||||
@ -897,13 +895,13 @@ def do_ue_edit(args, bypass_lock=False, dont_invalidate_cache=False):
|
|||||||
"edit an UE"
|
"edit an UE"
|
||||||
# check
|
# check
|
||||||
ue_id = args["ue_id"]
|
ue_id = args["ue_id"]
|
||||||
ue = do_ue_list({"ue_id": ue_id})[0]
|
ue = ue_list({"ue_id": ue_id})[0]
|
||||||
if (not bypass_lock) and ue_is_locked(ue["ue_id"]):
|
if (not bypass_lock) and ue_is_locked(ue["ue_id"]):
|
||||||
raise ScoLockedFormError()
|
raise ScoLockedFormError()
|
||||||
# check: acronyme unique dans cette formation
|
# check: acronyme unique dans cette formation
|
||||||
if "acronyme" in args:
|
if "acronyme" in args:
|
||||||
new_acro = args["acronyme"]
|
new_acro = args["acronyme"]
|
||||||
ues = do_ue_list({"formation_id": ue["formation_id"], "acronyme": new_acro})
|
ues = ue_list({"formation_id": ue["formation_id"], "acronyme": new_acro})
|
||||||
if ues and ues[0]["ue_id"] != ue_id:
|
if ues and ues[0]["ue_id"] != ue_id:
|
||||||
raise ScoValueError('Acronyme d\'UE "%s" déjà utilisé !' % args["acronyme"])
|
raise ScoValueError('Acronyme d\'UE "%s" déjà utilisé !' % args["acronyme"])
|
||||||
|
|
||||||
@ -926,7 +924,7 @@ def edit_ue_set_code_apogee(id=None, value=None):
|
|||||||
value = value.strip("-_ \t")
|
value = value.strip("-_ \t")
|
||||||
log("edit_ue_set_code_apogee: ue_id=%s code_apogee=%s" % (ue_id, value))
|
log("edit_ue_set_code_apogee: ue_id=%s code_apogee=%s" % (ue_id, value))
|
||||||
|
|
||||||
ues = do_ue_list(args={"ue_id": ue_id})
|
ues = ue_list(args={"ue_id": ue_id})
|
||||||
if not ues:
|
if not ues:
|
||||||
return "ue invalide"
|
return "ue invalide"
|
||||||
|
|
||||||
@ -966,11 +964,11 @@ def formation_table_recap(formation_id, format="html"):
|
|||||||
raise ScoValueError("invalid formation_id")
|
raise ScoValueError("invalid formation_id")
|
||||||
F = F[0]
|
F = F[0]
|
||||||
T = []
|
T = []
|
||||||
ue_list = do_ue_list(args={"formation_id": formation_id})
|
ue_list = ue_list(args={"formation_id": formation_id})
|
||||||
for UE in ue_list:
|
for UE in ue_list:
|
||||||
Matlist = sco_edit_matiere.do_matiere_list(args={"ue_id": UE["ue_id"]})
|
Matlist = sco_edit_matiere.matiere_list(args={"ue_id": UE["ue_id"]})
|
||||||
for Mat in Matlist:
|
for Mat in Matlist:
|
||||||
Modlist = sco_edit_module.do_module_list(
|
Modlist = sco_edit_module.module_list(
|
||||||
args={"matiere_id": Mat["matiere_id"]}
|
args={"matiere_id": Mat["matiere_id"]}
|
||||||
)
|
)
|
||||||
for Mod in Modlist:
|
for Mod in Modlist:
|
||||||
@ -1049,5 +1047,5 @@ def ue_list_semestre_ids(ue):
|
|||||||
Mais cela n'a pas toujours été le cas dans les programmes pédagogiques officiels,
|
Mais cela n'a pas toujours été le cas dans les programmes pédagogiques officiels,
|
||||||
aussi ScoDoc laisse le choix.
|
aussi ScoDoc laisse le choix.
|
||||||
"""
|
"""
|
||||||
Modlist = sco_edit_module.do_module_list(args={"ue_id": ue["ue_id"]})
|
Modlist = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
||||||
return sorted(list(set([mod["semestre_id"] for mod in Modlist])))
|
return sorted(list(set([mod["semestre_id"] for mod in Modlist])))
|
||||||
|
@ -33,10 +33,10 @@ XXX incompatible avec les ics HyperPlanning Paris 13 (était pour GPU).
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
|
|
||||||
import traceback
|
|
||||||
import icalendar
|
import icalendar
|
||||||
import pprint
|
import pprint
|
||||||
|
import traceback
|
||||||
|
import urllib
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
@ -80,7 +80,7 @@ def formsemestre_load_ics(sem):
|
|||||||
ics_data = ""
|
ics_data = ""
|
||||||
else:
|
else:
|
||||||
log("Loading edt from %s" % ics_url)
|
log("Loading edt from %s" % ics_url)
|
||||||
f = six.moves.urllib.request.urlopen(
|
f = urllib.request.urlopen(
|
||||||
ics_url, timeout=5
|
ics_url, timeout=5
|
||||||
) # 5s TODO: add config parameter, eg for slow networks
|
) # 5s TODO: add config parameter, eg for slow networks
|
||||||
ics_data = f.read()
|
ics_data = f.read()
|
||||||
|
@ -830,7 +830,7 @@ appreciations_edit = _appreciationsEditor.edit
|
|||||||
def read_etablissements():
|
def read_etablissements():
|
||||||
filename = os.path.join(scu.SCO_TOOLS_DIR, scu.CONFIG.ETABL_FILENAME)
|
filename = os.path.join(scu.SCO_TOOLS_DIR, scu.CONFIG.ETABL_FILENAME)
|
||||||
log("reading %s" % filename)
|
log("reading %s" % filename)
|
||||||
f = open(filename)
|
with open(filename) as f:
|
||||||
L = [x[:-1].split(";") for x in f]
|
L = [x[:-1].split(";") for x in f]
|
||||||
E = {}
|
E = {}
|
||||||
for l in L[1:]:
|
for l in L[1:]:
|
||||||
|
@ -179,7 +179,7 @@ def do_evaluation_list(args, sortkey=None):
|
|||||||
|
|
||||||
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
||||||
"list evaluations in this formsemestre"
|
"list evaluations in this formsemestre"
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
evals = []
|
evals = []
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
evals += do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
evals += do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
||||||
@ -213,7 +213,7 @@ def _check_evaluation_args(args):
|
|||||||
jour = args.get("jour", None)
|
jour = args.get("jour", None)
|
||||||
args["jour"] = jour
|
args["jour"] = jour
|
||||||
if jour:
|
if jour:
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
||||||
date_debut = datetime.date(y, m, d)
|
date_debut = datetime.date(y, m, d)
|
||||||
@ -301,8 +301,8 @@ def do_evaluation_create(
|
|||||||
r = _evaluationEditor.create(cnx, args)
|
r = _evaluationEditor.create(cnx, args)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.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"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
@ -332,7 +332,7 @@ def do_evaluation_edit(args):
|
|||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
_evaluationEditor.edit(cnx, args)
|
_evaluationEditor.edit(cnx, args)
|
||||||
# inval cache pour ce semestre
|
# inval cache pour ce semestre
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||||
|
|
||||||
|
|
||||||
@ -357,10 +357,10 @@ def do_evaluation_delete(evaluation_id):
|
|||||||
|
|
||||||
_evaluationEditor.delete(cnx, evaluation_id)
|
_evaluationEditor.delete(cnx, evaluation_id)
|
||||||
# inval cache pour ce semestre
|
# inval cache pour ce semestre
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||||
# news
|
# news
|
||||||
mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
mod["url"] = (
|
mod["url"] = (
|
||||||
scu.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
scu.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
@ -373,9 +373,6 @@ def do_evaluation_delete(evaluation_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_DEE_TOT = 0
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
|
def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
|
||||||
"""donne infos sur l'etat du evaluation
|
"""donne infos sur l'etat du evaluation
|
||||||
{ nb_inscrits, nb_notes, nb_abs, nb_neutre, nb_att,
|
{ nb_inscrits, nb_notes, nb_abs, nb_neutre, nb_att,
|
||||||
@ -412,8 +409,8 @@ def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=
|
|||||||
last_modif = None
|
last_modif = None
|
||||||
# ---- Liste des groupes complets et incomplets
|
# ---- Liste des groupes complets et incomplets
|
||||||
E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
# Si partition_id is None, prend 'all' ou bien la premiere:
|
# Si partition_id is None, prend 'all' ou bien la premiere:
|
||||||
@ -735,7 +732,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
|||||||
if not e["jour"]:
|
if not e["jour"]:
|
||||||
continue
|
continue
|
||||||
day = e["jour"].strftime("%Y-%m-%d")
|
day = e["jour"].strftime("%Y-%m-%d")
|
||||||
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
mod = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=e["moduleimpl_id"]
|
moduleimpl_id=e["moduleimpl_id"]
|
||||||
)[0]
|
)[0]
|
||||||
txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
|
txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
|
||||||
@ -812,7 +809,7 @@ def evaluation_date_first_completion(evaluation_id):
|
|||||||
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
||||||
# au module (pour gerer les modules optionnels correctement)
|
# au module (pour gerer les modules optionnels correctement)
|
||||||
# E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
# E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
# M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
# M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# formsemestre_id = M["formsemestre_id"]
|
# formsemestre_id = M["formsemestre_id"]
|
||||||
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits( formsemestre_id)
|
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits( formsemestre_id)
|
||||||
# insmod = sco_moduleimpl.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
# insmod = sco_moduleimpl.do_moduleimpl_inscription_list(moduleimpl_id=E["moduleimpl_id"])
|
||||||
@ -854,8 +851,8 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
evals = nt.get_sem_evaluation_etat_list()
|
evals = nt.get_sem_evaluation_etat_list()
|
||||||
T = []
|
T = []
|
||||||
for e in evals:
|
for e in evals:
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
M = sco_moduleimpl.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
||||||
Mod["module_type"] == scu.MODULE_MALUS
|
Mod["module_type"] == scu.MODULE_MALUS
|
||||||
):
|
):
|
||||||
@ -1035,8 +1032,8 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
|
|
||||||
E = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = E["moduleimpl_id"]
|
moduleimpl_id = E["moduleimpl_id"]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
u = sco_users.user_info(M["responsable_id"])
|
u = sco_users.user_info(M["responsable_id"])
|
||||||
resp = u["prenomnom"]
|
resp = u["prenomnom"]
|
||||||
@ -1065,7 +1062,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
]
|
]
|
||||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
if Mod["module_type"] == scu.MODULE_MALUS:
|
||||||
# Indique l'UE
|
# Indique l'UE
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
||||||
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
||||||
# store min/max values used by JS client-side checks:
|
# store min/max values used by JS client-side checks:
|
||||||
H.append(
|
H.append(
|
||||||
@ -1115,7 +1112,7 @@ def evaluation_create_form(
|
|||||||
the_eval = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
the_eval = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = the_eval["moduleimpl_id"]
|
moduleimpl_id = the_eval["moduleimpl_id"]
|
||||||
#
|
#
|
||||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
is_malus = M["module"]["module_type"] == scu.MODULE_MALUS # True si module de malus
|
is_malus = M["module"]["module_type"] == scu.MODULE_MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
||||||
@ -1174,7 +1171,7 @@ def evaluation_create_form(
|
|||||||
else:
|
else:
|
||||||
min_note_max_str = "0"
|
min_note_max_str = "0"
|
||||||
#
|
#
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
#
|
#
|
||||||
help = """<div class="help"><p class="help">
|
help = """<div class="help"><p class="help">
|
||||||
Le coefficient d'une évaluation n'est utilisé que pour pondérer les évaluations au sein d'un module.
|
Le coefficient d'une évaluation n'est utilisé que pour pondérer les évaluations au sein d'un module.
|
||||||
|
@ -285,10 +285,25 @@ class ScoExcelSheet:
|
|||||||
|
|
||||||
def make_cell(self, value: any = None, style=None, comment=None):
|
def make_cell(self, value: any = None, style=None, comment=None):
|
||||||
"""Construit une cellule.
|
"""Construit une cellule.
|
||||||
value -- contenu de la cellule (texte ou numérique)
|
value -- contenu de la cellule (texte, numérique, booléen ou date)
|
||||||
style -- style par défaut (dictionnaire cf. excel_make_style) de la feuille si non spécifié
|
style -- style par défaut (dictionnaire cf. excel_make_style) de la feuille si non spécifié
|
||||||
"""
|
"""
|
||||||
cell = WriteOnlyCell(self.ws, value or "")
|
# adapatation des valeurs si nécessaire
|
||||||
|
if value is None:
|
||||||
|
value = ""
|
||||||
|
elif value is True:
|
||||||
|
value = 1
|
||||||
|
elif value is False:
|
||||||
|
value = 0
|
||||||
|
elif isinstance(value, datetime.datetime):
|
||||||
|
value = value.replace(
|
||||||
|
tzinfo=None
|
||||||
|
) # make date naive (cf https://openpyxl.readthedocs.io/en/latest/datetime.html#timezones)
|
||||||
|
|
||||||
|
# création de la cellule
|
||||||
|
cell = WriteOnlyCell(self.ws, value)
|
||||||
|
|
||||||
|
# recopie des styles
|
||||||
if style is None:
|
if style is None:
|
||||||
style = self.default_style
|
style = self.default_style
|
||||||
if "font" in style:
|
if "font" in style:
|
||||||
@ -310,7 +325,8 @@ class ScoExcelSheet:
|
|||||||
lines = comment.splitlines()
|
lines = comment.splitlines()
|
||||||
cell.comment.width = 7 * max([len(line) for line in lines])
|
cell.comment.width = 7 * max([len(line) for line in lines])
|
||||||
cell.comment.height = 20 * len(lines)
|
cell.comment.height = 20 * len(lines)
|
||||||
# test datatype at the end so that datetime format may be overwritten
|
|
||||||
|
# test datatype to overwrite datetime format
|
||||||
if isinstance(value, datetime.date):
|
if isinstance(value, datetime.date):
|
||||||
cell.data_type = "d"
|
cell.data_type = "d"
|
||||||
cell.number_format = FORMAT_DATE_DDMMYY
|
cell.number_format = FORMAT_DATE_DDMMYY
|
||||||
@ -318,6 +334,7 @@ class ScoExcelSheet:
|
|||||||
cell.data_type = "n"
|
cell.data_type = "n"
|
||||||
else:
|
else:
|
||||||
cell.data_type = "s"
|
cell.data_type = "s"
|
||||||
|
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
def make_row(self, values: list, style=None, comments=None):
|
def make_row(self, values: list, style=None, comments=None):
|
||||||
|
@ -98,7 +98,7 @@ def formation_export(formation_id, export_ids=False, export_tags=True, format=No
|
|||||||
in desired format
|
in desired format
|
||||||
"""
|
"""
|
||||||
F = formation_list(args={"formation_id": formation_id})[0]
|
F = formation_list(args={"formation_id": formation_id})[0]
|
||||||
ues = sco_edit_ue.do_ue_list({"formation_id": formation_id})
|
ues = sco_edit_ue.ue_list({"formation_id": formation_id})
|
||||||
F["ue"] = ues
|
F["ue"] = ues
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_id = ue["ue_id"]
|
ue_id = ue["ue_id"]
|
||||||
@ -107,14 +107,14 @@ def formation_export(formation_id, export_ids=False, export_tags=True, format=No
|
|||||||
del ue["formation_id"]
|
del ue["formation_id"]
|
||||||
if ue["ects"] is None:
|
if ue["ects"] is None:
|
||||||
del ue["ects"]
|
del ue["ects"]
|
||||||
mats = sco_edit_matiere.do_matiere_list({"ue_id": ue_id})
|
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
|
||||||
ue["matiere"] = mats
|
ue["matiere"] = mats
|
||||||
for mat in mats:
|
for mat in mats:
|
||||||
matiere_id = mat["matiere_id"]
|
matiere_id = mat["matiere_id"]
|
||||||
if not export_ids:
|
if not export_ids:
|
||||||
del mat["matiere_id"]
|
del mat["matiere_id"]
|
||||||
del mat["ue_id"]
|
del mat["ue_id"]
|
||||||
mods = sco_edit_module.do_module_list({"matiere_id": matiere_id})
|
mods = sco_edit_module.module_list({"matiere_id": matiere_id})
|
||||||
mat["module"] = mods
|
mat["module"] = mods
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
if export_tags:
|
if export_tags:
|
||||||
@ -130,7 +130,9 @@ def formation_export(formation_id, export_ids=False, export_tags=True, format=No
|
|||||||
if mod["ects"] is None:
|
if mod["ects"] is None:
|
||||||
del mod["ects"]
|
del mod["ects"]
|
||||||
|
|
||||||
return scu.sendResult(F, name="formation", format=format, force_outer_xml_tag=False, attached=True)
|
return scu.sendResult(
|
||||||
|
F, name="formation", format=format, force_outer_xml_tag=False, attached=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def formation_import_xml(doc: str, import_tags=True):
|
def formation_import_xml(doc: str, import_tags=True):
|
||||||
@ -364,7 +366,7 @@ def formation_create_new_version(formation_id, redirect=True):
|
|||||||
if redirect:
|
if redirect:
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_list",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=new_id,
|
formation_id=new_id,
|
||||||
msg="Nouvelle version !",
|
msg="Nouvelle version !",
|
||||||
|
@ -246,7 +246,7 @@ def do_formsemestre_create(args, silent=False):
|
|||||||
default=True,
|
default=True,
|
||||||
redirect=0,
|
redirect=0,
|
||||||
)
|
)
|
||||||
_group_id = sco_groups.createGroup(partition_id, default=True)
|
_group_id = sco_groups.create_group(partition_id, default=True)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
if "titre" not in args:
|
if "titre" not in args:
|
||||||
|
@ -51,6 +51,7 @@ from app.scodoc import sco_etud
|
|||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
|
from app.scodoc import sco_groups_copy
|
||||||
from app.scodoc import sco_modalites
|
from app.scodoc import sco_modalites
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
@ -58,7 +59,6 @@ from app.scodoc import sco_permissions_check
|
|||||||
from app.scodoc import sco_portal_apogee
|
from app.scodoc import sco_portal_apogee
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_users
|
from app.scodoc import sco_users
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
def _default_sem_title(F):
|
def _default_sem_title(F):
|
||||||
@ -171,7 +171,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
initvalues = sem
|
initvalues = sem
|
||||||
semestre_id = initvalues["semestre_id"]
|
semestre_id = initvalues["semestre_id"]
|
||||||
# add associated modules to tf-checked:
|
# add associated modules to tf-checked:
|
||||||
ams = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
ams = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
sem_module_ids = set([x["module_id"] for x in ams])
|
sem_module_ids = set([x["module_id"] for x in ams])
|
||||||
initvalues["tf-checked"] = ["MI" + str(x["module_id"]) for x in ams]
|
initvalues["tf-checked"] = ["MI" + str(x["module_id"]) for x in ams]
|
||||||
for x in ams:
|
for x in ams:
|
||||||
@ -205,11 +205,11 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
# on pourrait faire un simple module_list( )
|
# on pourrait faire un simple module_list( )
|
||||||
# mais si on veut l'ordre du PPN (groupe par UE et matieres) il faut:
|
# mais si on veut l'ordre du PPN (groupe par UE et matieres) il faut:
|
||||||
mods = [] # liste de dicts
|
mods = [] # liste de dicts
|
||||||
uelist = sco_edit_ue.do_ue_list({"formation_id": formation_id})
|
uelist = sco_edit_ue.ue_list({"formation_id": formation_id})
|
||||||
for ue in uelist:
|
for ue in uelist:
|
||||||
matlist = sco_edit_matiere.do_matiere_list({"ue_id": ue["ue_id"]})
|
matlist = sco_edit_matiere.matiere_list({"ue_id": ue["ue_id"]})
|
||||||
for mat in matlist:
|
for mat in matlist:
|
||||||
modsmat = sco_edit_module.do_module_list({"matiere_id": mat["matiere_id"]})
|
modsmat = sco_edit_module.module_list({"matiere_id": mat["matiere_id"]})
|
||||||
# XXX debug checks
|
# XXX debug checks
|
||||||
for m in modsmat:
|
for m in modsmat:
|
||||||
if m["ue_id"] != ue["ue_id"]:
|
if m["ue_id"] != ue["ue_id"]:
|
||||||
@ -751,7 +751,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
# (retire le "MI" du début du nom de champs)
|
# (retire le "MI" du début du nom de champs)
|
||||||
checkedmods = [int(x[2:]) for x in tf[2]["tf-checked"]]
|
checkedmods = [int(x[2:]) for x in tf[2]["tf-checked"]]
|
||||||
sco_formsemestre.do_formsemestre_edit(tf[2])
|
sco_formsemestre.do_formsemestre_edit(tf[2])
|
||||||
ams = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
ams = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
existingmods = [x["module_id"] for x in ams]
|
existingmods = [x["module_id"] for x in ams]
|
||||||
mods_tocreate = [x for x in checkedmods if not x in existingmods]
|
mods_tocreate = [x for x in checkedmods if not x in existingmods]
|
||||||
# modules a existants a modifier
|
# modules a existants a modifier
|
||||||
@ -767,7 +767,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
"responsable_id": tf[2]["MI" + str(module_id)],
|
"responsable_id": tf[2]["MI" + str(module_id)],
|
||||||
}
|
}
|
||||||
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(modargs)
|
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(modargs)
|
||||||
mod = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
msg += ["création de %s (%s)" % (mod["code"], mod["titre"])]
|
msg += ["création de %s (%s)" % (mod["code"], mod["titre"])]
|
||||||
# INSCRIPTIONS DES ETUDIANTS
|
# INSCRIPTIONS DES ETUDIANTS
|
||||||
log(
|
log(
|
||||||
@ -801,7 +801,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
ok, diag = formsemestre_delete_moduleimpls(formsemestre_id, mods_todelete)
|
ok, diag = formsemestre_delete_moduleimpls(formsemestre_id, mods_todelete)
|
||||||
msg += diag
|
msg += diag
|
||||||
for module_id in mods_toedit:
|
for module_id in mods_toedit:
|
||||||
moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
moduleimpl_id = sco_moduleimpl.moduleimpl_list(
|
||||||
formsemestre_id=formsemestre_id, module_id=module_id
|
formsemestre_id=formsemestre_id, module_id=module_id
|
||||||
)[0]["moduleimpl_id"]
|
)[0]["moduleimpl_id"]
|
||||||
modargs = {
|
modargs = {
|
||||||
@ -813,7 +813,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
sco_moduleimpl.do_moduleimpl_edit(
|
sco_moduleimpl.do_moduleimpl_edit(
|
||||||
modargs, formsemestre_id=formsemestre_id
|
modargs, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
mod = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
msg_html = (
|
msg_html = (
|
||||||
@ -846,10 +846,10 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
|
|||||||
msg = []
|
msg = []
|
||||||
for module_id in module_ids_to_del:
|
for module_id in module_ids_to_del:
|
||||||
# get id
|
# get id
|
||||||
moduleimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
moduleimpl_id = sco_moduleimpl.moduleimpl_list(
|
||||||
formsemestre_id=formsemestre_id, module_id=module_id
|
formsemestre_id=formsemestre_id, module_id=module_id
|
||||||
)[0]["moduleimpl_id"]
|
)[0]["moduleimpl_id"]
|
||||||
mod = sco_edit_module.do_module_list({"module_id": module_id})[0]
|
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
# Evaluations dans ce module ?
|
# Evaluations dans ce module ?
|
||||||
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||||
if evals:
|
if evals:
|
||||||
@ -1015,7 +1015,7 @@ def do_formsemestre_clone(
|
|||||||
formsemestre_id = sco_formsemestre.do_formsemestre_create(args)
|
formsemestre_id = sco_formsemestre.do_formsemestre_create(args)
|
||||||
log("created formsemestre %s" % formsemestre_id)
|
log("created formsemestre %s" % formsemestre_id)
|
||||||
# 2- create moduleimpls
|
# 2- create moduleimpls
|
||||||
mods_orig = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=orig_formsemestre_id)
|
mods_orig = sco_moduleimpl.moduleimpl_list(formsemestre_id=orig_formsemestre_id)
|
||||||
for mod_orig in mods_orig:
|
for mod_orig in mods_orig:
|
||||||
args = mod_orig.copy()
|
args = mod_orig.copy()
|
||||||
args["formsemestre_id"] = formsemestre_id
|
args["formsemestre_id"] = formsemestre_id
|
||||||
@ -1074,32 +1074,11 @@ def do_formsemestre_clone(
|
|||||||
args["formsemestre_id"] = formsemestre_id
|
args["formsemestre_id"] = formsemestre_id
|
||||||
_ = sco_compute_moy.formsemestre_ue_computation_expr_create(cnx, args)
|
_ = sco_compute_moy.formsemestre_ue_computation_expr_create(cnx, args)
|
||||||
|
|
||||||
# 5- Copy partitions
|
# 5- Copy partitions and groups
|
||||||
if clone_partitions:
|
if clone_partitions:
|
||||||
listgroups = []
|
sco_groups_copy.clone_partitions_and_groups(
|
||||||
listnamegroups = []
|
orig_formsemestre_id, formsemestre_id
|
||||||
# Création des partitions:
|
|
||||||
for part in sco_groups.get_partitions_list(orig_formsemestre_id):
|
|
||||||
if part["partition_name"] != None:
|
|
||||||
partname = part["partition_name"]
|
|
||||||
new_partition_id = sco_groups.partition_create(
|
|
||||||
formsemestre_id,
|
|
||||||
partition_name=partname,
|
|
||||||
redirect=0,
|
|
||||||
)
|
)
|
||||||
for g in sco_groups.get_partition_groups(part):
|
|
||||||
if g["group_name"] != None:
|
|
||||||
listnamegroups.append(g["group_name"])
|
|
||||||
listgroups.append([new_partition_id, listnamegroups])
|
|
||||||
listnamegroups = []
|
|
||||||
|
|
||||||
# Création des groupes dans les nouvelles partitions:
|
|
||||||
for newpart in sco_groups.get_partitions_list(formsemestre_id):
|
|
||||||
for g in listgroups:
|
|
||||||
if newpart["partition_id"] == g[0]:
|
|
||||||
part_id = g[0]
|
|
||||||
for group_name in g[1]:
|
|
||||||
_ = sco_groups.createGroup(part_id, group_name=group_name)
|
|
||||||
|
|
||||||
return formsemestre_id
|
return formsemestre_id
|
||||||
|
|
||||||
@ -1212,7 +1191,7 @@ def _reassociate_moduleimpls(cnx, formsemestre_id, ues_old2new, modules_old2new)
|
|||||||
et met à jour les décisions de jury (validations d'UE).
|
et met à jour les décisions de jury (validations d'UE).
|
||||||
"""
|
"""
|
||||||
# re-associate moduleimpls to new modules:
|
# re-associate moduleimpls to new modules:
|
||||||
modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
for mod in modimpls:
|
for mod in modimpls:
|
||||||
mod["module_id"] = modules_old2new[mod["module_id"]]
|
mod["module_id"] = modules_old2new[mod["module_id"]]
|
||||||
sco_moduleimpl.do_moduleimpl_edit(mod, formsemestre_id=formsemestre_id)
|
sco_moduleimpl.do_moduleimpl_edit(mod, formsemestre_id=formsemestre_id)
|
||||||
@ -1329,7 +1308,7 @@ def do_formsemestre_delete(formsemestre_id):
|
|||||||
sco_cache.EvaluationCache.invalidate_sem(formsemestre_id)
|
sco_cache.EvaluationCache.invalidate_sem(formsemestre_id)
|
||||||
|
|
||||||
# --- Destruction des modules de ce semestre
|
# --- Destruction des modules de ce semestre
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
# evaluations
|
# evaluations
|
||||||
evals = sco_evaluations.do_evaluation_list(
|
evals = sco_evaluations.do_evaluation_list(
|
||||||
|
@ -439,7 +439,7 @@ def _list_ue_with_coef_and_validations(sem, etudid):
|
|||||||
"""
|
"""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
ue_list = sco_edit_ue.do_ue_list({"formation_id": sem["formation_id"]})
|
ue_list = sco_edit_ue.ue_list({"formation_id": sem["formation_id"]})
|
||||||
for ue in ue_list:
|
for ue in ue_list:
|
||||||
# add coefficient
|
# add coefficient
|
||||||
uecoef = sco_formsemestre.formsemestre_uecoef_list(
|
uecoef = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
|
@ -237,7 +237,7 @@ def do_formsemestre_inscription_with_modules(
|
|||||||
gdone[group_id] = 1
|
gdone[group_id] = 1
|
||||||
|
|
||||||
# inscription a tous les modules de ce semestre
|
# inscription a tous les modules de ce semestre
|
||||||
modimpls = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
modimpls = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
formsemestre_id=formsemestre_id
|
formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
for mod in modimpls:
|
for mod in modimpls:
|
||||||
@ -448,7 +448,7 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Cherche les moduleimpls et les inscriptions
|
# Cherche les moduleimpls et les inscriptions
|
||||||
mods = sco_moduleimpl.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(etudid=etudid)
|
inscr = sco_moduleimpl.do_moduleimpl_inscription_list(etudid=etudid)
|
||||||
# Formulaire
|
# Formulaire
|
||||||
modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
modimpls_by_ue_ids = scu.DictDefault(defaultvalue=[]) # ue_id : [ moduleimpl_id ]
|
||||||
@ -680,7 +680,7 @@ def do_moduleimpl_incription_options(
|
|||||||
# inscriptions
|
# inscriptions
|
||||||
for moduleimpl_id in a_inscrire:
|
for moduleimpl_id in a_inscrire:
|
||||||
# verifie que ce module existe bien
|
# verifie que ce module existe bien
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"inscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
"inscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
||||||
@ -693,7 +693,7 @@ def do_moduleimpl_incription_options(
|
|||||||
# desinscriptions
|
# desinscriptions
|
||||||
for moduleimpl_id in a_desinscrire:
|
for moduleimpl_id in a_desinscrire:
|
||||||
# verifie que ce module existe bien
|
# verifie que ce module existe bien
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
"desinscription: invalid moduleimpl_id: %s" % moduleimpl_id
|
||||||
|
@ -141,7 +141,7 @@ def formsemestre_status_menubar(sem):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Voir la formation %(acronyme)s (v%(version)s)" % F,
|
"title": "Voir la formation %(acronyme)s (v%(version)s)" % F,
|
||||||
"endpoint": "notes.ue_list",
|
"endpoint": "notes.ue_table",
|
||||||
"args": {"formation_id": sem["formation_id"]},
|
"args": {"formation_id": sem["formation_id"]},
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
"helpmsg": "Tableau de bord du semestre",
|
"helpmsg": "Tableau de bord du semestre",
|
||||||
@ -453,7 +453,7 @@ def retreive_formsemestre_from_request() -> int:
|
|||||||
if "formsemestre_id" in args:
|
if "formsemestre_id" in args:
|
||||||
formsemestre_id = args["formsemestre_id"]
|
formsemestre_id = args["formsemestre_id"]
|
||||||
elif "moduleimpl_id" in args and args["moduleimpl_id"]:
|
elif "moduleimpl_id" in args and args["moduleimpl_id"]:
|
||||||
modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=args["moduleimpl_id"])
|
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=args["moduleimpl_id"])
|
||||||
if not modimpl:
|
if not modimpl:
|
||||||
return None # suppressed ?
|
return None # suppressed ?
|
||||||
modimpl = modimpl[0]
|
modimpl = modimpl[0]
|
||||||
@ -463,7 +463,7 @@ def retreive_formsemestre_from_request() -> int:
|
|||||||
if not E:
|
if not E:
|
||||||
return None # evaluation suppressed ?
|
return None # evaluation suppressed ?
|
||||||
E = E[0]
|
E = E[0]
|
||||||
modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
elif "group_id" in args:
|
elif "group_id" in args:
|
||||||
group = sco_groups.get_group(args["group_id"])
|
group = sco_groups.get_group(args["group_id"])
|
||||||
@ -593,9 +593,7 @@ def formsemestre_description_table(formsemestre_id, with_evals=False):
|
|||||||
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
|
|
||||||
R = []
|
R = []
|
||||||
sum_coef = 0
|
sum_coef = 0
|
||||||
@ -885,7 +883,7 @@ def html_expr_diagnostic(diagnostics):
|
|||||||
last_id, last_msg = None, None
|
last_id, last_msg = None, None
|
||||||
for diag in diagnostics:
|
for diag in diagnostics:
|
||||||
if "moduleimpl_id" in diag:
|
if "moduleimpl_id" in diag:
|
||||||
mod = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
mod = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=diag["moduleimpl_id"]
|
moduleimpl_id=diag["moduleimpl_id"]
|
||||||
)[0]
|
)[0]
|
||||||
H.append(
|
H.append(
|
||||||
@ -898,7 +896,7 @@ def html_expr_diagnostic(diagnostics):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if diag["ue_id"] != last_id or diag["msg"] != last_msg:
|
if diag["ue_id"] != last_id or diag["msg"] != last_msg:
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": diag["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": diag["ue_id"]})[0]
|
||||||
H.append(
|
H.append(
|
||||||
'<li>UE "%s": %s</li>'
|
'<li>UE "%s": %s</li>'
|
||||||
% (ue["acronyme"] or ue["titre"] or "?", diag["msg"])
|
% (ue["acronyme"] or ue["titre"] or "?", diag["msg"])
|
||||||
@ -928,7 +926,7 @@ def formsemestre_status_head(formsemestre_id=None, page_title=None):
|
|||||||
),
|
),
|
||||||
f"""<table>
|
f"""<table>
|
||||||
<tr><td class="fichetitre2">Formation: </td><td>
|
<tr><td class="fichetitre2">Formation: </td><td>
|
||||||
<a href="{url_for('notes.ue_list', scodoc_dept=g.scodoc_dept, formation_id=F['formation_id'])}"
|
<a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=F['formation_id'])}"
|
||||||
class="discretelink" title="Formation {F['acronyme']}, v{F['version']}">{F['titre']}</a>""",
|
class="discretelink" title="Formation {F['acronyme']}, v{F['version']}">{F['titre']}</a>""",
|
||||||
]
|
]
|
||||||
if sem["semestre_id"] >= 0:
|
if sem["semestre_id"] >= 0:
|
||||||
@ -982,9 +980,7 @@ def formsemestre_status(formsemestre_id=None):
|
|||||||
# porté du DTML
|
# porté du DTML
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
# inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
# inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
# args={"formsemestre_id": formsemestre_id}
|
# args={"formsemestre_id": formsemestre_id}
|
||||||
# )
|
# )
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
"""Semestres: validation semestre et UE dans parcours
|
"""Semestres: validation semestre et UE dans parcours
|
||||||
"""
|
"""
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error, time, datetime
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
@ -494,7 +494,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
with_links=False,
|
with_links=False,
|
||||||
with_all_columns=True,
|
with_all_columns=True,
|
||||||
a_url="",
|
a_url="",
|
||||||
sem_info={},
|
sem_info=None,
|
||||||
show_details=False,
|
show_details=False,
|
||||||
):
|
):
|
||||||
"""Tableau HTML recap parcours
|
"""Tableau HTML recap parcours
|
||||||
@ -502,6 +502,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
sem_info = { formsemestre_id : txt } permet d'ajouter des informations associées à chaque semestre
|
sem_info = { formsemestre_id : txt } permet d'ajouter des informations associées à chaque semestre
|
||||||
with_all_columns: si faux, pas de colonne "assiduité".
|
with_all_columns: si faux, pas de colonne "assiduité".
|
||||||
"""
|
"""
|
||||||
|
sem_info = sem_info or {}
|
||||||
H = []
|
H = []
|
||||||
linktmpl = '<span onclick="toggle_vis(this);" class="toggle_sem sem_%%s">%s</span>'
|
linktmpl = '<span onclick="toggle_vis(this);" class="toggle_sem sem_%%s">%s</span>'
|
||||||
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
||||||
@ -1021,7 +1022,7 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Toutes les UE de cette formation sont présentées (même celles des autres semestres)
|
# Toutes les UE de cette formation sont présentées (même celles des autres semestres)
|
||||||
ues = sco_edit_ue.do_ue_list({"formation_id": Fo["formation_id"]})
|
ues = sco_edit_ue.ue_list({"formation_id": Fo["formation_id"]})
|
||||||
ue_names = ["Choisir..."] + ["%(acronyme)s %(titre)s" % ue for ue in ues]
|
ue_names = ["Choisir..."] + ["%(acronyme)s %(titre)s" % ue for ue in ues]
|
||||||
ue_ids = [""] + [ue["ue_id"] for ue in ues]
|
ue_ids = [""] + [ue["ue_id"] for ue in ues]
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
@ -1233,7 +1234,7 @@ def check_formation_ues(formation_id):
|
|||||||
définition du programme: cette fonction retourne un bout de HTML
|
définition du programme: cette fonction retourne un bout de HTML
|
||||||
à afficher pour prévenir l'utilisateur, ou '' si tout est ok.
|
à afficher pour prévenir l'utilisateur, ou '' si tout est ok.
|
||||||
"""
|
"""
|
||||||
ues = sco_edit_ue.do_ue_list({"formation_id": formation_id})
|
ues = sco_edit_ue.ue_list({"formation_id": formation_id})
|
||||||
ue_multiples = {} # { ue_id : [ liste des formsemestre ] }
|
ue_multiples = {} # { ue_id : [ liste des formsemestre ] }
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
# formsemestres utilisant cette ue ?
|
# formsemestres utilisant cette ue ?
|
||||||
|
@ -47,7 +47,7 @@ from flask import url_for, make_response
|
|||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log, cache
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
@ -59,20 +59,6 @@ from app.scodoc.sco_exceptions import ScoException, AccessDenied, ScoValueError
|
|||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
def checkGroupName(
|
|
||||||
groupName,
|
|
||||||
): # XXX unused: now allow any string as a group or partition name
|
|
||||||
"Raises exception if not a valid group name"
|
|
||||||
if groupName and (
|
|
||||||
not re.match(r"^\w+$", groupName)
|
|
||||||
or (scu.simplesqlquote(groupName) != groupName)
|
|
||||||
):
|
|
||||||
log("!!! invalid group name: " + groupName)
|
|
||||||
raise ValueError("invalid group name: " + groupName)
|
|
||||||
|
|
||||||
|
|
||||||
partitionEditor = ndb.EditableTable(
|
partitionEditor = ndb.EditableTable(
|
||||||
"partition",
|
"partition",
|
||||||
@ -219,7 +205,7 @@ def get_default_group(formsemestre_id, fix_if_missing=False):
|
|||||||
partition_id = partition_create(
|
partition_id = partition_create(
|
||||||
formsemestre_id, default=True, redirect=False
|
formsemestre_id, default=True, redirect=False
|
||||||
)
|
)
|
||||||
group_id = createGroup(partition_id, default=True)
|
group_id = create_group(partition_id, default=True)
|
||||||
return group_id
|
return group_id
|
||||||
# debug check
|
# debug check
|
||||||
if len(r) != 1:
|
if len(r) != 1:
|
||||||
@ -452,6 +438,7 @@ def etud_add_group_infos(etud, sem, sep=" "):
|
|||||||
return etud
|
return etud
|
||||||
|
|
||||||
|
|
||||||
|
@cache.memoize(timeout=50) # seconds
|
||||||
def get_etud_groups_in_partition(partition_id):
|
def get_etud_groups_in_partition(partition_id):
|
||||||
"""Returns { etudid : group }, with all students in this partition"""
|
"""Returns { etudid : group }, with all students in this partition"""
|
||||||
infos = ndb.SimpleDictFetch(
|
infos = ndb.SimpleDictFetch(
|
||||||
@ -724,7 +711,7 @@ def setGroups(
|
|||||||
|
|
||||||
# Supprime les groupes indiqués comme supprimés:
|
# Supprime les groupes indiqués comme supprimés:
|
||||||
for group_id in groupsToDelete:
|
for group_id in groupsToDelete:
|
||||||
suppressGroup(group_id, partition_id=partition_id)
|
delete_group(group_id, partition_id=partition_id)
|
||||||
|
|
||||||
# Crée les nouveaux groupes
|
# Crée les nouveaux groupes
|
||||||
for line in groupsToCreate.split("\n"): # for each group_name (one per line)
|
for line in groupsToCreate.split("\n"): # for each group_name (one per line)
|
||||||
@ -732,11 +719,7 @@ def setGroups(
|
|||||||
group_name = fs[0].strip()
|
group_name = fs[0].strip()
|
||||||
if not group_name:
|
if not group_name:
|
||||||
continue
|
continue
|
||||||
# ajax arguments are encoded in utf-8:
|
group_id = create_group(partition_id, group_name)
|
||||||
# group_name = six.text_type(group_name, "utf-8").encode(
|
|
||||||
# scu.SCO_ENCODING
|
|
||||||
# ) # #py3 #sco8
|
|
||||||
group_id = createGroup(partition_id, group_name)
|
|
||||||
# Place dans ce groupe les etudiants indiqués:
|
# Place dans ce groupe les etudiants indiqués:
|
||||||
for etudid in fs[1:-1]:
|
for etudid in fs[1:-1]:
|
||||||
change_etud_group_in_partition(etudid, group_id, partition)
|
change_etud_group_in_partition(etudid, group_id, partition)
|
||||||
@ -749,7 +732,7 @@ def setGroups(
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def createGroup(partition_id, group_name="", default=False):
|
def create_group(partition_id, group_name="", default=False) -> int:
|
||||||
"""Create a new group in this partition"""
|
"""Create a new group in this partition"""
|
||||||
partition = get_partition(partition_id)
|
partition = get_partition(partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
@ -769,12 +752,12 @@ def createGroup(partition_id, group_name="", default=False):
|
|||||||
group_id = groupEditor.create(
|
group_id = groupEditor.create(
|
||||||
cnx, {"partition_id": partition_id, "group_name": group_name}
|
cnx, {"partition_id": partition_id, "group_name": group_name}
|
||||||
)
|
)
|
||||||
log("createGroup: created group_id=%s" % group_id)
|
log("create_group: created group_id=%s" % group_id)
|
||||||
#
|
#
|
||||||
return group_id
|
return group_id
|
||||||
|
|
||||||
|
|
||||||
def suppressGroup(group_id, partition_id=None):
|
def delete_group(group_id, partition_id=None):
|
||||||
"""form suppression d'un groupe.
|
"""form suppression d'un groupe.
|
||||||
(ne desinscrit pas les etudiants, change juste leur
|
(ne desinscrit pas les etudiants, change juste leur
|
||||||
affectation aux groupes)
|
affectation aux groupes)
|
||||||
@ -791,7 +774,7 @@ def suppressGroup(group_id, partition_id=None):
|
|||||||
if not sco_permissions_check.can_change_groups(partition["formsemestre_id"]):
|
if not sco_permissions_check.can_change_groups(partition["formsemestre_id"]):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
log(
|
log(
|
||||||
"suppressGroup: group_id=%s group_name=%s partition_name=%s"
|
"delete_group: group_id=%s group_name=%s partition_name=%s"
|
||||||
% (group_id, group["group_name"], partition["partition_name"])
|
% (group_id, group["group_name"], partition["partition_name"])
|
||||||
)
|
)
|
||||||
group_delete(group)
|
group_delete(group)
|
||||||
@ -808,7 +791,7 @@ def partition_create(
|
|||||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
if partition_name:
|
if partition_name:
|
||||||
partition_name = partition_name.strip()
|
partition_name = str(partition_name).strip()
|
||||||
if default:
|
if default:
|
||||||
partition_name = None
|
partition_name = None
|
||||||
if not partition_name and not default:
|
if not partition_name and not default:
|
||||||
@ -840,7 +823,7 @@ def partition_create(
|
|||||||
return partition_id
|
return partition_id
|
||||||
|
|
||||||
|
|
||||||
def getArrowIconsTags():
|
def get_arrow_icons_tags():
|
||||||
"""returns html tags for arrows"""
|
"""returns html tags for arrows"""
|
||||||
#
|
#
|
||||||
arrow_up = scu.icontag("arrow_up", title="remonter")
|
arrow_up = scu.icontag("arrow_up", title="remonter")
|
||||||
@ -856,7 +839,7 @@ def editPartitionForm(formsemestre_id=None):
|
|||||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
partitions = get_partitions_list(formsemestre_id)
|
partitions = get_partitions_list(formsemestre_id)
|
||||||
arrow_up, arrow_down, arrow_none = getArrowIconsTags()
|
arrow_up, arrow_down, arrow_none = get_arrow_icons_tags()
|
||||||
suppricon = scu.icontag(
|
suppricon = scu.icontag(
|
||||||
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
"delete_small_img", border="0", alt="supprimer", title="Supprimer"
|
||||||
)
|
)
|
||||||
@ -1123,7 +1106,7 @@ def partition_rename(partition_id):
|
|||||||
|
|
||||||
def partition_set_name(partition_id, partition_name, redirect=1):
|
def partition_set_name(partition_id, partition_name, redirect=1):
|
||||||
"""Set partition name"""
|
"""Set partition name"""
|
||||||
partition_name = partition_name.strip()
|
partition_name = str(partition_name).strip()
|
||||||
if not partition_name:
|
if not partition_name:
|
||||||
raise ValueError("partition name must be non empty")
|
raise ValueError("partition name must be non empty")
|
||||||
partition = get_partition(partition_id)
|
partition = get_partition(partition_id)
|
||||||
@ -1159,7 +1142,7 @@ def partition_set_name(partition_id, partition_name, redirect=1):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def group_set_name(group_id, group_name, redirect=1):
|
def group_set_name(group_id, group_name, redirect=True):
|
||||||
"""Set group name"""
|
"""Set group name"""
|
||||||
if group_name:
|
if group_name:
|
||||||
group_name = group_name.strip()
|
group_name = group_name.strip()
|
||||||
@ -1229,7 +1212,7 @@ def group_rename(group_id):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# form submission
|
# form submission
|
||||||
return group_set_name(group_id, tf[2]["group_name"], redirect=1)
|
return group_set_name(group_id, tf[2]["group_name"])
|
||||||
|
|
||||||
|
|
||||||
def groups_auto_repartition(partition_id=None):
|
def groups_auto_repartition(partition_id=None):
|
||||||
@ -1304,7 +1287,7 @@ def groups_auto_repartition(partition_id=None):
|
|||||||
# except:
|
# except:
|
||||||
# H.append('<p class="warning">Nom de groupe invalide: %s</p>'%group_name)
|
# H.append('<p class="warning">Nom de groupe invalide: %s</p>'%group_name)
|
||||||
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer()
|
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer()
|
||||||
group_ids.append(createGroup(partition_id, group_name))
|
group_ids.append(create_group(partition_id, group_name))
|
||||||
#
|
#
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > identdict
|
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > identdict
|
||||||
identdict = nt.identdict
|
identdict = nt.identdict
|
||||||
@ -1364,6 +1347,7 @@ def create_etapes_partition(formsemestre_id, partition_name="apo_etapes"):
|
|||||||
"""
|
"""
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
|
|
||||||
|
partition_name = str(partition_name)
|
||||||
log("create_etapes_partition(%s)" % formsemestre_id)
|
log("create_etapes_partition(%s)" % formsemestre_id)
|
||||||
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
args={"formsemestre_id": formsemestre_id}
|
args={"formsemestre_id": formsemestre_id}
|
||||||
@ -1388,7 +1372,7 @@ def create_etapes_partition(formsemestre_id, partition_name="apo_etapes"):
|
|||||||
groups_by_names = {g["group_name"]: g for g in groups}
|
groups_by_names = {g["group_name"]: g for g in groups}
|
||||||
for etape in etapes:
|
for etape in etapes:
|
||||||
if not (etape in groups_by_names):
|
if not (etape in groups_by_names):
|
||||||
gid = createGroup(pid, etape)
|
gid = create_group(pid, etape)
|
||||||
g = get_group(gid)
|
g = get_group(gid)
|
||||||
groups_by_names[etape] = g
|
groups_by_names[etape] = g
|
||||||
# Place les etudiants dans les groupes
|
# Place les etudiants dans les groupes
|
||||||
@ -1409,6 +1393,7 @@ def do_evaluation_listeetuds_groups(
|
|||||||
Si include_dems, compte aussi les etudiants démissionnaires
|
Si include_dems, compte aussi les etudiants démissionnaires
|
||||||
(sinon, par défaut, seulement les 'I')
|
(sinon, par défaut, seulement les 'I')
|
||||||
"""
|
"""
|
||||||
|
# nb: pour notes_table / do_evaluation_etat, getallstudents est vrai et include_dems faux
|
||||||
fromtables = [
|
fromtables = [
|
||||||
"notes_moduleimpl_inscription Im",
|
"notes_moduleimpl_inscription Im",
|
||||||
"notes_formsemestre_inscription Isem",
|
"notes_formsemestre_inscription Isem",
|
||||||
@ -1444,10 +1429,9 @@ def do_evaluation_listeetuds_groups(
|
|||||||
req += " and Isem.etat='I'"
|
req += " and Isem.etat='I'"
|
||||||
req += r
|
req += r
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor()
|
||||||
cursor.execute(req, {"evaluation_id": evaluation_id})
|
cursor.execute(req, {"evaluation_id": evaluation_id})
|
||||||
res = cursor.fetchall()
|
return [x[0] for x in cursor]
|
||||||
return [x[0] for x in res]
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_listegroupes(evaluation_id, include_default=False):
|
def do_evaluation_listegroupes(evaluation_id, include_default=False):
|
||||||
@ -1461,7 +1445,7 @@ def do_evaluation_listegroupes(evaluation_id, include_default=False):
|
|||||||
else:
|
else:
|
||||||
c = " AND p.partition_name is not NULL"
|
c = " AND p.partition_name is not NULL"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT DISTINCT gd.id AS group_id
|
"""SELECT DISTINCT gd.id AS group_id
|
||||||
FROM group_descr gd, group_membership gm, partition p,
|
FROM group_descr gd, group_membership gm, partition p,
|
||||||
@ -1475,8 +1459,7 @@ def do_evaluation_listegroupes(evaluation_id, include_default=False):
|
|||||||
+ c,
|
+ c,
|
||||||
{"evaluation_id": evaluation_id},
|
{"evaluation_id": evaluation_id},
|
||||||
)
|
)
|
||||||
res = cursor.fetchall()
|
group_ids = [x[0] for x in cursor]
|
||||||
group_ids = [x[0] for x in res]
|
|
||||||
return listgroups(group_ids)
|
return listgroups(group_ids)
|
||||||
|
|
||||||
|
|
||||||
|
66
app/scodoc/sco_groups_copy.py
Normal file
66
app/scodoc/sco_groups_copy.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
from app import db
|
||||||
|
|
||||||
|
from app.scodoc import sco_groups
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
|
|
||||||
|
|
||||||
|
def clone_partitions_and_groups(
|
||||||
|
orig_formsemestre_id: int, formsemestre_id: int, inscrit_etuds=False
|
||||||
|
):
|
||||||
|
"""Crée dans le semestre formsemestre_id les mêmes partitions et groupes que ceux
|
||||||
|
de orig_formsemestre_id.
|
||||||
|
Si inscrit_etuds, inscrit les mêmes étudiants (rarement souhaité).
|
||||||
|
"""
|
||||||
|
list_groups_per_part = []
|
||||||
|
list_groups = []
|
||||||
|
groups_old2new = {} # old group_id : new_group_id
|
||||||
|
# Création des partitions:
|
||||||
|
for part in sco_groups.get_partitions_list(orig_formsemestre_id):
|
||||||
|
if part["partition_name"] is not None:
|
||||||
|
partname = part["partition_name"]
|
||||||
|
new_partition_id = sco_groups.partition_create(
|
||||||
|
formsemestre_id,
|
||||||
|
partition_name=partname,
|
||||||
|
numero=part["numero"],
|
||||||
|
redirect=False,
|
||||||
|
)
|
||||||
|
for group in sco_groups.get_partition_groups(part):
|
||||||
|
if group["group_name"] != None:
|
||||||
|
list_groups.append(group)
|
||||||
|
list_groups_per_part.append([new_partition_id, list_groups])
|
||||||
|
list_groups = []
|
||||||
|
|
||||||
|
# Création des groupes dans les nouvelles partitions:
|
||||||
|
for newpart in sco_groups.get_partitions_list(formsemestre_id):
|
||||||
|
for (new_partition_id, list_groups) in list_groups_per_part:
|
||||||
|
if newpart["partition_id"] == new_partition_id:
|
||||||
|
for group in list_groups:
|
||||||
|
new_group_id = sco_groups.create_group(
|
||||||
|
new_partition_id, group_name=group["group_name"]
|
||||||
|
)
|
||||||
|
groups_old2new[group["group_id"]] = new_group_id
|
||||||
|
#
|
||||||
|
if inscrit_etuds:
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
cursor = cnx.cursor()
|
||||||
|
for old_group_id, new_group_id in groups_old2new.items():
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
WITH etuds AS (
|
||||||
|
SELECT gm.etudid
|
||||||
|
FROM group_membership gm, notes_formsemestre_inscription ins
|
||||||
|
WHERE ins.etudid = gm.etudid
|
||||||
|
AND ins.formsemestre_id = %(orig_formsemestre_id)s
|
||||||
|
AND gm.group_id=%(old_group_id)s
|
||||||
|
)
|
||||||
|
INSERT INTO group_membership (etudid, group_id)
|
||||||
|
SELECT *, %(new_group_id)s FROM etuds
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"orig_formsemestre_id": orig_formsemestre_id,
|
||||||
|
"old_group_id": old_group_id,
|
||||||
|
"new_group_id": new_group_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
cnx.commit()
|
@ -42,7 +42,7 @@ def affect_groups(partition_id):
|
|||||||
partition = sco_groups.get_partition(partition_id)
|
partition = sco_groups.get_partition(partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
if not sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
|
if not sco_groups.sco_permissions_check.can_change_groups(formsemestre_id):
|
||||||
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
|
raise AccessDenied("vous n'avez pas la permission de modifier les groupes")
|
||||||
return render_template(
|
return render_template(
|
||||||
"scolar/affect_groups.html",
|
"scolar/affect_groups.html",
|
||||||
sco_header=html_sco_header.sco_header(
|
sco_header=html_sco_header.sco_header(
|
||||||
|
@ -304,7 +304,7 @@ class DisplayedGroupsInfos(object):
|
|||||||
else:
|
else:
|
||||||
group_ids = [int(g) for g in group_ids]
|
group_ids = [int(g) for g in group_ids]
|
||||||
if not formsemestre_id and moduleimpl_id:
|
if not formsemestre_id and moduleimpl_id:
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if len(mods) != 1:
|
if len(mods) != 1:
|
||||||
raise ValueError("invalid moduleimpl_id")
|
raise ValueError("invalid moduleimpl_id")
|
||||||
formsemestre_id = mods[0]["formsemestre_id"]
|
formsemestre_id = mods[0]["formsemestre_id"]
|
||||||
@ -777,13 +777,7 @@ def groups_table(
|
|||||||
m["parcours"] = Se.get_parcours_descr()
|
m["parcours"] = Se.get_parcours_descr()
|
||||||
m["codeparcours"], _ = sco_report.get_codeparcoursetud(etud)
|
m["codeparcours"], _ = sco_report.get_codeparcoursetud(etud)
|
||||||
|
|
||||||
def dicttakestr(d, keys):
|
L = [[m.get(k, "") for k in keys] for m in groups_infos.members]
|
||||||
r = []
|
|
||||||
for k in keys:
|
|
||||||
r.append(str(d.get(k, "")))
|
|
||||||
return r
|
|
||||||
|
|
||||||
L = [dicttakestr(m, keys) for m in groups_infos.members]
|
|
||||||
title = "etudiants_%s" % groups_infos.groups_filename
|
title = "etudiants_%s" % groups_infos.groups_filename
|
||||||
xls = sco_excel.excel_simple_table(titles=titles, lines=L, sheet_name=title)
|
xls = sco_excel.excel_simple_table(titles=titles, lines=L, sheet_name=title)
|
||||||
filename = title
|
filename = title
|
||||||
|
@ -27,27 +27,23 @@
|
|||||||
|
|
||||||
"""Import d'utilisateurs via fichier Excel
|
"""Import d'utilisateurs via fichier Excel
|
||||||
"""
|
"""
|
||||||
import random, time
|
import random
|
||||||
import re
|
import time
|
||||||
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.text import MIMEText
|
from flask import g, url_for
|
||||||
from email.header import Header
|
from flask_login import current_user
|
||||||
|
|
||||||
from app import db, Departement
|
from app import db
|
||||||
|
from app import email
|
||||||
|
from app.auth.models import User, UserRole
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoException
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
from app.scodoc import sco_excel
|
from app.scodoc import sco_excel
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_users
|
from app.scodoc import sco_users
|
||||||
|
|
||||||
from flask import g
|
|
||||||
from flask_login import current_user
|
|
||||||
from app.auth.models import User, UserRole
|
|
||||||
|
|
||||||
from app import email
|
|
||||||
|
|
||||||
|
|
||||||
TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")
|
TITLES = ("user_name", "nom", "prenom", "email", "roles", "dept")
|
||||||
COMMENTS = (
|
COMMENTS = (
|
||||||
@ -86,11 +82,11 @@ def generate_excel_sample():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def import_excel_file(datafile):
|
def import_excel_file(datafile, force=""):
|
||||||
"""
|
"""
|
||||||
Import scodoc users from Excel file.
|
Import scodoc users from Excel file.
|
||||||
This method:
|
This method:
|
||||||
* checks that the current_user has the ability to do so (at the moment only a SuperAdmin). He may thereoff import users with any well formed role into any deprtment (or all)
|
* checks that the current_user has the ability to do so (at the moment only a SuperAdmin). He may thereoff import users with any well formed role into any department (or all)
|
||||||
* Once the check is done ans successfull, build the list of users (does not check the data)
|
* Once the check is done ans successfull, build the list of users (does not check the data)
|
||||||
* call :func:`import_users` to actually do the job
|
* call :func:`import_users` to actually do the job
|
||||||
history: scodoc7 with no SuperAdmin every Admin_XXX could import users.
|
history: scodoc7 with no SuperAdmin every Admin_XXX could import users.
|
||||||
@ -98,7 +94,6 @@ def import_excel_file(datafile):
|
|||||||
:return: same as import users
|
:return: same as import users
|
||||||
"""
|
"""
|
||||||
# Check current user privilege
|
# Check current user privilege
|
||||||
auth_dept = current_user.dept
|
|
||||||
auth_name = str(current_user)
|
auth_name = str(current_user)
|
||||||
if not current_user.is_administrator():
|
if not current_user.is_administrator():
|
||||||
raise AccessDenied("invalid user (%s) must be SuperAdmin" % auth_name)
|
raise AccessDenied("invalid user (%s) must be SuperAdmin" % auth_name)
|
||||||
@ -127,7 +122,8 @@ def import_excel_file(datafile):
|
|||||||
del cols[tit]
|
del cols[tit]
|
||||||
if cols or unknown:
|
if cols or unknown:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"colonnes incorrectes (on attend %d, et non %d) <br/> (colonnes manquantes: %s, colonnes invalides: %s)"
|
"""colonnes incorrectes (on attend %d, et non %d) <br/>
|
||||||
|
(colonnes manquantes: %s, colonnes invalides: %s)"""
|
||||||
% (len(TITLES), len(fs), list(cols.keys()), unknown)
|
% (len(TITLES), len(fs), list(cols.keys()), unknown)
|
||||||
)
|
)
|
||||||
# ok, same titles... : build the list of dictionaries
|
# ok, same titles... : build the list of dictionaries
|
||||||
@ -138,10 +134,10 @@ def import_excel_file(datafile):
|
|||||||
d[fs[i]] = line[i]
|
d[fs[i]] = line[i]
|
||||||
users.append(d)
|
users.append(d)
|
||||||
|
|
||||||
return import_users(users)
|
return import_users(users=users, force=force)
|
||||||
|
|
||||||
|
|
||||||
def import_users(users):
|
def import_users(users, force=""):
|
||||||
"""
|
"""
|
||||||
Import users from a list of users_descriptors.
|
Import users from a list of users_descriptors.
|
||||||
|
|
||||||
@ -182,19 +178,17 @@ def import_users(users):
|
|||||||
line = line + 1
|
line = line + 1
|
||||||
user_ok, msg = sco_users.check_modif_user(
|
user_ok, msg = sco_users.check_modif_user(
|
||||||
0,
|
0,
|
||||||
ignore_optionals=False,
|
enforce_optionals=not force,
|
||||||
user_name=u["user_name"],
|
user_name=u["user_name"],
|
||||||
nom=u["nom"],
|
nom=u["nom"],
|
||||||
prenom=u["prenom"],
|
prenom=u["prenom"],
|
||||||
email=u["email"],
|
email=u["email"],
|
||||||
roles=u["roles"].split(","),
|
roles=[r for r in u["roles"].split(",") if r],
|
||||||
dept=u["dept"],
|
dept=u["dept"],
|
||||||
)
|
)
|
||||||
if not user_ok:
|
if not user_ok:
|
||||||
append_msg("identifiant '%s' %s" % (u["user_name"], msg))
|
append_msg("identifiant '%s' %s" % (u["user_name"], msg))
|
||||||
# raise ScoValueError(
|
|
||||||
# "données invalides pour %s: %s" % (u["user_name"], msg)
|
|
||||||
# )
|
|
||||||
u["passwd"] = generate_password()
|
u["passwd"] = generate_password()
|
||||||
#
|
#
|
||||||
# check identifiant
|
# check identifiant
|
||||||
@ -224,7 +218,7 @@ def import_users(users):
|
|||||||
import_ok = False
|
import_ok = False
|
||||||
except ScoValueError as value_error:
|
except ScoValueError as value_error:
|
||||||
log("import_users: exception: abort create %s" % str(created.keys()))
|
log("import_users: exception: abort create %s" % str(created.keys()))
|
||||||
raise ScoValueError(msg) # re-raise exception
|
raise ScoValueError(msg) from value_error
|
||||||
if import_ok:
|
if import_ok:
|
||||||
for u in created.values():
|
for u in created.values():
|
||||||
# Création de l'utilisateur (via SQLAlchemy)
|
# Création de l'utilisateur (via SQLAlchemy)
|
||||||
@ -244,7 +238,7 @@ def import_users(users):
|
|||||||
|
|
||||||
|
|
||||||
ALPHABET = r"""ABCDEFGHIJKLMNPQRSTUVWXYZ123456789123456789AEIOU"""
|
ALPHABET = r"""ABCDEFGHIJKLMNPQRSTUVWXYZ123456789123456789AEIOU"""
|
||||||
PASSLEN = 6
|
PASSLEN = 8
|
||||||
RNG = random.Random(time.time())
|
RNG = random.Random(time.time())
|
||||||
|
|
||||||
|
|
||||||
@ -259,23 +253,18 @@ def generate_password():
|
|||||||
return "".join(RNG.sample(l, PASSLEN))
|
return "".join(RNG.sample(l, PASSLEN))
|
||||||
|
|
||||||
|
|
||||||
def mail_password(u, context=None, reset=False):
|
def mail_password(user: dict, reset=False) -> None:
|
||||||
"Send password by email"
|
"Send password by email"
|
||||||
if not u["email"]:
|
if not user["email"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
u[
|
user["url"] = url_for("scodoc.index", _external=True)
|
||||||
"url"
|
|
||||||
] = (
|
|
||||||
scu.ScoURL()
|
|
||||||
) # TODO set auth page URL ? (shared by all departments) ../auth/login
|
|
||||||
|
|
||||||
txt = (
|
txt = (
|
||||||
"""
|
"""
|
||||||
Bonjour %(prenom)s %(nom)s,
|
Bonjour %(prenom)s %(nom)s,
|
||||||
|
|
||||||
"""
|
"""
|
||||||
% u
|
% user
|
||||||
)
|
)
|
||||||
if reset:
|
if reset:
|
||||||
txt += (
|
txt += (
|
||||||
@ -288,7 +277,7 @@ Votre nom d'utilisateur est %(user_name)s
|
|||||||
Vous devrez changer ce mot de passe lors de votre première connexion
|
Vous devrez changer ce mot de passe lors de votre première connexion
|
||||||
sur %(url)s
|
sur %(url)s
|
||||||
"""
|
"""
|
||||||
% u
|
% user
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
txt += (
|
txt += (
|
||||||
@ -300,16 +289,15 @@ Votre mot de passe est: %(passwd)s
|
|||||||
|
|
||||||
Le logiciel est accessible sur: %(url)s
|
Le logiciel est accessible sur: %(url)s
|
||||||
|
|
||||||
Vous êtes invité à changer ce mot de passe au plus vite (cliquez sur
|
Vous êtes invité à changer ce mot de passe au plus vite (cliquez sur votre nom en haut à gauche de la page d'accueil).
|
||||||
votre nom en haut à gauche de la page d'accueil).
|
|
||||||
"""
|
"""
|
||||||
% u
|
% user
|
||||||
)
|
)
|
||||||
|
|
||||||
txt += (
|
txt += (
|
||||||
"""
|
"""
|
||||||
|
_______
|
||||||
ScoDoc est un logiciel libre développé à l'Université Paris 13 par Emmanuel Viennet.
|
ScoDoc est un logiciel libre développé par Emmanuel Viennet et l'association ScoDoc.
|
||||||
Pour plus d'informations sur ce logiciel, voir %s
|
Pour plus d'informations sur ce logiciel, voir %s
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -321,4 +309,4 @@ Pour plus d'informations sur ce logiciel, voir %s
|
|||||||
else:
|
else:
|
||||||
subject = "Votre accès ScoDoc"
|
subject = "Votre accès ScoDoc"
|
||||||
sender = sco_preferences.get_preference("email_from_addr")
|
sender = sco_preferences.get_preference("email_from_addr")
|
||||||
email.send_email(subject, sender, [u["email"]], txt)
|
email.send_email(subject, sender, [user["email"]], txt)
|
||||||
|
@ -228,8 +228,8 @@ def _make_table_notes(
|
|||||||
return "<p>Aucune évaluation !</p>"
|
return "<p>Aucune évaluation !</p>"
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
moduleimpl_id = E["moduleimpl_id"]
|
moduleimpl_id = E["moduleimpl_id"]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
# (debug) check that all evals are in same module:
|
# (debug) check that all evals are in same module:
|
||||||
for e in evals:
|
for e in evals:
|
||||||
@ -872,9 +872,7 @@ def formsemestre_check_absences_html(formsemestre_id):
|
|||||||
</p>""",
|
</p>""",
|
||||||
]
|
]
|
||||||
# Modules, dans l'ordre
|
# Modules, dans l'ordre
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
evals = sco_evaluations.do_evaluation_list(
|
evals = sco_evaluations.do_evaluation_list(
|
||||||
{"moduleimpl_id": M["moduleimpl_id"]}
|
{"moduleimpl_id": M["moduleimpl_id"]}
|
||||||
|
@ -100,7 +100,7 @@ def do_moduleimpl_delete(oid, formsemestre_id=None):
|
|||||||
) # > moduleimpl_delete
|
) # > moduleimpl_delete
|
||||||
|
|
||||||
|
|
||||||
def do_moduleimpl_list(moduleimpl_id=None, formsemestre_id=None, module_id=None):
|
def moduleimpl_list(moduleimpl_id=None, formsemestre_id=None, module_id=None):
|
||||||
"list moduleimpls"
|
"list moduleimpls"
|
||||||
args = locals()
|
args = locals()
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
@ -122,10 +122,11 @@ def do_moduleimpl_edit(args, formsemestre_id=None, cnx=None):
|
|||||||
) # > modif moduleimpl
|
) # > modif moduleimpl
|
||||||
|
|
||||||
|
|
||||||
def do_moduleimpl_withmodule_list(
|
def moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=None, formsemestre_id=None, module_id=None
|
moduleimpl_id=None, formsemestre_id=None, module_id=None
|
||||||
):
|
):
|
||||||
"""Liste les moduleimpls et ajoute dans chacun le module correspondant
|
"""Liste les moduleimpls et ajoute dans chacun
|
||||||
|
l'UE, la matière et le module auxquels ils appartiennent.
|
||||||
Tri la liste par semestre/UE/numero_matiere/numero_module.
|
Tri la liste par semestre/UE/numero_matiere/numero_module.
|
||||||
|
|
||||||
Attention: Cette fonction fait partie de l'API ScoDoc 7 et est publiée.
|
Attention: Cette fonction fait partie de l'API ScoDoc 7 et est publiée.
|
||||||
@ -134,22 +135,33 @@ def do_moduleimpl_withmodule_list(
|
|||||||
from app.scodoc import sco_edit_matiere
|
from app.scodoc import sco_edit_matiere
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
|
|
||||||
args = locals()
|
modimpls = moduleimpl_list(
|
||||||
modimpls = do_moduleimpl_list(
|
|
||||||
**{
|
**{
|
||||||
"moduleimpl_id": moduleimpl_id,
|
"moduleimpl_id": moduleimpl_id,
|
||||||
"formsemestre_id": formsemestre_id,
|
"formsemestre_id": formsemestre_id,
|
||||||
"module_id": module_id,
|
"module_id": module_id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
for mo in modimpls:
|
ues = {}
|
||||||
mo["module"] = sco_edit_module.do_module_list(
|
matieres = {}
|
||||||
args={"module_id": mo["module_id"]}
|
modules = {}
|
||||||
|
for mi in modimpls:
|
||||||
|
module_id = mi["module_id"]
|
||||||
|
if not mi["module_id"] in modules:
|
||||||
|
modules[module_id] = sco_edit_module.module_list(
|
||||||
|
args={"module_id": module_id}
|
||||||
)[0]
|
)[0]
|
||||||
mo["ue"] = sco_edit_ue.do_ue_list(args={"ue_id": mo["module"]["ue_id"]})[0]
|
mi["module"] = modules[module_id]
|
||||||
mo["matiere"] = sco_edit_matiere.do_matiere_list(
|
ue_id = mi["module"]["ue_id"]
|
||||||
args={"matiere_id": mo["module"]["matiere_id"]}
|
if not ue_id in ues:
|
||||||
|
ues[ue_id] = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||||
|
mi["ue"] = ues[ue_id]
|
||||||
|
matiere_id = mi["module"]["matiere_id"]
|
||||||
|
if not matiere_id in matieres:
|
||||||
|
matieres[matiere_id] = sco_edit_matiere.matiere_list(
|
||||||
|
args={"matiere_id": matiere_id}
|
||||||
)[0]
|
)[0]
|
||||||
|
mi["matiere"] = matieres[matiere_id]
|
||||||
|
|
||||||
# tri par semestre/UE/numero_matiere/numero_module
|
# tri par semestre/UE/numero_matiere/numero_module
|
||||||
modimpls.sort(
|
modimpls.sort(
|
||||||
@ -173,7 +185,7 @@ def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
|
|||||||
return _moduleimpl_inscriptionEditor.list(cnx, args)
|
return _moduleimpl_inscriptionEditor.list(cnx, args)
|
||||||
|
|
||||||
|
|
||||||
def do_moduleimpl_listeetuds(moduleimpl_id):
|
def moduleimpl_listeetuds(moduleimpl_id):
|
||||||
"retourne liste des etudids inscrits a ce module"
|
"retourne liste des etudids inscrits a ce module"
|
||||||
req = """SELECT DISTINCT Im.etudid
|
req = """SELECT DISTINCT Im.etudid
|
||||||
FROM notes_moduleimpl_inscription Im,
|
FROM notes_moduleimpl_inscription Im,
|
||||||
@ -306,7 +318,7 @@ def can_change_module_resp(moduleimpl_id):
|
|||||||
"""Check if current user can modify module resp. (raise exception if not).
|
"""Check if current user can modify module resp. (raise exception if not).
|
||||||
= Admin, et dir des etud. (si option l'y autorise)
|
= Admin, et dir des etud. (si option l'y autorise)
|
||||||
"""
|
"""
|
||||||
M = do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
# -- check lock
|
# -- check lock
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
if not sem["etat"]:
|
if not sem["etat"]:
|
||||||
@ -322,7 +334,7 @@ def can_change_module_resp(moduleimpl_id):
|
|||||||
|
|
||||||
def can_change_ens(moduleimpl_id, raise_exc=True):
|
def can_change_ens(moduleimpl_id, raise_exc=True):
|
||||||
"check if current user can modify ens list (raise exception if not)"
|
"check if current user can modify ens list (raise exception if not)"
|
||||||
M = do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
# -- check lock
|
# -- check lock
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
if not sem["etat"]:
|
if not sem["etat"]:
|
||||||
|
@ -63,9 +63,9 @@ def moduleimpl_inscriptions_edit(moduleimpl_id, etuds=[], submitted=False):
|
|||||||
|
|
||||||
* Si pas les droits: idem en readonly
|
* Si pas les droits: idem en readonly
|
||||||
"""
|
"""
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
# -- check lock
|
# -- check lock
|
||||||
if not sem["etat"]:
|
if not sem["etat"]:
|
||||||
@ -263,9 +263,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
|||||||
can_change = authuser.has_permission(Permission.ScoEtudInscrit) and sem["etat"]
|
can_change = authuser.has_permission(Permission.ScoEtudInscrit) and sem["etat"]
|
||||||
|
|
||||||
# Liste des modules
|
# Liste des modules
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
# Decrit les inscriptions aux modules:
|
# Decrit les inscriptions aux modules:
|
||||||
commons = [] # modules communs a tous les etuds du semestre
|
commons = [] # modules communs a tous les etuds du semestre
|
||||||
options = [] # modules ou seuls quelques etudiants sont inscrits
|
options = [] # modules ou seuls quelques etudiants sont inscrits
|
||||||
@ -341,7 +339,7 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
|||||||
UECaps = get_etuds_with_capitalized_ue(formsemestre_id)
|
UECaps = get_etuds_with_capitalized_ue(formsemestre_id)
|
||||||
if UECaps:
|
if UECaps:
|
||||||
H.append('<h3>Etudiants avec UEs capitalisées:</h3><ul class="ue_inscr_list">')
|
H.append('<h3>Etudiants avec UEs capitalisées:</h3><ul class="ue_inscr_list">')
|
||||||
ues = [sco_edit_ue.do_ue_list({"ue_id": ue_id})[0] for ue_id in UECaps.keys()]
|
ues = [sco_edit_ue.ue_list({"ue_id": ue_id})[0] for ue_id in UECaps.keys()]
|
||||||
ues.sort(key=lambda u: u["numero"])
|
ues.sort(key=lambda u: u["numero"])
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -58,7 +58,7 @@ from app.scodoc import sco_users
|
|||||||
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
|
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
|
||||||
"Menu avec actions sur une evaluation"
|
"Menu avec actions sur une evaluation"
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
modimpl = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
||||||
|
|
||||||
@ -156,9 +156,9 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
|
|||||||
|
|
||||||
def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
||||||
"""Tableau de bord module (liste des evaluations etc)"""
|
"""Tableau de bord module (liste des evaluations etc)"""
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
@ -176,7 +176,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
current_user, moduleimpl_id, allow_ens=sem["ens_can_edit_eval"]
|
current_user, moduleimpl_id, allow_ens=sem["ens_can_edit_eval"]
|
||||||
)
|
)
|
||||||
caneditnotes = sco_permissions_check.can_edit_notes(current_user, moduleimpl_id)
|
caneditnotes = sco_permissions_check.can_edit_notes(current_user, moduleimpl_id)
|
||||||
arrow_up, arrow_down, arrow_none = sco_groups.getArrowIconsTags()
|
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
|
||||||
#
|
#
|
||||||
module_resp = User.query.get(M["responsable_id"])
|
module_resp = User.query.get(M["responsable_id"])
|
||||||
H = [
|
H = [
|
||||||
|
@ -174,7 +174,7 @@ def _get_formsemestre_infos_from_news(n):
|
|||||||
elif n["type"] == NEWS_NOTE:
|
elif n["type"] == NEWS_NOTE:
|
||||||
moduleimpl_id = n["object"]
|
moduleimpl_id = n["object"]
|
||||||
if n["object"]:
|
if n["object"]:
|
||||||
mods = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)
|
||||||
if not mods:
|
if not mods:
|
||||||
return {} # module does not exists anymore
|
return {} # module does not exists anymore
|
||||||
return {} # pas d'indication du module
|
return {} # pas d'indication du module
|
||||||
|
@ -350,7 +350,6 @@ def pdf_basic_page(
|
|||||||
|
|
||||||
|
|
||||||
# Gestion du lock pdf
|
# Gestion du lock pdf
|
||||||
import threading, time, six.moves.queue, six.moves._thread
|
|
||||||
|
|
||||||
|
|
||||||
class PDFLock(object):
|
class PDFLock(object):
|
||||||
|
@ -26,7 +26,7 @@ def can_edit_notes(authuser, moduleimpl_id, allow_ens=True):
|
|||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
|
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
if not sem["etat"]:
|
if not sem["etat"]:
|
||||||
return False # semestre verrouillé
|
return False # semestre verrouillé
|
||||||
@ -64,7 +64,7 @@ def can_edit_evaluation(moduleimpl_id=None):
|
|||||||
# acces pour resp. moduleimpl et resp. form semestre (dir etud)
|
# acces pour resp. moduleimpl et resp. form semestre (dir etud)
|
||||||
if moduleimpl_id is None:
|
if moduleimpl_id is None:
|
||||||
raise ValueError("no moduleimpl specified") # bug
|
raise ValueError("no moduleimpl specified") # bug
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -244,10 +244,10 @@ class PlacementRunner:
|
|||||||
# gr_title = sco_groups.listgroups_abbrev(d['groups'])
|
# gr_title = sco_groups.listgroups_abbrev(d['groups'])
|
||||||
self.current_user = current_user
|
self.current_user = current_user
|
||||||
self.moduleimpl_id = self.eval_data["moduleimpl_id"]
|
self.moduleimpl_id = self.eval_data["moduleimpl_id"]
|
||||||
self.moduleimpl_data = sco_moduleimpl.do_moduleimpl_list(
|
self.moduleimpl_data = sco_moduleimpl.moduleimpl_list(
|
||||||
moduleimpl_id=self.moduleimpl_id
|
moduleimpl_id=self.moduleimpl_id
|
||||||
)[0]
|
)[0]
|
||||||
self.module_data = sco_edit_module.do_module_list(
|
self.module_data = sco_edit_module.module_list(
|
||||||
args={"module_id": self.moduleimpl_data["module_id"]}
|
args={"module_id": self.moduleimpl_data["module_id"]}
|
||||||
)[0]
|
)[0]
|
||||||
self.sem = sco_formsemestre.get_formsemestre(
|
self.sem = sco_formsemestre.get_formsemestre(
|
||||||
|
@ -39,7 +39,6 @@ import app.scodoc.sco_utils as scu
|
|||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
import six
|
|
||||||
|
|
||||||
SCO_CACHE_ETAPE_FILENAME = os.path.join(scu.SCO_TMP_DIR, "last_etapes.xml")
|
SCO_CACHE_ETAPE_FILENAME = os.path.join(scu.SCO_TMP_DIR, "last_etapes.xml")
|
||||||
|
|
||||||
@ -386,7 +385,8 @@ def get_etapes_apogee():
|
|||||||
# cache le resultat (utile si le portail repond de façon intermitente)
|
# cache le resultat (utile si le portail repond de façon intermitente)
|
||||||
if infos:
|
if infos:
|
||||||
log("get_etapes_apogee: caching result")
|
log("get_etapes_apogee: caching result")
|
||||||
open(SCO_CACHE_ETAPE_FILENAME, "w").write(doc)
|
with open(SCO_CACHE_ETAPE_FILENAME, "w") as f:
|
||||||
|
f.write(doc)
|
||||||
except:
|
except:
|
||||||
log("invalid XML response from getEtapes Web Service\n%s" % etapes_url)
|
log("invalid XML response from getEtapes Web Service\n%s" % etapes_url)
|
||||||
# Avons nous la copie d'une réponse récente ?
|
# Avons nous la copie d'une réponse récente ?
|
||||||
|
@ -92,7 +92,7 @@ def _descr_decisions_ues(nt, etudid, decisions_ue, decision_sem):
|
|||||||
and sco_codes_parcours.code_semestre_validant(decision_sem["code"])
|
and sco_codes_parcours.code_semestre_validant(decision_sem["code"])
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
ue = sco_edit_ue.do_ue_list(args={"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||||
uelist.append(ue)
|
uelist.append(ue)
|
||||||
except:
|
except:
|
||||||
log("descr_decisions_ues: ue_id=%s decisions_ue=%s" % (ue_id, decisions_ue))
|
log("descr_decisions_ues: ue_id=%s decisions_ue=%s" % (ue_id, decisions_ue))
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
@ -1399,7 +1398,8 @@ def graph_parcours(
|
|||||||
# Genere graphe
|
# Genere graphe
|
||||||
_, path = tempfile.mkstemp(".gr")
|
_, path = tempfile.mkstemp(".gr")
|
||||||
g.write(path=path, format=format)
|
g.write(path=path, format=format)
|
||||||
data = open(path, "rb").read()
|
with open(path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
log("dot generated %d bytes in %s format" % (len(data), format))
|
log("dot generated %d bytes in %s format" % (len(data), format))
|
||||||
if not data:
|
if not data:
|
||||||
log("graph.to_string=%s" % g.to_string())
|
log("graph.to_string=%s" % g.to_string())
|
||||||
|
@ -45,6 +45,7 @@ from app.scodoc.sco_exceptions import (
|
|||||||
AccessDenied,
|
AccessDenied,
|
||||||
InvalidNoteValue,
|
InvalidNoteValue,
|
||||||
NoteProcessError,
|
NoteProcessError,
|
||||||
|
ScoGenError,
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
)
|
)
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
@ -72,13 +73,16 @@ def convert_note_from_string(
|
|||||||
note_max,
|
note_max,
|
||||||
note_min=scu.NOTES_MIN,
|
note_min=scu.NOTES_MIN,
|
||||||
etudid=None,
|
etudid=None,
|
||||||
absents=[],
|
absents=None,
|
||||||
tosuppress=[],
|
tosuppress=None,
|
||||||
invalids=[],
|
invalids=None,
|
||||||
):
|
):
|
||||||
"""converti une valeur (chaine saisie) vers une note numérique (float)
|
"""converti une valeur (chaine saisie) vers une note numérique (float)
|
||||||
Les listes absents, tosuppress et invalids sont modifiées
|
Les listes absents, tosuppress et invalids sont modifiées
|
||||||
"""
|
"""
|
||||||
|
absents = absents or []
|
||||||
|
tosuppress = tosuppress or []
|
||||||
|
invalids = invalids or []
|
||||||
invalid = False
|
invalid = False
|
||||||
note_value = None
|
note_value = None
|
||||||
note = note.replace(",", ".")
|
note = note.replace(",", ".")
|
||||||
@ -173,13 +177,10 @@ def do_evaluation_upload_xls():
|
|||||||
evaluation_id = int(vals["evaluation_id"])
|
evaluation_id = int(vals["evaluation_id"])
|
||||||
comment = vals["comment"]
|
comment = vals["comment"]
|
||||||
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_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
0
|
|
||||||
]
|
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and 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"]):
|
||||||
# XXX imaginer un redirect + msg erreur
|
|
||||||
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
raise AccessDenied("Modification des notes impossible pour %s" % authuser)
|
||||||
#
|
#
|
||||||
diag, lines = sco_excel.excel_file_to_list(vals["notefile"])
|
diag, lines = sco_excel.excel_file_to_list(vals["notefile"])
|
||||||
@ -250,8 +251,8 @@ def do_evaluation_upload_xls():
|
|||||||
)
|
)
|
||||||
# news
|
# news
|
||||||
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.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
mod["url"] = url_for(
|
mod["url"] = url_for(
|
||||||
"notes.moduleimpl_status",
|
"notes.moduleimpl_status",
|
||||||
@ -289,9 +290,7 @@ def do_evaluation_upload_xls():
|
|||||||
def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
||||||
"""Initialisation des notes manquantes"""
|
"""Initialisation des notes manquantes"""
|
||||||
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_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
0
|
|
||||||
]
|
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and responsable_id)
|
||||||
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
||||||
@ -337,8 +336,8 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
|||||||
comment = "Initialisation notes manquantes"
|
comment = "Initialisation notes manquantes"
|
||||||
nb_changed, _, _ = _notes_add(current_user, evaluation_id, L, comment)
|
nb_changed, _, _ = _notes_add(current_user, evaluation_id, L, comment)
|
||||||
# news
|
# news
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
mod["url"] = url_for(
|
mod["url"] = url_for(
|
||||||
"notes.moduleimpl_status",
|
"notes.moduleimpl_status",
|
||||||
@ -426,8 +425,8 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
|||||||
% E["moduleimpl_id"]
|
% E["moduleimpl_id"]
|
||||||
]
|
]
|
||||||
# news
|
# news
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.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.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"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
@ -473,7 +472,7 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
|||||||
nb_changed = 0
|
nb_changed = 0
|
||||||
nb_suppress = 0
|
nb_suppress = 0
|
||||||
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.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
existing_decisions = (
|
existing_decisions = (
|
||||||
[]
|
[]
|
||||||
) # etudids pour lesquels il y a une decision de jury et que la note change
|
) # etudids pour lesquels il y a une decision de jury et que la note change
|
||||||
@ -573,12 +572,13 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
|||||||
except:
|
except:
|
||||||
log("*** exception in _notes_add")
|
log("*** exception in _notes_add")
|
||||||
if do_it:
|
if do_it:
|
||||||
|
cnx.rollback() # abort
|
||||||
# inval cache
|
# inval cache
|
||||||
sco_cache.invalidate_formsemestre(
|
sco_cache.invalidate_formsemestre(
|
||||||
formsemestre_id=M["formsemestre_id"]
|
formsemestre_id=M["formsemestre_id"]
|
||||||
) # > modif notes (exception)
|
) # > modif notes (exception)
|
||||||
cnx.rollback() # abort
|
sco_cache.EvaluationCache.delete(evaluation_id)
|
||||||
raise # re-raise exception
|
raise ScoGenError("Erreur enregistrement note: merci de ré-essayer")
|
||||||
if do_it:
|
if do_it:
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
sco_cache.invalidate_formsemestre(
|
sco_cache.invalidate_formsemestre(
|
||||||
@ -588,13 +588,13 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
|||||||
return nb_changed, nb_suppress, existing_decisions
|
return nb_changed, nb_suppress, existing_decisions
|
||||||
|
|
||||||
|
|
||||||
def saisie_notes_tableur(evaluation_id, group_ids=[]):
|
def saisie_notes_tableur(evaluation_id, group_ids=()):
|
||||||
"""Saisie des notes via un fichier Excel"""
|
"""Saisie des notes via un fichier Excel"""
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
if not sco_permissions_check.can_edit_notes(current_user, E["moduleimpl_id"]):
|
||||||
return (
|
return (
|
||||||
@ -765,9 +765,9 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]):
|
|||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
mod_responsable = sco_users.user_info(M["responsable_id"])
|
mod_responsable = sco_users.user_info(M["responsable_id"])
|
||||||
if E["jour"]:
|
if E["jour"]:
|
||||||
@ -845,7 +845,7 @@ def has_existing_decision(M, E, etudid):
|
|||||||
return True
|
return True
|
||||||
dec_ues = nt.get_etud_decision_ues(etudid)
|
dec_ues = nt.get_etud_decision_ues(etudid)
|
||||||
if dec_ues:
|
if dec_ues:
|
||||||
mod = sco_edit_module.do_module_list({"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.module_list({"module_id": M["module_id"]})[0]
|
||||||
ue_id = mod["ue_id"]
|
ue_id = mod["ue_id"]
|
||||||
if ue_id in dec_ues:
|
if ue_id in dec_ues:
|
||||||
return True # decision pour l'UE a laquelle appartient cette evaluation
|
return True # decision pour l'UE a laquelle appartient cette evaluation
|
||||||
@ -864,9 +864,7 @@ def saisie_notes(evaluation_id, group_ids=[]):
|
|||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
0
|
|
||||||
]
|
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and responsable_id)
|
||||||
@ -1226,8 +1224,8 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment=""):
|
|||||||
% (evaluation_id, etudid, authuser, value)
|
% (evaluation_id, etudid, authuser, value)
|
||||||
)
|
)
|
||||||
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.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
Mod["url"] = url_for(
|
Mod["url"] = url_for(
|
||||||
"notes.moduleimpl_status",
|
"notes.moduleimpl_status",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
@ -242,7 +242,7 @@ def module_tag_set(module_id="", taglist=None):
|
|||||||
taglist = [t.strip() for t in taglist]
|
taglist = [t.strip() for t in taglist]
|
||||||
# log("module_tag_set: module_id=%s taglist=%s" % (module_id, taglist))
|
# log("module_tag_set: module_id=%s taglist=%s" % (module_id, taglist))
|
||||||
# Sanity check:
|
# Sanity check:
|
||||||
Mod = sco_edit_module.do_module_list(args={"module_id": module_id})
|
Mod = sco_edit_module.module_list(args={"module_id": module_id})
|
||||||
if not Mod:
|
if not Mod:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
|
|
||||||
|
@ -174,9 +174,7 @@ def external_ue_inscrit_et_note(moduleimpl_id, formsemestre_id, notes_etuds):
|
|||||||
|
|
||||||
def get_existing_external_ue(formation_id):
|
def get_existing_external_ue(formation_id):
|
||||||
"la liste de toutes les UE externes définies dans cette formation"
|
"la liste de toutes les UE externes définies dans cette formation"
|
||||||
return sco_edit_ue.do_ue_list(
|
return sco_edit_ue.ue_list(args={"formation_id": formation_id, "is_external": True})
|
||||||
args={"formation_id": formation_id, "is_external": True}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_external_moduleimpl_id(formsemestre_id, ue_id):
|
def get_external_moduleimpl_id(formsemestre_id, ue_id):
|
||||||
|
@ -149,7 +149,7 @@ def list_operations(evaluation_id):
|
|||||||
def evaluation_list_operations(evaluation_id):
|
def evaluation_list_operations(evaluation_id):
|
||||||
"""Page listing operations on evaluation"""
|
"""Page listing operations on evaluation"""
|
||||||
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.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
Ops = list_operations(evaluation_id)
|
Ops = list_operations(evaluation_id)
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
from flask.templating import render_template
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import cracklib # pylint: disable=import-error
|
|
||||||
|
|
||||||
from app import db, Departement
|
from app import db, Departement
|
||||||
|
|
||||||
@ -56,23 +56,6 @@ from app.scodoc.sco_exceptions import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_valid_password(cleartxt):
|
|
||||||
"""Check password.
|
|
||||||
returns True if OK.
|
|
||||||
"""
|
|
||||||
if (
|
|
||||||
hasattr(scu.CONFIG, "MIN_PASSWORD_LENGTH")
|
|
||||||
and scu.CONFIG.MIN_PASSWORD_LENGTH > 0
|
|
||||||
and len(cleartxt) < scu.CONFIG.MIN_PASSWORD_LENGTH
|
|
||||||
):
|
|
||||||
return False # invalid: too short
|
|
||||||
try:
|
|
||||||
_ = cracklib.FascistCheck(cleartxt)
|
|
||||||
return True
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
@ -289,105 +272,9 @@ def user_info(user_name_or_id=None, user=None):
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def user_info_page(user_name=None):
|
|
||||||
"""Display page of info about given user.
|
|
||||||
If user_name not specified, user current_user
|
|
||||||
"""
|
|
||||||
from app.scodoc.sco_permissions_check import can_handle_passwd
|
|
||||||
|
|
||||||
# peut on divulguer ces infos ?
|
|
||||||
if not can_handle_passwd(current_user, allow_admindepts=True):
|
|
||||||
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
|
|
||||||
|
|
||||||
dept = g.scodoc_dept
|
|
||||||
if not user_name:
|
|
||||||
user = current_user
|
|
||||||
else:
|
|
||||||
user = User.query.filter_by(user_name=user_name).first()
|
|
||||||
if not user:
|
|
||||||
raise ScoValueError("invalid user_name")
|
|
||||||
H = [
|
|
||||||
html_sco_header.sco_header(
|
|
||||||
page_title="Utilisateur %s" % user.user_name,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
F = html_sco_header.sco_footer()
|
|
||||||
H.append("<h2>Utilisateur: %s" % user.user_name)
|
|
||||||
info = user.to_dict()
|
|
||||||
if info:
|
|
||||||
H.append(" (%(status_txt)s)" % info)
|
|
||||||
H.append("</h2>")
|
|
||||||
if not info:
|
|
||||||
H.append(
|
|
||||||
"<p>L' utilisateur '%s' n'est pas défini dans ce module.</p>" % user_name
|
|
||||||
)
|
|
||||||
if user.has_permission(Permission.ScoEditAllNotes, dept):
|
|
||||||
H.append("<p>(il peut modifier toutes les notes de %s)</p>" % dept)
|
|
||||||
if user.has_permission(Permission.ScoEditAllEvals, dept):
|
|
||||||
H.append("<p>(il peut modifier toutes les évaluations de %s)</p>" % dept)
|
|
||||||
if user.has_permission(Permission.ScoImplement, dept):
|
|
||||||
H.append("<p>(il peut creer des formations en %s)</p>" % dept)
|
|
||||||
else:
|
|
||||||
H.append(
|
|
||||||
"""<p>
|
|
||||||
<b>Login :</b> %(user_name)s<br/>
|
|
||||||
<b>Nom :</b> %(nom)s<br/>
|
|
||||||
<b>Prénom :</b> %(prenom)s<br/>
|
|
||||||
<b>Mail :</b> %(email)s<br/>
|
|
||||||
<b>Roles :</b> %(roles_string)s<br/>
|
|
||||||
<b>Dept :</b> %(dept)s<br/>
|
|
||||||
<b>Dernière modif mot de passe:</b> %(date_modif_passwd)s<br/>
|
|
||||||
<b>Date d'expiration:</b> %(date_expiration)s
|
|
||||||
<p><ul>
|
|
||||||
<li><a class="stdlink" href="form_change_password?user_name=%(user_name)s">changer le mot de passe</a></li>"""
|
|
||||||
% info
|
|
||||||
)
|
|
||||||
if current_user.has_permission(Permission.ScoUsersAdmin, dept):
|
|
||||||
H.append(
|
|
||||||
f"""
|
|
||||||
<li><a class="stdlink" href="{url_for('users.create_user_form', scodoc_dept=g.scodoc_dept,
|
|
||||||
user_name=user.user_name, edit=1)}">modifier ce compte</a>
|
|
||||||
</li>
|
|
||||||
<li><a class="stdlink" href="{url_for('users.toggle_active_user', scodoc_dept=g.scodoc_dept,
|
|
||||||
user_name=user.user_name)
|
|
||||||
}">{"désactiver" if user.active else "activer"} ce compte</a>
|
|
||||||
</li>
|
|
||||||
"""
|
|
||||||
% info
|
|
||||||
)
|
|
||||||
|
|
||||||
H.append("</ul>")
|
|
||||||
|
|
||||||
if current_user.user_name == user_name:
|
|
||||||
H.append(
|
|
||||||
'<p><b>Se déconnecter: <a class="stdlink" href="%s">logout</a></b></p>'
|
|
||||||
% url_for("auth.logout")
|
|
||||||
)
|
|
||||||
# Liste des permissions
|
|
||||||
H.append(
|
|
||||||
'<div class="permissions"><p>Permissions de cet utilisateur dans le département %s:</p><ul>'
|
|
||||||
% dept
|
|
||||||
)
|
|
||||||
for p in Permission.description:
|
|
||||||
perm = getattr(Permission, p)
|
|
||||||
if user.has_permission(perm, dept):
|
|
||||||
b = "oui"
|
|
||||||
else:
|
|
||||||
b = "non"
|
|
||||||
H.append("<li>%s : %s</li>" % (Permission.description[p], b))
|
|
||||||
H.append("</ul></div>")
|
|
||||||
|
|
||||||
if current_user.has_permission(Permission.ScoUsersAdmin, dept):
|
|
||||||
H.append(
|
|
||||||
'<p><a class="stdlink" href="%s">Liste de tous les utilisateurs</a></p>'
|
|
||||||
% url_for("users.index_html", scodoc_dept=g.scodoc_dept)
|
|
||||||
)
|
|
||||||
return "\n".join(H) + F
|
|
||||||
|
|
||||||
|
|
||||||
def check_modif_user(
|
def check_modif_user(
|
||||||
edit,
|
edit,
|
||||||
ignore_optionals=False,
|
enforce_optionals=False,
|
||||||
user_name="",
|
user_name="",
|
||||||
nom="",
|
nom="",
|
||||||
prenom="",
|
prenom="",
|
||||||
@ -400,9 +287,9 @@ def check_modif_user(
|
|||||||
returns (ok, msg)
|
returns (ok, msg)
|
||||||
- ok : si vrai, peut continuer avec ces parametres
|
- ok : si vrai, peut continuer avec ces parametres
|
||||||
(si ok est faux, l'utilisateur peut quand même forcer la creation)
|
(si ok est faux, l'utilisateur peut quand même forcer la creation)
|
||||||
- msg: message warning a presenter l'utilisateur
|
- msg: message warning à presenter à l'utilisateur
|
||||||
"""
|
"""
|
||||||
MSG_OPT = """Attention: %s (vous pouvez forcer l'opération en cochant "<em>Ignorer les avertissements</em>" en bas de page)"""
|
MSG_OPT = """<br/>Attention: (vous pouvez forcer l'opération en cochant "<em>Ignorer les avertissements</em>" en bas de page)"""
|
||||||
# ce login existe ?
|
# ce login existe ?
|
||||||
user = _user_list(user_name)
|
user = _user_list(user_name)
|
||||||
if edit and not user: # safety net, le user_name ne devrait pas changer
|
if edit and not user: # safety net, le user_name ne devrait pas changer
|
||||||
@ -417,11 +304,11 @@ def check_modif_user(
|
|||||||
"identifiant '%s' invalide (pas d'accents ni de caractères spéciaux)"
|
"identifiant '%s' invalide (pas d'accents ni de caractères spéciaux)"
|
||||||
% user_name,
|
% user_name,
|
||||||
)
|
)
|
||||||
if ignore_optionals and len(user_name) > 64:
|
if enforce_optionals and len(user_name) > 64:
|
||||||
return False, "identifiant '%s' trop long (64 caractères)" % user_name
|
return False, "identifiant '%s' trop long (64 caractères)" % user_name
|
||||||
if ignore_optionals and len(nom) > 64:
|
if enforce_optionals and len(nom) > 64:
|
||||||
return False, "nom '%s' trop long (64 caractères)" % nom + MSG_OPT
|
return False, "nom '%s' trop long (64 caractères)" % nom + MSG_OPT
|
||||||
if ignore_optionals and len(prenom) > 64:
|
if enforce_optionals and len(prenom) > 64:
|
||||||
return False, "prenom '%s' trop long (64 caractères)" % prenom + MSG_OPT
|
return False, "prenom '%s' trop long (64 caractères)" % prenom + MSG_OPT
|
||||||
# check that tha same user_name has not already been described in this import
|
# check that tha same user_name has not already been described in this import
|
||||||
if not email:
|
if not email:
|
||||||
@ -432,13 +319,22 @@ def check_modif_user(
|
|||||||
return False, "l'adresse mail semble incorrecte"
|
return False, "l'adresse mail semble incorrecte"
|
||||||
# check département
|
# check département
|
||||||
if (
|
if (
|
||||||
ignore_optionals
|
enforce_optionals
|
||||||
and dept != ""
|
and dept != ""
|
||||||
and Departement.query.filter_by(acronym=dept).first() is None
|
and Departement.query.filter_by(acronym=dept).first() is None
|
||||||
):
|
):
|
||||||
return False, "département '%s' inexistant" % u["dept"] + MSG_OPT
|
return False, "département '%s' inexistant" % dept + MSG_OPT
|
||||||
if ignore_optionals and not roles:
|
if enforce_optionals and not roles:
|
||||||
return False, "aucun rôle sélectionné, êtes vous sûr ?" + MSG_OPT
|
return False, "aucun rôle sélectionné, êtes vous sûr ?" + MSG_OPT
|
||||||
|
# Unicité du mail
|
||||||
|
users_with_this_mail = User.query.filter_by(email=email).all()
|
||||||
|
if edit: # modification
|
||||||
|
if email != user["email"] and len(users_with_this_mail) > 0:
|
||||||
|
return False, "un autre utilisateur existe déjà avec cette adresse mail"
|
||||||
|
else: # création utilisateur
|
||||||
|
if len(users_with_this_mail) > 0:
|
||||||
|
return False, "un autre utilisateur existe déjà avec cette adresse mail"
|
||||||
|
|
||||||
# ok
|
# ok
|
||||||
# Des noms/prénoms semblables existent ?
|
# Des noms/prénoms semblables existent ?
|
||||||
nom = nom.lower().strip()
|
nom = nom.lower().strip()
|
||||||
@ -450,7 +346,7 @@ def check_modif_user(
|
|||||||
minmatch = 1
|
minmatch = 1
|
||||||
else:
|
else:
|
||||||
minmatch = 0
|
minmatch = 0
|
||||||
if len(similar_users) > minmatch:
|
if enforce_optionals and len(similar_users) > minmatch:
|
||||||
return (
|
return (
|
||||||
False,
|
False,
|
||||||
"des utilisateurs proches existent: "
|
"des utilisateurs proches existent: "
|
||||||
|
@ -290,8 +290,7 @@ SCO_DEV_MAIL = "emmanuel.viennet@gmail.com" # SVP ne pas changer
|
|||||||
|
|
||||||
# Adresse pour l'envoi des dumps (pour assistance technnique):
|
# Adresse pour l'envoi des dumps (pour assistance technnique):
|
||||||
# ne pas changer (ou vous perdez le support)
|
# ne pas changer (ou vous perdez le support)
|
||||||
SCO_DUMP_UP_URL = "https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/upload-dump"
|
SCO_DUMP_UP_URL = "https://scodoc.org/scodoc-installmgr/upload-dump"
|
||||||
# SCO_DUMP_UP_URL = "http://192.168.56.1:5000/upload_dump"
|
|
||||||
|
|
||||||
CSV_FIELDSEP = ";"
|
CSV_FIELDSEP = ";"
|
||||||
CSV_LINESEP = "\n"
|
CSV_LINESEP = "\n"
|
||||||
|
30
app/static/js/user_form.js
Normal file
30
app/static/js/user_form.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
function refresh() {
|
||||||
|
if ($("input[name='welcome:list']").is(":checked")) {
|
||||||
|
$("input[name='reset_password:list']").closest("tr").css("display", "table-row")
|
||||||
|
if ($("input[name='reset_password:list']").is(":checked")) {
|
||||||
|
$("#tf_password").closest('tr').css("display", "none");
|
||||||
|
$("#tf_password2").closest('tr').css("display", "none");
|
||||||
|
} else {
|
||||||
|
// Le mot de passe doit être saisi
|
||||||
|
$("#tf_password").closest('tr').css("display", "table-row");
|
||||||
|
$("#tf_password2").closest('tr').css("display", "table-row");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Le mot de passe doit être saisi
|
||||||
|
$("input[name='reset_password:list']").closest("tr").css("display", "none")
|
||||||
|
$("#tf_password").closest('tr').css("display", "table-row");
|
||||||
|
$("#tf_password2").closest('tr').css("display", "table-row");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$("input[name='welcome:list']").click(function () {
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
|
$("input[name='reset_password:list']").click(function () {
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
|
|
42
app/templates/auth/change_password.html
Normal file
42
app/templates/auth/change_password.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% macro render_field(field) %}
|
||||||
|
<tr style="">
|
||||||
|
<td class="wtf-field">{{ field.label }}</td>
|
||||||
|
<td class="wtf-field">{{ field(**kwargs)|safe }}
|
||||||
|
{% if field.errors %}
|
||||||
|
<ul class=errors>
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Modification du compte ScoDoc <tt>{{form.user_name.data}}</tt></h1>
|
||||||
|
<div class="help">
|
||||||
|
<p>Identifiez-vous avez votre mot de passe actuel</p>
|
||||||
|
<p>Vous pouvez changer le mot de passe et/ou l'adresse email.</p>
|
||||||
|
<p>Les champs vides ne seront pas changés.</p>
|
||||||
|
</div>
|
||||||
|
<form method=post>
|
||||||
|
{{ form.user_name }}
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<table class="tf"><tbody>
|
||||||
|
{{ render_field(form.old_password, size=14,
|
||||||
|
style="padding:1px; margin-left: 1em; margin-top: 4px;") }}
|
||||||
|
{{ render_field(form.new_password, size=14,
|
||||||
|
style="padding:1px; margin-left: 1em; margin-top: 12px;") }}
|
||||||
|
{{ render_field(form.bis_password, size=14,
|
||||||
|
style="padding:1px; margin-left: 1em; margin-top: 4px;") }}
|
||||||
|
{{ render_field(form.email, size=40,
|
||||||
|
style="padding:1px; margin-top: 12px;margin-bottom: 16px; margin-left: 1em;") }}
|
||||||
|
</tbody></table>
|
||||||
|
<input type="submit" value="Valider">
|
||||||
|
<input type="submit" name="cancel" value="Annuler" style="margin-left: 1em;>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@ -2,6 +2,11 @@
|
|||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
|
|
||||||
|
{% if message %}
|
||||||
|
<div class="alert alert-danger" role="alert">{{ message }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h1>Connexion</h1>
|
<h1>Connexion</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
@ -2,8 +2,13 @@
|
|||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
<h1>Reset Your Password</h1>
|
<h1>Changez votre mot de passe ScoDoc</h1>
|
||||||
<div class="row">
|
|
||||||
|
<div class="row" style="margin-top: 30px;">
|
||||||
|
<div class="col-md-4">Votre identifiant: <b>{{user.user_name}}</b></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top: 30px;">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
{{ wtf.quick_form(form) }}
|
{{ wtf.quick_form(form) }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
<h1>Reset Password</h1>
|
<h1>Demande d'un nouveau mot de passe</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
{{ wtf.quick_form(form) }}
|
{{ wtf.quick_form(form) }}
|
||||||
|
67
app/templates/auth/user_info_page.html
Normal file
67
app/templates/auth/user_info_page.html
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
|
<h2>Utilisateur: {{user.user_name}} ({{'actif' if user.active else 'fermé'}})</h2>
|
||||||
|
<p>
|
||||||
|
<b>Login :</b> {{user.user_name}}<br/>
|
||||||
|
<b>Nom :</b> {{user.nom or ""}}<br/>
|
||||||
|
<b>Prénom :</b> {{user.prenom or ""}}<br/>
|
||||||
|
<b>Mail :</b> {{user.email}}<br/>
|
||||||
|
<b>Roles :</b> {{user.get_roles_string()}}<br/>
|
||||||
|
<b>Dept :</b> {{user.dept or ""}}<br/>
|
||||||
|
<b>Dernière modif mot de passe:</b>
|
||||||
|
{{user.date_modif_passwd.isoformat() if user.date_modif_passwd else ""}}<br/>
|
||||||
|
<b>Date d'expiration:</b>
|
||||||
|
{{user.date_expiration.isoformat() if user.date_expiration else "(sans limite)"}}
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for( 'users.form_change_password',
|
||||||
|
scodoc_dept=g.scodoc_dept, user_name=user.user_name)
|
||||||
|
}}">modifier le mot de passe ou l'adresse mail</a>
|
||||||
|
</li>
|
||||||
|
{% if current_user.has_permission(Permission.ScoUsersAdmin, dept) %}
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for('users.create_user_form', scodoc_dept=g.scodoc_dept,
|
||||||
|
user_name=user.user_name, edit=1)
|
||||||
|
}}">modifier ce compte</a>
|
||||||
|
</li>
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for('users.toggle_active_user', scodoc_dept=g.scodoc_dept,
|
||||||
|
user_name=user.user_name)
|
||||||
|
}}">{{"désactiver" if user.active else "activer"}} ce compte</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% if current_user.id == user.id %}
|
||||||
|
<p><b>Se déconnecter:
|
||||||
|
<a class="stdlink" href="{{url_for('auth.logout')}}">logout</a>
|
||||||
|
</b></p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Liste des permissions #}
|
||||||
|
<div class="permissions">
|
||||||
|
<p>Permissions de cet utilisateur dans le département {dept}:</p>
|
||||||
|
<ul>
|
||||||
|
{% for p in Permission.description %}
|
||||||
|
<li>{{Permission.description[p]}} :
|
||||||
|
{{
|
||||||
|
"oui" if user.has_permission(Permission.get_by_name(p), dept) else "non"
|
||||||
|
}}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if current_user.has_permission(Permission.ScoUsersAdmin, dept) %}
|
||||||
|
<p><a class="stdlink" href="
|
||||||
|
{{url_for('users.index_html', scodoc_dept=g.scodoc_dept)}}
|
||||||
|
">Liste de tous les utilisateurs</a></p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -22,12 +22,19 @@
|
|||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="{{ url_for('scodoc.index') }}">ScoDoc</a>
|
<a class="navbar-brand" href="{{ url_for('scodoc.index') }}">ScoDoc</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
{% if current_user.is_administrator() %}
|
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li><a href="{{ url_for('scodoc.configuration') }}">configuration</a></li>
|
{% if current_user.is_administrator() %}
|
||||||
</ul>
|
<li><a href="{{ url_for('scodoc.configuration') }}">Configuration</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if g.scodoc_dept %}
|
||||||
|
<li><a href="{{
|
||||||
|
url_for('scolar.index_html', scodoc_dept=g.scodoc_dept)
|
||||||
|
}}">Dept. {{ g.scodoc_dept }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
{% if current_user.is_anonymous %}
|
{% if current_user.is_anonymous %}
|
||||||
<li><a href="{{ url_for('auth.login') }}">connexion</a></li>
|
<li><a href="{{ url_for('auth.login') }}">connexion</a></li>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
cliquez sur ce lien
|
cliquez sur ce lien
|
||||||
</a>.
|
</a>.
|
||||||
</p>
|
</p>
|
||||||
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web::</p>
|
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web:</p>
|
||||||
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
|
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
|
||||||
|
|
||||||
<p>Si vous n'avez pas demandé à réinitialiser votre mot de passe sur
|
<p>Si vous n'avez pas demandé à réinitialiser votre mot de passe sur
|
||||||
|
18
app/templates/email/welcome.html
Normal file
18
app/templates/email/welcome.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<p>Bienvenue {{ user.prenom }} {{ user.nom }},</p>
|
||||||
|
<p>
|
||||||
|
Votre accès à ScoDoc vient d'être validé.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Votre identifiant de connexion est: <b>{{ user.user_name }}</b>
|
||||||
|
</p>
|
||||||
|
{% if token %}
|
||||||
|
<p>Pour initialiser votre mot de passe ScoDoc,
|
||||||
|
<a href="{{ url_for('auth.reset_password', token=token, _external=True) }}">
|
||||||
|
cliquez sur ce lien
|
||||||
|
</a>.
|
||||||
|
</p>
|
||||||
|
<p>Vous pouvez aussi copier ce lien dans votre navigateur Web:</p>
|
||||||
|
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>A bientôt !</p>
|
11
app/templates/email/welcome.txt
Normal file
11
app/templates/email/welcome.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Bienvenue {{ user.prenom }} {{ user.nom }},
|
||||||
|
|
||||||
|
Votre accès à ScoDoc vient d'être validé.
|
||||||
|
Votre identifiant de connexion est: {{ user.user_name }}
|
||||||
|
|
||||||
|
{% if token %}
|
||||||
|
Pour initialiser votre mot de passe ScoDoc, suivre le lien:
|
||||||
|
{{ url_for('auth.reset_password', token=token, _external=True) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>A bientôt !</p>
|
@ -27,7 +27,7 @@ def start_scodoc_request():
|
|||||||
"""Affecte toutes les requêtes, de tous les blueprints"""
|
"""Affecte toutes les requêtes, de tous les blueprints"""
|
||||||
# current_app.logger.info(f"start_scodoc_request")
|
# current_app.logger.info(f"start_scodoc_request")
|
||||||
ndb.open_db_connection()
|
ndb.open_db_connection()
|
||||||
if current_user.is_authenticated:
|
if current_user and current_user.is_authenticated:
|
||||||
current_user.last_seen = datetime.datetime.utcnow()
|
current_user.last_seen = datetime.datetime.utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
# caches locaux (durée de vie=la requête en cours)
|
# caches locaux (durée de vie=la requête en cours)
|
||||||
|
@ -35,6 +35,7 @@ Note: Code très ancien, porté de Zope/DTML, peu utilisable
|
|||||||
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import urllib
|
||||||
|
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
@ -166,14 +167,14 @@ def index_html(etud_nom=None, limit=50, offset="", format="html"):
|
|||||||
if offset:
|
if offset:
|
||||||
webparams["offset"] = max((offset or 0) - limit, 0)
|
webparams["offset"] = max((offset or 0) - limit, 0)
|
||||||
prev_lnk = '<a class="stdlink" href="%s">précédentes</a>' % (
|
prev_lnk = '<a class="stdlink" href="%s">précédentes</a>' % (
|
||||||
request.base_url + "?" + six.moves.urllib.parse.urlencode(webparams)
|
request.base_url + "?" + urllib.parse.urlencode(webparams)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
prev_lnk = ""
|
prev_lnk = ""
|
||||||
if len(entreprises) >= limit:
|
if len(entreprises) >= limit:
|
||||||
webparams["offset"] = (offset or 0) + limit
|
webparams["offset"] = (offset or 0) + limit
|
||||||
next_lnk = '<a class="stdlink" href="%s">suivantes</a>' % (
|
next_lnk = '<a class="stdlink" href="%s">suivantes</a>' % (
|
||||||
request.base_url + "?" + six.moves.urllib.parse.urlencode(webparams)
|
request.base_url + "?" + urllib.parse.urlencode(webparams)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
next_lnk = ""
|
next_lnk = ""
|
||||||
|
@ -160,7 +160,7 @@ def sco_publish(route, function, permission, methods=["GET"]):
|
|||||||
# <p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
# <p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
||||||
# laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
# laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
||||||
# </p>
|
# </p>
|
||||||
# <a href="url_for('notes.ue_list', scodoc-dept=g.scodoc_dept, formation_id='XXX')">reprendre</a>
|
# <a href="url_for('notes.ue_table', scodoc-dept=g.scodoc_dept, formation_id='XXX')">reprendre</a>
|
||||||
# """
|
# """
|
||||||
# raise ScoGenError(err_page)
|
# raise ScoGenError(err_page)
|
||||||
# # raise ScoGenError("une erreur banale")
|
# # raise ScoGenError("une erreur banale")
|
||||||
@ -334,7 +334,7 @@ sco_publish(
|
|||||||
Permission.ScoChangeFormation,
|
Permission.ScoChangeFormation,
|
||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish("/ue_list", sco_edit_ue.ue_list, Permission.ScoView)
|
sco_publish("/ue_list", sco_edit_ue.ue_table, Permission.ScoView)
|
||||||
sco_publish("/ue_sharing_code", sco_edit_ue.ue_sharing_code, Permission.ScoView)
|
sco_publish("/ue_sharing_code", sco_edit_ue.ue_sharing_code, Permission.ScoView)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/edit_ue_set_code_apogee",
|
"/edit_ue_set_code_apogee",
|
||||||
@ -396,7 +396,7 @@ sco_publish(
|
|||||||
sco_edit_module.edit_module_set_code_apogee,
|
sco_edit_module.edit_module_set_code_apogee,
|
||||||
Permission.ScoChangeFormation,
|
Permission.ScoChangeFormation,
|
||||||
)
|
)
|
||||||
sco_publish("/module_list", sco_edit_module.module_list, Permission.ScoView)
|
sco_publish("/module_list", sco_edit_module.module_table, Permission.ScoView)
|
||||||
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/module_tag_set",
|
"/module_tag_set",
|
||||||
@ -548,8 +548,8 @@ sco_publish(
|
|||||||
)
|
)
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/do_ue_list",
|
"/ue_list",
|
||||||
sco_edit_ue.do_ue_list,
|
sco_edit_ue.ue_list,
|
||||||
Permission.ScoView,
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1059,11 +1059,11 @@ def edit_moduleimpl_expr(moduleimpl_id):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def view_module_abs(moduleimpl_id, format="html"):
|
def view_module_abs(moduleimpl_id, format="html"):
|
||||||
"""Visualisation des absences a un module"""
|
"""Visualisation des absences a un module"""
|
||||||
M = sco_moduleimpl.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
debut_sem = ndb.DateDMYtoISO(sem["date_debut"])
|
||||||
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
fin_sem = ndb.DateDMYtoISO(sem["date_fin"])
|
||||||
list_insc = sco_moduleimpl.do_moduleimpl_listeetuds(moduleimpl_id)
|
list_insc = sco_moduleimpl.moduleimpl_listeetuds(moduleimpl_id)
|
||||||
|
|
||||||
T = []
|
T = []
|
||||||
for etudid in list_insc:
|
for etudid in list_insc:
|
||||||
@ -1142,7 +1142,7 @@ def edit_ue_expr(formsemestre_id, ue_id):
|
|||||||
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
|
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
#
|
#
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": ue_id})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
"Modification règle de calcul de l'UE %s (%s)"
|
"Modification règle de calcul de l'UE %s (%s)"
|
||||||
@ -1213,7 +1213,7 @@ def formsemestre_enseignants_list(formsemestre_id, format="html"):
|
|||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
# resp. de modules:
|
# resp. de modules:
|
||||||
mods = sco_moduleimpl.do_moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
sem_ens = {}
|
sem_ens = {}
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
if not mod["responsable_id"] in sem_ens:
|
if not mod["responsable_id"] in sem_ens:
|
||||||
@ -1527,8 +1527,8 @@ def evaluation_delete(evaluation_id):
|
|||||||
if not El:
|
if not El:
|
||||||
raise ValueError("Evalution inexistante ! (%s)" % evaluation_id)
|
raise ValueError("Evalution inexistante ! (%s)" % evaluation_id)
|
||||||
E = El[0]
|
E = El[0]
|
||||||
M = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.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.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
|
tit = "Suppression de l'évaluation %(description)s (%(jour)s)" % E
|
||||||
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
||||||
H = [
|
H = [
|
||||||
@ -2424,14 +2424,14 @@ def check_sem_integrity(formsemestre_id, fix=False):
|
|||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
modimpls = sco_moduleimpl.do_moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
bad_ue = []
|
bad_ue = []
|
||||||
bad_sem = []
|
bad_sem = []
|
||||||
formations_set = set() # les formations mentionnées dans les UE et modules
|
formations_set = set() # les formations mentionnées dans les UE et modules
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
mod = sco_edit_module.do_module_list({"module_id": modimpl["module_id"]})[0]
|
mod = sco_edit_module.module_list({"module_id": modimpl["module_id"]})[0]
|
||||||
formations_set.add(mod["formation_id"])
|
formations_set.add(mod["formation_id"])
|
||||||
ue = sco_edit_ue.do_ue_list({"ue_id": mod["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list({"ue_id": mod["ue_id"]})[0]
|
||||||
formations_set.add(ue["formation_id"])
|
formations_set.add(ue["formation_id"])
|
||||||
if ue["formation_id"] != mod["formation_id"]:
|
if ue["formation_id"] != mod["formation_id"]:
|
||||||
modimpl["mod"] = mod
|
modimpl["mod"] = mod
|
||||||
@ -2490,12 +2490,12 @@ def check_sem_integrity(formsemestre_id, fix=False):
|
|||||||
def check_form_integrity(formation_id, fix=False):
|
def check_form_integrity(formation_id, fix=False):
|
||||||
"debug"
|
"debug"
|
||||||
log("check_form_integrity: formation_id=%s fix=%s" % (formation_id, fix))
|
log("check_form_integrity: formation_id=%s fix=%s" % (formation_id, fix))
|
||||||
ues = sco_edit_ue.do_ue_list(args={"formation_id": formation_id})
|
ues = sco_edit_ue.ue_list(args={"formation_id": formation_id})
|
||||||
bad = []
|
bad = []
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
mats = sco_edit_matiere.do_matiere_list(args={"ue_id": ue["ue_id"]})
|
mats = sco_edit_matiere.matiere_list(args={"ue_id": ue["ue_id"]})
|
||||||
for mat in mats:
|
for mat in mats:
|
||||||
mods = sco_edit_module.do_module_list({"matiere_id": mat["matiere_id"]})
|
mods = sco_edit_module.module_list({"matiere_id": mat["matiere_id"]})
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
if mod["ue_id"] != ue["ue_id"]:
|
if mod["ue_id"] != ue["ue_id"]:
|
||||||
if fix:
|
if fix:
|
||||||
@ -2534,9 +2534,7 @@ def check_formsemestre_integrity(formsemestre_id):
|
|||||||
# de formations
|
# de formations
|
||||||
diag = []
|
diag = []
|
||||||
|
|
||||||
Mlist = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
)
|
|
||||||
for mod in Mlist:
|
for mod in Mlist:
|
||||||
if mod["module"]["ue_id"] != mod["matiere"]["ue_id"]:
|
if mod["module"]["ue_id"] != mod["matiere"]["ue_id"]:
|
||||||
diag.append(
|
diag.append(
|
||||||
@ -2593,14 +2591,14 @@ def check_integrity_all():
|
|||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Support for legacy ScoDoc 7 API
|
# Support for legacy ScoDoc 7 API
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
@bp.route("/do_moduleimpl_list")
|
@bp.route("/moduleimpl_list")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def do_moduleimpl_list(
|
def moduleimpl_list(
|
||||||
moduleimpl_id=None, formsemestre_id=None, module_id=None, format="json"
|
moduleimpl_id=None, formsemestre_id=None, module_id=None, format="json"
|
||||||
):
|
):
|
||||||
data = sco_moduleimpl.do_moduleimpl_list(
|
data = sco_moduleimpl.moduleimpl_list(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
module_id=module_id,
|
module_id=module_id,
|
||||||
@ -2608,15 +2606,16 @@ def do_moduleimpl_list(
|
|||||||
return scu.sendResult(data, format=format)
|
return scu.sendResult(data, format=format)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/do_moduleimpl_withmodule_list")
|
@bp.route("/do_moduleimpl_withmodule_list") # ancien nom
|
||||||
|
@bp.route("/moduleimpl_withmodule_list")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def do_moduleimpl_withmodule_list(
|
def moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=None, formsemestre_id=None, module_id=None
|
moduleimpl_id=None, formsemestre_id=None, module_id=None
|
||||||
):
|
):
|
||||||
"""API ScoDoc 7"""
|
"""API ScoDoc 7"""
|
||||||
data = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
data = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
module_id=module_id,
|
module_id=module_id,
|
||||||
|
@ -669,9 +669,18 @@ sco_publish(
|
|||||||
|
|
||||||
sco_publish("/setGroups", sco_groups.setGroups, Permission.ScoView)
|
sco_publish("/setGroups", sco_groups.setGroups, Permission.ScoView)
|
||||||
|
|
||||||
sco_publish("/createGroup", sco_groups.createGroup, Permission.ScoView)
|
sco_publish("/create_group", sco_groups.create_group, Permission.ScoView)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/suppressGroup") # backward compat (ScoDoc7 API)
|
||||||
|
@bp.route("/delete_group")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoView)
|
||||||
|
@scodoc7func
|
||||||
|
def delete_group(group_id, partition_id):
|
||||||
|
sco_groups.delete_group(group_id=group_id, partition_id=partition_id)
|
||||||
|
return "", 204
|
||||||
|
|
||||||
sco_publish("/suppressGroup", sco_groups.suppressGroup, Permission.ScoView)
|
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/group_set_name",
|
"/group_set_name",
|
||||||
|
@ -38,10 +38,12 @@ import re
|
|||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for, request
|
from flask import g, url_for, request, current_app, flash
|
||||||
from flask import redirect, render_template
|
from flask import redirect, render_template
|
||||||
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
from wtforms import HiddenField, PasswordField, StringField, SubmitField
|
||||||
|
from wtforms.validators import DataRequired, Email, ValidationError, EqualTo
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.auth.forms import DeactivateUserForm
|
from app.auth.forms import DeactivateUserForm
|
||||||
@ -49,6 +51,8 @@ from app.auth.models import Permission
|
|||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.auth.models import Role
|
from app.auth.models import Role
|
||||||
from app.auth.models import UserRole
|
from app.auth.models import UserRole
|
||||||
|
from app.auth.models import is_valid_password
|
||||||
|
from app.email import send_email
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
|
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
@ -63,9 +67,53 @@ from app.scodoc import sco_utils as scu
|
|||||||
from app.scodoc import sco_xml
|
from app.scodoc import sco_xml
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
|
from app.scodoc.sco_import_users import generate_password
|
||||||
from app.scodoc.sco_permissions_check import can_handle_passwd
|
from app.scodoc.sco_permissions_check import can_handle_passwd
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
from app.views import users_bp as bp
|
from app.views import users_bp as bp
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
|
||||||
|
_ = lambda x: x # sans babel
|
||||||
|
_l = _
|
||||||
|
|
||||||
|
|
||||||
|
class ChangePasswordForm(FlaskForm):
|
||||||
|
user_name = HiddenField()
|
||||||
|
old_password = PasswordField(_l("Identifiez-vous"))
|
||||||
|
new_password = PasswordField(_l("Nouveau mot de passe"))
|
||||||
|
bis_password = PasswordField(
|
||||||
|
_l("Répéter"),
|
||||||
|
validators=[
|
||||||
|
EqualTo(
|
||||||
|
"new_password",
|
||||||
|
message="Les deux saisies sont " "différentes, recommencez",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
email = StringField(
|
||||||
|
_l("Email"),
|
||||||
|
validators=[
|
||||||
|
DataRequired(),
|
||||||
|
Email(message="adresse email invalide, recommencez"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
submit = SubmitField()
|
||||||
|
cancel = SubmitField("Annuler")
|
||||||
|
|
||||||
|
def validate_email(self, email):
|
||||||
|
user = User.query.filter_by(email=email.data.strip()).first()
|
||||||
|
if user is not None and self.user_name.data != user.user_name:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Cette adresse e-mail est déjà attribuée à un autre compte")
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_new_password(self, new_password):
|
||||||
|
if new_password.data != "" and not is_valid_password(new_password.data):
|
||||||
|
raise ValidationError(f"Mot de passe trop simple, recommencez")
|
||||||
|
|
||||||
|
def validate_old_password(self, old_password):
|
||||||
|
if not current_user.check_password(old_password.data):
|
||||||
|
raise ValidationError("Mot de passe actuel incorrect, ré-essayez")
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/")
|
@bp.route("/")
|
||||||
@ -100,7 +148,12 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
initvalues = {}
|
initvalues = {}
|
||||||
edit = int(edit)
|
edit = int(edit)
|
||||||
all_roles = int(all_roles)
|
all_roles = int(all_roles)
|
||||||
H = [html_sco_header.sco_header(bodyOnLoad="init_tf_form('')")]
|
H = [
|
||||||
|
html_sco_header.sco_header(
|
||||||
|
bodyOnLoad="init_tf_form('')",
|
||||||
|
javascripts=["js/user_form.js"],
|
||||||
|
)
|
||||||
|
]
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
if edit:
|
if edit:
|
||||||
if not user_name:
|
if not user_name:
|
||||||
@ -214,9 +267,11 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
"title": "Pseudo (login)",
|
"title": "Pseudo (login)",
|
||||||
"size": 20,
|
"size": 20,
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
"explanation": "nom utilisé pour la connexion. Doit être unique parmi tous les utilisateurs.",
|
"explanation": "nom utilisé pour la connexion. Doit être unique parmi tous les utilisateurs. "
|
||||||
|
"Lettres ou chiffres uniquement.",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
("formsemestre_id", {"input_type": "hidden"}),
|
||||||
(
|
(
|
||||||
"password",
|
"password",
|
||||||
{
|
{
|
||||||
@ -257,6 +312,32 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
if not edit: # options création utilisateur
|
||||||
|
descr += [
|
||||||
|
(
|
||||||
|
"welcome",
|
||||||
|
{
|
||||||
|
"title": "Message d'accueil",
|
||||||
|
"input_type": "checkbox",
|
||||||
|
"explanation": "Envoie un mail d'accueil à l'utilisateur.",
|
||||||
|
"labels": ("",),
|
||||||
|
"allowed_values": ("1",),
|
||||||
|
"default": "1",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"reset_password",
|
||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"input_type": "checkbox",
|
||||||
|
"explanation": "indiquer par mail de changer le mot de passe initial",
|
||||||
|
"labels": ("",),
|
||||||
|
"allowed_values": ("1",),
|
||||||
|
"default": "1",
|
||||||
|
# "attributes": ["style='margin-left:20pt'"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
if not auth_dept:
|
if not auth_dept:
|
||||||
# si auth n'a pas de departement (admin global)
|
# si auth n'a pas de departement (admin global)
|
||||||
@ -380,14 +461,14 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
if err:
|
if err:
|
||||||
H.append(tf_error_message("""Erreur: %s""" % err))
|
H.append(tf_error_message("""Erreur: %s""" % err))
|
||||||
return "\n".join(H) + "\n" + tf[1] + F
|
return "\n".join(H) + "\n" + tf[1] + F
|
||||||
|
|
||||||
ok, msg = sco_users.check_modif_user(
|
ok, msg = sco_users.check_modif_user(
|
||||||
edit,
|
edit,
|
||||||
ignore_optionals=force,
|
enforce_optionals=not force,
|
||||||
user_name=user_name,
|
user_name=user_name,
|
||||||
nom=vals["nom"],
|
nom=vals["nom"],
|
||||||
prenom=vals["prenom"],
|
prenom=vals["prenom"],
|
||||||
email=vals["email"],
|
email=vals["email"],
|
||||||
|
dept=vals.get("dept", auth_dept),
|
||||||
roles=vals["roles"],
|
roles=vals["roles"],
|
||||||
)
|
)
|
||||||
if not ok:
|
if not ok:
|
||||||
@ -400,6 +481,9 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
vals["date_expiration"] = datetime.datetime.strptime(
|
vals["date_expiration"] = datetime.datetime.strptime(
|
||||||
vals["date_expiration"], "%d/%m/%Y"
|
vals["date_expiration"], "%d/%m/%Y"
|
||||||
)
|
)
|
||||||
|
if vals["date_expiration"] < datetime.datetime.now():
|
||||||
|
H.append(tf_error_message("date expiration passée"))
|
||||||
|
return "\n".join(H) + "\n" + tf[1] + F
|
||||||
else:
|
else:
|
||||||
vals["date_expiration"] = None
|
vals["date_expiration"] = None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -444,14 +528,29 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
"identifiant invalide (pas d'accents ni de caractères spéciaux)"
|
"identifiant invalide (pas d'accents ni de caractères spéciaux)"
|
||||||
)
|
)
|
||||||
return "\n".join(H) + msg + "\n" + tf[1] + F
|
return "\n".join(H) + msg + "\n" + tf[1] + F
|
||||||
|
# Traitement initial (mode) : 3 cas
|
||||||
|
# A: envoi de welcome + procedure de reset
|
||||||
|
# B: envoi de welcome seulement (mot de passe saisie dans le formulaire)
|
||||||
|
# C: Aucun envoi (mot de passe saisi dans le formulaire)
|
||||||
|
if vals["welcome:list"] == "1":
|
||||||
|
if vals["reset_password:list"] == "1":
|
||||||
|
mode = "A"
|
||||||
|
else:
|
||||||
|
mode = "B"
|
||||||
|
else:
|
||||||
|
mode = "C"
|
||||||
|
|
||||||
# check passwords
|
# check passwords
|
||||||
|
if mode == "A":
|
||||||
|
vals["password"] = generate_password()
|
||||||
|
else:
|
||||||
if vals["password"]:
|
if vals["password"]:
|
||||||
if vals["password"] != vals["password2"]:
|
if vals["password"] != vals["password2"]:
|
||||||
msg = tf_error_message(
|
msg = tf_error_message(
|
||||||
"""Les deux mots de passes ne correspondent pas !"""
|
"""Les deux mots de passes ne correspondent pas !"""
|
||||||
)
|
)
|
||||||
return "\n".join(H) + msg + "\n" + tf[1] + F
|
return "\n".join(H) + msg + "\n" + tf[1] + F
|
||||||
if not sco_users.is_valid_password(vals["password"]):
|
if not is_valid_password(vals["password"]):
|
||||||
msg = tf_error_message(
|
msg = tf_error_message(
|
||||||
"""Mot de passe trop simple, recommencez !"""
|
"""Mot de passe trop simple, recommencez !"""
|
||||||
)
|
)
|
||||||
@ -467,6 +566,22 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
u.from_dict(vals, new_user=True)
|
u.from_dict(vals, new_user=True)
|
||||||
db.session.add(u)
|
db.session.add(u)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
# envoi éventuel d'un message
|
||||||
|
if mode == "A" or mode == "B":
|
||||||
|
if mode == "A":
|
||||||
|
token = u.get_reset_password_token()
|
||||||
|
else:
|
||||||
|
token = None
|
||||||
|
send_email(
|
||||||
|
"[ScoDoc] Création de votre compte",
|
||||||
|
sender=current_app.config["ADMINS"][0],
|
||||||
|
recipients=[u.email],
|
||||||
|
text_body=render_template("email/welcome.txt", user=u, token=token),
|
||||||
|
html_body=render_template(
|
||||||
|
"email/welcome.html", user=u, token=token
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"users.user_info_page",
|
"users.user_info_page",
|
||||||
@ -531,6 +646,16 @@ def import_users_form():
|
|||||||
"xlsfile",
|
"xlsfile",
|
||||||
{"title": "Fichier Excel:", "input_type": "file", "size": 40},
|
{"title": "Fichier Excel:", "input_type": "file", "size": 40},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"force",
|
||||||
|
{
|
||||||
|
"title": "Ignorer les avertissements",
|
||||||
|
"input_type": "checkbox",
|
||||||
|
"explanation": "passer outre les avertissements (homonymes, etc)",
|
||||||
|
"labels": ("",),
|
||||||
|
"allowed_values": ("1",),
|
||||||
|
},
|
||||||
|
),
|
||||||
("formsemestre_id", {"input_type": "hidden"}),
|
("formsemestre_id", {"input_type": "hidden"}),
|
||||||
),
|
),
|
||||||
submitlabel="Télécharger",
|
submitlabel="Télécharger",
|
||||||
@ -541,14 +666,16 @@ def import_users_form():
|
|||||||
return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept))
|
return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept))
|
||||||
else:
|
else:
|
||||||
# IMPORT
|
# IMPORT
|
||||||
ok, diag, nb_created = sco_import_users.import_excel_file(tf[2]["xlsfile"])
|
ok, diag, nb_created = sco_import_users.import_excel_file(
|
||||||
|
tf[2]["xlsfile"], tf[2]["force"]
|
||||||
|
)
|
||||||
H = [html_sco_header.sco_header(page_title="Import utilisateurs")]
|
H = [html_sco_header.sco_header(page_title="Import utilisateurs")]
|
||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
for d in diag:
|
for d in diag:
|
||||||
H.append("<li>%s</li>" % d)
|
H.append("<li>%s</li>" % d)
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
if ok:
|
if ok:
|
||||||
dest = url_for("users.index_html", scodoc_dept=g.scodoc_dept)
|
dest = url_for("users.index_html", scodoc_dept=g.scodoc_dept, all_depts=1)
|
||||||
H.append("<p>Ok, Import terminé (%s utilisateurs créés)!</p>" % nb_created)
|
H.append("<p>Ok, Import terminé (%s utilisateurs créés)!</p>" % nb_created)
|
||||||
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % dest)
|
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % dest)
|
||||||
else:
|
else:
|
||||||
@ -562,8 +689,31 @@ def import_users_form():
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoUsersView)
|
@permission_required(Permission.ScoUsersView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def user_info_page(user_name):
|
def user_info_page(user_name=None):
|
||||||
return sco_users.user_info_page(user_name=user_name)
|
"""Display page of info about given user.
|
||||||
|
If user_name not specified, user current_user
|
||||||
|
"""
|
||||||
|
from app.scodoc.sco_permissions_check import can_handle_passwd
|
||||||
|
|
||||||
|
# peut on divulguer ces infos ?
|
||||||
|
if not can_handle_passwd(current_user, allow_admindepts=True):
|
||||||
|
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
|
||||||
|
|
||||||
|
dept = g.scodoc_dept
|
||||||
|
if not user_name:
|
||||||
|
user = current_user
|
||||||
|
else:
|
||||||
|
user = User.query.filter_by(user_name=user_name).first()
|
||||||
|
if not user:
|
||||||
|
raise ScoValueError("invalid user_name")
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"auth/user_info_page.html",
|
||||||
|
user=user,
|
||||||
|
title=f"Utilisateur {user.user_name}",
|
||||||
|
Permission=Permission,
|
||||||
|
dept=dept,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/get_user_list_xml")
|
@bp.route("/get_user_list_xml")
|
||||||
@ -594,7 +744,7 @@ def get_user_list_xml(dept=None, start="", limit=25):
|
|||||||
return scu.send_file(data, mime=scu.XML_MIMETYPE)
|
return scu.send_file(data, mime=scu.XML_MIMETYPE)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/form_change_password")
|
@bp.route("/form_change_password", methods=["GET", "POST"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
@ -603,36 +753,42 @@ def form_change_password(user_name=None):
|
|||||||
Un utilisateur peut toujours changer son propre mot de passe.
|
Un utilisateur peut toujours changer son propre mot de passe.
|
||||||
"""
|
"""
|
||||||
if not user_name:
|
if not user_name:
|
||||||
u = current_user
|
user = current_user
|
||||||
else:
|
else:
|
||||||
u = User.query.filter_by(user_name=user_name).first()
|
user = User.query.filter_by(user_name=user_name).first()
|
||||||
H = [html_sco_header.sco_header(user_check=False)]
|
|
||||||
F = html_sco_header.sco_footer()
|
|
||||||
# check access
|
# check access
|
||||||
if not can_handle_passwd(u):
|
if not can_handle_passwd(user):
|
||||||
return (
|
return "\n".join(
|
||||||
"\n".join(H)
|
[
|
||||||
+ "<p>Vous n'avez pas la permission de changer ce mot de passe</p>"
|
html_sco_header.sco_header(user_check=False),
|
||||||
+ F
|
"<p>Vous n'avez pas la permission de changer ce mot de passe</p>",
|
||||||
|
html_sco_header.sco_footer(),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
#
|
form = ChangePasswordForm(user_name=user.user_name, email=user.email)
|
||||||
H.append(
|
destination = url_for(
|
||||||
"""<h2>Changement du mot de passe de <font color="red">%(nomplogin)s</font></h2>
|
"users.user_info_page",
|
||||||
<p>
|
scodoc_dept=g.scodoc_dept,
|
||||||
<form action="change_password" method="post"><table>
|
user_name=user_name,
|
||||||
<tr><td>Nouveau mot de passe:</td><td><input type="password" size="14" name="password"/></td></tr>
|
)
|
||||||
<tr><td>Confirmation: </td><td><input type="password" size="14" name="password2" /></td></tr>
|
if request.method == "POST" and form.cancel.data: # cancel button clicked
|
||||||
</table>
|
return redirect(destination)
|
||||||
<input type="hidden" value="%(user_name)s" name="user_name">
|
if form.validate_on_submit():
|
||||||
<input type="submit" value="Changer">
|
messages = []
|
||||||
</p>
|
if form.new_password.data != "": # change password
|
||||||
<p class="help">Note: en ScoDoc 9, les utilisateurs peuvent changer eux-même leur mot de passe
|
user.set_password(form.new_password.data)
|
||||||
en indiquant l'adresse mail associée à leur compte.
|
messages.append("Mot de passe modifié")
|
||||||
</p>
|
if form.email.data.strip() != user.email: # change email
|
||||||
"""
|
user.email = form.email.data.strip()
|
||||||
% {"nomplogin": u.get_nomplogin(), "user_name": user_name}
|
messages.append("Adresse email modifiée")
|
||||||
|
db.session.commit()
|
||||||
|
flash("\n".join(messages))
|
||||||
|
return redirect(destination)
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"auth/change_password.html", form=form, title="Modification compte ScoDoc"
|
||||||
)
|
)
|
||||||
return "\n".join(H) + F
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/change_password", methods=["POST"])
|
@bp.route("/change_password", methods=["POST"])
|
||||||
@ -660,7 +816,7 @@ def change_password(user_name, password, password2):
|
|||||||
% user_name
|
% user_name
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not sco_users.is_valid_password(password):
|
if not is_valid_password(password):
|
||||||
H.append(
|
H.append(
|
||||||
"""<p><b>ce mot de passe n\'est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
|
"""<p><b>ce mot de passe n\'est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
|
||||||
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>
|
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>
|
||||||
|
13
bench.py
Normal file
13
bench.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"""Script pour faciliter le lancement de benchmarks
|
||||||
|
"""
|
||||||
|
|
||||||
|
from tests.bench.notes_table import bench_notes_table
|
||||||
|
|
||||||
|
BENCH_DEPT = "RT"
|
||||||
|
BENCH_FORMSEMESTRE_IDS = (
|
||||||
|
149, # RT S1 2020-21
|
||||||
|
145, # RT S2 2021
|
||||||
|
119, # RT S1 2029
|
||||||
|
)
|
||||||
|
|
||||||
|
bench_notes_table(BENCH_DEPT, BENCH_FORMSEMESTRE_IDS)
|
@ -1,57 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""Change un identifiant d'enseignant (pour corriger une erreur, typiquement un doublon)
|
|
||||||
|
|
||||||
(à lancer en tant qu'utilisateur postgres)
|
|
||||||
Emmanuel Viennet, 2007 - 2014
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import pdb, os, sys
|
|
||||||
import psycopg2
|
|
||||||
from six.moves import input
|
|
||||||
|
|
||||||
if len(sys.argv) != 4:
|
|
||||||
print("Usage: %s database ancien_utilisateur nouvel_utilisateur" % sys.argv[0])
|
|
||||||
print("Exemple: change_enseignant.py SCOGEII toto tata")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
dbname = sys.argv[1]
|
|
||||||
OLD_ID = sys.argv[2]
|
|
||||||
NEW_ID = sys.argv[3]
|
|
||||||
|
|
||||||
DBCNXSTRING = "dbname=%s" % dbname
|
|
||||||
|
|
||||||
# Confirmation
|
|
||||||
ans = input(
|
|
||||||
"Remplacer le l'utilisateur %s par %s dans toute la base du departement %s ?"
|
|
||||||
% (OLD_ID, NEW_ID, dbname)
|
|
||||||
).strip()
|
|
||||||
if not ans or ans[0].lower() not in "oOyY":
|
|
||||||
print("annulation")
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
cnx = psycopg2.connect(DBCNXSTRING)
|
|
||||||
|
|
||||||
cursor = cnx.cursor()
|
|
||||||
req = "update %s set %s=%%(new_id)s where %s=%%(old_id)s"
|
|
||||||
args = {"old_id": OLD_ID, "new_id": NEW_ID}
|
|
||||||
|
|
||||||
tables_attr = {
|
|
||||||
"notes_formsemestre": "responsable_id",
|
|
||||||
"entreprise_contact": "enseignant",
|
|
||||||
"admissions": "rapporteur",
|
|
||||||
"notes_moduleimpl": "responsable_id",
|
|
||||||
"notes_modules_enseignants": "ens_id",
|
|
||||||
"notes_notes": "uid",
|
|
||||||
"notes_notes_log": "uid",
|
|
||||||
"notes_appreciations": "author",
|
|
||||||
}
|
|
||||||
|
|
||||||
for (table, attr) in tables_attr.items():
|
|
||||||
cursor.execute(req % (table, attr, attr), args)
|
|
||||||
print("table %s: %s" % (table, cursor.statusmessage))
|
|
||||||
|
|
||||||
cnx.commit()
|
|
@ -78,7 +78,7 @@ pp(sem)
|
|||||||
# semdescr = GET(s, f"Notes/formsemestre_description?formsemestre_id={sem['formsemestre_id']}&with_evals=0&format=json" )
|
# semdescr = GET(s, f"Notes/formsemestre_description?formsemestre_id={sem['formsemestre_id']}&with_evals=0&format=json" )
|
||||||
|
|
||||||
# ---- Liste les modules et prend le premier
|
# ---- Liste les modules et prend le premier
|
||||||
mods = GET(s, f"/Notes/do_moduleimpl_list?formsemestre_id={sem['formsemestre_id']}")
|
mods = GET(s, f"/Notes/moduleimpl_list?formsemestre_id={sem['formsemestre_id']}")
|
||||||
print(f"{len(mods)} modules dans le semestre {sem['titre']}")
|
print(f"{len(mods)} modules dans le semestre {sem['titre']}")
|
||||||
|
|
||||||
mod = mods[0]
|
mod = mods[0]
|
||||||
|
@ -58,7 +58,6 @@ redis==3.5.3
|
|||||||
reportlab==3.6.1
|
reportlab==3.6.1
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
rq==1.9.0
|
rq==1.9.0
|
||||||
six==1.16.0
|
|
||||||
SQLAlchemy==1.4.22
|
SQLAlchemy==1.4.22
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
urllib3==1.26.6
|
urllib3==1.26.6
|
||||||
|
50
tests/bench/notes_table.py
Normal file
50
tests/bench/notes_table.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Simple benchmark
|
||||||
|
# mesure temps execution NotesTable
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from flask import g
|
||||||
|
from flask_login import login_user
|
||||||
|
|
||||||
|
from config import RunningConfig as BenchConfig
|
||||||
|
import app
|
||||||
|
from app import db, create_app
|
||||||
|
from app import clear_scodoc_cache
|
||||||
|
from app.auth.models import get_super_admin
|
||||||
|
from app.scodoc import notesdb as ndb
|
||||||
|
from app.scodoc import notes_table
|
||||||
|
|
||||||
|
|
||||||
|
def setup_generator(dept: str):
|
||||||
|
# Setup
|
||||||
|
apptest = create_app(BenchConfig)
|
||||||
|
# Run tests:
|
||||||
|
with apptest.test_client() as client:
|
||||||
|
with apptest.app_context():
|
||||||
|
with apptest.test_request_context():
|
||||||
|
# Clear application cache:
|
||||||
|
print("clearing cache...")
|
||||||
|
clear_scodoc_cache()
|
||||||
|
# initialize scodoc "g":
|
||||||
|
g.stored_get_formsemestre = {}
|
||||||
|
# Loge l'utilisateur super-admin
|
||||||
|
admin_user = get_super_admin()
|
||||||
|
login_user(admin_user)
|
||||||
|
app.set_sco_dept(dept) # set db connection
|
||||||
|
yield client
|
||||||
|
ndb.close_db_connection()
|
||||||
|
# Teardown:
|
||||||
|
db.session.commit()
|
||||||
|
db.session.remove()
|
||||||
|
|
||||||
|
|
||||||
|
def bench_notes_table(dept: str, formsemestre_ids: list[int]) -> float:
|
||||||
|
for client in setup_generator(dept):
|
||||||
|
tot_time = 0.0
|
||||||
|
for formsemestre_id in formsemestre_ids:
|
||||||
|
print(f"building sem {formsemestre_id}...")
|
||||||
|
t0 = time.time()
|
||||||
|
nt = notes_table.NotesTable(formsemestre_id)
|
||||||
|
tot_time += time.time() - t0
|
||||||
|
print(f"Total time: {tot_time}")
|
||||||
|
return tot_time
|
@ -52,7 +52,7 @@ def run_scenario1():
|
|||||||
]
|
]
|
||||||
|
|
||||||
# --- Implémentation des modules
|
# --- Implémentation des modules
|
||||||
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
modules = sco_edit_module.module_list({"formation_id": formation_id})
|
||||||
mods_imp = []
|
mods_imp = []
|
||||||
for mod in modules:
|
for mod in modules:
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
|
@ -170,7 +170,7 @@ class ScoFake(object):
|
|||||||
if numero is None:
|
if numero is None:
|
||||||
numero = sco_edit_ue.next_ue_numero(formation_id, 0)
|
numero = sco_edit_ue.next_ue_numero(formation_id, 0)
|
||||||
oid = sco_edit_ue.do_ue_create(locals())
|
oid = sco_edit_ue.do_ue_create(locals())
|
||||||
oids = sco_edit_ue.do_ue_list(args={"ue_id": oid})
|
oids = sco_edit_ue.ue_list(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]
|
||||||
@ -178,7 +178,7 @@ class ScoFake(object):
|
|||||||
@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(locals())
|
oid = sco_edit_matiere.do_matiere_create(locals())
|
||||||
oids = sco_edit_matiere.do_matiere_list(args={"matiere_id": oid})
|
oids = sco_edit_matiere.matiere_list(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]
|
||||||
@ -203,7 +203,7 @@ class ScoFake(object):
|
|||||||
module_type=None,
|
module_type=None,
|
||||||
):
|
):
|
||||||
oid = sco_edit_module.do_module_create(locals())
|
oid = sco_edit_module.do_module_create(locals())
|
||||||
oids = sco_edit_module.do_module_list(args={"module_id": oid})
|
oids = sco_edit_module.module_list(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]
|
||||||
@ -251,7 +251,7 @@ class ScoFake(object):
|
|||||||
if not responsable_id:
|
if not responsable_id:
|
||||||
responsable_id = self.default_user.id
|
responsable_id = self.default_user.id
|
||||||
oid = sco_moduleimpl.do_moduleimpl_create(locals())
|
oid = sco_moduleimpl.do_moduleimpl_create(locals())
|
||||||
oids = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=oid) # API inconsistency
|
oids = sco_moduleimpl.moduleimpl_list(moduleimpl_id=oid) # API inconsistency
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("moduleimpl not created !")
|
raise ScoValueError("moduleimpl not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
|
@ -119,7 +119,7 @@ def test_abs_basic(test_client):
|
|||||||
- sco_abs.get_abs_count(etudid, sem)
|
- sco_abs.get_abs_count(etudid, sem)
|
||||||
- ListeAbsEtud
|
- ListeAbsEtud
|
||||||
- partition_create
|
- partition_create
|
||||||
- createGroup
|
- create_group
|
||||||
- set_group
|
- set_group
|
||||||
- EtatAbsenceGr
|
- EtatAbsenceGr
|
||||||
- AddBilletAbsence
|
- AddBilletAbsence
|
||||||
@ -268,7 +268,7 @@ def test_abs_basic(test_client):
|
|||||||
partition_name="Eleve",
|
partition_name="Eleve",
|
||||||
)
|
)
|
||||||
li1 = sco_groups.get_partitions_list(sem["formsemestre_id"])
|
li1 = sco_groups.get_partitions_list(sem["formsemestre_id"])
|
||||||
_ = sco_groups.createGroup(li1[0]["partition_id"], "Groupe 1")
|
_ = sco_groups.create_group(li1[0]["partition_id"], "Groupe 1")
|
||||||
|
|
||||||
# --- Affectation des élèves dans des groupes
|
# --- Affectation des élèves dans des groupes
|
||||||
|
|
||||||
|
@ -30,14 +30,14 @@
|
|||||||
# - formation_list
|
# - formation_list
|
||||||
# - formation_export
|
# - formation_export
|
||||||
# - formsemestre_list
|
# - formsemestre_list
|
||||||
# - do_moduleimpl_list
|
# - moduleimpl_list
|
||||||
# - do_module_impl_with_module_list
|
# - do_module_impl_with_module_list
|
||||||
# - do_formsemestre_delete
|
# - do_formsemestre_delete
|
||||||
# - do_module_list
|
# - module_list
|
||||||
# - do_module_delete
|
# - do_module_delete
|
||||||
# - do_matiere_list
|
# - matiere_list
|
||||||
# - do_matiere_delete
|
# - do_matiere_delete
|
||||||
# - do_ue_list
|
# - ue_list
|
||||||
# - do_ue_delete
|
# - do_ue_delete
|
||||||
# - do_formation_delete
|
# - do_formation_delete
|
||||||
|
|
||||||
@ -231,28 +231,24 @@ def test_formations(test_client):
|
|||||||
|
|
||||||
# --- Liste des modules
|
# --- Liste des modules
|
||||||
|
|
||||||
lim_sem1 = sco_moduleimpl.do_moduleimpl_list(
|
lim_sem1 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem1["formsemestre_id"])
|
||||||
formsemestre_id=sem1["formsemestre_id"]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert len(lim_sem1) == 2
|
assert len(lim_sem1) == 2
|
||||||
assert mod["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
assert mod["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
||||||
assert mod2["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
assert mod2["module_id"] in (lim_sem1[0]["module_id"], lim_sem1[1]["module_id"])
|
||||||
|
|
||||||
lim_modid = sco_moduleimpl.do_moduleimpl_list(module_id=mod["module_id"])
|
lim_modid = sco_moduleimpl.moduleimpl_list(module_id=mod["module_id"])
|
||||||
|
|
||||||
assert len(lim_modid) == 1
|
assert len(lim_modid) == 1
|
||||||
|
|
||||||
lim_modimpl_id = sco_moduleimpl.do_moduleimpl_list(
|
lim_modimpl_id = sco_moduleimpl.moduleimpl_list(moduleimpl_id=mi["moduleimpl_id"])
|
||||||
moduleimpl_id=mi["moduleimpl_id"]
|
|
||||||
)
|
|
||||||
# print(lim_modimpl_id)
|
# print(lim_modimpl_id)
|
||||||
|
|
||||||
# ---- Test de do_moduleimpl_withmodule_list
|
# ---- Test de moduleimpl_withmodule_list
|
||||||
|
|
||||||
assert lim_modid == lim_modimpl_id # doit etre le meme resultat
|
assert lim_modid == lim_modimpl_id # doit etre le meme resultat
|
||||||
|
|
||||||
liimp_sem1 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
liimp_sem1 = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
formsemestre_id=sem1["formsemestre_id"]
|
formsemestre_id=sem1["formsemestre_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -262,16 +258,14 @@ def test_formations(test_client):
|
|||||||
liimp_sem1[0]["module_id"],
|
liimp_sem1[0]["module_id"],
|
||||||
liimp_sem1[1]["module_id"],
|
liimp_sem1[1]["module_id"],
|
||||||
)
|
)
|
||||||
liimp_sem2 = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
liimp_sem2 = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
formsemestre_id=sem2["formsemestre_id"]
|
formsemestre_id=sem2["formsemestre_id"]
|
||||||
)
|
)
|
||||||
assert modt["module_id"] == liimp_sem2[0]["module_id"]
|
assert modt["module_id"] == liimp_sem2[0]["module_id"]
|
||||||
liimp_modid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
liimp_modid = sco_moduleimpl.moduleimpl_withmodule_list(module_id=mod["module_id"])
|
||||||
module_id=mod["module_id"]
|
|
||||||
)
|
|
||||||
assert len(liimp_modid) == 1
|
assert len(liimp_modid) == 1
|
||||||
|
|
||||||
liimp_modimplid = sco_moduleimpl.do_moduleimpl_withmodule_list(
|
liimp_modimplid = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
moduleimpl_id=mi["moduleimpl_id"]
|
moduleimpl_id=mi["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -296,31 +290,29 @@ def test_formations(test_client):
|
|||||||
|
|
||||||
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
||||||
|
|
||||||
li_module = sco_edit_module.do_module_list()
|
li_module = sco_edit_module.module_list()
|
||||||
assert len(li_module) == 4
|
assert len(li_module) == 4
|
||||||
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre
|
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre
|
||||||
# sco_formsemestre_edit.formsemestre_delete_moduleimpls( formsemestre_id=sem2["formsemestre_id"], module_ids_to_del=[modt["module_id"]])
|
# sco_formsemestre_edit.formsemestre_delete_moduleimpls( formsemestre_id=sem2["formsemestre_id"], module_ids_to_del=[modt["module_id"]])
|
||||||
# deuxieme methode de supression d'un module
|
# deuxieme methode de supression d'un module
|
||||||
li_module2 = sco_edit_module.do_module_list()
|
li_module2 = sco_edit_module.module_list()
|
||||||
|
|
||||||
assert len(li_module2) == 3 # verification de la suppression du module
|
assert len(li_module2) == 3 # verification de la suppression du module
|
||||||
|
|
||||||
lim_sem2 = sco_moduleimpl.do_moduleimpl_list(
|
lim_sem2 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem2["formsemestre_id"])
|
||||||
formsemestre_id=sem2["formsemestre_id"]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup
|
assert len(lim_sem2) == 0 # deuxieme vérification si le module s'est bien sup
|
||||||
|
|
||||||
li_mat = sco_edit_matiere.do_matiere_list()
|
li_mat = sco_edit_matiere.matiere_list()
|
||||||
assert len(li_mat) == 4
|
assert len(li_mat) == 4
|
||||||
sco_edit_matiere.do_matiere_delete(oid=matt["matiere_id"]) # on supprime la matiere
|
sco_edit_matiere.do_matiere_delete(oid=matt["matiere_id"]) # on supprime la matiere
|
||||||
li_mat2 = sco_edit_matiere.do_matiere_list()
|
li_mat2 = sco_edit_matiere.matiere_list()
|
||||||
assert len(li_mat2) == 3 # verification de la suppression de la matiere
|
assert len(li_mat2) == 3 # verification de la suppression de la matiere
|
||||||
|
|
||||||
li_ue = sco_edit_ue.do_ue_list()
|
li_ue = sco_edit_ue.ue_list()
|
||||||
assert len(li_ue) == 4
|
assert len(li_ue) == 4
|
||||||
sco_edit_ue.ue_delete(ue_id=uet["ue_id"], dialog_confirmed=True)
|
sco_edit_ue.ue_delete(ue_id=uet["ue_id"], dialog_confirmed=True)
|
||||||
li_ue2 = sco_edit_ue.do_ue_list()
|
li_ue2 = sco_edit_ue.ue_list()
|
||||||
assert len(li_ue2) == 3 # verification de la suppression de l'UE
|
assert len(li_ue2) == 3 # verification de la suppression de l'UE
|
||||||
|
|
||||||
# --- Suppression d'une formation
|
# --- Suppression d'une formation
|
||||||
@ -363,7 +355,7 @@ def test_import_formation(test_client):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
# et les modules
|
# et les modules
|
||||||
modules = sco_edit_module.do_module_list({"formation_id": formation_id})
|
modules = sco_edit_module.module_list({"formation_id": formation_id})
|
||||||
for mod in modules:
|
for mod in modules:
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=mod["module_id"],
|
module_id=mod["module_id"],
|
||||||
|
@ -52,7 +52,7 @@ else
|
|||||||
SN=""
|
SN=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CMD="curl --fail --connect-timeout 5 --silent https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=$mode\&release=${SCODOC_RELEASE}\&sn=${SN}"
|
CMD="curl --fail --connect-timeout 5 --silent https://scodoc.org/scodoc-installmgr/version?mode=$mode\&release=${SCODOC_RELEASE}\&sn=${SN}"
|
||||||
|
|
||||||
SVERSION="$(${CMD})"
|
SVERSION="$(${CMD})"
|
||||||
if [ "$?" == 0 ]; then
|
if [ "$?" == 0 ]; then
|
||||||
|
@ -83,7 +83,7 @@ su -c "(cd $SCODOC_DIR && source venv/bin/activate && pip install wheel && pip i
|
|||||||
|
|
||||||
# ------------
|
# ------------
|
||||||
SCODOC_RELEASE=$(grep SCOVERSION sco_version.py | awk '{ print substr($3, 2, length($3)-2) }')
|
SCODOC_RELEASE=$(grep SCOVERSION sco_version.py | awk '{ print substr($3, 2, length($3)-2) }')
|
||||||
SVERSION=$(curl --silent https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/version?mode=install\&release="$SCODOC_RELEASE")
|
SVERSION=$(curl --silent https://scodoc.org/scodoc-installmgr/version?mode=install\&release="$SCODOC_RELEASE")
|
||||||
echo "$SVERSION" > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
echo "$SVERSION" > "${SCODOC_VERSION_DIR}/scodoc.sn"
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user