diff --git a/app/models/events.py b/app/models/events.py
index 4e3fcb2bd..e499dc74a 100644
--- a/app/models/events.py
+++ b/app/models/events.py
@@ -249,9 +249,10 @@ class ScolarNews(db.Model):
news_list = cls.last_news(n=n)
if not news_list:
return ""
+ dept_news_url = url_for("scolar.dept_news", scodoc_dept=g.scodoc_dept)
H = [
f"""
"""
]
@@ -261,17 +262,22 @@ class ScolarNews(db.Model):
f"""- {news.formatted_date()}{news}
"""
)
+ H.append(
+ f"""-
+ ...
+
+
"""
+ )
- H.append("
")
+ H.append("
")
# Informations générales
H.append(
f"""
- Pour en savoir plus sur ScoDoc voir le site
-
scodoc.org.
+ Pour en savoir plus sur ScoDoc voir
+
scodoc.org
"""
)
- H.append("")
return "\n".join(H)
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 00bac5c20..84ba4c373 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -247,7 +247,7 @@ class FormSemestre(models.ScoDocModel):
def to_dict_api(self):
"""
- Un dict avec les informations sur le semestre destiné à l'api
+ Un dict avec les informations sur le semestre destinées à l'api
"""
d = dict(self.__dict__)
d.pop("_sa_instance_state", None)
diff --git a/app/scodoc/sco_dept.py b/app/scodoc/sco_dept.py
index 2196ab8ec..97fce15c2 100644
--- a/app/scodoc/sco_dept.py
+++ b/app/scodoc/sco_dept.py
@@ -3,7 +3,7 @@
##############################################################################
#
-# Gestion scolarite IUT
+# ScoDoc
#
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
#
@@ -28,93 +28,119 @@
"""Page accueil département (liste des semestres, etc)
"""
-from flask import g
-from flask import url_for
+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 ScolarNews
+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
-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
+from app.views import ScoData
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())
+ # 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
+ html_table_formsemestres = _sem_table_gt(
+ formsemestres, showcodes=showcodes
+ ).html()
+ else:
+ html_table_formsemestres = None
- # Avertissement de mise à jour:
- H.append("""""")
+ 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(),
+ )
- # Liste de toutes les sessions:
- sems = sco_formsemestre.do_formsemestre_list()
- cursems = [] # semestres "courants"
- othersems = [] # autres (verrouillés)
+
+def _convert_formsemestres_to_dicts(
+ formsemestres: Query, showcodes: bool
+) -> list[dict]:
+ """ """
# 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)
+ # génère liste de dict
+ sems = []
+ for formsemestre in formsemestres:
+ nb_inscrits = len(formsemestre.inscriptions)
+ sem = {
+ "anneescolaire": formsemestre.annee_scolaire(),
+ "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(),
+ "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"{sem['formsemestre_id']} | " if showcodes else ""
+ ),
+ }
+ sems.append(sem)
+ return sems
- if showcodes:
- sem["tmpcode"] = f"{sem['formsemestre_id']} | "
- 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(
- """Aucun utilisateur défini !
Pour définir des utilisateurs
- passez par la page Utilisateurs.
-
- Définissez au moins un utilisateur avec le rôle AdminXXX
- (le responsable du département XXX).
-
- """
- )
+def _show_current_formsemestres(formsemestres: Query, showcodes: bool) -> str:
+ """html div avec les formsemestres courants de la page d'accueil"""
- H.append("""""")
- # Liste des formsemestres "courants"
- if cursems:
- H.append(
- f"""
-
Sessions en cours
- { _sem_table(cursems) }
- """
- )
+ 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(
@@ -127,125 +153,16 @@ def index_html(showcodes=0, showsemtable=0):
"
Mettre en place un nouveau semestre de formation..."
"""
)
-
- if showsemtable:
- H.append(
- f"""
-
Semestres de {sco_preferences.get_preference("DeptName")}
- """
- )
- H.append(_sem_table_gt(sems, showcodes=showcodes).html())
- H.append("")
- else:
- H.append(
- f"""
-
Voir table des semestres (dont {len(othersems)}
- verrouillé{'s' if len(othersems) else ''})
-
"""
- )
-
- H.append(
- f"""
-
-
- """
- )
- #
- H.append(
- """
-
-
Gestion des étudiants
-
")
- #
- if current_user.has_permission(Permission.EditApogee):
- H.append(
- f"""
-
- """
- )
- #
- H.append(
- """
-
- """
- )
- #
- 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()
- )
+ return "\n".join(H)
-def _sem_table(sems):
+def _sem_table(sems: list[dict]) -> str:
"""Affiche liste des semestres, utilisée pour semestres en cours"""
- tmpl = """%(tmpcode)s
- %(lockimg)s %(groupicon)s |
+ tmpl = f"""
%(tmpcode)s
+ %(lockimg)s %(groupicon)s |
%(mois_debut)s - %(mois_fin)s |
- %(titre_num)s
+ | %(titre_num)s
(%(responsable_name)s)
|
@@ -267,19 +184,26 @@ def _sem_table(sems):
cur_idx = sem["semestre_id"]
else:
sem["trclass"] = ""
- sem["notes_url"] = scu.NotesURL()
H.append(tmpl % sem)
H.append("")
return "\n".join(H)
-def _sem_table_gt(sems, showcodes=False):
- """Nouvelle version de la table des semestres
+def _sem_table_gt(formsemestres: Query, showcodes=False) -> GenTable:
+ """Table des semestres
Utilise une datatables.
"""
- _style_sems(sems)
+ sems = _style_sems(_convert_formsemestres_to_dicts(formsemestres, showcodes))
+ 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",
"semestre_id_n",
"modalite",
#'mois_debut',
@@ -327,22 +251,35 @@ def _sem_table_gt(sems, showcodes=False):
return tab
-def _style_sems(sems):
+def _style_sems(sems: list[dict]) -> list[dict]:
"""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
+ 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"] = ' %(anneescolaire)s' % sem
sem["_dash_mois_fin_class"] = "datesem"
sem["titre_resp"] = (
- """%(titre_num)s
- (%(responsable_name)s)"""
- % sem
+ f"""{sem['titre_num']} ({sem['responsable_name']})"""
)
+ sem["published"] = (
+ scu.icontag(
+ "hide_img",
+ border="0",
+ title="Bulletins NON publiés sur la passerelle étudiants",
+ )
+ if sem["bul_hide_xml"]
+ else scu.icontag(
+ "eye_img",
+ border="0",
+ title="Bulletins publiés sur la passerelle étudiants",
+ )
+ )
+
sem["_css_row_class"] = "css_S%d css_M%s" % (
sem["semestre_id"],
sem["modalite"],
@@ -363,6 +300,7 @@ def _style_sems(sems):
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:
diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py
index 437969eb2..bebe7fccd 100644
--- a/app/scodoc/sco_formsemestre.py
+++ b/app/scodoc/sco_formsemestre.py
@@ -494,7 +494,7 @@ def table_formsemestres(
):
"""Une table presentant des semestres"""
for sem in sems:
- sem_set_responsable_name(sem)
+ sem_set_responsable_name(sem) # TODO utiliser formsemestre.responsables_str()
sem["_titre_num_target"] = url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
diff --git a/app/scodoc/sco_modalites.py b/app/scodoc/sco_modalites.py
index 805d0d48b..621373f71 100644
--- a/app/scodoc/sco_modalites.py
+++ b/app/scodoc/sco_modalites.py
@@ -50,8 +50,8 @@ def list_formsemestres_modalites(sems):
return modalites
-def group_sems_by_modalite(sems):
- """Given the list of fromsemestre, group them by modalite,
+def group_sems_by_modalite(sems: list[dict]):
+ """Given the list of formsemestre, group them by modalite,
sorted in each one by semestre id and date
"""
sems_by_mod = collections.defaultdict(list)
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 6987406e0..eb6793e54 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -40,6 +40,10 @@ h3 {
font-weight: bold;
}
+details > summary:first-of-type {
+ display: list-item!important;
+}
+
div.container {
margin-bottom: 24px;
}
@@ -592,10 +596,6 @@ table.listesems tr.firstsem td {
padding-top: 0.8em;
}
-td.datesem {
- font-size: 80%;
- white-space: nowrap;
-}
h2.listesems {
padding-top: 10px;
@@ -683,27 +683,33 @@ table.semlist tbody tr td.modalite {
}
div#gtrcontent table.semlist tbody tr.css_S-1 td {
- background-color: rgb(251, 250, 216);
+ background-color: rgb(211, 213, 255);
}
div#gtrcontent table.semlist tbody tr.css_S1 td {
- background-color: rgb(92%, 95%, 94%);
+ background-color:#e9efef;
}
div#gtrcontent table.semlist tbody tr.css_S2 td {
- background-color: rgb(214, 223, 236);
+ background-color: #d4ebd7;
}
div#gtrcontent table.semlist tbody tr.css_S3 td {
- background-color: rgb(167, 216, 201);
+ background-color: #bedebe;
}
div#gtrcontent table.semlist tbody tr.css_S4 td {
- background-color: rgb(131, 225, 140);
+ background-color: #afd7ad;
+}
+div#gtrcontent table.semlist tbody tr.css_S5 td {
+ background-color: #a0cd9a;
+}
+div#gtrcontent table.semlist tbody tr.css_S6 td {
+ background-color: #7dcf78;
}
div#gtrcontent table.semlist tbody tr.css_MEXT td {
- color: #0b6e08;
+ color: #fefcdf;
}
/* ----- Liste des news ----- */
@@ -2019,7 +2025,8 @@ ul.ue_inscr_list li.etud {
.sem-groups-partition .stdlink, .sem-groups-partition .stdlink:visited {
color: black;
- text-decoration-style: dashed;
+ text-decoration-style: dotted;
+ text-underline-offset: 3px;
}
.sem-groups-list .stdlink, .sem-groups-list .stdlink:visited {
color:rgb(0, 0, 192);
diff --git a/app/templates/scolar/index.j2 b/app/templates/scolar/index.j2
new file mode 100644
index 000000000..09c3e9de9
--- /dev/null
+++ b/app/templates/scolar/index.j2
@@ -0,0 +1,127 @@
+{# page accueil département #}
+
+{% extends "sco_page.j2" %}
+
+{% block app_content %}
+
+
+{# News #}
+{{scolar_news_summary|safe}}
+
+{# Avertissement de mise à jour: #}
+
+
+{% if nb_user_accounts == 0 %}
+ Aucun utilisateur défini !
+ Pour définir des utilisateurs passez par la page Utilisateurs.
+ Définissez au moins un utilisateur avec le rôle AdminXXX
+ (le responsable du département XXX).
+
+{% endif %}
+
+{# Les semestres courants (cad non verrouillés) #}
+
+ {{html_current_formsemestres|safe}}
+
+
+{# Table de tous les semestres #}
+
+{% if html_table_formsemestres %}
+
+
+ Semestres de {{dept_name}}
+
+ {{ html_table_formsemestres|safe }}
+
+{% else %}
+ Voir table des {{formsemestres.count()}} semestres
+ {% if nb_locked %}
+ (dont {{nb_locked}} verrouillé{{'s' if nb_locked > 1 else ''}})
+ {%endif%}
+
+
+{% endif %}
+
+
+{# Recherche d'un semestre par code Apogée #}
+
+
+{# Gestion des étudiants #}
+
+
Gestion des étudiants
+
+
+
+{# Apogée #}
+{% if current_user.has_permission(Permission.EditApogee) %}
+
+{% endif %}
+
+{# Assistance #}
+
+
+{% endblock app_content %}
+
+{% block scripts %}
+{{ super() }}
+
+{% endblock scripts %}
\ No newline at end of file