forked from ScoDoc/ScoDoc
Affichage et suppression possible de toutes les décisions de jury
This commit is contained in:
parent
fdfffb70be
commit
b026349e74
144
app/api/jury.py
144
app/api/jury.py
@ -12,11 +12,20 @@ from flask_json import as_json
|
||||
from flask_login import login_required
|
||||
|
||||
import app
|
||||
from app.api import api_bp as bp, api_web_bp
|
||||
from app import db, log
|
||||
from app.api import api_bp as bp, api_web_bp, tools
|
||||
from app.decorators import scodoc, permission_required
|
||||
from app.scodoc.sco_exceptions import ScoException
|
||||
from app.but import jury_but_results
|
||||
from app.models import FormSemestre
|
||||
from app.models import (
|
||||
ApcValidationAnnee,
|
||||
ApcValidationRCUE,
|
||||
FormSemestre,
|
||||
Identite,
|
||||
ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
)
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
|
||||
|
||||
@ -36,3 +45,134 @@ def decisions_jury(formsemestre_id: int):
|
||||
return rows
|
||||
else:
|
||||
raise ScoException("non implemente")
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_ue/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@api_web_bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_ue/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@as_json
|
||||
def validation_ue_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
return _validation_ue_delete(etudid, validation_id)
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_formsemestre/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@api_web_bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_formsemestre/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@as_json
|
||||
def validation_formsemestre_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
# c'est la même chose (formations classiques)
|
||||
return _validation_ue_delete(etudid, validation_id)
|
||||
|
||||
|
||||
def _validation_ue_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation (semestres classiques ou UEs)"
|
||||
etud = tools.get_etud(etudid)
|
||||
if etud is None:
|
||||
return "étudiant inconnu", 404
|
||||
validation = ScolarFormSemestreValidation.query.filter_by(
|
||||
id=validation_id, etudid=etudid
|
||||
).first_or_404()
|
||||
log(f"validation_ue_delete: etuid={etudid} {validation}")
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/autorisation_inscription/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@api_web_bp.route(
|
||||
"/etudiant/<int:etudid>/jury/autorisation_inscription/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@as_json
|
||||
def autorisation_inscription_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
etud = tools.get_etud(etudid)
|
||||
if etud is None:
|
||||
return "étudiant inconnu", 404
|
||||
validation = ScolarAutorisationInscription.query.filter_by(
|
||||
id=validation_id, etudid=etudid
|
||||
).first_or_404()
|
||||
log(f"autorisation_inscription_delete: etuid={etudid} {validation}")
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_rcue/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@api_web_bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_rcue/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@as_json
|
||||
def validation_rcue_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
etud = tools.get_etud(etudid)
|
||||
if etud is None:
|
||||
return "étudiant inconnu", 404
|
||||
validation = ApcValidationRCUE.query.filter_by(
|
||||
id=validation_id, etudid=etudid
|
||||
).first_or_404()
|
||||
log(f"validation_ue_delete: etuid={etudid} {validation}")
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_annee_but/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@api_web_bp.route(
|
||||
"/etudiant/<int:etudid>/jury/validation_annee_but/<int:validation_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@login_required
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
@as_json
|
||||
def validation_annee_but_delete(etudid: int, validation_id: int):
|
||||
"Efface cette validation"
|
||||
etud = tools.get_etud(etudid)
|
||||
if etud is None:
|
||||
return "étudiant inconnu", 404
|
||||
validation = ApcValidationAnnee.query.filter_by(
|
||||
id=validation_id, etudid=etudid
|
||||
).first_or_404()
|
||||
log(f"validation_annee_but: etuid={etudid} {validation}")
|
||||
db.session.delete(validation)
|
||||
sco_cache.invalidate_formsemestre_etud(etud)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
66
app/but/jury_edit_manual.py
Normal file
66
app/but/jury_edit_manual.py
Normal file
@ -0,0 +1,66 @@
|
||||
##############################################################################
|
||||
# ScoDoc
|
||||
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""Jury édition manuelle des décisions (correction d'erreurs, parcours hors normes)
|
||||
|
||||
Non spécifique au BUT.
|
||||
"""
|
||||
|
||||
import flask
|
||||
from flask import flash, render_template, url_for
|
||||
from flask import g, request
|
||||
|
||||
from app import db
|
||||
|
||||
from app.models import (
|
||||
ApcValidationAnnee,
|
||||
ApcValidationRCUE,
|
||||
FormSemestre,
|
||||
Identite,
|
||||
UniteEns,
|
||||
ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
)
|
||||
from app.views import ScoData
|
||||
|
||||
|
||||
def jury_delete_manual(etud: Identite):
|
||||
"""Vue (réservée au chef de dept.)
|
||||
présentant *toutes* les décisions de jury concernant cet étudiant
|
||||
et permettant de les supprimer une à une.
|
||||
"""
|
||||
sem_vals = ScolarFormSemestreValidation.query.filter_by(
|
||||
etudid=etud.id, ue_id=None
|
||||
).order_by(ScolarFormSemestreValidation.event_date)
|
||||
ue_vals = (
|
||||
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
|
||||
.join(UniteEns)
|
||||
.order_by(ScolarFormSemestreValidation.event_date, UniteEns.numero)
|
||||
)
|
||||
autorisations = ScolarAutorisationInscription.query.filter_by(
|
||||
etudid=etud.id
|
||||
).order_by(
|
||||
ScolarAutorisationInscription.semestre_id, ScolarAutorisationInscription.date
|
||||
)
|
||||
rcue_vals = (
|
||||
ApcValidationRCUE.query.filter_by(etudid=etud.id)
|
||||
.join(UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id)
|
||||
.order_by(UniteEns.semestre_idx, UniteEns.numero, ApcValidationRCUE.date)
|
||||
)
|
||||
annee_but_vals = ApcValidationAnnee.query.filter_by(etudid=etud.id).order_by(
|
||||
ApcValidationAnnee.ordre, ApcValidationAnnee.date
|
||||
)
|
||||
return render_template(
|
||||
"jury/jury_delete_manual.j2",
|
||||
etud=etud,
|
||||
sem_vals=sem_vals,
|
||||
ue_vals=ue_vals,
|
||||
autorisations=autorisations,
|
||||
rcue_vals=rcue_vals,
|
||||
annee_but_vals=annee_but_vals,
|
||||
sco=ScoData(),
|
||||
title=f"Toutes les décisions de jury enregistrées pour {etud.html_link_fiche()}",
|
||||
)
|
@ -78,6 +78,12 @@ class Identite(db.Model):
|
||||
f"<Etud {self.id}/{self.departement.acronym} {self.nom!r} {self.prenom!r}>"
|
||||
)
|
||||
|
||||
def html_link_fiche(self) -> str:
|
||||
"lien vers la fiche"
|
||||
return f"""<a class="stdlink" href="{
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=self.id)
|
||||
}">{self.nomprenom}</a>"""
|
||||
|
||||
@classmethod
|
||||
def from_request(cls, etudid=None, code_nip=None) -> "Identite":
|
||||
"""Étudiant à partir de l'etudid ou du code_nip, soit
|
||||
|
@ -76,12 +76,14 @@ class ScolarFormSemestreValidation(db.Model):
|
||||
d.pop("_sa_instance_state", None)
|
||||
return d
|
||||
|
||||
def html(self) -> str:
|
||||
def html(self, detail=False) -> str:
|
||||
"Affichage html"
|
||||
if self.ue_id is not None:
|
||||
return f"""Validation de l'UE {self.ue.acronyme}
|
||||
(<b>{self.code}</b>
|
||||
le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")})
|
||||
return f"""Validation de l'UE {self.ue.acronyme} de {self.ue.formation.acronyme}
|
||||
{("émise par " + self.formsemestre.html_link_status())
|
||||
if self.formsemestre else ""}
|
||||
:<b>{self.code}</b>
|
||||
le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")}
|
||||
"""
|
||||
else:
|
||||
return f"""Validation du semestre S{
|
||||
|
@ -312,7 +312,13 @@ def ficheEtud(etudid=None):
|
||||
] = f"""<span class="link_bul_pdf"><a class="stdlink" href="{
|
||||
url_for("notes.formsemestre_inscription_with_modules_form",
|
||||
scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
}">inscrire à un autre semestre</a></span>"""
|
||||
}">inscrire à un autre semestre</a></span>
|
||||
<span class="link_bul_pdf"><a class="stdlink" href="{
|
||||
url_for("notes.jury_delete_manual",
|
||||
scodoc_dept=g.scodoc_dept, etudid=etudid)
|
||||
}">éditer toutes décisions de jury</a></span>
|
||||
"""
|
||||
|
||||
else:
|
||||
info["link_inscrire_ailleurs"] = ""
|
||||
else:
|
||||
|
9
app/static/css/jury_delete_manual.css
Normal file
9
app/static/css/jury_delete_manual.css
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
div.jury_decisions_list div {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.jury_decisions_list form {
|
||||
display: inline-block;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
{% block app_content %}
|
||||
|
||||
{% if not validations %}
|
||||
<p>Aucune validation de jury enregistrée pour <b>{{etud.nom_disp()}}</b> sur
|
||||
<p>Aucune validation de jury enregistrée pour <b>{{etud.html_link_fiche()}}</b> sur
|
||||
<b>l'année {{annee}}</b>
|
||||
de la formation <em>{{ formation.html() }}</em>
|
||||
</p>
|
||||
@ -13,7 +13,7 @@ de la formation <em>{{ formation.html() }}</em>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
<h2>Effacer les décisions de jury pour l'année {{annee}} de {{etud.nom_disp()}} ?</h2>
|
||||
<h2>Effacer les décisions de jury pour l'année {{annee}} de {{etud.html_link_fiche()}} ?</h2>
|
||||
|
||||
<p class="help">Affectera toutes les décisions concernant l'année {{annee}} de la formation,
|
||||
quelle que soit leur origine.</p>
|
||||
|
134
app/templates/jury/jury_delete_manual.j2
Normal file
134
app/templates/jury/jury_delete_manual.j2
Normal file
@ -0,0 +1,134 @@
|
||||
{% extends 'base.j2' %}
|
||||
|
||||
{% block styles %}
|
||||
{{super()}}
|
||||
<link href="{{scu.STATIC_DIR}}/css/jury_delete_manual.css" rel="stylesheet" type="text/css" />
|
||||
{% endblock %}
|
||||
|
||||
{% block app_content %}
|
||||
|
||||
|
||||
<h2>Décisions de jury enregistrées pour {{etud.html_link_fiche()|safe}}</h2>
|
||||
|
||||
<p class="help">
|
||||
Cette page liste toutes les décisions de jury connus de ScoDoc concernant cet étudiant
|
||||
et permet de les effacer une par une.
|
||||
</p>
|
||||
<p class="help">
|
||||
<b>Attention</b>, il vous appartient de vérifier la cohérence du résultat !
|
||||
En principe, <b>l'usage de cette page devrait rester exceptionnel</b>.
|
||||
Aucune annulation n'est ici possible (vous devrez re-saisir les décisions via les
|
||||
pages de saisie de jury habituelles).
|
||||
</p>
|
||||
{% if sem_vals.first() %}
|
||||
<div class="jury_decisions_list jury_decisions_sems">
|
||||
<div>Décisions de semestres</div>
|
||||
<ul>
|
||||
{% for v in sem_vals %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_formsemestre">effacer</button></form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if ue_vals.first() %}
|
||||
<div class="jury_decisions_list jury_decisions_ues">
|
||||
<div>Décisions d'UEs</div>
|
||||
<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>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if rcue_vals.first() %}
|
||||
<div class="jury_decisions_list jury_decisions_rcues">
|
||||
<div>Décisions de RCUE (niveaux de compétences)</div>
|
||||
<ul>
|
||||
{% for v in rcue_vals %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="validation_rcue">effacer</button></form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if annee_but_vals.first() %}
|
||||
<div class="jury_decisions_list jury_decisions_annees_but">
|
||||
<div>Décisions d'années BUT</div>
|
||||
<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>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if autorisations.first() %}
|
||||
<div class="jury_decisions_list jury_decisions_autorisation_inscription">
|
||||
<div>Autorisations d'inscriptions (passages)</div>
|
||||
<ul>
|
||||
{% for v in autorisations %}
|
||||
<li>{{v.html()|safe}}
|
||||
<form><button data-v_id="{{v.id}}" data-type="autorisation_inscription">effacer</button></form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not(
|
||||
sem_vals.first() or sem_ues.first() or sem_rcues.first()
|
||||
or annee_but_vals.first() or autorisations.first())
|
||||
%}
|
||||
<div>
|
||||
<p class="fontred">aucune décision enregistrée</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<a class="stdlink" href="{{etud.html_link_fiche()}}">retour à sa fiche</a>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
{{super()}}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const buttons = document.querySelectorAll('.jury_decisions_list button');
|
||||
|
||||
buttons.forEach(button => {
|
||||
button.addEventListener('click', (event) => {
|
||||
// Handle button click event here
|
||||
event.preventDefault();
|
||||
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`,
|
||||
{
|
||||
method: "POST",
|
||||
}).then(response => {
|
||||
// Handle the response
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
throw new Error('Request failed');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
@ -47,11 +47,12 @@ from app.but import jury_but, jury_but_validation_auto
|
||||
from app.but.forms import jury_but_forms
|
||||
from app.but import jury_but_pv
|
||||
from app.but import jury_but_view
|
||||
from app.but import jury_edit_manual
|
||||
|
||||
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.but_refcomp import ApcNiveau, ApcParcours
|
||||
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
|
||||
@ -2940,6 +2941,18 @@ def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
|
||||
)
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/jury_delete_manual/<int:etudid>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoEtudInscrit)
|
||||
def jury_delete_manual(etudid: int):
|
||||
"""Efface toute les décisions d'une année pour cet étudiant"""
|
||||
etud: Identite = Identite.query.get_or_404(etudid)
|
||||
return jury_edit_manual.jury_delete_manual(etud)
|
||||
|
||||
|
||||
sco_publish(
|
||||
"/formsemestre_lettres_individuelles",
|
||||
sco_pv_forms.formsemestre_lettres_individuelles,
|
||||
|
Loading…
Reference in New Issue
Block a user