# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # 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 flask import g from flask import url_for from flask_login import current_user import app from app import log from app.models import ScolarNews import app.scodoc.sco_utils as scu from app.scodoc.gen_tables import GenTable from app.scodoc.sco_permissions import Permission from app.scodoc import html_sco_header import app.scodoc.notesdb as ndb from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_modalites from app.scodoc import sco_preferences from app.scodoc import sco_users def index_html(showcodes=0, showsemtable=0): "Page accueil département (liste des semestres)" showcodes = int(showcodes) showsemtable = int(showsemtable) H = [] # News: H.append(ScolarNews.scolar_news_summary_html()) # Avertissement de mise à jour: H.append("""<div id="update_warning"></div>""") # Liste de toutes les sessions: sems = sco_formsemestre.do_formsemestre_list() cursems = [] # semestres "courants" othersems = [] # autres (verrouillés) # icon image: 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") # Sélection sur l'etat du semestre for sem in sems: if sem["etat"] and sem["modalite"] != "EXT": sem["lockimg"] = "" cursems.append(sem) else: sem["lockimg"] = lockicon othersems.append(sem) # Responsable de formation: sco_formsemestre.sem_set_responsable_name(sem) if showcodes: sem["tmpcode"] = f"<td><tt>{sem['formsemestre_id']}</tt></td>" else: sem["tmpcode"] = "" # Nombre d'inscrits: args = {"formsemestre_id": sem["formsemestre_id"]} ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(args=args) nb = len(ins) # nb etudiants sem["nb_inscrits"] = nb if nb > 0: sem["groupicon"] = groupicon else: sem["groupicon"] = emptygroupicon # S'il n'y a pas d'utilisateurs dans la base, affiche message if not sco_users.get_users_count(dept=g.scodoc_dept): H.append( """<h2>Aucun utilisateur défini !</h2><p>Pour définir des utilisateurs <a href="Users">passez par la page Utilisateurs</a>. <br> Définissez au moins un utilisateur avec le rôle AdminXXX (le responsable du département XXX). </p> """ ) # Liste des formsemestres "courants" if cursems: H.append('<h2 class="listesems">Sessions en cours</h2>') H.append(_sem_table(cursems)) else: # aucun semestre courant: affiche aide H.append( """<h2 class="listesems">Aucune session en cours !</h2> <p>Pour ajouter une session, aller dans <a href="Notes" id="link-programmes">Formations</a>, choisissez une formation, puis suivez le lien "<em>UE, modules, semestres</em>". </p><p> Là, en bas de page, suivez le lien "<em>Mettre en place un nouveau semestre de formation...</em>" </p>""" ) if showsemtable: H.append( f"""<hr> <h2>Semestres de {sco_preferences.get_preference("DeptName")}</h2> """ ) H.append(_sem_table_gt(sems, showcodes=showcodes).html()) H.append("</table>") if not showsemtable: H.append( f"""<hr> <p><a class="stdlink" href="{url_for('scolar.index_html', scodoc_dept=g.scodoc_dept, showsemtable=1) }">Voir table des semestres (dont {len(othersems)} verrouillé{'s' if len(othersems) else ''})</a> </p>""" ) H.append( f"""<p> <form action="{url_for('notes.view_formsemestre_by_etape', scodoc_dept=g.scodoc_dept)}"> Chercher étape courante: <input name="etape_apo" type="text" size="8" spellcheck="false"></input> </form> </p>""" ) # H.append( """<hr> <h3>Gestion des étudiants</h3> <ul> """ ) if current_user.has_permission(Permission.EtudInscrit): H.append( f""" <li><a class="stdlink" href="{ url_for("scolar.etudident_create_form", scodoc_dept=g.scodoc_dept) }">créer <em>un</em> nouvel étudiant</a> </li> <li><a class="stdlink" href="{ url_for("scolar.form_students_import_excel", scodoc_dept=g.scodoc_dept) }">importer de nouveaux étudiants</a> (<em>ne pas utiliser</em> sauf cas particulier : utilisez plutôt le lien dans le tableau de bord semestre si vous souhaitez inscrire les étudiants importés à un semestre) </li> """ ) H.append( f""" <li><a class="stdlink" href="{ url_for("scolar.export_etudiants_courants", scodoc_dept=g.scodoc_dept) }">exporter tableau des étudiants des semestres en cours</a> </li> """ ) if current_user.has_permission( Permission.EtudInscrit ) and sco_preferences.get_preference("portal_url"): H.append( f""" <li><a class="stdlink" href="{ url_for("scolar.formsemestre_import_etud_admission", scodoc_dept=g.scodoc_dept, tous_courants=1) }">resynchroniser les données étudiants des semestres en cours depuis le portail</a> </li> """ ) H.append("</ul>") # if current_user.has_permission(Permission.EditApogee): H.append( f"""<hr> <h3>Exports Apogée</h3> <ul> <li><a class="stdlink" href="{url_for('notes.semset_page', scodoc_dept=g.scodoc_dept) }">Années scolaires / exports Apogée</a></li> </ul> """ ) # H.append( """<hr> <h3>Assistance</h3> <ul> <li><a class="stdlink" href="https://scodoc.org/Contact" target="_blank" rel="noopener noreferrer">Contact (Discord)</a></li> <li><a class="stdlink" href="sco_dump_and_send_db">Envoyer données</a></li> </ul> """ ) # return ( html_sco_header.sco_header( page_title=f"ScoDoc {g.scodoc_dept}", javascripts=["js/scolar_index.js"] ) + "\n".join(H) + html_sco_header.sco_footer() ) def _sem_table(sems): """Affiche liste des semestres, utilisée pour semestres en cours""" tmpl = """<tr class="%(trclass)s">%(tmpcode)s <td class="semicon">%(lockimg)s <a href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s#groupes">%(groupicon)s</a></td> <td class="datesem">%(mois_debut)s <a title="%(session_id)s">-</a> %(mois_fin)s</td> <td><a class="stdlink" href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a> <span class="respsem">(%(responsable_name)s)</span> </td> </tr> """ # Liste des semestres, groupés par modalités sems_by_mod, modalites = sco_modalites.group_sems_by_modalite(sems) H = ['<table class="listesems">'] for modalite in modalites: if len(modalites) > 1: H.append('<tr><th colspan="3">%s</th></tr>' % 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"] = "" sem["notes_url"] = scu.NotesURL() H.append(tmpl % sem) H.append("</table>") return "\n".join(H) def _sem_table_gt(sems, showcodes=False): """Nouvelle version de la table des semestres Utilise une datatables. """ _style_sems(sems) columns_ids = ( "lockimg", "semestre_id_n", "modalite", #'mois_debut', "dash_mois_fin", "titre_resp", "nb_inscrits", "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": "", "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.", }, 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): """ajoute quelques attributs de présentation pour la table""" for sem in sems: sem["notes_url"] = scu.NotesURL() sem["_groupicon_target"] = ( "%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s" % sem ) sem["_formsemestre_id_class"] = "blacktt" sem["dash_mois_fin"] = '<a title="%(session_id)s"></a> %(anneescolaire)s' % sem sem["_dash_mois_fin_class"] = "datesem" sem["titre_resp"] = ( """<a class="stdlink" href="%(notes_url)s/formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a> <span class="respsem">(%(responsable_name)s)</span>""" % sem ) 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']}" """ ) 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 ""