forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -10,7 +10,7 @@
|
||||
|
||||
from flask import g, url_for
|
||||
from flask_json import as_json
|
||||
from flask_login import login_required
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
import app
|
||||
from app import db, log
|
||||
@ -29,6 +29,7 @@ from app.models import (
|
||||
)
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_utils import json_error
|
||||
|
||||
|
||||
@bp.route("/formsemestre/<int:formsemestre_id>/decisions_jury")
|
||||
@ -73,7 +74,7 @@ def _news_delete_jury_etud(etud: Identite):
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@permission_required(Permission.ScoView)
|
||||
@as_json
|
||||
def validation_ue_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
@ -90,7 +91,7 @@ def validation_ue_delete(etudid: int, validation_id: int):
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@permission_required(Permission.ScoView)
|
||||
@as_json
|
||||
def validation_formsemestre_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
@ -106,6 +107,24 @@ def _validation_ue_delete(etudid: int, validation_id: int):
|
||||
validation = ScolarFormSemestreValidation.query.filter_by(
|
||||
id=validation_id, etudid=etudid
|
||||
).first_or_404()
|
||||
# Vérification de la permission:
|
||||
# A le droit de supprimer cette validation: le chef de dept ou quelqu'un ayant
|
||||
# le droit de saisir des décisions de jury dans le formsemestre concerné s'il y en a un
|
||||
# (c'est le cas pour les validations de jury, mais pas pour les "antérieures" non
|
||||
# rattachées à un formsemestre)
|
||||
if not g.scodoc_dept: # accès API
|
||||
if not current_user.has_permission(Permission.ScoEtudInscrit):
|
||||
return json_error(403, "validation_delete: non autorise")
|
||||
else:
|
||||
if validation.formsemestre:
|
||||
if (
|
||||
validation.formsemestre.dept_id != g.scodoc_dept_id
|
||||
) or not validation.formsemestre.can_edit_jury():
|
||||
return json_error(403, "validation_delete: non autorise")
|
||||
elif not current_user.has_permission(Permission.ScoEtudInscrit):
|
||||
# Validation non rattachée à un semestre: on doit être chef
|
||||
return json_error(403, "validation_delete: non autorise")
|
||||
|
||||
log(f"validation_ue_delete: etuid={etudid} {validation}")
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
|
@ -8,6 +8,8 @@ from app import log
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.models import CODE_STR_LEN
|
||||
from app.models.events import Scolog
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
class ScolarFormSemestreValidation(db.Model):
|
||||
@ -70,6 +72,14 @@ class ScolarFormSemestreValidation(db.Model):
|
||||
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
|
||||
self.event_date.strftime("%d/%m/%Y")}"""
|
||||
|
||||
def delete(self):
|
||||
"Efface cette validation"
|
||||
log(f"{self.__class__.__name__}.delete({self})")
|
||||
etud = self.etud
|
||||
db.session.delete(self)
|
||||
db.session.commit()
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"as a dict"
|
||||
d = dict(self.__dict__)
|
||||
@ -79,15 +89,22 @@ class ScolarFormSemestreValidation(db.Model):
|
||||
def html(self, detail=False) -> str:
|
||||
"Affichage html"
|
||||
if self.ue_id is not None:
|
||||
return f"""Validation de l'UE <b>{self.ue.acronyme}</b>
|
||||
moyenne = (
|
||||
f", moyenne {scu.fmt_note(self.moy_ue)}/20 "
|
||||
if self.moy_ue is not None
|
||||
else ""
|
||||
)
|
||||
return f"""Validation
|
||||
{'<span class="redboldtext">externe</span>' if self.is_external else ""}
|
||||
de l'UE <b>{self.ue.acronyme}</b>
|
||||
{('parcours <span class="parcours">'
|
||||
+ ", ".join([p.code for p in self.ue.parcours]))
|
||||
+ "</span>"
|
||||
if self.ue.parcours else ""}
|
||||
de {self.ue.formation.acronyme}
|
||||
{("émise par " + self.formsemestre.html_link_status())
|
||||
if self.formsemestre else ""}
|
||||
: <b>{self.code}</b>
|
||||
if self.formsemestre else "externe/antérieure"}
|
||||
: <b>{self.code}</b>{moyenne}
|
||||
le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")}
|
||||
"""
|
||||
else:
|
||||
|
@ -1238,7 +1238,7 @@ def make_menu_autres_operations(
|
||||
"enabled": current_user.has_permission(Permission.ScoImplement),
|
||||
},
|
||||
{
|
||||
"title": "Enregistrer une validation d'UE antérieure",
|
||||
"title": "Gérer les validations d'UEs antérieures",
|
||||
"endpoint": "notes.formsemestre_validate_previous_ue",
|
||||
"args": {
|
||||
"formsemestre_id": formsemestre.id,
|
||||
|
@ -972,7 +972,7 @@ def do_formsemestre_validate_ue(
|
||||
moy_ue = ue_status["moy"] if ue_status else ""
|
||||
args["moy_ue"] = moy_ue
|
||||
log("formsemestre_validate_ue: create %s" % args)
|
||||
if code != None:
|
||||
if code is not None:
|
||||
scolar_formsemestre_validation_create(cnx, args)
|
||||
else:
|
||||
log("formsemestre_validate_ue: code is None, not recording validation")
|
||||
|
@ -502,7 +502,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
||||
else:
|
||||
clone_form = ""
|
||||
bonus_div = """<div id="bonus_description"></div>"""
|
||||
ue_div = """<div id="ue_list_code"></div>"""
|
||||
ue_div = """<div id="ue_list_code" class="sco_box sco_green_bg"></div>"""
|
||||
return (
|
||||
"\n".join(H)
|
||||
+ tf[1]
|
||||
@ -1375,13 +1375,12 @@ def _ue_table_modules(
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def ue_sharing_code(ue_code=None, ue_id=None, hide_ue_id=None):
|
||||
def ue_sharing_code(ue_code: str = "", ue_id: int = None, hide_ue_id: int = None):
|
||||
"""HTML list of UE sharing this code
|
||||
Either ue_code or ue_id may be specified.
|
||||
hide_ue_id spécifie un id à retirer de la liste.
|
||||
"""
|
||||
ue_code = str(ue_code)
|
||||
if ue_id:
|
||||
if ue_id is not None:
|
||||
ue = UniteEns.query.get_or_404(ue_id)
|
||||
if not ue_code:
|
||||
ue_code = ue.ue_code
|
||||
@ -1400,29 +1399,36 @@ def ue_sharing_code(ue_code=None, ue_id=None, hide_ue_id=None):
|
||||
.filter_by(dept_id=g.scodoc_dept_id)
|
||||
)
|
||||
|
||||
if hide_ue_id: # enlève l'ue de depart
|
||||
if hide_ue_id is not None: # enlève l'ue de depart
|
||||
q_ues = q_ues.filter(UniteEns.id != hide_ue_id)
|
||||
|
||||
ues = q_ues.all()
|
||||
msg = " dans les formations du département "
|
||||
if not ues:
|
||||
if ue_id:
|
||||
return (
|
||||
f"""<span class="ue_share">Seule UE avec code {ue_code or '-'}</span>"""
|
||||
)
|
||||
if ue_id is not None:
|
||||
return f"""<span class="ue_share">Seule UE avec code {
|
||||
ue_code if ue_code is not None else '-'}{msg}</span>"""
|
||||
else:
|
||||
return f"""<span class="ue_share">Aucune UE avec code {ue_code or '-'}</span>"""
|
||||
return f"""<span class="ue_share">Aucune UE avec code {
|
||||
ue_code if ue_code is not None else '-'}{msg}</span>"""
|
||||
H = []
|
||||
if ue_id:
|
||||
H.append(
|
||||
f"""<span class="ue_share">Autres UE avec le code {ue_code or '-'}:</span>"""
|
||||
f"""<span class="ue_share">Pour information, autres UEs avec le code {
|
||||
ue_code if ue_code is not None else '-'}{msg}:</span>"""
|
||||
)
|
||||
else:
|
||||
H.append(f"""<span class="ue_share">UE avec le code {ue_code or '-'}:</span>""")
|
||||
H.append(
|
||||
f"""<span class="ue_share">UE avec le code {
|
||||
ue_code if ue_code is not None else '-'}{msg}:</span>"""
|
||||
)
|
||||
H.append("<ul>")
|
||||
for ue in ues:
|
||||
H.append(
|
||||
f"""<li>{ue.acronyme} ({ue.titre}) dans <a class="stdlink"
|
||||
href="{url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)}"
|
||||
f"""<li>{ue.acronyme} ({ue.titre}) dans
|
||||
<a class="stdlink" 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}
|
||||
</li>
|
||||
"""
|
||||
|
@ -517,7 +517,7 @@ def _record_ue_validations_and_coefs(
|
||||
)
|
||||
assert code is None or (note) # si code validant, il faut une note
|
||||
sco_formsemestre_validation.do_formsemestre_validate_previous_ue(
|
||||
formsemestre.id,
|
||||
formsemestre,
|
||||
etud.id,
|
||||
ue.id,
|
||||
note,
|
||||
|
@ -31,8 +31,9 @@ import time
|
||||
|
||||
import flask
|
||||
from flask import url_for, flash, g, request
|
||||
from app.models.etudiants import Identite
|
||||
import sqlalchemy as sa
|
||||
|
||||
from app.models.etudiants import Identite
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app import db, log
|
||||
@ -1081,50 +1082,29 @@ def formsemestre_validation_suppress_etud(formsemestre_id, etudid):
|
||||
) # > suppr. decision jury (peut affecter de plusieurs semestres utilisant UE capitalisée)
|
||||
|
||||
|
||||
def formsemestre_validate_previous_ue(formsemestre_id, etudid):
|
||||
def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite):
|
||||
"""Form. saisie UE validée hors ScoDoc
|
||||
(pour étudiants arrivant avec un UE antérieurement validée).
|
||||
"""
|
||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||
formation: Formation = Formation.query.get_or_404(sem["formation_id"])
|
||||
H = [
|
||||
html_sco_header.sco_header(
|
||||
page_title="Validation UE",
|
||||
javascripts=["js/validate_previous_ue.js"],
|
||||
),
|
||||
'<table style="width: 100%"><tr><td>',
|
||||
"""<h2 class="formsemestre">%s: validation d'une UE antérieure</h2>"""
|
||||
% etud["nomprenom"],
|
||||
(
|
||||
'</td><td style="text-align: right;"><a href="%s">%s</a></td></tr></table>'
|
||||
% (
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid),
|
||||
sco_photos.etud_photo_html(etud, title="fiche de %s" % etud["nom"]),
|
||||
)
|
||||
),
|
||||
f"""<p class="help">Utiliser cette page pour enregistrer une UE validée antérieurement,
|
||||
<em>dans un semestre hors ScoDoc</em>.</p>
|
||||
<p><b>Les UE validées dans ScoDoc sont déjà
|
||||
automatiquement prises en compte</b>. Cette page n'est utile que pour les étudiants ayant
|
||||
suivi un début de cursus dans <b>un autre établissement</b>, ou bien dans un semestre géré
|
||||
<b>sans ScoDoc</b> et qui <b>redouble</b> ce semestre
|
||||
(<em>ne pas utiliser pour les semestres précédents !</em>).
|
||||
</p>
|
||||
<p>Notez que l'UE est validée, avec enregistrement immédiat de la décision et
|
||||
l'attribution des ECTS.</p>
|
||||
<p>On ne peut prendre en compte ici que les UE du cursus <b>{formation.titre}</b></p>
|
||||
""",
|
||||
]
|
||||
formation: Formation = formsemestre.formation
|
||||
|
||||
# Toutes les UE de cette formation sont présentées (même celles des autres semestres)
|
||||
ues = formation.ues.order_by(UniteEns.numero)
|
||||
ue_names = ["Choisir..."] + [f"{ue.acronyme} {ue.titre}" for ue in ues]
|
||||
# Toutes les UEs non bonus de cette formation sont présentées
|
||||
# avec indice de semestre <= semestre courant ou NULL
|
||||
ues = formation.ues.filter(
|
||||
UniteEns.type != UE_SPORT,
|
||||
db.or_(
|
||||
UniteEns.semestre_idx == None,
|
||||
UniteEns.semestre_idx <= formsemestre.semestre_id,
|
||||
),
|
||||
).order_by(UniteEns.semestre_idx, UniteEns.numero)
|
||||
|
||||
ue_names = ["Choisir..."] + [
|
||||
f"""{('S'+str(ue.semestre_idx)+' : ') if ue.semestre_idx is not None else ''
|
||||
}{ue.acronyme} {ue.titre} ({ue.ue_code or ""})"""
|
||||
for ue in ues
|
||||
]
|
||||
ue_ids = [""] + [ue.id for ue in ues]
|
||||
tf = TrivialFormulator(
|
||||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
(
|
||||
form_descr = [
|
||||
("etudid", {"input_type": "hidden"}),
|
||||
("formsemestre_id", {"input_type": "hidden"}),
|
||||
(
|
||||
@ -1137,6 +1117,9 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid):
|
||||
"labels": ue_names,
|
||||
},
|
||||
),
|
||||
]
|
||||
if not formation.is_apc():
|
||||
form_descr.append(
|
||||
(
|
||||
"semestre_id",
|
||||
{
|
||||
@ -1147,7 +1130,9 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid):
|
||||
"allowed_values": [""] + [x for x in range(11)],
|
||||
"labels": ["-"] + list(range(11)),
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
form_descr += [
|
||||
(
|
||||
"date",
|
||||
{
|
||||
@ -1167,49 +1152,137 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid):
|
||||
"title": "Moyenne (/20) obtenue dans cette UE:",
|
||||
},
|
||||
),
|
||||
),
|
||||
cancelbutton="Annuler",
|
||||
]
|
||||
tf = TrivialFormulator(
|
||||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
form_descr,
|
||||
cancelbutton="Revenir au bulletin",
|
||||
submitlabel="Enregistrer validation d'UE",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
X = """
|
||||
<div id="ue_list_etud_validations"><!-- filled by get_etud_ue_cap_html --></div>
|
||||
<div id="ue_list_code"><!-- filled by ue_sharing_code --></div>
|
||||
return f"""
|
||||
{html_sco_header.sco_header(
|
||||
page_title="Validation UE antérieure",
|
||||
javascripts=["js/validate_previous_ue.js"],
|
||||
cssstyles=["css/jury_delete_manual.css"],
|
||||
etudid=etud.id,
|
||||
)}
|
||||
<h2 class="formsemestre">Gestion des validations d'UEs antérieures
|
||||
de {etud.html_link_fiche()}
|
||||
</h2>
|
||||
|
||||
<p class="help">Utiliser cette page pour enregistrer une UE validée antérieurement,
|
||||
<em>dans un semestre hors ScoDoc</em>.</p>
|
||||
<p class="expl"><b>Les UE validées dans ScoDoc sont déjà
|
||||
automatiquement prises en compte</b>. Cette page n'est utile que pour les étudiants ayant
|
||||
suivi un début de cursus dans <b>un autre établissement</b>, ou bien dans un semestre géré
|
||||
<b>sans ScoDoc</b> et qui <b>redouble</b> ce semestre
|
||||
(<em>pour les semestres précédents gérés avec ScoDoc,
|
||||
passer par la page jury normale)</em>).
|
||||
</p>
|
||||
<p>Notez que l'UE est validée (ADM), avec enregistrement immédiat de la décision et
|
||||
l'attribution des ECTS.</p>
|
||||
<p>On ne peut valider ici que les UEs du cursus <b>{formation.titre}</b></p>
|
||||
|
||||
{_get_etud_ue_cap_html(etud, formsemestre)}
|
||||
|
||||
<div class="sco_box">
|
||||
<div class="sco_box_title">
|
||||
Enregistrer une UE antérieure
|
||||
</div>
|
||||
{tf[1]}
|
||||
</div>
|
||||
<div id="ue_list_code" class="sco_box sco_green_bg">
|
||||
<!-- filled by ue_sharing_code -->
|
||||
</div>
|
||||
{check_formation_ues(formation.id)[0]}
|
||||
{html_sco_header.sco_footer()}
|
||||
"""
|
||||
warn, ue_multiples = check_formation_ues(formation.id)
|
||||
return "\n".join(H) + tf[1] + X + warn + html_sco_header.sco_footer()
|
||||
elif tf[0] == -1:
|
||||
return flask.redirect(
|
||||
scu.NotesURL()
|
||||
+ "/formsemestre_status?formsemestre_id="
|
||||
+ str(formsemestre_id)
|
||||
|
||||
dest_url = url_for(
|
||||
"notes.formsemestre_validate_previous_ue",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id,
|
||||
)
|
||||
else:
|
||||
if tf[2]["semestre_id"]:
|
||||
if tf[0] == -1:
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_bulletinetud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id,
|
||||
)
|
||||
)
|
||||
if tf[2].get("semestre_id"):
|
||||
semestre_id = int(tf[2]["semestre_id"])
|
||||
else:
|
||||
semestre_id = None
|
||||
|
||||
do_formsemestre_validate_previous_ue(
|
||||
formsemestre_id,
|
||||
etudid,
|
||||
formsemestre,
|
||||
etud.id,
|
||||
tf[2]["ue_id"],
|
||||
tf[2]["moy_ue"],
|
||||
tf[2]["date"],
|
||||
semestre_id=semestre_id,
|
||||
)
|
||||
flash("Validation d'UE enregistrée")
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_bulletinetud",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
etudid=etudid,
|
||||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def _get_etud_ue_cap_html(etud: Identite, formsemestre: FormSemestre) -> str:
|
||||
"""HTML listant les validations d'UEs pour cet étudiant dans des formations de même
|
||||
code que celle du formsemestre indiqué.
|
||||
"""
|
||||
validations: list[ScolarFormSemestreValidation] = (
|
||||
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
|
||||
.join(UniteEns)
|
||||
.join(Formation)
|
||||
.filter_by(formation_code=formsemestre.formation.formation_code)
|
||||
.order_by(
|
||||
sa.desc(UniteEns.semestre_idx),
|
||||
UniteEns.acronyme,
|
||||
sa.desc(ScolarFormSemestreValidation.event_date),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
if not validations:
|
||||
return ""
|
||||
H = [
|
||||
f"""<div class="sco_box sco_lightgreen_bg ue_list_etud_validations">
|
||||
<div class="sco_box_title">Validations d'UEs dans cette formation</div>
|
||||
<div class="help">Liste de toutes les UEs validées par {etud.html_link_fiche()},
|
||||
sur des semestres ou déclarées comme "antérieures" (externes).
|
||||
</div>
|
||||
<ul>"""
|
||||
]
|
||||
for validation in validations:
|
||||
if validation.formsemestre_id is None:
|
||||
origine = " enregistrée d'un parcours antérieur (hors ScoDoc)"
|
||||
else:
|
||||
origine = f", du semestre {formsemestre.html_link_status()}"
|
||||
if validation.semestre_id is not None:
|
||||
origine += f" (<b>S{validation.semestre_id}</b>)"
|
||||
H.append(
|
||||
f"""
|
||||
<li>{validation.html()}
|
||||
<form class="inline-form">
|
||||
<button
|
||||
data-v_id="{validation.id}" data-type="validation_ue" data-etudid="{etud.id}"
|
||||
>effacer</button>
|
||||
</form>
|
||||
</li>
|
||||
""",
|
||||
)
|
||||
H.append("</ul></div>")
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def do_formsemestre_validate_previous_ue(
|
||||
formsemestre_id,
|
||||
formsemestre: FormSemestre,
|
||||
etudid,
|
||||
ue_id,
|
||||
moy_ue,
|
||||
@ -1222,21 +1295,20 @@ def do_formsemestre_validate_previous_ue(
|
||||
Si le coefficient est spécifié, modifie le coefficient de
|
||||
cette UE (utile seulement pour les semestres extérieurs).
|
||||
"""
|
||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
ue: UniteEns = UniteEns.query.get_or_404(ue_id)
|
||||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
if ue_coefficient != None:
|
||||
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
||||
cnx, formsemestre_id, ue_id, ue_coefficient
|
||||
cnx, formsemestre.id, ue_id, ue_coefficient
|
||||
)
|
||||
else:
|
||||
sco_formsemestre.do_formsemestre_uecoef_delete(cnx, formsemestre_id, ue_id)
|
||||
sco_formsemestre.do_formsemestre_uecoef_delete(cnx, formsemestre.id, ue_id)
|
||||
sco_cursus_dut.do_formsemestre_validate_ue(
|
||||
cnx,
|
||||
nt,
|
||||
formsemestre_id, # "importe" cette UE dans le semestre (new 3/2015)
|
||||
formsemestre.id, # "importe" cette UE dans le semestre (new 3/2015)
|
||||
etudid,
|
||||
ue_id,
|
||||
code,
|
||||
@ -1274,62 +1346,6 @@ def _invalidate_etud_formation_caches(etudid, formation_id):
|
||||
) # > modif decision UE (inval tous semestres avec cet etudiant, ok mais conservatif)
|
||||
|
||||
|
||||
def get_etud_ue_cap_html(etudid, formsemestre_id, ue_id):
|
||||
"""Ramene bout de HTML pour pouvoir supprimer une validation de cette UE"""
|
||||
valids = ndb.SimpleDictFetch(
|
||||
"""SELECT SFV.*
|
||||
FROM scolar_formsemestre_validation SFV
|
||||
WHERE ue_id=%(ue_id)s
|
||||
AND etudid=%(etudid)s""",
|
||||
{"etudid": etudid, "ue_id": ue_id},
|
||||
)
|
||||
if not valids:
|
||||
return ""
|
||||
H = [
|
||||
'<div class="existing_valids"><span>Validations existantes pour cette UE:</span><ul>'
|
||||
]
|
||||
for valid in valids:
|
||||
valid["event_date"] = ndb.DateISOtoDMY(valid["event_date"])
|
||||
if valid["moy_ue"] != None:
|
||||
valid["m"] = ", moyenne %(moy_ue)g/20" % valid
|
||||
else:
|
||||
valid["m"] = ""
|
||||
if valid["formsemestre_id"]:
|
||||
sem = sco_formsemestre.get_formsemestre(valid["formsemestre_id"])
|
||||
valid["s"] = ", du semestre %s" % sem["titreannee"]
|
||||
else:
|
||||
valid["s"] = " enregistrée d'un parcours antérieur (hors ScoDoc)"
|
||||
if valid["semestre_id"]:
|
||||
valid["s"] += " (<b>S%d</b>)" % valid["semestre_id"]
|
||||
valid["ds"] = formsemestre_id
|
||||
H.append(
|
||||
'<li>%(code)s%(m)s%(s)s, le %(event_date)s <a class="stdlink" href="etud_ue_suppress_validation?etudid=%(etudid)s&ue_id=%(ue_id)s&formsemestre_id=%(ds)s" title="supprime cette validation">effacer</a></li>'
|
||||
% valid
|
||||
)
|
||||
H.append("</ul></div>")
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def etud_ue_suppress_validation(etudid, formsemestre_id, ue_id):
|
||||
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
||||
log("etud_ue_suppress_validation( %s, %s, %s)" % (etudid, formsemestre_id, ue_id))
|
||||
cnx = ndb.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"DELETE FROM scolar_formsemestre_validation WHERE etudid=%(etudid)s and ue_id=%(ue_id)s",
|
||||
{"etudid": etudid, "ue_id": ue_id},
|
||||
)
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||
_invalidate_etud_formation_caches(etudid, sem["formation_id"])
|
||||
|
||||
return flask.redirect(
|
||||
scu.NotesURL()
|
||||
+ "/formsemestre_validate_previous_ue?etudid=%s&formsemestre_id=%s"
|
||||
% (etudid, formsemestre_id)
|
||||
)
|
||||
|
||||
|
||||
def check_formation_ues(formation_id):
|
||||
"""Verifie que les UE d'une formation sont chacune utilisée dans un seul semestre_id
|
||||
Si ce n'est pas le cas, c'est probablement (mais pas forcément) une erreur de
|
||||
|
@ -4,10 +4,6 @@ div.jury_decisions_list div {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.jury_decisions_list form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
span.parcours {
|
||||
color:blueviolet;
|
||||
}
|
||||
|
@ -76,16 +76,16 @@ div.flashes {
|
||||
}
|
||||
|
||||
div.alert {
|
||||
/*
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px; */
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
font-size: 200%;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
div.alert-info {
|
||||
color: #0019d7;
|
||||
background-color: #68f36d;
|
||||
border-color: #0a8d0c;
|
||||
color: #208d3b;
|
||||
background-color: #fffd97;
|
||||
border-color: #208d3b;
|
||||
}
|
||||
|
||||
div.alert-error {
|
||||
@ -94,6 +94,9 @@ div.alert-error {
|
||||
border-color: #8d0a17;
|
||||
}
|
||||
|
||||
form.inline-form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div.tab-content {
|
||||
margin-top: 10px;
|
||||
@ -1112,9 +1115,11 @@ a.discretelink:hover {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.expl, .help {
|
||||
max-width: var(--sco-content-max-width);
|
||||
}
|
||||
.help {
|
||||
font-style: italic;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.help_important {
|
||||
@ -1122,13 +1127,28 @@ a.discretelink:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.sco_help {
|
||||
div.sco_box, div.sco_help {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 0px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid grey;
|
||||
max-width: var(--sco-content-max-width);
|
||||
}
|
||||
div.sco_help {
|
||||
font-style: italic;
|
||||
max-width: 800px;
|
||||
background-color: rgb(209, 255, 214);
|
||||
}
|
||||
div.sco_box_title {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.sco_green_bg {
|
||||
background-color: rgb(155, 218, 155);
|
||||
}
|
||||
.sco_lightgreen_bg {
|
||||
background-color: rgb(209, 255, 214);
|
||||
}
|
||||
|
||||
@ -2504,13 +2524,7 @@ input.sco_tag_checkbox {
|
||||
}
|
||||
|
||||
div#ue_list_code {
|
||||
background-color: rgb(155, 218, 155);
|
||||
padding: 10px;
|
||||
border: 1px solid blue;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
ul.notes_module_list {
|
||||
@ -2596,16 +2610,6 @@ div#ue_list_modules {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
div#ue_list_etud_validations {
|
||||
background-color: rgb(220, 250, 220);
|
||||
padding-left: 4px;
|
||||
padding-bottom: 1px;
|
||||
margin: 3ex;
|
||||
}
|
||||
|
||||
div#ue_list_etud_validations span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.ue_share {
|
||||
font-weight: bold;
|
||||
|
@ -1,31 +1,43 @@
|
||||
// Affiche et met a jour la liste des UE partageant le meme code
|
||||
|
||||
$().ready(function () {
|
||||
update_ue_validations();
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
update_ue_list();
|
||||
$("#tf_ue_id").bind("change", update_ue_list);
|
||||
$("#tf_ue_id").bind("change", update_ue_validations);
|
||||
});
|
||||
|
||||
const buttons = document.querySelectorAll(".ue_list_etud_validations button");
|
||||
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", (event) => {
|
||||
// Handle button click event here
|
||||
event.preventDefault();
|
||||
const etudid = event.target.dataset.etudid;
|
||||
const v_id = event.target.dataset.v_id;
|
||||
const validation_type = event.target.dataset.type;
|
||||
if (confirm("Supprimer cette validation ?")) {
|
||||
fetch(
|
||||
`${SCO_URL}/../api/etudiant/${etudid}/jury/${validation_type}/${v_id}/delete`,
|
||||
{
|
||||
method: "POST",
|
||||
}
|
||||
).then((response) => {
|
||||
// Handle the response
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
throw new Error("Request failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function update_ue_list() {
|
||||
var ue_id = $("#tf_ue_id")[0].value;
|
||||
if (ue_id) {
|
||||
var query = "ue_sharing_code?ue_id=" + ue_id;
|
||||
$.get(query, '', function (data) {
|
||||
var query = SCO_URL + "/Notes/ue_sharing_code?ue_id=" + ue_id;
|
||||
$.get(query, "", function (data) {
|
||||
$("#ue_list_code").html(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function update_ue_validations() {
|
||||
var etudid = $("#tf_etudid")[0].value;
|
||||
var ue_id = $("#tf_ue_id")[0].value;
|
||||
var formsemestre_id = $("#tf_formsemestre_id")[0].value;
|
||||
if (ue_id) {
|
||||
var query = SCO_URL + "/Notes/get_etud_ue_cap_html?ue_id=" + ue_id + "&etudid=" + etudid + "&formsemestre_id=" + formsemestre_id;
|
||||
$.get(query, '', function (data) {
|
||||
$("#ue_list_etud_validations").html(data);
|
||||
});
|
||||
}
|
||||
}
|
@ -26,7 +26,10 @@ pages de saisie de jury habituelles).
|
||||
<ul>
|
||||
{% for v in sem_vals %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_formsemestre">effacer</button></form>
|
||||
<form>
|
||||
<button
|
||||
data-v_id="{{v.id}}" data-type="validation_formsemestre" data-etudid="{{etud.id}}"
|
||||
>effacer</button></form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -39,7 +42,10 @@ pages de saisie de jury habituelles).
|
||||
<ul>
|
||||
{% for v in ue_vals %}
|
||||
<li>{{v.html(detail=True)|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_ue">effacer</button></form>
|
||||
<form class="inline-form">
|
||||
<button data-v_id="{{v.id}}" data-type="validation_ue" data-etudid="{{etud.id"}}
|
||||
>effacer</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -52,7 +58,10 @@ pages de saisie de jury habituelles).
|
||||
<ul>
|
||||
{% for v in rcue_vals %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_rcue">effacer</button></form>
|
||||
<form>
|
||||
<button data-v_id="{{v.id}}" data-type="validation_rcue" data-etudid="{{etud.id}}"
|
||||
>effacer</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -65,7 +74,10 @@ pages de saisie de jury habituelles).
|
||||
<ul>
|
||||
{% for v in annee_but_vals %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_annee_but">effacer</button></form>
|
||||
<form>
|
||||
<button data-v_id="{{v.id}}" data-type="validation_annee_but" data-etudid="{{etud.id}}"
|
||||
>effacer</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -78,7 +90,10 @@ pages de saisie de jury habituelles).
|
||||
<ul>
|
||||
{% for v in autorisations %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="autorisation_inscription">effacer</button></form>
|
||||
<form>
|
||||
<button data-v_id="{{v.id}}" data-type="autorisation_inscription" data-etudid="{{etud.id}}"
|
||||
>effacer</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -113,10 +128,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
button.addEventListener('click', (event) => {
|
||||
// Handle button click event here
|
||||
event.preventDefault();
|
||||
const etudid = event.target.dataset.etudid;
|
||||
const v_id = event.target.dataset.v_id;
|
||||
const validation_type = event.target.dataset.type;
|
||||
if (confirm("Supprimer cette validation ?")) {
|
||||
fetch(`${SCO_URL}/../api/etudiant/{{etud.id}}/jury/${validation_type}/${v_id}/delete`,
|
||||
fetch(`${SCO_URL}/../api/etudiant/${etudid}/jury/${validation_type}/${v_id}/delete`,
|
||||
{
|
||||
method: "POST",
|
||||
}).then(response => {
|
||||
|
@ -56,17 +56,22 @@ from app.but.forms import jury_but_forms
|
||||
|
||||
from app.comp import jury, res_sem
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import Formation, ScolarAutorisationInscription, ScolarNews, Scolog
|
||||
from app.models import (
|
||||
Formation,
|
||||
ScolarFormSemestreValidation,
|
||||
ScolarAutorisationInscription,
|
||||
ScolarNews,
|
||||
Scolog,
|
||||
)
|
||||
from app.models.but_refcomp import ApcNiveau
|
||||
from app.models.config import ScoDocSiteConfig
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.formsemestre import FormSemestre
|
||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
||||
from app.models.formsemestre import FormSemestreUEComputationExpr
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.models.modules import Module
|
||||
from app.models.ues import DispenseUE, UniteEns
|
||||
from app.scodoc.sco_exceptions import ScoFormationConflict, ScoPermissionDenied
|
||||
from app.tables import jury_recap
|
||||
from app.views import notes_bp as bp
|
||||
|
||||
from app.decorators import (
|
||||
@ -483,7 +488,21 @@ def ue_set_internal(ue_id):
|
||||
)
|
||||
|
||||
|
||||
sco_publish("/ue_sharing_code", sco_edit_ue.ue_sharing_code, Permission.ScoView)
|
||||
@bp.route("/ue_sharing_code")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@scodoc7func
|
||||
def ue_sharing_code():
|
||||
ue_code = request.args.get("ue_code")
|
||||
ue_id = request.args.get("ue_id")
|
||||
hide_ue_id = request.args.get("hide_ue_id")
|
||||
return sco_edit_ue.ue_sharing_code(
|
||||
ue_code=ue_code,
|
||||
ue_id=None if ue_id is None else int(ue_id),
|
||||
hide_ue_id=None if hide_ue_id is None else int(hide_ue_id),
|
||||
)
|
||||
|
||||
|
||||
sco_publish(
|
||||
"/edit_ue_set_code_apogee",
|
||||
sco_edit_ue.edit_ue_set_code_apogee,
|
||||
@ -2621,10 +2640,12 @@ def formsemestre_validation_auto_but(formsemestre_id: int = None):
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/formsemestre_validate_previous_ue", methods=["GET", "POST"])
|
||||
@bp.route(
|
||||
"/formsemestre_validate_previous_ue/<int:formsemestre_id>/<int:etudid>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@scodoc7func
|
||||
def formsemestre_validate_previous_ue(formsemestre_id, etudid=None):
|
||||
"Form. saisie UE validée hors ScoDoc"
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
@ -2636,9 +2657,15 @@ def formsemestre_validate_previous_ue(formsemestre_id, etudid=None):
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
etud: Identite = (
|
||||
Identite.query.filter_by(id=etudid)
|
||||
.join(FormSemestreInscription)
|
||||
.filter_by(formsemestre_id=formsemestre_id)
|
||||
.first_or_404()
|
||||
)
|
||||
|
||||
return sco_formsemestre_validation.formsemestre_validate_previous_ue(
|
||||
formsemestre_id, etudid
|
||||
formsemestre, etud
|
||||
)
|
||||
|
||||
|
||||
@ -2671,34 +2698,6 @@ def formsemestre_ext_edit_ue_validations(formsemestre_id, etudid=None):
|
||||
)
|
||||
|
||||
|
||||
sco_publish(
|
||||
"/get_etud_ue_cap_html",
|
||||
sco_formsemestre_validation.get_etud_ue_cap_html,
|
||||
Permission.ScoView,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/etud_ue_suppress_validation")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@scodoc7func
|
||||
def etud_ue_suppress_validation(etudid, formsemestre_id, ue_id):
|
||||
"""Suppress a validation (ue_id, etudid) and redirect to formsemestre"""
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if not formsemestre.can_edit_jury():
|
||||
raise ScoPermissionDenied(
|
||||
dest_url=url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
|
||||
return sco_formsemestre_validation.etud_ue_suppress_validation(
|
||||
etudid, formsemestre_id, ue_id
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/formsemestre_validation_auto")
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
|
Loading…
Reference in New Issue
Block a user