page infos UE + qq corrections

This commit is contained in:
Emmanuel Viennet 2021-12-10 00:54:57 +01:00
parent 8ce6c907f3
commit acebc8ab08
9 changed files with 246 additions and 32 deletions

View File

@ -3,7 +3,6 @@
"""ScoDoc models: formsemestre """ScoDoc models: formsemestre
""" """
import datetime import datetime
from typing import Any
import flask_sqlalchemy import flask_sqlalchemy
@ -13,9 +12,7 @@ from app.models import SHORT_STR_LEN
from app.models import CODE_STR_LEN from app.models import CODE_STR_LEN
from app.models import UniteEns from app.models import UniteEns
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import sco_evaluation_db
from app.models.ues import UniteEns from app.models.ues import UniteEns
from app.models.modules import Module from app.models.modules import Module
from app.models.moduleimpls import ModuleImpl from app.models.moduleimpls import ModuleImpl
@ -216,6 +213,22 @@ class FormSemestre(db.Model):
"-".join((imputation_dept, parcours_name, modalite, semestre_id, annee_sco)) "-".join((imputation_dept, parcours_name, modalite, semestre_id, annee_sco))
) )
def titre_mois(self) -> str:
"""Le titre et les dates du semestre, pour affichage dans des listes
Ex: "BUT QLIO (PN 2022) semestre 1 FI (Sept 2022 - Jan 2023)"
"""
return f"""{self.titre_num()} {self.modalite or ''} ({
scu.MONTH_NAMES_ABBREV[self.date_debut.month-1]} {
self.date_debut.year} - {
scu.MONTH_NAMES_ABBREV[self.date_fin.month -1]} {
self.date_fin.year})"""
def titre_num(self) -> str:
"""Le titre est le semestre, ex ""DUT Informatique semestre 2"" """
if self.semestre_id == sco_codes_parcours.NO_SEMESTRE_ID:
return self.titre
return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}"
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre # Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
notes_formsemestre_responsables = db.Table( notes_formsemestre_responsables = db.Table(
@ -238,7 +251,7 @@ class FormsemestreEtape(db.Model):
db.Integer, db.Integer,
db.ForeignKey("notes_formsemestre.id"), db.ForeignKey("notes_formsemestre.id"),
) )
etape_apo = db.Column(db.String(APO_CODE_STR_LEN)) etape_apo = db.Column(db.String(APO_CODE_STR_LEN), index=True)
def __repr__(self): def __repr__(self):
return f"<Etape {self.id} apo={self.etape_apo}>" return f"<Etape {self.id} apo={self.etape_apo}>"

View File

@ -52,16 +52,19 @@ class ScolarFormsemestreValidation(db.Model):
etudid = db.Column( etudid = db.Column(
db.Integer, db.Integer,
db.ForeignKey("identite.id"), db.ForeignKey("identite.id"),
index=True,
) )
formsemestre_id = db.Column( formsemestre_id = db.Column(
db.Integer, db.Integer,
db.ForeignKey("notes_formsemestre.id"), db.ForeignKey("notes_formsemestre.id"),
index=True,
) )
ue_id = db.Column( ue_id = db.Column(
db.Integer, db.Integer,
db.ForeignKey("notes_ue.id"), db.ForeignKey("notes_ue.id"),
index=True,
) )
code = db.Column(db.String(CODE_STR_LEN), nullable=False) code = db.Column(db.String(CODE_STR_LEN), nullable=False, index=True)
# NULL pour les UE, True|False pour les semestres: # NULL pour les UE, True|False pour les semestres:
assidu = db.Column(db.Boolean) assidu = db.Column(db.Boolean)
event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())

View File

@ -25,12 +25,14 @@
"""Édition formation APC (BUT) """Édition formation APC (BUT)
""" """
import flask import flask
from flask import url_for, render_template from flask import url_for
from flask.templating import render_template
from flask import g, request from flask import g, request
from flask_login import current_user from flask_login import current_user
from app.models import Formation, UniteEns, Matiere, Module
import app.scodoc.notesdb as ndb from app import db
from app.models import Formation, UniteEns, Matiere, Module, FormSemestre, ModuleImpl
from app.models.notes import ScolarFormsemestreValidation
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
@ -135,3 +137,37 @@ def html_edit_formation_apc(
] ]
return "\n".join(H) return "\n".join(H)
def html_ue_infos(ue):
"""page d'information sur une UE"""
from app.views import ScoData
formsemestres = (
db.session.query(FormSemestre)
.filter(
ue.id == Module.ue_id,
Module.id == ModuleImpl.module_id,
FormSemestre.id == ModuleImpl.formsemestre_id,
)
.all()
)
nb_etuds_valid_ue = ScolarFormsemestreValidation.query.filter_by(
ue_id=ue.id
).count()
can_safely_be_suppressed = (
(nb_etuds_valid_ue == 0)
and (len(formsemestres) == 0)
and ue.modules.count() == 0
and ue.matieres.count() == 0
)
return render_template(
"pn/ue_infos.html",
# "pn/tmp.html",
titre=f"UE {ue.acronyme} {ue.titre}",
ue=ue,
formsemestres=formsemestres,
nb_etuds_valid_ue=nb_etuds_valid_ue,
can_safely_be_suppressed=can_safely_be_suppressed,
sco=ScoData(),
)

View File

@ -1672,7 +1672,7 @@ ul.notes_module_list {
font-style: normal; font-style: normal;
} }
.notes_ue_list a.discretelink, .notes_ue_list a.stdlink { .notes_ue_list a.stdlink {
color: #001084; color: #001084;
text-decoration: underline; text-decoration: underline;
} }

View File

@ -2,34 +2,39 @@
<!-- formsemestre_header --> <!-- formsemestre_header -->
<div class="formsemestre_page_title"> <div class="formsemestre_page_title">
<div class="infos"> <div class="infos">
<span class="semtitle"><a class="stdlink" title="{{sco.sem.session_id()}}" <span class="semtitle"><a class="stdlink" title="{{sco.sem.session_id()}}" href="{{
href="{{
url_for('notes.formsemestre_status', url_for('notes.formsemestre_status',
scodoc_dept=g.scodoc_dept, formsemestre_id=sco.sem.id) scodoc_dept=g.scodoc_dept, formsemestre_id=sco.sem.id)
}}">{{sco.sem.titre}}</a> }}">{{sco.sem.titre}}</a>
<a title="{{sco.sem.etapes_apo_str()}}"> <a title="{{sco.sem.etapes_apo_str()}}">
{% if sco.sem.semestre_id != -1 %}, {{sco.sem.formation.get_parcours().SESSION_NAME}} {{sco.sem.semestre_id}} {% if sco.sem.semestre_id != -1 %}, {{sco.sem.formation.get_parcours().SESSION_NAME}}
{% endif %}</a> {{sco.sem.semestre_id}}
{% if sco.sem.modalite %} en {{sco.sem.modalite}}{% endif %}</span> {% endif %}</a>
{% if sco.sem.modalite %} en {{sco.sem.modalite}}{% endif %}</span>
<span class="dates"> <span class="dates">
<a title="du {{sco.sem.date_debut.strftime('%d/%m/%Y')}} <a title="du {{sco.sem.date_debut.strftime('%d/%m/%Y')}}
au {{sco.sem.date_fin.strftime('%d/%m/%Y')}} ">{{sco.scu.MONTH_NAMES_ABBREV[ sco.sem.date_debut.month]}} {{sco.sem.date_debut.year}} - {{sco.scu.MONTH_NAMES_ABBREV[sco.sem.date_fin.month]}} {{sco.sem.date_fin.year}}</a></span> au {{sco.sem.date_fin.strftime('%d/%m/%Y')}} ">{{sco.scu.MONTH_NAMES_ABBREV[ sco.sem.date_debut.month - 1]}}
{{sco.sem.date_debut.year}} - {{sco.scu.MONTH_NAMES_ABBREV[sco.sem.date_fin.month - 1]}}
{{sco.sem.date_fin.year}}</a></span>
<span class="resp"><a <span class="resp"><a
title="{{sco.sem.responsables_str(abbrev_prenom=False)}}">{{sco.sem.responsables_str()}}</a></span> title="{{sco.sem.responsables_str(abbrev_prenom=False)}}">{{sco.sem.responsables_str()}}</a></span>
<span class="nbinscrits"><a class="discretelink" <span class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_view', scodoc_dept=g.scodoc_dept,
href="{{url_for('scolar.groups_view', scodoc_dept=g.scodoc_dept, formsemestre_id=sco.sem.id)}}">{{sco.sem.inscriptions|length}} inscrits</a></span><span class="lock">{% if
formsemestre_id=sco.sem.id)}}">{{sco.sem.inscriptions|length}} inscrits</a></span><span class="lock">{% if sco.sem.etat %}<a href="{{url_for("notes.formsemestre_change_lock", scodoc_dept=g.scodoc_dept, formsemestre_id=sco.sem.id)}}">{{sco.scu.icontag("lock_img", border="0", title="Semestre verrouillé")|safe}}</a>{% endif %}</span><span class="eye"> sco.sem.etat %}<a href="{{url_for(" notes.formsemestre_change_lock", scodoc_dept=g.scodoc_dept,
{% if sco.prefs["bul_display_publication"] %} formsemestre_id=sco.sem.id)}}">{{sco.scu.icontag("lock_img", border="0", title="Semestre
<a href="{{url_for("notes.formsemestre_change_publication_bul", scodoc_dept=g.scodoc_dept, formsemestre_id=sco.sem.id)}}"> verrouillé")|safe}}</a>{% endif %}</span><span class="eye">
{% if sco.sem.bul_hide_xml %} {% if sco.prefs["bul_display_publication"] %}
{{ sco.scu.icontag("hide_img", border="0", title="Bulletins NON publiés")|safe}} <a href="{{url_for(" notes.formsemestre_change_publication_bul", scodoc_dept=g.scodoc_dept,
{% else %} formsemestre_id=sco.sem.id)}}">
{{ sco.scu.icontag("eye_img", border="0", title="Bulletins publiés")|safe }} {% if sco.sem.bul_hide_xml %}
{% endif %} {{ sco.scu.icontag("hide_img", border="0", title="Bulletins NON publiés")|safe}}
{% endif %} {% else %}
{{ sco.scu.icontag("eye_img", border="0", title="Bulletins publiés")|safe }}
{% endif %}
{% endif %}
</span> </span>
</div> </div>
{{ sco.sem_menu_bar|safe }} {{ sco.sem_menu_bar|safe }}
</div> </div>
<!-- end of formsemestre_header --> <!-- end of formsemestre_header -->

View File

@ -4,7 +4,9 @@
{% for semestre_idx in semestre_ids %} {% for semestre_idx in semestre_ids %}
<div class="formation_list_ues_sem">Semestre S{{semestre_idx}}</div> <div class="formation_list_ues_sem">Semestre S{{semestre_idx}}</div>
<ul class="apc_ue_list"> <ul class="apc_ue_list">
{% for ue in formation.ues.filter_by(semestre_idx=semestre_idx).order_by(UniteEns.semestre_idx, UniteEns.numero, UniteEns.acronyme) %} {% for ue in formation.ues.filter_by(semestre_idx=semestre_idx).order_by(
UniteEns.semestre_idx, UniteEns.numero, UniteEns.acronyme
) %}
<li class="notes_ue_list"> <li class="notes_ue_list">
{% if editable and not loop.first %} {% if editable and not loop.first %}
<a href="{{ url_for('notes.ue_move', <a href="{{ url_for('notes.ue_move',
@ -29,7 +31,10 @@
{{icons.delete_disabled|safe}} {{icons.delete_disabled|safe}}
{% endif %} {% endif %}
<b>{{ue.acronyme}}</b> {{ue.titre}} <b>{{ue.acronyme}}</b> <a class="discretelink" href="{{
url_for('notes.ue_infos', scodoc_dept=g.scodoc_dept, ue_id=ue.id)}}"
>{{ue.titre}}</a>
{% if editable and not ue.is_locked() %} {% if editable and not ue.is_locked() %}
<a class="stdlink" href="{{ url_for('notes.ue_edit', <a class="stdlink" href="{{ url_for('notes.ue_edit',
scodoc_dept=g.scodoc_dept, ue_id=ue.id) scodoc_dept=g.scodoc_dept, ue_id=ue.id)

View File

@ -0,0 +1,64 @@
{# Informations sur une UE #}
{% extends "sco_page.html" %}
{% block app_content %}
<h2>Unité d'Enseignement {{ue.acronyme}} {{ue.titre}}</h2>
<div class="ue_infos">
<ul>
<li>{{ue.acronyme}}
<ul>
<li>Semestre: {{ue.semestre_idx}}</li>
<li>Code: {{ue.code}}</li>
<li>Type: {{ue.type}}</li>
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
<li>Code Apogée: {{ue.code_apogee}}</li>
</ul>
</li>
<li>Formation:
<ul>
<li>Acronyme: {{ue.formation.acronyme}}</li>
<li>Titre: {{ue.formation.titre}}</li>
<li>Version: {{ue.formation.version}}</li>
</ul>
</li>
</ul>
<h3>Utilisation de l'unité {{ue.acronyme}}</h3>
<ul>
<li>Modules rattachés: {{ue.modules.count()}}</li>
<li>Matières rattachées: {{ue.matieres.count()}}</li>
<li>Semestres avec modules rattachés à cette UE:
{% for sem in formsemestres %}
<a href="{{url_for('notes.formsemestre_status',
scodoc_dept=g.scodoc_dept, formsemestre_id=sem.id )}}"
>{{sem.titre_mois()}}</a>
{% else %}
<em>aucun</em>
{% endfor %}
</li>
<li>Étudiants ayant validé cette UE: {{nb_etuds_valid_ue}}
</li>
<li>
{% if can_safely_be_suppressed %}
cette UE pourrait être supprimée
{% else %}
cette UE ne peut pas être supprimée
{% endif %}
</ul>
<ul>
<li><a href="url_for('notes.ue_edit', scodoc_dept=g.scodoc_dept, ue_id=ue.id)"
>modifier cette UE</a>
</li>
<li><a href="{{url_for("notes.ue_table",
scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)}}"
>retour à la page d'édition de la formation</a>
</li>
</ul>
</div>
{% endblock %}

View File

@ -43,6 +43,7 @@ from flask import current_app, g, request
from flask_login import current_user from flask_login import current_user
from werkzeug.utils import redirect from werkzeug.utils import redirect
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
from app.models.ues import UniteEns
from config import Config from config import Config
@ -88,6 +89,7 @@ from app.scodoc import sco_cache
from app.scodoc import sco_compute_moy from app.scodoc import sco_compute_moy
from app.scodoc import sco_cost_formation from app.scodoc import sco_cost_formation
from app.scodoc import sco_debouche from app.scodoc import sco_debouche
from app.scodoc import sco_edit_apc
from app.scodoc import sco_edit_formation from app.scodoc import sco_edit_formation
from app.scodoc import sco_edit_matiere from app.scodoc import sco_edit_matiere
from app.scodoc import sco_edit_module from app.scodoc import sco_edit_module
@ -375,6 +377,14 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):
) )
@bp.route("/ue_infos/<ue_id>")
@scodoc
@permission_required(Permission.ScoView)
def ue_infos(ue_id):
ue = UniteEns.query.get_or_404(ue_id)
return sco_edit_apc.html_ue_infos(ue)
@bp.route("/ue_set_internal", methods=["GET", "POST"]) @bp.route("/ue_set_internal", methods=["GET", "POST"])
@scodoc @scodoc
@permission_required(Permission.ScoChangeFormation) @permission_required(Permission.ScoChangeFormation)

View File

@ -0,0 +1,78 @@
"""index on validations
Revision ID: 730ac71eea23
Revises: 92789d50f6b6
Create Date: 2021-12-09 23:58:51.162711
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "730ac71eea23"
down_revision = "92789d50f6b6"
branch_labels = None
depends_on = None
def upgrade():
# Met à "STANDARD" (0) le type des modules sans types
op.execute("UPDATE notes_modules set module_type = 0 where module_type is NULL;")
# ### commands auto generated by Alembic - please adjust! ###
op.create_index(
op.f("ix_notes_formsemestre_etapes_etape_apo"),
"notes_formsemestre_etapes",
["etape_apo"],
unique=False,
)
op.create_index(
op.f("ix_scolar_formsemestre_validation_code"),
"scolar_formsemestre_validation",
["code"],
unique=False,
)
op.create_index(
op.f("ix_scolar_formsemestre_validation_etudid"),
"scolar_formsemestre_validation",
["etudid"],
unique=False,
)
op.create_index(
op.f("ix_scolar_formsemestre_validation_formsemestre_id"),
"scolar_formsemestre_validation",
["formsemestre_id"],
unique=False,
)
op.create_index(
op.f("ix_scolar_formsemestre_validation_ue_id"),
"scolar_formsemestre_validation",
["ue_id"],
unique=False,
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(
op.f("ix_scolar_formsemestre_validation_ue_id"),
table_name="scolar_formsemestre_validation",
)
op.drop_index(
op.f("ix_scolar_formsemestre_validation_formsemestre_id"),
table_name="scolar_formsemestre_validation",
)
op.drop_index(
op.f("ix_scolar_formsemestre_validation_etudid"),
table_name="scolar_formsemestre_validation",
)
op.drop_index(
op.f("ix_scolar_formsemestre_validation_code"),
table_name="scolar_formsemestre_validation",
)
op.drop_index(
op.f("ix_notes_formsemestre_etapes_etape_apo"),
table_name="notes_formsemestre_etapes",
)
# ### end Alembic commands ###