# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # ScoDoc # # Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Emmanuel Viennet emmanuel.viennet@viennet.net # ############################################################################## """Page accueil département (liste des semestres, etc) """ from sqlalchemy import desc from flask import g, url_for, render_template from flask_login import current_user from flask_sqlalchemy.query import Query import app from app import log from app.models import FormSemestre, ScolarNews import app.scodoc.sco_utils as scu from app.scodoc.gen_tables import GenTable from app.scodoc.sco_permissions import Permission import app.scodoc.notesdb as ndb from app.scodoc import sco_modalites from app.scodoc import sco_preferences from app.scodoc import sco_users from app.views import ScoData def index_html(showcodes=0, showsemtable=0, export_table_formsemestres=False): "Page accueil département (liste des semestres)" showcodes = int(showcodes) showsemtable = int(showsemtable) or export_table_formsemestres # Liste tous les formsemestres du dept, le plus récent d'abord current_formsemestres = ( FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id, etat=True) .filter(FormSemestre.modalite != "EXT") .order_by(desc(FormSemestre.date_debut)) ) locked_formsemestres = ( FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id, etat=False) .filter(FormSemestre.modalite != "EXT") .order_by(desc(FormSemestre.date_debut)) ) formsemestres = ( FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id) .filter(FormSemestre.modalite != "EXT") .order_by(desc(FormSemestre.date_debut)) ) if showsemtable: # table de tous les formsemestres table = _sem_table_gt( formsemestres, showcodes=showcodes, fmt="xlsx" if export_table_formsemestres else "html", ) if export_table_formsemestres: return table # cas spécial: on renvoie juste cette table html_table_formsemestres = table.html() else: html_table_formsemestres = None return render_template( "scolar/index.j2", current_user=current_user, dept_name=sco_preferences.get_preference("DeptName"), formsemestres=formsemestres, html_current_formsemestres=_show_current_formsemestres( current_formsemestres, showcodes ), html_table_formsemestres=html_table_formsemestres, locked_formsemestres=locked_formsemestres, nb_locked=locked_formsemestres.count(), nb_user_accounts=sco_users.get_users_count(dept=g.scodoc_dept), page_title=f"ScoDoc {g.scodoc_dept}", Permission=Permission, scolar_news_summary=ScolarNews.scolar_news_summary_html(), showsemtable=showsemtable, sco=ScoData(), ) def _convert_formsemestres_to_dicts( formsemestres: Query, showcodes: bool, fmt: str = "html" ) -> list[dict]: """ """ if fmt == "html": # icon images: groupicon = scu.icontag("groupicon_img", title="Inscrits", border="0") emptygroupicon = scu.icontag( "emptygroupicon_img", title="Pas d'inscrits", border="0" ) lockicon = scu.icontag("lock32_img", title="verrouillé", border="0") else: groupicon = "X" emptygroupicon = "" lockicon = "X" # génère liste de dict sems = [] for formsemestre in formsemestres: nb_inscrits = len(formsemestre.inscriptions) formation = formsemestre.formation sem = { "anneescolaire": formsemestre.annee_scolaire(), "anneescolaire_str": formsemestre.annee_scolaire_str(), "bul_hide_xml": formsemestre.bul_hide_xml, "dateord": formsemestre.date_debut, "elt_annee_apo": formsemestre.elt_annee_apo, "elt_sem_apo": formsemestre.elt_sem_apo, "etapes_apo_str": formsemestre.etapes_apo_str(), "formation": f"{formation.acronyme} v{formation.version}", "_formation_target": url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation.id, semestre_idx=formsemestre.semestre_id, ), "formsemestre_id": formsemestre.id, "groupicon": groupicon if nb_inscrits > 0 else emptygroupicon, "lockimg": lockicon, "modalite": formsemestre.modalite, "mois_debut": formsemestre.mois_debut(), "mois_fin": formsemestre.mois_fin(), "nb_inscrits": nb_inscrits, "responsable_name": formsemestre.responsables_str(), "semestre_id": formsemestre.semestre_id, "session_id": formsemestre.session_id(), "titre_num": formsemestre.titre_num(), "tmpcode": (f"{formsemestre.id}" if showcodes else ""), } sems.append(sem) return sems def _show_current_formsemestres(formsemestres: Query, showcodes: bool) -> str: """html div avec les formsemestres courants de la page d'accueil""" H = [] if formsemestres.count(): H.append("""
Sessions en cours
""") H.append(_sem_table(_convert_formsemestres_to_dicts(formsemestres, showcodes))) else: # aucun semestre courant: affiche aide H.append( """
Aucune session en cours !

Pour ajouter une session, aller dans Formations, choisissez une formation, puis suivez le lien "UE, modules, semestres".

Là, en bas de page, suivez le lien "Mettre en place un nouveau semestre de formation..."

""" ) return "\n".join(H) def _sem_table(sems: list[dict]) -> str: """Affiche liste des semestres, utilisée pour semestres en cours""" tmpl = f"""%(tmpcode)s %(lockimg)s %(groupicon)s %(mois_debut)s - %(mois_fin)s %(titre_num)s (%(responsable_name)s) """ # Liste des semestres, groupés par modalités sems_by_mod, modalites = sco_modalites.group_sems_by_modalite(sems) H = [''] for modalite in modalites: if len(modalites) > 1: H.append('' % modalite["titre"]) if sems_by_mod[modalite["modalite"]]: cur_idx = sems_by_mod[modalite["modalite"]][0]["semestre_id"] for sem in sems_by_mod[modalite["modalite"]]: if cur_idx != sem["semestre_id"]: sem["trclass"] = "firstsem" # separe les groupes de semestres cur_idx = sem["semestre_id"] else: sem["trclass"] = "" H.append(tmpl % sem) H.append("
%s
") return "\n".join(H) def _sem_table_gt(formsemestres: Query, showcodes=False, fmt="html") -> GenTable: """Table des semestres Utilise une datatables. """ sems = _style_sems( _convert_formsemestres_to_dicts(formsemestres, showcodes, fmt=fmt), fmt=fmt ) sems.sort( key=lambda s: ( -s["anneescolaire"], s["semestre_id"] if s["semestre_id"] > 0 else -s["semestre_id"] * 1000, s["modalite"], ) ) columns_ids = ( "lockimg", "published", "dash_mois_fin", "semestre_id_n", "modalite", "titre_resp", "nb_inscrits", "formation", "etapes_apo_str", "elt_annee_apo", "elt_sem_apo", ) if showcodes: columns_ids = ("formsemestre_id",) + columns_ids html_class = "stripe cell-border compact hover order-column table_leftalign semlist" if current_user.has_permission(Permission.EditApogee): html_class += " apo_editable" tab = GenTable( titles={ "formsemestre_id": "id", "semestre_id_n": "S#", "modalite": "" if fmt == "html" else "Modalité", "mois_debut": "Début", "dash_mois_fin": "Année", "titre_resp": "Semestre", "nb_inscrits": "N", "etapes_apo_str": "Étape Apo.", "elt_annee_apo": "Elt. année Apo.", "elt_sem_apo": "Elt. sem. Apo.", "formation": "Formation", }, columns_ids=columns_ids, rows=sems, table_id="semlist", html_class_ignore_default=True, html_class=html_class, html_sortable=True, html_table_attrs=f""" data-apo_save_url="{url_for('notes.formsemestre_set_apo_etapes', scodoc_dept=g.scodoc_dept)}" data-elt_annee_apo_save_url="{url_for('notes.formsemestre_set_elt_annee_apo', scodoc_dept=g.scodoc_dept)}" data-elt_sem_apo_save_url="{url_for('notes.formsemestre_set_elt_sem_apo', scodoc_dept=g.scodoc_dept)}" """, html_with_td_classes=True, preferences=sco_preferences.SemPreferences(), ) return tab def _style_sems(sems: list[dict], fmt="html") -> list[dict]: """ajoute quelques attributs de présentation pour la table""" is_h = fmt == "html" if is_h: icon_published = scu.ICON_PUBLISHED icon_hidden = scu.ICON_HIDDEN else: icon_published = "publié" icon_hidden = "non publié" for sem in sems: status_url = url_for( "notes.formsemestre_status", scodoc_dept=g.scodoc_dept, formsemestre_id=sem["formsemestre_id"], ) sem["_groupicon_target"] = status_url sem["_formsemestre_id_class"] = "blacktt" sem["dash_mois_fin"] = ( (f"""{sem['anneescolaire_str']}""") if is_h else sem["anneescolaire_str"] ) sem["_dash_mois_fin_class"] = "datesem" sem["titre_resp"] = ( ( f"""{sem['titre_num']} ({sem['responsable_name']})""" ) if is_h else f"""{sem['titre_num']} ({sem["responsable_name"]})""" ) sem["published"] = icon_hidden if sem["bul_hide_xml"] else icon_published sem["_css_row_class"] = "css_S%d css_M%s" % ( sem["semestre_id"], sem["modalite"], ) sem["_semestre_id_class"] = "semestre_id" sem["_modalite_class"] = "modalite" if sem["semestre_id"] == -1: sem["semestre_id_n"] = "" else: sem["semestre_id_n"] = sem["semestre_id"] # pour édition codes Apogée: sem["_etapes_apo_str_td_attrs"] = ( f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['etapes_apo_str']}" """ ) sem["_elt_annee_apo_td_attrs"] = ( f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['elt_annee_apo']}" """ ) sem["_elt_sem_apo_td_attrs"] = ( f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['elt_sem_apo']}" """ ) return sems def delete_dept(dept_id: int) -> str: """Suppression irréversible d'un département et de tous les objets rattachés""" assert isinstance(dept_id, int) # Un peu complexe, merci JMP :) cnx = ndb.GetDBConnexion() cursor = cnx.cursor() try: # 1- Create temp tables to store ids reqs = [ "create temp table etudids_temp as select id from identite where dept_id = %(dept_id)s", """create temp table formsemestres_temp as select id from notes_formsemestre where dept_id = %(dept_id)s""", """create temp table moduleimpls_temp as select id from notes_moduleimpl where formsemestre_id in (select id from formsemestres_temp)""", """create temp table formations_temp as select id from notes_formations where dept_id = %(dept_id)s""", "create temp table tags_temp as select id from notes_tags where dept_id = %(dept_id)s", ] for r in reqs: log(f"delete_dept: {r}") cursor.execute(r, {"dept_id": dept_id}) # 2- Delete student-related informations # ordered list of tables etud_tables = [ "notes_notes", "group_membership", "billet_absence", "adresse", "absences", "notes_notes_log", "notes_moduleimpl_inscription", "itemsuivi", "notes_appreciations", "scolar_autorisation_inscription", "absences_notifications", "notes_formsemestre_inscription", "scolar_formsemestre_validation", "scolar_events", ] for table in etud_tables: log(f"delete from {table}") cursor.execute( f"delete from {table} where etudid in (select id from etudids_temp)" ) reqs = [ """delete from apc_validation_annee where referentiel_competence_id in (select id from apc_referentiel_competences where dept_id = %(dept_id)s)""", "delete from apc_referentiel_competences where dept_id = %(dept_id)s", "delete from sco_prefs where dept_id = %(dept_id)s", """delete from notes_semset_formsemestre where formsemestre_id in (select id from formsemestres_temp)""", """delete from notes_evaluation where moduleimpl_id in (select id from moduleimpls_temp)""", """delete from notes_modules_enseignants where moduleimpl_id in (select id from moduleimpls_temp)""", """delete from notes_formsemestre_uecoef where formsemestre_id in (select id from formsemestres_temp)""", """delete from notes_formsemestre_ue_computation_expr where formsemestre_id in (select id from formsemestres_temp)""", """delete from notes_formsemestre_responsables where formsemestre_id in (select id from formsemestres_temp)""", """delete from notes_moduleimpl where formsemestre_id in (select id from formsemestres_temp)""", """delete from notes_modules_tags where tag_id in (select id from tags_temp)""", "delete from notes_tags where dept_id = %(dept_id)s", "delete from notes_modules where formation_id in (select id from formations_temp)", """delete from notes_matieres where ue_id in (select id from notes_ue where formation_id in (select id from formations_temp))""", """delete from notes_formsemestre_etapes where formsemestre_id in (select id from formsemestres_temp)""", """delete from group_descr where partition_id in (select id from partition where formsemestre_id in (select id from formsemestres_temp))""", "delete from partition where formsemestre_id in (select id from formsemestres_temp)", """delete from notes_formsemestre_custommenu where formsemestre_id in (select id from formsemestres_temp)""", "delete from notes_ue where formation_id in (select id from formations_temp)", "delete from notes_formsemestre where dept_id = %(dept_id)s", "delete from scolar_news where dept_id = %(dept_id)s", "delete from notes_semset where dept_id = %(dept_id)s", "delete from notes_formations where dept_id = %(dept_id)s", "delete from itemsuivi_tags where dept_id = %(dept_id)s", "delete from identite where dept_id = %(dept_id)s", "delete from departement where id = %(dept_id)s", "drop table tags_temp", "drop table formations_temp", "drop table moduleimpls_temp", "drop table etudids_temp", "drop table formsemestres_temp", ] for r in reqs: log(f"delete_dept: {r}") cursor.execute(r, {"dept_id": dept_id}) except Exception as e: cnx.rollback() return str(e) finally: cnx.commit() app.clear_scodoc_cache() return ""