Attention: {len(deca.niveaux_competences)}
- niveaux mais {len(deca.decisions_rcue_by_niveau)} regroupements RCUE.
"""
- if (deca.parcour is None) and len(formsemestre.parcours) > 0:
- warning += (
- """L'étudiant n'est pas inscrit à un parcours.
"""
- )
- if formsemestre.date_fin - datetime.date.today() > datetime.timedelta(days=12):
- # encore loin de la fin du semestre de départ de ce jury ?
- warning += f"""Le semestre S{formsemestre.semestre_id}
- terminera le {formsemestre.date_fin.strftime(scu.DATE_FMT)} :
- êtes-vous certain de vouloir enregistrer une décision de jury ?
-
"""
-
- if deca.formsemestre_impair:
- inscription = deca.formsemestre_impair.etuds_inscriptions.get(etud.id)
- if (not inscription) or inscription.etat != scu.INSCRIT:
- etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
- warning += f"""Impossible de statuer sur cet étudiant:
- il a des notes dans des évaluations qui seront débloquées plus tard:
- voir {", ".join(links_evals)}
- """
-
- if warning:
- warning = f"""
{warning}
"""
- H.append(
- f"""
-
-
-
-
Jury BUT{deca.annee_but}
- - Parcours {(deca.parcour.libelle if deca.parcour else False) or "non spécifié"}
- - {deca.annee_scolaire_str()}
-
{etud.html_link_fiche()}
-
-
-
- {warning}
-
-
-
")
-
- # Affichage cursus BUT
- but_cursus = cursus_but.EtudCursusBUT(etud, deca.formsemestre.formation)
- H += [
- """
-
Niveaux de compétences enregistrés :
- """,
- render_template(
- "but/cursus_etud.j2",
- cursus=but_cursus,
- scu=scu,
- ),
- "
",
- ]
- H.append(
- render_template(
- "but/documentation_codes_jury.j2",
- nom_univ=f"""Export {sco_preferences.get_preference("InstituteName")
- or sco_preferences.get_preference("UnivName")
- or "Apogée"}""",
- codes=ScoDocSiteConfig.get_codes_apo_dict(),
- )
- )
- H.append(
- f"""
- {scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE capitalisées (note > 10)
- lors d'une année précédente peuvent être prise en compte pour former
- un RCUE (associé à un niveau de compétence du BUT).
-
- """
- )
- return "\n".join(H) + html_sco_header.sco_footer()
-
-
-@bp.route(
- "/formsemestre_validation_auto_but/
", methods=["GET", "POST"]
-)
-@scodoc
-@permission_required(Permission.ScoView)
-def formsemestre_validation_auto_but(formsemestre_id: int = None):
- "Saisie automatique des décisions de jury BUT"
- 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,
- )
- )
- if not formsemestre.formation.is_apc():
- raise ScoValueError(
- "formsemestre_validation_auto_but est réservé aux formations APC"
- )
-
- formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
- form = jury_but_forms.FormSemestreValidationAutoBUTForm()
- if request.method == "POST":
- if not form.cancel.data:
- nb_etud_modif, _ = (
- jury_but_validation_auto.formsemestre_validation_auto_but(formsemestre)
- )
- flash(f"Décisions enregistrées ({nb_etud_modif} étudiants modifiés)")
- return redirect(
- url_for(
- "notes.formsemestre_recapcomplet",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- mode_jury=1,
- )
- )
- # Avertissement si formsemestre impair
- formsemestres_suspects = {}
- if formsemestre.semestre_id % 2:
- _, decas = jury_but_validation_auto.formsemestre_validation_auto_but(
- formsemestre, dry_run=True
- )
- # regarde si il y a des semestres pairs postérieurs qui ne soient pas bloqués
- formsemestres_suspects = {
- deca.formsemestre_pair.id: deca.formsemestre_pair
- for deca in decas
- if deca.formsemestre_pair
- and deca.formsemestre_pair.date_debut > formsemestre.date_debut
- and not deca.formsemestre_pair.block_moyennes
- }
-
- return render_template(
- "but/formsemestre_validation_auto_but.j2",
- form=form,
- formsemestres_suspects=formsemestres_suspects,
- sco=ScoData(formsemestre=formsemestre),
- title="Calcul automatique jury BUT",
- )
-
-
-@bp.route(
- "/formsemestre_validate_previous_ue//",
- methods=["GET", "POST"],
-)
-@scodoc
-@permission_required(Permission.ScoView)
-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)
- if not formsemestre.can_edit_jury():
- raise ScoPermissionDenied(
- dest_url=url_for(
- "notes.formsemestre_status",
- scodoc_dept=g.scodoc_dept,
- 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, etud
- )
-
-
sco_publish(
"/formsemestre_ext_create_form",
sco_formsemestre_exterieurs.formsemestre_ext_create_form,
@@ -2727,150 +2196,6 @@ sco_publish(
)
-@bp.route("/formsemestre_ext_edit_ue_validations", methods=["GET", "POST"])
-@scodoc
-@permission_required(Permission.ScoView)
-@scodoc7func
-def formsemestre_ext_edit_ue_validations(formsemestre_id, etudid=None):
- "Form. edition UE semestre extérieur"
- 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_exterieurs.formsemestre_ext_edit_ue_validations(
- formsemestre_id, etudid
- )
-
-
-@bp.route("/formsemestre_validation_auto")
-@scodoc
-@permission_required(Permission.ScoView)
-@scodoc7func
-def formsemestre_validation_auto(formsemestre_id):
- "Formulaire saisie automatisee des decisions d'un semestre"
- formsemestre: FormSemestre = FormSemestre.query.filter_by(
- id=formsemestre_id, dept_id=g.scodoc_dept_id
- ).first_or_404()
- if not formsemestre.can_edit_jury():
- raise ScoPermissionDenied(
- dest_url=url_for(
- "notes.formsemestre_status",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- )
- )
-
- if formsemestre.formation.is_apc():
- return redirect(
- url_for(
- "notes.formsemestre_validation_auto_but",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre.id,
- )
- )
- return sco_formsemestre_validation.formsemestre_validation_auto(formsemestre_id)
-
-
-@bp.route("/do_formsemestre_validation_auto")
-@scodoc
-@permission_required(Permission.ScoView)
-@scodoc7func
-def do_formsemestre_validation_auto(formsemestre_id):
- "Formulaire saisie automatisee des decisions d'un semestre"
- 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.do_formsemestre_validation_auto(formsemestre_id)
-
-
-@bp.route("/formsemestre_validation_suppress_etud", methods=["GET", "POST"])
-@scodoc
-@permission_required(Permission.ScoView)
-@scodoc7func
-def formsemestre_validation_suppress_etud(
- formsemestre_id, etudid, dialog_confirmed=False
-):
- """Suppression des décisions de jury pour un étudiant."""
- 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,
- )
- )
- etud = Identite.get_etud(etudid)
- if formsemestre.formation.is_apc():
- next_url = url_for(
- "scolar.fiche_etud",
- scodoc_dept=g.scodoc_dept,
- etudid=etudid,
- )
- else:
- next_url = url_for(
- "notes.formsemestre_validation_etud_form",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- etudid=etudid,
- )
- if not dialog_confirmed:
- d = sco_bulletins_json.dict_decision_jury(
- etud, formsemestre, with_decisions=True
- )
-
- descr_ues = [f"{u['acronyme']}: {u['code']}" for u in d.get("decision_ue", [])]
- dec_annee = d.get("decision_annee")
- if dec_annee:
- descr_annee = dec_annee.get("code", "-")
- else:
- descr_annee = "-"
-
- existing = f"""
-
- - Semestre : {d.get("decision", {"code":"-"})['code'] or "-"}
- - Année BUT: {descr_annee}
- - UEs : {", ".join(descr_ues)}
- - RCUEs: {len(d.get("decision_rcue", []))} décisions
- - Autorisations: {descr_autorisations(ScolarAutorisationInscription.query.filter_by(origin_formsemestre_id=formsemestre_id,
- etudid=etudid))}
-
- """
- return scu.confirm_dialog(
- f"""Confirmer la suppression des décisions du semestre
- {formsemestre.titre_mois()} pour {etud.nomprenom}
-
- Cette opération est irréversible.
-
- {existing}
-
- """,
- OK="Supprimer",
- dest_url="",
- cancel_url=next_url,
- parameters={"etudid": etudid, "formsemestre_id": formsemestre_id},
- )
-
- sco_formsemestre_validation.formsemestre_validation_suppress_etud(
- formsemestre_id, etudid
- )
- flash("Décisions supprimées")
- return flask.redirect(next_url)
-
-
# ------------- PV de JURY et archives
sco_publish(
"/formsemestre_pvjury", sco_pv_forms.formsemestre_pvjury, Permission.ScoView
@@ -2878,192 +2203,6 @@ sco_publish(
sco_publish("/pvjury_page_but", jury_but_pv.pvjury_page_but, Permission.ScoView)
-
-@bp.route("/formsemestre_saisie_jury")
-@scodoc
-@permission_required(Permission.ScoView)
-@scodoc7func
-def formsemestre_saisie_jury(formsemestre_id: int, selected_etudid: int = None):
- """Page de saisie: liste des étudiants et lien vers page jury
- sinon, redirect vers page recap en mode jury
- """
- return redirect(
- url_for(
- "notes.formsemestre_recapcomplet",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- mode_jury=1,
- )
- )
-
-
-@bp.route(
- "/formsemestre_jury_erase/",
- methods=["GET", "POST"],
- defaults={"etudid": None},
-)
-@bp.route(
- "/formsemestre_jury_erase//",
- methods=["GET", "POST"],
-)
-@scodoc
-@permission_required(Permission.ScoView)
-def formsemestre_jury_erase(formsemestre_id: int, etudid: int = None):
- """Supprime toutes les décisions de jury (classique ou BUT) pour cette année.
- Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
- En BUT, si only_one_sem n'efface que pour le formsemestre indiqué, pas les deux de l'année.
- En classique, n'affecte que les décisions issues de ce formsemestre.
- """
- only_one_sem = int(request.args.get("only_one_sem") or False)
- formsemestre: FormSemestre = FormSemestre.query.filter_by(
- id=formsemestre_id, dept_id=g.scodoc_dept_id
- ).first_or_404()
- if not formsemestre.can_edit_jury():
- raise ScoPermissionDenied(
- dest_url=url_for(
- "notes.formsemestre_status",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- )
- )
- is_apc = formsemestre.formation.is_apc()
- if etudid is None:
- etud = None
- etuds = formsemestre.get_inscrits(include_demdef=True)
- dest_url = url_for(
- "notes.formsemestre_recapcomplet",
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- mode_jury=1,
- )
- else:
- etud = Identite.get_etud(etudid)
- etuds = [etud]
- endpoint = (
- "notes.formsemestre_validation_but"
- if is_apc
- else "notes.formsemestre_validation_etud_form"
- )
- dest_url = url_for(
- endpoint,
- scodoc_dept=g.scodoc_dept,
- formsemestre_id=formsemestre_id,
- etudid=etudid,
- )
- if request.method == "POST":
- with sco_cache.DeferredSemCacheManager():
- for etud in etuds:
- if is_apc:
- deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
- deca.erase(only_one_sem=only_one_sem)
- else:
- sco_formsemestre_validation.formsemestre_validation_suppress_etud(
- formsemestre.id, etud.id
- )
- log(f"formsemestre_jury_erase({formsemestre_id}, {etud.id})")
- flash(
- (
- "décisions de jury du semestre effacées"
- if (only_one_sem or is_apc)
- else "décisions de jury des semestres de l'année BUT effacées"
- )
- + f" pour {len(etuds)} étudiant{'s' if len(etuds) > 1 else ''}"
- )
- return redirect(dest_url)
-
- return render_template(
- "confirm_dialog.j2",
- title=f"""Effacer les validations de jury {
- ("de " + etud.nomprenom)
- if etud
- else ("des " + str(len(etuds)) + " étudiants inscrits dans ce semestre")
- } ?""",
- explanation=(
- (
- f"""Les validations d'UE et autorisations de passage
- du semestre S{formsemestre.semestre_id} seront effacées."""
- if (only_one_sem or is_apc)
- else """Les validations de toutes les UE, RCUE (compétences) et année
- issues de cette année scolaire seront effacées.
- """
- )
- + """
- Les décisions des années scolaires précédentes ne seront pas modifiées.
- """
- + """
- Efface aussi toutes les validations concernant l'année BUT de ce semestre,
- même si elles ont été acquises ailleurs, ainsi que les validations de DUT en 120 ECTS
- obtenues après BUT1/BUT2.
-
- """
- if is_apc
- else ""
- + """
- Cette opération est irréversible !
- A n'utiliser que dans des cas exceptionnels, vérifiez bien tous les étudiants ensuite.
-
- """
- ),
- cancel_url=dest_url,
- )
-
-
-@bp.route(
- "/erase_decisions_annee_formation///",
- methods=["GET", "POST"],
-)
-@scodoc
-@permission_required(Permission.EtudInscrit)
-def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
- """Efface toute les décisions d'une année pour cet étudiant"""
- etud: Identite = Identite.query.get_or_404(etudid)
- formation: Formation = Formation.query.filter_by(
- id=formation_id, dept_id=g.scodoc_dept_id
- ).first_or_404()
- if request.method == "POST":
- jury.erase_decisions_annee_formation(etud, formation, annee, delete=True)
- flash("Décisions de jury effacées")
- return redirect(
- url_for(
- "scolar.fiche_etud",
- scodoc_dept=g.scodoc_dept,
- etudid=etud.id,
- )
- )
- validations = jury.erase_decisions_annee_formation(etud, formation, annee)
- formsemestre_origine_id = request.args.get("formsemestre_id")
- formsemestre_origine = (
- FormSemestre.query.get_or_404(formsemestre_origine_id)
- if formsemestre_origine_id
- else None
- )
- return render_template(
- "jury/erase_decisions_annee_formation.j2",
- annee=annee,
- cancel_url=url_for(
- "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
- ),
- etud=etud,
- formation=formation,
- formsemestre_origine=formsemestre_origine,
- validations=validations,
- sco=ScoData(),
- title=f"Effacer décisions de jury {etud.nom} - année {annee}",
- )
-
-
-@bp.route(
- "/jury_delete_manual/",
- methods=["GET", "POST"],
-)
-@scodoc
-@permission_required(Permission.EtudInscrit)
-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,
@@ -3306,12 +2445,12 @@ def check_sem_integrity(formsemestre_id, fix=False):
if not bad_ue and not bad_sem:
H.append("Aucun problème à signaler !
")
else:
- log("check_sem_integrity: problem detected: formations_set=%s" % formations_set)
+ log(f"check_sem_integrity: problem detected: formations_set={formations_set}")
if sem["formation_id"] in formations_set:
formations_set.remove(sem["formation_id"])
if len(formations_set) == 1:
if fix:
- log("check_sem_integrity: trying to fix %s" % formsemestre_id)
+ log(f"check_sem_integrity: trying to fix {formsemestre_id}")
formation_id = formations_set.pop()
if sem["formation_id"] != formation_id:
sem["formation_id"] = formation_id
@@ -3319,11 +2458,11 @@ def check_sem_integrity(formsemestre_id, fix=False):
H.append("""Problème réparé: vérifiez
""")
else:
H.append(
- """
+ f"""
Problème détecté réparable:
- réparer maintenant
+ réparer maintenant
"""
- % (formsemestre_id,)
)
else:
H.append("""Problème détecté !
""")
diff --git a/misc/example-api-python2.py b/misc/example-api-python2.py
deleted file mode 100644
index 03fd26be..00000000
--- a/misc/example-api-python2.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python
-# -*- mode: python -*-
-# -*- coding: utf-8 -*-
-
-"""Exemple connexion sur ScoDoc et utilisation de l'API
-
-Attention: cet exemple est en Python 2.
-Voir example-api-1.py pour une version en Python3 plus moderne.
-"""
-
-import urllib, urllib2
-
-# A modifier pour votre serveur:
-BASEURL = "https://scodoc.xxx.net/ScoDoc/RT/Scolarite"
-USER = "XXX"
-PASSWORD = "XXX"
-
-values = {
- "__ac_name": USER,
- "__ac_password": PASSWORD,
-}
-
-# Configure memorisation des cookies:
-opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
-urllib2.install_opener(opener)
-
-data = urllib.urlencode(values)
-
-req = urllib2.Request(BASEURL, data) # this is a POST http request
-response = urllib2.urlopen(req)
-
-# --- Use API
-
-# Affiche la liste des formations en format XML
-req = urllib2.Request(BASEURL + "/Notes/formation_list?fmt=xml")
-response = urllib2.urlopen(req)
-print response.read()[:100] # limite aux 100 premiers caracteres...
-
-# Recupere la liste de tous les semestres:
-req = urllib2.Request(BASEURL + "/Notes/formsemestre_list?fmt=json") # format json
-response = urllib2.urlopen(req)
-js_data = response.read()
-
-# Plus amusant: va retrouver le bulletin de notes du premier etudiant (au hasard donc) du premier semestre (au hasard aussi)
-try:
- import json # Attention: ceci demande Python >= 2.6
-except:
- import simplejson as json # python2.4 with simplejson installed
-
-data = json.loads(js_data) # decode la reponse JSON
-if not data:
- print "Aucun semestre !"
-else:
- formsemestre_id = str(data[0]["formsemestre_id"])
- # Obtient la liste des groupes:
- req = urllib2.Request(
- BASEURL
- + "/Notes/formsemestre_partition_list?fmt=json&formsemestre_id="
- + str(formsemestre_id)
- ) # format json
- response = urllib2.urlopen(req)
- js_data = response.read()
- data = json.loads(js_data)
- group_id = data[0]["group"][0][
- "group_id"
- ] # premier groupe (normalement existe toujours)
- # Liste les étudiants de ce groupe:
- req = urllib2.Request(
- BASEURL + "/Notes/group_list?fmt=json&with_codes=1&group_id=" + str(group_id)
- ) # format json
- response = urllib2.urlopen(req)
- js_data = response.read()
- data = json.loads(js_data)
- # Le code du premier étudiant:
- if not data:
- print ("pas d'etudiants dans ce semestre !")
- else:
- etudid = data[0]["etudid"]
- # Récupère bulletin de notes:
- req = urllib2.Request(
- BASEURL
- + "/Notes/formsemestre_bulletinetud?formsemestre_id="
- + str(formsemestre_id)
- + "&etudid="
- + str(etudid)
- + "&fmt=xml"
- ) # format XML ici !
- response = urllib2.urlopen(req)
- xml_bulletin = response.read()
- print "----- Bulletin de notes en XML:"
- print xml_bulletin
- # Récupère la moyenne générale:
- import xml.dom.minidom
-
- doc = xml.dom.minidom.parseString(xml_bulletin)
- moy = doc.getElementsByTagName("note")[0].getAttribute(
- "value"
- ) # une chaine unicode
- print "\nMoyenne generale: ", moy