2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
#
##############################################################################
2021-06-16 18:18:32 +02:00
""" Ajout/Modification/Suppression UE
2020-09-26 16:19:37 +02:00
"""
2024-07-31 13:40:30 +02:00
2023-02-27 15:39:29 +01:00
import re
2023-04-03 17:40:45 +02:00
import sqlalchemy as sa
2021-07-31 18:01:10 +02:00
import flask
2022-02-27 10:19:25 +01:00
from flask import flash , render_template , url_for
2021-11-18 00:24:56 +01:00
from flask import g , request
2021-07-31 18:01:10 +02:00
from flask_login import current_user
2023-07-11 06:57:38 +02:00
from app import db , log
2022-04-29 08:17:04 +02:00
from app . but import apc_edit_ue
2022-03-18 19:55:46 +01:00
from app . models import APO_CODE_STR_LEN , SHORT_STR_LEN
2022-07-13 18:52:07 +02:00
from app . models import (
Formation ,
2023-01-14 18:01:54 +01:00
FormSemestre ,
2022-07-13 18:52:07 +02:00
FormSemestreUEComputationExpr ,
FormSemestreUECoef ,
Matiere ,
UniteEns ,
)
from app . models import ApcValidationRCUE , ScolarFormSemestreValidation , ScolarEvent
2022-04-12 17:12:51 +02:00
from app . models import ScolarNews
2021-06-19 23:21:37 +02:00
import app . scodoc . notesdb as ndb
import app . scodoc . sco_utils as scu
2021-11-12 22:17:46 +01:00
from app . scodoc . sco_utils import ModuleType
2022-01-27 00:18:50 +01:00
from app . scodoc . TrivialFormulator import TrivialFormulator
2021-06-19 23:21:37 +02:00
from app . scodoc . sco_permissions import Permission
2022-01-04 20:03:38 +01:00
from app . scodoc . sco_exceptions import (
ScoValueError ,
ScoLockedFormError ,
ScoNonEmptyFormationObject ,
)
2021-06-19 23:21:37 +02:00
from app . scodoc import html_sco_header
2023-02-12 13:36:47 +01:00
from app . scodoc import codes_cursus
2021-11-17 10:28:51 +01:00
from app . scodoc import sco_edit_apc
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_edit_matiere
from app . scodoc import sco_edit_module
from app . scodoc import sco_groups
from app . scodoc import sco_moduleimpl
from app . scodoc import sco_tag_module
2020-09-26 16:19:37 +02:00
2021-06-16 18:18:32 +02:00
_ueEditor = ndb . EditableTable (
" notes_ue " ,
" ue_id " ,
(
" ue_id " ,
" formation_id " ,
" acronyme " ,
" numero " ,
" titre " ,
2021-11-14 18:09:20 +01:00
" semestre_idx " ,
2021-06-16 18:18:32 +02:00
" type " ,
" ue_code " ,
" ects " ,
" is_external " ,
" code_apogee " ,
2024-06-09 15:18:03 +02:00
" code_apogee_rcue " ,
2021-06-16 18:18:32 +02:00
" coefficient " ,
2022-06-24 12:39:54 +02:00
" coef_rcue " ,
2022-01-25 10:45:13 +01:00
" color " ,
2022-07-13 19:23:55 +02:00
" niveau_competence_id " ,
2021-06-16 18:18:32 +02:00
) ,
2024-01-26 14:57:50 +01:00
convert_empty_to_nulls = False , # necessaire pour ue_code == ""
2021-06-16 18:18:32 +02:00
sortkey = " numero " ,
2021-08-11 00:36:07 +02:00
input_formators = {
" type " : ndb . int_null_is_zero ,
2022-08-06 22:31:41 +02:00
" is_external " : scu . to_bool ,
2022-02-28 11:00:24 +01:00
" ects " : ndb . float_null_is_null ,
2021-08-11 00:36:07 +02:00
} ,
2021-06-16 18:18:32 +02:00
output_formators = {
" numero " : ndb . int_null_is_zero ,
" ects " : ndb . float_null_is_null ,
" coefficient " : ndb . float_null_is_zero ,
2021-11-14 18:09:20 +01:00
" semestre_idx " : ndb . int_null_is_null ,
2021-06-16 18:18:32 +02:00
} ,
)
2021-10-17 23:19:26 +02:00
def ue_list ( * args , * * kw ) :
2021-06-16 18:18:32 +02:00
" list UEs "
cnx = ndb . GetDBConnexion ( )
return _ueEditor . list ( cnx , * args , * * kw )
2024-01-26 14:57:50 +01:00
def do_ue_create ( args , allow_empty_ue_code = False ) :
2021-06-16 18:18:32 +02:00
" create an ue "
cnx = ndb . GetDBConnexion ( )
# check duplicates
2021-10-17 23:19:26 +02:00
ues = ue_list ( { " formation_id " : args [ " formation_id " ] , " acronyme " : args [ " acronyme " ] } )
2021-06-16 18:18:32 +02:00
if ues :
2021-12-18 17:39:03 +01:00
raise ScoValueError (
2023-12-15 01:07:08 +01:00
f """ Acronyme d ' UE " { args [ ' acronyme ' ] } " déjà utilisé !
2021-12-18 17:39:03 +01:00
( chaque UE doit avoir un acronyme unique dans la formation ) """
)
2024-01-26 14:57:50 +01:00
if " ue_code " not in args or args [ " ue_code " ] is None or not args [ " ue_code " ] . strip ( ) :
if allow_empty_ue_code :
args [ " ue_code " ] = " "
else :
# évite les conflits: génère nouveau ue_code
while True :
cursor = db . session . execute ( sa . text ( " select notes_newid_ucod(); " ) )
code = cursor . fetchone ( ) [ 0 ]
if UniteEns . query . filter_by ( ue_code = code ) . count ( ) == 0 :
break
args [ " ue_code " ] = code
2024-02-08 15:56:58 +01:00
# last checks
if not args . get ( " acronyme " ) :
raise ScoValueError ( " acronyme vide " )
args [ " coefficient " ] = args . get ( " coefficient " , None )
if args [ " coefficient " ] == " " :
args [ " coefficient " ] = None
2021-06-16 18:18:32 +02:00
# create
2024-02-08 15:56:58 +01:00
# XXX TODO utiliser UniteEns.create_from_dict
2021-12-13 23:44:13 +01:00
ue_id = _ueEditor . create ( cnx , args )
2022-09-08 01:20:04 +02:00
log ( f " do_ue_create: created { ue_id } with { args } " )
2021-06-16 18:18:32 +02:00
2023-07-11 06:57:38 +02:00
formation : Formation = db . session . get ( Formation , args [ " formation_id " ] )
2021-12-13 23:44:13 +01:00
formation . invalidate_module_coefs ( )
2021-06-16 18:18:32 +02:00
# news
2023-07-11 06:57:38 +02:00
formation = db . session . get ( Formation , args [ " formation_id " ] )
2022-04-12 17:12:51 +02:00
ScolarNews . add (
typ = ScolarNews . NEWS_FORM ,
obj = args [ " formation_id " ] ,
2022-03-15 10:57:52 +01:00
text = f " Modification de la formation { formation . acronyme } " ,
2021-06-16 18:18:32 +02:00
)
2022-02-14 18:33:36 +01:00
formation . invalidate_cached_sems ( )
2021-12-13 23:44:13 +01:00
return ue_id
2021-06-16 18:18:32 +02:00
2022-07-13 18:52:07 +02:00
def do_ue_delete ( ue : UniteEns , delete_validations = False , force = False ) :
""" delete UE and attached matieres (but not modules).
Si force , pas de confirmation dialog et pas de redirect
"""
formation : Formation = ue . formation
2022-05-10 17:56:21 +02:00
semestre_idx = ue . semestre_idx
2022-06-08 17:42:52 +02:00
if not ue . can_be_deleted ( ) :
2022-01-04 20:03:38 +01:00
raise ScoNonEmptyFormationObject (
2022-06-08 17:42:52 +02:00
f " UE (id= { ue . id } , dud) " ,
2024-02-13 13:55:16 +01:00
msg = f " { ue . titre or ' ' } ( { ue . acronyme } ) " ,
2022-01-04 20:03:38 +01:00
dest_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
2022-06-24 03:34:52 +02:00
formation_id = formation . id ,
2022-05-10 17:56:21 +02:00
semestre_idx = semestre_idx ,
2022-01-04 20:03:38 +01:00
) ,
)
2022-07-13 18:52:07 +02:00
log ( f " do_ue_delete: ue_id= { ue . id } , delete_validations= { delete_validations } " )
2021-06-16 18:18:32 +02:00
# Il y a-t-il des etudiants ayant validé cette UE ?
# si oui, propose de supprimer les validations
2022-07-13 18:52:07 +02:00
validations_ue = ScolarFormSemestreValidation . query . filter_by ( ue_id = ue . id ) . all ( )
validations_rcue = ApcValidationRCUE . query . filter (
( ApcValidationRCUE . ue1_id == ue . id ) | ( ApcValidationRCUE . ue2_id == ue . id )
) . all ( )
if (
( len ( validations_ue ) > 0 or len ( validations_rcue ) > 0 )
and not delete_validations
and not force
) :
2021-06-16 18:18:32 +02:00
return scu . confirm_dialog (
2022-07-13 18:52:07 +02:00
f """ <p>Des étudiants ont une décision de jury sur l ' UE { ue . acronyme } ( { ue . titre } )</p>
< p > Si vous supprimez cette UE , ces décisions vont être supprimées ! < / p > """ ,
2021-06-16 18:18:32 +02:00
dest_url = " " ,
target_variable = " delete_validations " ,
2021-10-22 23:09:15 +02:00
cancel_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
2022-06-24 03:34:52 +02:00
formation_id = formation . id ,
2022-05-10 17:56:21 +02:00
semestre_idx = semestre_idx ,
2021-10-22 23:09:15 +02:00
) ,
2022-01-04 20:03:38 +01:00
parameters = { " ue_id " : ue . id , " dialog_confirmed " : 1 } ,
2021-06-16 18:18:32 +02:00
)
if delete_validations :
2022-05-10 17:56:21 +02:00
log ( f " deleting all validations of UE { ue . id } " )
2022-07-13 18:52:07 +02:00
for v in validations_ue :
db . session . delete ( v )
for v in validations_rcue :
db . session . delete ( v )
2022-06-29 13:27:29 +02:00
# delete old formulas
2022-07-13 18:52:07 +02:00
formulas = FormSemestreUEComputationExpr . query . filter_by ( ue_id = ue . id ) . all ( )
for formula in formulas :
db . session . delete ( formula )
# delete all matieres in this UE
for mat in Matiere . query . filter_by ( ue_id = ue . id ) :
db . session . delete ( mat )
# delete uecoefs
for uecoef in FormSemestreUECoef . query . filter_by ( ue_id = ue . id ) :
db . session . delete ( uecoef )
# delete events
for event in ScolarEvent . query . filter_by ( ue_id = ue . id ) :
db . session . delete ( event )
db . session . flush ( )
db . session . delete ( ue )
db . session . commit ( )
# cas compliqué, mais rarement utilisé: acceptable de tout invalider
2022-06-24 03:34:52 +02:00
formation . invalidate_module_coefs ( )
2022-07-13 18:52:07 +02:00
# -> invalide aussi les formsemestres
2021-06-16 18:18:32 +02:00
# news
2022-04-12 17:12:51 +02:00
ScolarNews . add (
typ = ScolarNews . NEWS_FORM ,
2022-06-24 03:34:52 +02:00
obj = formation . id ,
text = f " Modification de la formation { formation . acronyme } " ,
2021-06-16 18:18:32 +02:00
)
#
if not force :
2021-07-31 18:01:10 +02:00
return flask . redirect (
url_for (
2021-10-17 23:19:26 +02:00
" notes.ue_table " ,
2021-07-31 18:01:10 +02:00
scodoc_dept = g . scodoc_dept ,
2022-06-24 03:34:52 +02:00
formation_id = formation . id ,
2022-05-10 17:56:21 +02:00
semestre_idx = semestre_idx ,
2021-07-31 18:01:10 +02:00
)
2021-06-16 18:18:32 +02:00
)
2022-01-04 20:03:38 +01:00
return None
2021-06-16 18:18:32 +02:00
2020-09-26 16:19:37 +02:00
2022-02-02 10:23:40 +01:00
def ue_create ( formation_id = None , default_semestre_idx = None ) :
""" Formulaire création d ' une UE """
return ue_edit (
create = True ,
formation_id = formation_id ,
default_semestre_idx = default_semestre_idx ,
)
2020-09-26 16:19:37 +02:00
2022-02-02 10:23:40 +01:00
def ue_edit ( ue_id = None , create = False , formation_id = None , default_semestre_idx = None ) :
""" Formulaire modification ou création d ' une UE """
2020-09-26 16:19:37 +02:00
create = int ( create )
if not create :
2022-02-02 21:13:39 +01:00
ue : UniteEns = UniteEns . query . get_or_404 ( ue_id )
ue_dict = ue . to_dict ( )
formation_id = ue . formation_id
title = f " Modification de l ' UE { ue . acronyme } { ue . titre } "
initvalues = ue_dict
2020-09-26 16:19:37 +02:00
submitlabel = " Modifier les valeurs "
2022-05-01 23:58:41 +02:00
can_change_semestre_id = (
( ue . modules . count ( ) == 0 ) or ( ue . semestre_idx is None )
) and ue . niveau_competence is None
2020-09-26 16:19:37 +02:00
else :
2022-02-02 21:13:39 +01:00
ue = None
2020-09-26 16:19:37 +02:00
title = " Création d ' une UE "
2023-02-27 15:39:29 +01:00
exp = re . compile ( r " UCOD( \ d+)$ " )
matches = { exp . match ( u . ue_code ) for u in UniteEns . query if exp . match ( u . ue_code ) }
max_code = (
max ( int ( match . group ( 1 ) ) for match in matches if match ) if matches else 0
)
proposed_code = f " UCOD { max_code + 1 } "
2022-02-02 22:04:18 +01:00
initvalues = {
" semestre_idx " : default_semestre_idx ,
" color " : ue_guess_color_default ( formation_id , default_semestre_idx ) ,
2022-06-24 12:39:54 +02:00
" coef_rcue " : 1.0 ,
2023-02-27 15:39:29 +01:00
" ue_code " : proposed_code ,
2022-02-02 22:04:18 +01:00
}
2020-09-26 16:19:37 +02:00
submitlabel = " Créer cette UE "
2022-02-02 21:13:39 +01:00
can_change_semestre_id = True
2023-07-11 06:57:38 +02:00
formation = db . session . get ( Formation , formation_id )
2021-11-14 18:09:20 +01:00
if not formation :
raise ScoValueError ( f " Formation inexistante ! (id= { formation_id } ) " )
2023-02-12 13:36:47 +01:00
cursus = formation . get_cursus ( )
is_apc = cursus . APC_SAE
semestres_indices = list ( range ( 1 , cursus . NB_SEM + 1 ) )
2020-09-26 16:19:37 +02:00
2023-02-12 13:36:47 +01:00
ue_types = cursus . ALLOWED_UE_TYPES
2020-09-26 16:19:37 +02:00
ue_types . sort ( )
2023-02-12 13:36:47 +01:00
ue_types_names = [ codes_cursus . UE_TYPE_NAME [ k ] for k in ue_types ]
2020-09-26 16:19:37 +02:00
ue_types = [ str ( x ) for x in ue_types ]
2022-02-02 21:13:39 +01:00
form_descr = [
2020-09-26 16:19:37 +02:00
( " ue_id " , { " input_type " : " hidden " } ) ,
( " create " , { " input_type " : " hidden " , " default " : create } ) ,
( " formation_id " , { " input_type " : " hidden " , " default " : formation_id } ) ,
2022-10-31 23:06:56 +01:00
( " titre " , { " size " : 48 , " explanation " : " nom de l ' UE " } ) ,
( " acronyme " , { " size " : 12 , " explanation " : " abbréviation " , " allow_null " : False } ) ,
2020-09-26 16:19:37 +02:00
(
" numero " ,
{
2022-03-01 23:25:42 +01:00
" size " : 4 ,
2020-09-26 16:19:37 +02:00
" explanation " : " numéro (1,2,3,4) de l ' UE pour l ' ordre d ' affichage " ,
" type " : " int " ,
} ,
) ,
2022-02-02 21:13:39 +01:00
]
if can_change_semestre_id :
form_descr + = [
(
" semestre_idx " ,
{
" input_type " : " menu " ,
" type " : " int " ,
" allow_null " : False ,
2023-02-12 13:36:47 +01:00
" title " : cursus . SESSION_NAME . capitalize ( ) ,
" explanation " : f " { cursus . SESSION_NAME } de l ' UE dans la formation " ,
2022-02-02 21:13:39 +01:00
" labels " : [ " non spécifié " ] + [ str ( x ) for x in semestres_indices ] ,
" allowed_values " : [ " " ] + semestres_indices ,
} ,
) ,
]
else :
form_descr + = [
( " semestre_idx " , { " default " : ue . semestre_idx , " input_type " : " hidden " } ) ,
]
form_descr + = [
2020-09-26 16:19:37 +02:00
(
" type " ,
{
" explanation " : " type d ' UE " ,
" input_type " : " menu " ,
" allowed_values " : ue_types ,
" labels " : ue_types_names ,
} ,
) ,
(
" ects " ,
{
" size " : 4 ,
" type " : " float " ,
2022-08-29 15:23:44 +02:00
" min_value " : 0 ,
" max_value " : 1000 ,
2020-09-26 16:19:37 +02:00
" title " : " ECTS " ,
2023-04-11 13:48:57 +02:00
" explanation " : " nombre de crédits ECTS (indiquer 0 si UE bonus) "
+ (
" . (si les ECTS dépendent du parcours, voir plus bas.) "
if is_apc
else " "
) ,
2022-02-28 11:00:24 +01:00
" allow_null " : not is_apc , # ects requis en APC
2020-09-26 16:19:37 +02:00
} ,
) ,
2022-06-24 12:39:54 +02:00
]
if is_apc : # coef pour la moyenne RCUE
form_descr . append (
(
" coef_rcue " ,
{
" size " : 4 ,
" type " : " float " ,
2022-08-29 15:23:44 +02:00
" min_value " : 0 ,
2022-06-24 12:39:54 +02:00
" title " : " Coef. RCUE " ,
" explanation " : """ pondération utilisée pour le calcul de la moyenne du RCUE. Laisser à 1, sauf si votre établissement a explicitement décidé de pondérations.
""" ,
" defaut " : 1.0 ,
" allow_null " : False ,
" enabled " : is_apc ,
} ,
)
)
else : # non APC, coef d'UE
form_descr . append (
(
" coefficient " ,
{
" size " : 4 ,
" type " : " float " ,
2022-08-29 15:23:44 +02:00
" min_value " : 0 ,
2022-06-24 12:39:54 +02:00
" title " : " Coefficient " ,
" explanation " : """ les coefficients d ' UE ne sont utilisés que
2021-11-14 18:09:20 +01:00
lorsque l ' option <em>Utiliser les coefficients d ' UE pour calculer
la moyenne générale < / em > est activée . Par défaut , le coefficient
d ' une UE est simplement la somme des coefficients des modules dans
lesquels l ' étudiant a des notes.
2022-01-30 08:17:25 +01:00
Jamais utilisé en BUT .
2021-11-14 18:09:20 +01:00
""" ,
2022-06-24 12:39:54 +02:00
" enabled " : not is_apc ,
} ,
)
)
form_descr + = [
2020-09-26 16:19:37 +02:00
(
" ue_code " ,
{
" size " : 12 ,
" title " : " Code UE " ,
2022-03-18 19:55:46 +01:00
" max_length " : SHORT_STR_LEN ,
2023-12-15 01:07:08 +01:00
" explanation " : """ code interne (non vide). Toutes les UE partageant le même code
( et le même code de formation ) sont compatibles ( compensation de semestres , capitalisation d ' UE).
2022-03-18 19:55:46 +01:00
Voir liste ci - dessous . """ ,
2023-02-23 21:19:57 +01:00
" allow_null " : False ,
2020-09-26 16:19:37 +02:00
} ,
) ,
(
" code_apogee " ,
{
" title " : " Code Apogée " ,
2021-06-24 23:09:06 +02:00
" size " : 25 ,
" explanation " : " (optionnel) code élément pédagogique Apogée ou liste de codes ELP séparés par des virgules " ,
2022-03-18 19:55:46 +01:00
" max_length " : APO_CODE_STR_LEN ,
2020-09-26 16:19:37 +02:00
} ,
) ,
2024-06-09 15:18:03 +02:00
]
if is_apc :
form_descr + = [
(
" code_apogee_rcue " ,
{
" title " : " Code Apogée du RCUE " ,
" size " : 25 ,
" explanation " : " (optionnel) code(s) élément pédagogique Apogée du RCUE " ,
" max_length " : APO_CODE_STR_LEN ,
} ,
) ,
]
form_descr + = [
2021-10-22 23:09:15 +02:00
(
" is_external " ,
{
" input_type " : " boolcheckbox " ,
" title " : " UE externe " ,
2023-06-13 21:28:37 +02:00
" readonly " : not create , # ne permet pas de transformer une UE existante en externe
2021-10-22 23:09:15 +02:00
" explanation " : " réservé pour les capitalisations d ' UE effectuées à l ' extérieur de l ' établissement " ,
} ,
) ,
2022-01-25 10:45:13 +01:00
(
" color " ,
{
" input_type " : " color " ,
" title " : " Couleur " ,
" explanation " : " pour affichages " ,
} ,
) ,
2020-09-26 16:19:37 +02:00
]
2023-02-12 13:36:47 +01:00
if create and not cursus . UE_IS_MODULE and not is_apc :
2022-02-02 21:13:39 +01:00
form_descr . append (
2020-09-26 16:19:37 +02:00
(
" create_matiere " ,
{
" input_type " : " boolcheckbox " ,
2021-11-14 18:09:20 +01:00
" default " : True ,
2020-09-26 16:19:37 +02:00
" title " : " Créer matière identique " ,
" explanation " : " créer immédiatement une matière dans cette UE (utile si on n ' utilise pas de matières) " ,
} ,
)
)
tf = TrivialFormulator (
2021-09-18 10:10:02 +02:00
request . base_url ,
2021-09-27 16:42:14 +02:00
scu . get_request_args ( ) ,
2022-02-02 21:13:39 +01:00
form_descr ,
2021-09-18 10:10:02 +02:00
initvalues = initvalues ,
submitlabel = submitlabel ,
2022-04-29 08:17:04 +02:00
cancelbutton = " Revenir à la formation " ,
2020-09-26 16:19:37 +02:00
)
if tf [ 0 ] == 0 :
2023-04-11 23:56:50 +02:00
ue_parcours_div = " "
2022-04-29 08:17:04 +02:00
if ue and is_apc :
2023-04-11 23:56:50 +02:00
ue_parcours_div = apc_edit_ue . form_ue_choix_parcours ( ue )
2022-02-11 09:43:53 +01:00
if ue and ue . modules . count ( ) and ue . semestre_idx is not None :
2024-03-31 10:21:44 +02:00
modules_div = f """ <div class= " scobox " id= " ue_list_modules " >
2022-02-02 21:13:39 +01:00
< div > < b > { ue . modules . count ( ) } modules sont rattachés
à cette UE < / b > du semestre S { ue . semestre_idx } ,
elle ne peut donc pas être changée de semestre . < / div >
< ul > """
for m in ue . modules :
modules_div + = f """ <li><a class= " stdlink " href= " { url_for (
2023-02-06 10:24:41 +01:00
" notes.module_edit " ,
scodoc_dept = g . scodoc_dept , module_id = m . id )
} " > {m.code} { m.titre or " sans titre " }</a></li> " " "
2022-02-02 21:13:39 +01:00
modules_div + = """ </ul></div> """
else :
modules_div = " "
2022-11-02 10:41:31 +01:00
if ue :
clone_form = f """
< form action = " ue_clone " class = " clone_form " method = " post " >
< input type = " hidden " name = " ue_id " value = " {ue.id} " >
< button type = " submit " > Créer une copie de cette UE < / button >
< / form >
"""
else :
clone_form = " "
2024-03-31 10:21:44 +02:00
return f """
{ html_sco_header . sco_header ( page_title = title , javascripts = [ " js/edit_ue.js " ] ) }
< h2 > { title } , ( formation { formation . acronyme } , version { formation . version } ) < / h2 >
< p class = " help " > Les UEs sont des groupes de modules dans une formation donnée ,
utilisés pour la validation ( on calcule des moyennes par UE et applique des
seuils ( " barres " ) ) .
< / p >
< p class = " help " > Note : sauf exception , l ' UE n ' a pas de coefficient associé .
Seuls les < em > modules < / em > ont des coefficients .
< / p >
< div class = " scobox " >
< div class = " scobox-title " >
Édition de l ' UE { ( ' du semestre S ' +str(ue.semestre_idx)) if is_apc and ue else ' ' }
< / div >
{ tf [ 1 ] }
< / div >
{ clone_form }
{ ue_parcours_div }
{ modules_div }
2024-06-24 16:48:13 +02:00
< div id = " bonus_description " class = " scobox " > < / div >
2024-03-31 10:21:44 +02:00
< div id = " ue_list_code " class = " sco_box sco_green_bg " > < / div >
{ html_sco_header . sco_footer ( ) }
"""
2022-07-09 12:55:23 +02:00
elif tf [ 0 ] == 1 :
2020-09-26 16:19:37 +02:00
if create :
if not tf [ 2 ] [ " ue_code " ] :
del tf [ 2 ] [ " ue_code " ]
if not tf [ 2 ] [ " numero " ] :
# numero regroupant par semestre ou année:
tf [ 2 ] [ " numero " ] = next_ue_numero (
2021-11-14 18:09:20 +01:00
formation_id , int ( tf [ 2 ] [ " semestre_idx " ] )
2020-09-26 16:19:37 +02:00
)
2021-08-20 01:09:55 +02:00
ue_id = do_ue_create ( tf [ 2 ] )
2023-02-12 13:36:47 +01:00
if is_apc or cursus . UE_IS_MODULE or tf [ 2 ] [ " create_matiere " ] :
2021-11-18 00:24:56 +01:00
# rappel: en APC, toutes les UE ont une matière, créée ici
# (inutilisée mais à laquelle les modules sont rattachés)
2021-06-17 00:08:37 +02:00
matiere_id = sco_edit_matiere . do_matiere_create (
{ " ue_id " : ue_id , " titre " : tf [ 2 ] [ " titre " ] , " numero " : 1 } ,
2020-09-26 16:19:37 +02:00
)
2023-02-12 13:36:47 +01:00
if cursus . UE_IS_MODULE :
2020-09-26 16:19:37 +02:00
# dans ce mode, crée un (unique) module dans l'UE:
2021-06-17 00:08:37 +02:00
_ = sco_edit_module . do_module_create (
2020-09-26 16:19:37 +02:00
{
" titre " : tf [ 2 ] [ " titre " ] ,
" code " : tf [ 2 ] [ " acronyme " ] ,
2023-02-06 10:24:41 +01:00
# tous les modules auront coef 1, et on utilisera les ECTS:
" coefficient " : 1.0 ,
2020-09-26 16:19:37 +02:00
" ue_id " : ue_id ,
" matiere_id " : matiere_id ,
" formation_id " : formation_id ,
2021-11-14 18:09:20 +01:00
" semestre_id " : tf [ 2 ] [ " semestre_idx " ] ,
2020-09-26 16:19:37 +02:00
} ,
)
2023-07-11 06:57:38 +02:00
ue = db . session . get ( UniteEns , ue_id )
2022-10-24 23:18:45 +02:00
flash ( f " UE créée (code { ue . ue_code } ) " )
2020-09-26 16:19:37 +02:00
else :
2023-07-05 19:15:33 +02:00
if not tf [ 2 ] [ " numero " ] :
tf [ 2 ] [ " numero " ] = 0
2021-08-20 01:09:55 +02:00
do_ue_edit ( tf [ 2 ] )
2022-02-28 11:47:39 +01:00
flash ( " UE modifiée " )
2022-06-29 09:08:31 +02:00
if tf [ 2 ] :
dest_semestre_idx = tf [ 2 ] [ " semestre_idx " ]
elif ue :
dest_semestre_idx = ue . semestre_idx
elif default_semestre_idx :
dest_semestre_idx = default_semestre_idx
elif " semestre_idx " in request . form :
dest_semestre_idx = request . form [ " semestre_idx " ]
else :
dest_semestre_idx = 1
return flask . redirect (
url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
formation_id = formation_id ,
semestre_idx = dest_semestre_idx ,
2020-09-26 16:19:37 +02:00
)
2022-06-29 09:08:31 +02:00
)
2020-09-26 16:19:37 +02:00
2021-11-17 10:28:51 +01:00
def _add_ue_semestre_id ( ues : list [ dict ] , is_apc ) :
2021-11-14 18:09:20 +01:00
""" ajoute semestre_id dans les ue, en regardant
2021-11-17 10:28:51 +01:00
semestre_idx ou à défaut , pour les formations non APC , le premier module
de chacune .
Les UE sans modules se voient attribuer le numero UE_SEM_DEFAULT ( 1000000 ) ,
2020-09-26 16:19:37 +02:00
qui les place à la fin de la liste .
"""
2021-10-21 06:32:03 +02:00
for ue in ues :
2021-11-14 18:09:20 +01:00
if ue [ " semestre_idx " ] is not None :
ue [ " semestre_id " ] = ue [ " semestre_idx " ]
2021-11-17 10:28:51 +01:00
elif is_apc :
2023-02-12 13:36:47 +01:00
ue [ " semestre_id " ] = codes_cursus . UE_SEM_DEFAULT
2020-09-26 16:19:37 +02:00
else :
2021-11-17 10:28:51 +01:00
# était le comportement ScoDoc7
2021-11-14 18:09:20 +01:00
modules = sco_edit_module . module_list ( args = { " ue_id " : ue [ " ue_id " ] } )
if modules :
ue [ " semestre_id " ] = modules [ 0 ] [ " semestre_id " ]
else :
2023-02-12 13:36:47 +01:00
ue [ " semestre_id " ] = codes_cursus . UE_SEM_DEFAULT
2020-09-26 16:19:37 +02:00
2021-08-20 01:09:55 +02:00
def next_ue_numero ( formation_id , semestre_id = None ) :
2020-09-26 16:19:37 +02:00
""" Numero d ' une nouvelle UE dans cette formation.
Si le semestre est specifie , cherche les UE ayant des modules de ce semestre
"""
2023-07-11 06:57:38 +02:00
formation = db . session . get ( Formation , formation_id )
2021-10-21 06:32:03 +02:00
ues = ue_list ( args = { " formation_id " : formation_id } )
if not ues :
2020-09-26 16:19:37 +02:00
return 0
if semestre_id is None :
2021-10-21 06:32:03 +02:00
return ues [ - 1 ] [ " numero " ] + 1000
2020-09-26 16:19:37 +02:00
else :
# Avec semestre: (prend le semestre du 1er module de l'UE)
2023-02-12 13:36:47 +01:00
_add_ue_semestre_id ( ues , formation . get_cursus ( ) . APC_SAE )
2021-10-21 06:32:03 +02:00
ue_list_semestre = [ ue for ue in ues if ue [ " semestre_id " ] == semestre_id ]
2020-09-26 16:19:37 +02:00
if ue_list_semestre :
return ue_list_semestre [ - 1 ] [ " numero " ] + 10
else :
2021-10-21 06:32:03 +02:00
return ues [ - 1 ] [ " numero " ] + 1000
2020-09-26 16:19:37 +02:00
2021-08-31 08:21:30 +02:00
def ue_delete ( ue_id = None , delete_validations = False , dialog_confirmed = False ) :
2020-09-26 16:19:37 +02:00
""" Delete an UE """
2022-01-04 20:03:38 +01:00
ue = UniteEns . query . get_or_404 ( ue_id )
if ue . modules . all ( ) :
raise ScoValueError (
f """ Suppression de l ' UE { ue . titre } impossible car
2022-01-09 21:48:58 +01:00
des modules ( ou SAÉ ou ressources ) lui sont rattachés . """ ,
dest_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
formation_id = ue . formation . id ,
semestre_idx = ue . semestre_idx ,
) ,
2022-01-04 20:03:38 +01:00
)
2022-06-08 17:42:52 +02:00
if not ue . can_be_deleted ( ) :
2022-01-04 20:03:38 +01:00
raise ScoNonEmptyFormationObject (
2024-02-13 13:55:16 +01:00
" UE " ,
msg = f " { ue . titre or ' ' } ( { ue . acronyme } ) " ,
2022-01-04 20:03:38 +01:00
dest_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
formation_id = ue . formation_id ,
semestre_idx = ue . semestre_idx ,
) ,
)
2020-09-26 16:19:37 +02:00
if not dialog_confirmed :
2021-06-02 22:40:34 +02:00
return scu . confirm_dialog (
2024-02-13 13:55:16 +01:00
f " <h2>Suppression de l ' UE { ue . titre or ' ' } ( { ue . acronyme } )</h2> " ,
2020-09-26 16:19:37 +02:00
dest_url = " " ,
2022-01-04 20:03:38 +01:00
parameters = { " ue_id " : ue . id } ,
2021-10-22 23:09:15 +02:00
cancel_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
2022-01-04 20:03:38 +01:00
formation_id = ue . formation_id ,
semestre_idx = ue . semestre_idx ,
2021-10-22 23:09:15 +02:00
) ,
2020-09-26 16:19:37 +02:00
)
2022-07-13 18:52:07 +02:00
return do_ue_delete ( ue , delete_validations = delete_validations )
2020-09-26 16:19:37 +02:00
2021-11-18 00:24:56 +01:00
def ue_table ( formation_id = None , semestre_idx = 1 , msg = " " ) : # was ue_list
2021-01-01 18:40:47 +01:00
""" Liste des matières et modules d ' une formation, avec liens pour
2021-10-17 23:19:26 +02:00
éditer ( si non verrouillée ) .
2020-09-26 16:19:37 +02:00
"""
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formsemestre_validation
2023-07-11 06:57:38 +02:00
formation : Formation = db . session . get ( Formation , formation_id )
2021-11-17 10:28:51 +01:00
if not formation :
2020-09-26 16:19:37 +02:00
raise ScoValueError ( " invalid formation_id " )
2023-02-12 13:36:47 +01:00
parcours = formation . get_cursus ( )
2021-11-13 12:09:30 +01:00
is_apc = parcours . APC_SAE
2022-11-03 14:14:30 +01:00
if semestre_idx == " all " or semestre_idx == " " :
2021-11-18 00:24:56 +01:00
semestre_idx = None
else :
semestre_idx = int ( semestre_idx )
2024-01-30 22:12:55 +01:00
show_tags = scu . to_bool ( request . args . get ( " show_tags " , 0 ) )
2023-02-17 22:07:03 +01:00
locked = formation . has_locked_sems ( semestre_idx )
2021-11-18 00:24:56 +01:00
semestre_ids = range ( 1 , parcours . NB_SEM + 1 )
2021-11-22 00:31:53 +01:00
# transition: on requete ici via l'ORM mais on utilise les fonctions ScoDoc7
# basées sur des dicts
2022-02-10 23:14:33 +01:00
ues_obj = UniteEns . query . filter_by (
formation_id = formation_id , is_external = False
) . order_by ( UniteEns . semestre_idx , UniteEns . numero )
2022-12-03 22:52:01 +01:00
# safety check: renumérote les ue s'il en manque ou s'il y a des ex-aequo.
# cela facilite le travail de la passerelle !
numeros = { ue . numero for ue in ues_obj }
if ( None in numeros ) or len ( numeros ) < ues_obj . count ( ) :
scu . objects_renumber ( db , ues_obj )
2021-11-22 00:31:53 +01:00
ues_externes_obj = UniteEns . query . filter_by (
formation_id = formation_id , is_external = True
)
2023-02-23 21:19:57 +01:00
# liste ordonnée des formsemestres de cette formation:
formsemestres = sorted (
FormSemestre . query . filter_by ( formation_id = formation_id ) . all ( ) ,
key = lambda s : s . sort_key ( ) ,
reverse = True ,
)
2021-11-22 00:31:53 +01:00
if is_apc :
2022-02-02 22:04:18 +01:00
# Pour faciliter la transition des anciens programmes non APC
2021-11-22 00:31:53 +01:00
for ue in ues_obj :
ue . guess_semestre_idx ( )
2022-02-02 22:04:18 +01:00
# vérifie qu'on a bien au moins une matière dans chaque UE
2022-01-27 00:18:50 +01:00
if ue . matieres . count ( ) < 1 :
mat = Matiere ( ue_id = ue . id )
db . session . add ( mat )
2022-02-02 22:04:18 +01:00
# donne des couleurs aux UEs crées avant
colorie_anciennes_ues ( ues_obj )
2022-01-27 00:18:50 +01:00
db . session . commit ( )
2021-11-22 00:31:53 +01:00
ues = [ ue . to_dict ( ) for ue in ues_obj ]
ues_externes = [ ue . to_dict ( ) for ue in ues_externes_obj ]
2020-09-26 16:19:37 +02:00
# tri par semestre et numero:
2021-11-17 10:28:51 +01:00
_add_ue_semestre_id ( ues , is_apc )
_add_ue_semestre_id ( ues_externes , is_apc )
2021-10-21 06:32:03 +02:00
ues . sort ( key = lambda u : ( u [ " semestre_id " ] , u [ " numero " ] ) )
2021-10-22 23:09:15 +02:00
ues_externes . sort ( key = lambda u : ( u [ " semestre_id " ] , u [ " numero " ] ) )
2022-02-19 16:16:52 +01:00
# Codes dupliqués (pour aider l'utilisateur)
seen = set ( )
duplicated_codes = {
ue [ " ue_code " ] for ue in ues if ue [ " ue_code " ] in seen or seen . add ( ue [ " ue_code " ] )
}
ues_with_duplicated_code = [ ue for ue in ues if ue [ " ue_code " ] in duplicated_codes ]
2020-09-26 16:19:37 +02:00
2023-09-29 21:17:31 +02:00
has_perm_change = current_user . has_permission ( Permission . EditFormation )
2021-10-22 23:09:15 +02:00
# editable = (not locked) and has_perm_change
2021-11-17 10:28:51 +01:00
# On autorise maintenant la modification des formations qui ont
# des semestres verrouillés, sauf si cela affect les notes passées
# (verrouillées):
2020-09-26 16:19:37 +02:00
# - pas de modif des modules utilisés dans des semestres verrouillés
# - pas de changement des codes d'UE utilisés dans des semestres verrouillés
2021-10-22 23:09:15 +02:00
editable = has_perm_change
2021-06-12 22:43:22 +02:00
tag_editable = (
2023-09-29 21:17:31 +02:00
current_user . has_permission ( Permission . EditFormationTags ) or has_perm_change
2021-06-12 22:43:22 +02:00
)
2020-09-26 16:19:37 +02:00
if locked :
2021-02-04 20:02:44 +01:00
lockicon = scu . icontag ( " lock32_img " , title = " verrouillé " )
2020-09-26 16:19:37 +02:00
else :
lockicon = " "
2021-10-12 16:05:50 +02:00
arrow_up , arrow_down , arrow_none = sco_groups . get_arrow_icons_tags ( )
2021-02-04 20:02:44 +01:00
delete_icon = scu . icontag (
2020-09-26 16:19:37 +02:00
" delete_small_img " , title = " Supprimer (module inutilisé) " , alt = " supprimer "
)
2021-02-04 20:02:44 +01:00
delete_disabled_icon = scu . icontag (
2020-09-26 16:19:37 +02:00
" delete_small_dis_img " , title = " Suppression impossible (module utilisé) "
)
H = [
2024-08-15 08:19:17 +02:00
<< << << < HEAD
== == == =
2021-06-13 19:12:20 +02:00
html_sco_header . sco_header (
2024-07-31 13:40:30 +02:00
cssstyles = html_sco_header . BOOTSTRAP_CSS
2024-03-24 08:27:09 +01:00
+ [ " libjs/jQuery-tagEditor/jquery.tag-editor.css " , " css/ue_table.css " ] ,
2024-07-31 13:40:30 +02:00
javascripts = html_sco_header . BOOTSTRAP_JS
2023-04-03 17:46:31 +02:00
+ [
2020-09-26 16:19:37 +02:00
" libjs/jinplace-1.2.1.min.js " ,
" js/ue_list.js " ,
2022-07-09 12:55:23 +02:00
" js/edit_ue.js " ,
2020-09-26 16:19:37 +02:00
" libjs/jQuery-tagEditor/jquery.tag-editor.min.js " ,
" libjs/jQuery-tagEditor/jquery.caret.min.js " ,
" js/module_tag_editor.js " ,
] ,
2024-02-14 21:45:58 +01:00
page_title = f " Formation { formation . acronyme } v { formation . version } " ,
2020-09-26 16:19:37 +02:00
) ,
2024-08-15 08:19:17 +02:00
>> >> >> > iziram - frontend
2023-06-18 09:37:13 +02:00
f """ <h2> { formation . html ( ) } { lockicon }
2021-11-17 10:28:51 +01:00
< / h2 >
""" ,
2020-09-26 16:19:37 +02:00
]
if locked :
H . append (
2023-02-06 10:24:41 +01:00
""" <p class= " help " >Cette formation est verrouillée car
2021-12-17 22:53:34 +01:00
des semestres verrouillés s ' y réferent.
2023-12-15 01:07:08 +01:00
Si vous souhaitez modifier cette formation ( par exemple pour y ajouter un module ) ,
2021-08-30 23:28:15 +02:00
vous devez :
2020-09-26 16:19:37 +02:00
< / p >
< ul class = " help " >
2021-08-30 23:28:15 +02:00
< li > soit créer une nouvelle version de cette formation pour pouvoir l ' éditer
librement ( vous pouvez passer par la fonction " Associer à une nouvelle version
du programme " (menu " Semestre " ) si vous avez un semestre en cours);
< / li >
< li > soit déverrouiller le ou les semestres qui s ' y réfèrent (attention, en
principe ces semestres sont archivés et ne devraient pas être modifiés ) .
< / li >
2020-09-26 16:19:37 +02:00
< / ul > """
)
if msg :
H . append ( ' <p class= " msg " > ' + msg + " </p> " )
2022-02-19 16:16:52 +01:00
if ues_with_duplicated_code :
2020-09-26 16:19:37 +02:00
H . append (
2023-02-06 10:24:41 +01:00
f """ <div class= " ue_warning " ><span>Attention: plusieurs UEs de cette
2022-02-19 16:16:52 +01:00
formation ont le même code : < tt > {
' , ' . join ( [
2023-02-06 10:24:41 +01:00
' <a class= " stdlink " href= " ' + url_for ( " notes.ue_edit " ,
scodoc_dept = g . scodoc_dept , ue_id = ue [ " ue_id " ] )
2022-02-19 16:16:52 +01:00
+ ' " > ' + ue [ " acronyme " ] + " (code " + ue [ " ue_code " ] + " )</a> "
for ue in ues_with_duplicated_code ] )
} < / tt > .
2023-02-06 10:24:41 +01:00
Il faut corriger cela , sinon les capitalisations et ECTS seront
2022-02-19 16:16:52 +01:00
erronés ! < / span > < / div > """
2020-09-26 16:19:37 +02:00
)
# Description de la formation
H . append (
2021-11-18 00:24:56 +01:00
render_template (
2023-01-25 15:17:52 +01:00
" pn/form_descr.j2 " ,
2021-11-18 00:24:56 +01:00
formation = formation ,
parcours = parcours ,
editable = editable ,
2020-09-26 16:19:37 +02:00
)
2021-11-18 00:24:56 +01:00
)
2021-11-17 10:28:51 +01:00
2021-11-13 12:09:30 +01:00
# Formation APC (BUT) ?
if is_apc :
2023-02-22 22:45:39 +01:00
lock_info = (
""" <span class= " lock_info " >verrouillé (voir liste des semestres utilisateurs
en bas de page ) < / span >
"""
if locked
else " "
)
2021-11-13 12:09:30 +01:00
H . append (
f """ <div class= " formation_apc_infos " >
2021-11-18 00:24:56 +01:00
< div class = " ue_list_tit " > Formation par compétences ( BUT )
2023-02-22 22:45:39 +01:00
- { _html_select_semestre_idx ( formation_id , semestre_ids , semestre_idx ) }
2021-11-18 00:24:56 +01:00
< / form >
2023-02-22 22:45:39 +01:00
{ lock_info }
2021-11-18 00:24:56 +01:00
< / div >
"""
)
2021-12-03 11:03:33 +01:00
if formation . referentiel_competence is None :
descr_refcomp = " "
msg_refcomp = " associer à un référentiel de compétences "
else :
2023-02-06 10:24:41 +01:00
descr_refcomp = f """ Référentiel de compétences:
2023-12-15 01:07:08 +01:00
< a href = " { url_for( ' notes.refcomp_show ' ,
2022-06-26 22:45:53 +02:00
scodoc_dept = g . scodoc_dept , refcomp_id = formation . referentiel_competence . id ) } "
class = " stdlink " >
2024-04-07 19:52:22 +02:00
{ formation . referentiel_competence . get_title ( ) }
2022-03-01 23:25:42 +01:00
< / a > & nbsp ; """
2021-12-03 11:03:33 +01:00
msg_refcomp = " changer "
2022-03-15 23:09:41 +01:00
H . append ( f """ <ul><li> { descr_refcomp } """ )
2023-09-29 21:17:31 +02:00
if current_user . has_permission ( Permission . EditFormation ) :
2022-11-01 19:37:09 +01:00
if (
formation . referentiel_competence is None
or formation . formsemestres . count ( ) == 0
) :
H . append (
2023-02-06 10:24:41 +01:00
f """ <a class= " stdlink " href= " { url_for ( ' notes.refcomp_assoc_formation ' ,
2022-11-01 19:37:09 +01:00
scodoc_dept = g . scodoc_dept , formation_id = formation_id )
} " > {msg_refcomp} </a> " " "
)
elif formation . referentiel_competence is not None :
H . append ( """ (non modifiable car utilisé par des semestres) """ )
2023-04-10 11:25:46 +02:00
H . append ( " </li> " )
if formation . referentiel_competence is not None :
H . append (
""" <li>Parcours, compétences et UEs :
< div class = " formation_parcs " >
"""
)
for parc in formation . referentiel_competence . parcours :
H . append (
2023-12-15 01:07:08 +01:00
f """ <div><a href= " { url_for ( " notes.parcour_formation " ,
2023-04-10 11:25:46 +02:00
scodoc_dept = g . scodoc_dept , formation_id = formation . id , parcour_id = parc . id )
} " > {parc.code} </a></div> " " "
)
H . append ( """ </div></li> """ )
2022-03-15 23:09:41 +01:00
H . append (
2023-04-10 11:25:46 +02:00
f """
2022-03-01 23:25:42 +01:00
< li > < a class = " stdlink " href = " {
2023-12-15 01:07:08 +01:00
url_for ( ' notes.edit_modules_ue_coefs ' ,
2023-02-06 10:24:41 +01:00
scodoc_dept = g . scodoc_dept , formation_id = formation_id , semestre_idx = semestre_idx )
2023-02-06 10:13:01 +01:00
} " > { ' Visualiser ' if locked else ' Éditer ' } les coefficients des ressources et SAÉs</a>
2021-12-03 11:03:33 +01:00
< / li >
2021-11-13 12:09:30 +01:00
< / ul >
2021-11-18 00:24:56 +01:00
"""
2021-11-13 12:09:30 +01:00
)
2020-09-26 16:19:37 +02:00
# Description des UE/matières/modules
2021-10-22 23:09:15 +02:00
H . append (
2024-01-30 22:12:55 +01:00
f """
2021-11-17 10:28:51 +01:00
< div class = " formation_ue_list " >
2024-02-14 21:45:58 +01:00
< div class = " ue_list_tit " > Formation ( programme pédagogique ) : < / div >
2021-11-17 10:28:51 +01:00
< form >
2024-01-30 22:12:55 +01:00
< input type = " checkbox " class = " sco_tag_checkbox "
{ ' checked ' if show_tags else ' ' }
2024-02-20 21:30:08 +01:00
> Montrer les tags des modules voire en ajouter
< i > ( ceux correspondant aux titres des compétences étant ajoutés par défaut ) < / i >
< / input >
2021-11-17 10:28:51 +01:00
< / form >
"""
2021-10-22 23:09:15 +02:00
)
2021-11-17 10:28:51 +01:00
if is_apc :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
sco_edit_apc . html_edit_formation_apc (
2021-11-18 00:24:56 +01:00
formation ,
semestre_idx = semestre_idx ,
editable = editable ,
tag_editable = tag_editable ,
2021-11-17 10:28:51 +01:00
)
2020-09-26 16:19:37 +02:00
)
2021-11-17 10:28:51 +01:00
else :
2022-02-27 17:49:39 +01:00
H . append ( ' <div class= " formation_classic_infos " > ' )
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
_ue_table_ues (
parcours ,
ues ,
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
)
2020-09-26 16:19:37 +02:00
)
2021-11-17 10:28:51 +01:00
if editable :
H . append (
f """ <ul>
< li > < a class = " stdlink " href = " {
url_for ( ' notes.ue_create ' , scodoc_dept = g . scodoc_dept , formation_id = formation_id )
} " >Ajouter une UE</a>
< / li >
< li > < a href = " {
2023-12-15 01:07:08 +01:00
url_for ( ' notes.formation_add_malus_modules ' ,
2021-11-17 10:28:51 +01:00
scodoc_dept = g . scodoc_dept , formation_id = formation_id )
} " class= " stdlink " >Ajouter des modules de malus dans chaque UE</a>
< / li >
< / ul >
"""
)
2022-02-27 17:49:39 +01:00
H . append ( " </div> " )
2020-09-26 16:19:37 +02:00
H . append ( " </div> " ) # formation_ue_list
2021-10-22 23:09:15 +02:00
if ues_externes :
H . append (
2021-11-17 10:28:51 +01:00
f """
< div class = " formation_ue_list formation_ue_list_externes " >
< div class = " ue_list_tit " > UE externes déclarées ( pour information ) :
< / div >
{ _ue_table_ues (
2021-10-22 23:09:15 +02:00
parcours ,
ues_externes ,
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
) }
< / div >
"""
2021-10-22 23:09:15 +02:00
)
2020-09-26 16:19:37 +02:00
H . append ( " <p><ul> " )
2023-02-23 21:19:57 +01:00
if has_perm_change :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
f """
< li > < a class = " stdlink " href = " {
2023-03-22 21:39:55 +01:00
url_for ( ' notes.formsemestre_associate_new_version ' ,
2021-11-17 10:28:51 +01:00
scodoc_dept = g . scodoc_dept , formation_id = formation_id
)
2023-02-23 21:19:57 +01:00
} " >Créer une nouvelle version de la formation</a> (copie non verrouillée)
2021-11-17 10:28:51 +01:00
< / li >
2023-12-15 01:07:08 +01:00
2021-11-17 10:28:51 +01:00
"""
2020-09-26 16:19:37 +02:00
)
2023-02-23 21:19:57 +01:00
if not len ( formsemestres ) :
H . append (
f """
< li > < a class = " stdlink " href = " {
2023-12-15 01:07:08 +01:00
url_for ( ' notes.formation_delete ' ,
2023-02-23 21:19:57 +01:00
scodoc_dept = g . scodoc_dept , formation_id = formation_id
)
} " >Supprimer cette formation</a> (pas encore utilisée par des semestres)
< / li >
"""
)
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
f """
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_table_recap ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id )
} " >Table récapitulative de la formation</a>
2023-12-15 01:07:08 +01:00
< / li >
2024-01-30 22:12:55 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_tag_modules_by_type ' , scodoc_dept = g . scodoc_dept ,
2024-01-31 22:55:59 +01:00
formation_id = formation_id ,
semestre_idx = 1 if semestre_idx is None else semestre_idx
)
2024-01-30 22:12:55 +01:00
} " >Tagguer tous les modules par leur type</a> (tag <tt>res</tt>, <tt>sae</tt>).
< / li >
2021-11-17 10:28:51 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_export ' , scodoc_dept = g . scodoc_dept ,
2023-09-21 10:20:19 +02:00
formation_id = formation_id , fmt = ' xml ' )
2023-01-25 15:17:52 +01:00
} " >Export XML de la formation</a> ou
< a class = " stdlink " href = " {
url_for ( ' notes.formation_export ' , scodoc_dept = g . scodoc_dept ,
2023-09-21 10:20:19 +02:00
formation_id = formation_id , fmt = ' xml ' , export_codes_apo = 0 )
2023-01-25 15:17:52 +01:00
} " >sans codes Apogée</a>
( permet de l ' enregistrer pour l ' échanger avec un autre site )
2021-11-17 10:28:51 +01:00
< / li >
2020-09-26 16:19:37 +02:00
2021-11-17 10:28:51 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_export ' , scodoc_dept = g . scodoc_dept ,
2023-09-21 10:20:19 +02:00
formation_id = formation_id , fmt = ' json ' )
2021-11-17 10:28:51 +01:00
} " >Export JSON de la formation</a>
< / li >
2020-09-26 16:19:37 +02:00
2021-11-17 10:28:51 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.module_table ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id )
2023-01-14 18:01:54 +01:00
} " >Liste détaillée des modules de la formation</a> (debug)
2021-11-17 10:28:51 +01:00
< / li >
< / ul >
< / p > """
2020-09-26 16:19:37 +02:00
)
2021-10-22 23:09:15 +02:00
if has_perm_change :
2020-09-26 16:19:37 +02:00
H . append (
"""
< h3 > < a name = " sems " > Semestres ou sessions de cette formation < / a > < / h3 >
< p > < ul > """
)
2023-02-23 21:19:57 +01:00
for formsemestre in formsemestres :
2023-06-18 09:37:13 +02:00
H . append ( f """ <li> { formsemestre . html_link_status ( ) } """ )
2023-01-14 18:01:54 +01:00
if not formsemestre . etat :
2020-09-26 16:19:37 +02:00
H . append ( " [verrouillé] " )
else :
H . append (
2023-01-14 18:01:54 +01:00
f """ <a class= " stdlink " href= " { url_for ( " notes.formsemestre_editwithmodules " ,
scodoc_dept = g . scodoc_dept , formsemestre_id = formsemestre . id
) } " >Modifier</a> " " "
2020-09-26 16:19:37 +02:00
)
H . append ( " </li> " )
H . append ( " </ul> " )
2023-09-29 21:17:31 +02:00
if current_user . has_permission ( Permission . EditFormSemestre ) :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
f """ <ul>
2024-06-18 01:21:33 +02:00
< li > < b > < a class = " stdlink " href = " {
2021-11-17 10:28:51 +01:00
url_for ( ' notes.formsemestre_createwithmodules ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id , semestre_id = 1 )
2024-06-18 01:21:33 +02:00
} " >Mettre en place un nouveau semestre de formation {formation.acronyme} </a></b>
2021-11-17 10:28:51 +01:00
< / li >
< / ul > """
2020-09-26 16:19:37 +02:00
)
# <li>(debug) <a class="stdlink" href="check_form_integrity?formation_id=%(formation_id)s">Vérifier cohérence</a></li>
2024-02-14 21:45:58 +01:00
warn , _ = sco_formsemestre_validation . check_formation_ues ( formation )
2020-09-26 16:19:37 +02:00
H . append ( warn )
2024-08-15 00:04:35 +02:00
return render_template (
" sco_page_dept.j2 " ,
content = " " . join ( H ) ,
page_title = f " Formation { formation . acronyme } v { formation . version } " ,
cssstyles = html_sco_header . BOOTSTRAP_MULTISELECT_CSS
+ [ " libjs/jQuery-tagEditor/jquery.tag-editor.css " , " css/ue_table.css " ] ,
javascripts = html_sco_header . BOOTSTRAP_MULTISELECT_JS
+ [
" libjs/jinplace-1.2.1.min.js " ,
" js/ue_list.js " ,
" js/edit_ue.js " ,
" libjs/jQuery-tagEditor/jquery.tag-editor.min.js " ,
" libjs/jQuery-tagEditor/jquery.caret.min.js " ,
" js/module_tag_editor.js " ,
] ,
)
2020-09-26 16:19:37 +02:00
2021-11-18 00:24:56 +01:00
def _html_select_semestre_idx ( formation_id , semestre_ids , semestre_idx ) :
2023-02-22 22:45:39 +01:00
htm = """ <form method= " get " >Semestre:
2021-11-18 00:24:56 +01:00
< select onchange = " this.form.submit() " name = " semestre_idx " id = " semestre_idx " >
"""
for i in list ( semestre_ids ) + [ " all " ] :
if i == " all " :
label = " tous "
else :
label = f " S { i } "
htm + = f """ <option value= " { i } " {
2023-12-15 01:07:08 +01:00
' selected '
if ( semestre_idx == i )
or ( i == " all " and semestre_idx is None )
2021-11-18 00:24:56 +01:00
else ' '
} > { label } < / option >
"""
htm + = f """
< / select >
< input type = " hidden " name = " formation_id " value = " {formation_id} " > < / input >
2024-01-30 22:12:55 +01:00
< input type = " hidden " name = " show_tags " value = " 0 " > < / input >
2021-11-18 00:24:56 +01:00
< / form > """
return htm
2021-10-22 23:09:15 +02:00
def _ue_table_ues (
parcours ,
2022-06-20 17:56:27 +02:00
ues : list [ dict ] ,
2021-10-22 23:09:15 +02:00
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2022-06-20 17:56:27 +02:00
) - > str :
2021-11-17 10:28:51 +01:00
""" Édition de programme: liste des UEs (avec leurs matières et modules).
Pour les formations classiques ( non APC / BUT )
"""
2021-10-22 23:09:15 +02:00
H = [ ]
cur_ue_semestre_id = None
iue = 0
for ue in ues :
2022-02-28 11:00:24 +01:00
if ue [ " ects " ] is None :
2021-10-22 23:09:15 +02:00
ue [ " ects_str " ] = " "
2022-02-28 11:00:24 +01:00
else :
ue [ " ects_str " ] = " , %g ECTS " % ue [ " ects " ]
2021-10-22 23:09:15 +02:00
if editable :
klass = " span_apo_edit "
else :
klass = " "
2024-06-21 00:53:52 +02:00
edit_url = url_for (
" apiweb.ue_set_code_apogee " ,
scodoc_dept = g . scodoc_dept ,
ue_id = ue [ " ue_id " ] ,
2021-10-22 23:09:15 +02:00
)
2024-07-31 13:40:30 +02:00
ue [ " code_apogee_str " ] = f """ , Apo: <span
2024-06-21 00:53:52 +02:00
class = " {klass} " data - url = " {edit_url} " id = " {ue['ue_id']} "
data - placeholder = " {scu.APO_MISSING_CODE_STR} " > {
ue [ " code_apogee " ] or " "
} < / span > """
2021-10-22 23:09:15 +02:00
if cur_ue_semestre_id != ue [ " semestre_id " ] :
cur_ue_semestre_id = ue [ " semestre_id " ]
2023-02-12 13:36:47 +01:00
if ue [ " semestre_id " ] == codes_cursus . UE_SEM_DEFAULT :
2021-10-22 23:09:15 +02:00
lab = " Pas d ' indication de semestre: "
else :
2022-06-20 17:56:27 +02:00
lab = f """ Semestre { ue [ " semestre_id " ] } : """
2022-02-20 15:10:15 +01:00
H . append (
2022-06-20 17:56:27 +02:00
f ' <div class= " ue_list_div " ><div class= " ue_list_tit_sem " > { lab } </div> '
2022-02-20 15:10:15 +01:00
)
2021-10-22 23:09:15 +02:00
H . append ( ' <ul class= " notes_ue_list " > ' )
H . append ( ' <li class= " notes_ue_list " > ' )
if iue != 0 and editable :
H . append (
' <a href= " ue_move?ue_id= %s &after=0 " class= " aud " > %s </a> '
% ( ue [ " ue_id " ] , arrow_up )
)
else :
H . append ( arrow_none )
if iue < len ( ues ) - 1 and editable :
H . append (
' <a href= " ue_move?ue_id= %s &after=1 " class= " aud " > %s </a> '
% ( ue [ " ue_id " ] , arrow_down )
)
else :
H . append ( arrow_none )
ue [ " acro_titre " ] = str ( ue [ " acronyme " ] )
if ue [ " titre " ] != ue [ " acronyme " ] :
ue [ " acro_titre " ] + = " " + str ( ue [ " titre " ] )
H . append (
""" %(acro_titre)s <span class= " ue_code " >(code %(ue_code)s %(ects_str)s , coef. %(coefficient)3.2f %(code_apogee_str)s )</span>
< span class = " ue_coef " > < / span >
"""
% ue
)
2023-02-12 13:36:47 +01:00
if ue [ " type " ] != codes_cursus . UE_STANDARD :
2021-10-22 23:09:15 +02:00
H . append (
' <span class= " ue_type " > %s </span> '
2023-02-12 13:36:47 +01:00
% codes_cursus . UE_TYPE_NAME [ ue [ " type " ] ]
2021-10-22 23:09:15 +02:00
)
if ue [ " is_external " ] :
# Cas spécial: si l'UE externe a plus d'un module, c'est peut être une UE
# qui a été déclarée externe par erreur (ou suite à un bug d'import/export xml)
# Dans ce cas, propose de changer le type (même si verrouillée)
if len ( sco_moduleimpl . moduleimpls_in_external_ue ( ue [ " ue_id " ] ) ) > 1 :
H . append ( ' <span class= " ue_is_external " > ' )
if has_perm_change :
H . append (
f """ <a class= " stdlink " href= " {
2024-03-31 10:21:44 +02:00
url_for ( " notes.ue_set_internal " ,
scodoc_dept = g . scodoc_dept , ue_id = ue [ " ue_id " ] )
2021-10-22 23:09:15 +02:00
} " >transformer en UE ordinaire</a> " " "
)
H . append ( " </span> " )
ue_editable = editable and not ue_is_locked ( ue [ " ue_id " ] )
if ue_editable :
H . append (
2024-03-31 10:21:44 +02:00
f """ <a class= " stdlink " href= " {
url_for ( " notes.ue_edit " , scodoc_dept = g . scodoc_dept , ue_id = ue [ " ue_id " ] )
} " >modifier</a> " " "
2021-10-22 23:09:15 +02:00
)
else :
H . append ( ' <span class= " locked " >[verrouillé]</span> ' )
H . append (
2021-11-18 00:24:56 +01:00
_ue_table_matieres (
2021-10-22 23:09:15 +02:00
parcours ,
ue ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
)
)
2022-02-19 16:16:52 +01:00
if ( iue > = len ( ues ) - 1 ) or ue [ " semestre_id " ] != ues [ iue + 1 ] [ " semestre_id " ] :
H . append (
2023-12-15 01:07:08 +01:00
f """ </ul><ul><li><a href= " { url_for ( ' notes.ue_create ' , scodoc_dept = g . scodoc_dept ,
2022-02-19 16:16:52 +01:00
formation_id = ue [ ' formation_id ' ] , semestre_idx = ue [ ' semestre_id ' ] )
2022-02-20 15:10:15 +01:00
} " >Ajouter une UE dans le semestre { ue[ ' semestre_id ' ] or ' ' }</a></li></ul>
< / div >
"""
2022-02-19 16:16:52 +01:00
)
iue + = 1
2021-10-22 23:09:15 +02:00
return " \n " . join ( H )
def _ue_table_matieres (
parcours ,
ue ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
) :
""" Édition de programme: liste des matières (et leurs modules) d ' une UE. """
H = [ ]
if not parcours . UE_IS_MODULE :
H . append ( ' <ul class= " notes_matiere_list " > ' )
matieres = sco_edit_matiere . matiere_list ( args = { " ue_id " : ue [ " ue_id " ] } )
for mat in matieres :
if not parcours . UE_IS_MODULE :
H . append ( ' <li class= " notes_matiere_list " > ' )
if editable and not sco_edit_matiere . matiere_is_locked ( mat [ " matiere_id " ] ) :
H . append (
f """ <a class= " stdlink " href= " {
2023-12-15 01:07:08 +01:00
url_for ( " notes.matiere_edit " ,
2021-10-22 23:09:15 +02:00
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] )
} " >
"""
)
H . append ( " %(titre)s " % mat )
if editable and not sco_edit_matiere . matiere_is_locked ( mat [ " matiere_id " ] ) :
H . append ( " </a> " )
modules = sco_edit_module . module_list ( args = { " matiere_id " : mat [ " matiere_id " ] } )
H . append (
_ue_table_modules (
parcours ,
2022-02-01 11:37:05 +01:00
ue ,
2021-10-22 23:09:15 +02:00
mat ,
modules ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
)
)
2021-11-08 19:44:25 +01:00
if not parcours . UE_IS_MODULE :
H . append ( " </li> " )
2021-10-22 23:09:15 +02:00
if not matieres :
H . append ( " <li>Aucune matière dans cette UE ! " )
if editable :
H . append (
""" <a class= " stdlink " href= " ue_delete?ue_id= %(ue_id)s " >supprimer l ' UE</a> """
% ue
)
H . append ( " </li> " )
if editable and not parcours . UE_IS_MODULE :
H . append (
' <li><a class= " stdlink " href= " matiere_create?ue_id= %(ue_id)s " >créer une matière</a> </li> '
% ue
)
if not parcours . UE_IS_MODULE :
H . append ( " </ul> " )
return " \n " . join ( H )
def _ue_table_modules (
parcours ,
2022-02-01 11:37:05 +01:00
ue ,
2021-10-22 23:09:15 +02:00
mat ,
modules ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-08 19:44:25 +01:00
unit_name = " matière " ,
add_suppress_link = True , # lien "supprimer cette matière"
empty_list_msg = " Aucun élément dans cette matière " ,
create_element_msg = " créer un module " ,
2021-10-22 23:09:15 +02:00
) :
""" Édition de programme: liste des modules d ' une matière d ' une UE """
H = [ ' <ul class= " notes_module_list " > ' ]
im = 0
for mod in modules :
mod [ " nb_moduleimpls " ] = sco_edit_module . module_count_moduleimpls (
mod [ " module_id " ]
)
klass = " notes_module_list "
2021-11-12 22:17:46 +01:00
if mod [ " module_type " ] == ModuleType . MALUS :
2021-10-22 23:09:15 +02:00
klass + = " module_malus "
H . append ( ' <li class= " %s " > ' % klass )
H . append ( ' <span class= " notes_module_list_buts " > ' )
if im != 0 and editable :
H . append (
' <a href= " module_move?module_id= %s &after=0 " class= " aud " > %s </a> '
% ( mod [ " module_id " ] , arrow_up )
)
else :
H . append ( arrow_none )
if im < len ( modules ) - 1 and editable :
H . append (
' <a href= " module_move?module_id= %s &after=1 " class= " aud " > %s </a> '
% ( mod [ " module_id " ] , arrow_down )
)
else :
H . append ( arrow_none )
im + = 1
if mod [ " nb_moduleimpls " ] == 0 and editable :
2022-01-04 20:03:38 +01:00
icon = delete_icon
2021-10-22 23:09:15 +02:00
else :
2022-01-04 20:03:38 +01:00
icon = delete_disabled_icon
H . append (
' <a class= " smallbutton " href= " module_delete?module_id= %s " > %s </a> '
% ( mod [ " module_id " ] , icon )
)
2021-10-22 23:09:15 +02:00
H . append ( " </span> " )
mod_editable = (
editable # and not sco_edit_module.module_is_locked( Mod['module_id'])
)
if mod_editable :
H . append (
' <a class= " discretelink " title= " Modifier le module numéro %(numero)s , utilisé par %(nb_moduleimpls)d sessions " href= " module_edit?module_id= %(module_id)s " > '
% mod
)
2023-12-15 01:07:08 +01:00
if mod [ " module_type " ] not in ( scu . ModuleType . STANDARD , scu . ModuleType . MALUS ) :
H . append (
f """ <span class= " invalid-module-type " > { scu . EMO_WARNING } type incompatible </span> """
)
2021-10-22 23:09:15 +02:00
H . append (
' <span class= " formation_module_tit " > %s </span> '
% scu . join_words ( mod [ " code " ] , mod [ " titre " ] )
)
if mod_editable :
H . append ( " </a> " )
heurescoef = (
" %(heures_cours)s / %(heures_td)s / %(heures_tp)s , coef. %(coefficient)s " % mod
)
2024-06-21 00:53:52 +02:00
edit_url = url_for (
2024-07-18 16:54:48 +02:00
" apiweb.formation_module_set_code_apogee " ,
2024-06-21 00:53:52 +02:00
scodoc_dept = g . scodoc_dept ,
module_id = mod [ " module_id " ] ,
2021-10-22 23:09:15 +02:00
)
2024-06-21 00:53:52 +02:00
heurescoef + = f """ , Apo: <span
class = " { ' span_apo_edit ' if editable else ' ' } "
data - url = " {edit_url} " id = " {mod["module_id"]} "
data - placeholder = " {scu.APO_MISSING_CODE_STR} " > {
mod [ " code_apogee " ] or " "
} < / span > """
2021-10-22 23:09:15 +02:00
if tag_editable :
tag_cls = " module_tag_editor "
else :
tag_cls = " module_tag_editor_ro "
tag_mk = """ <span class= " sco_tag_edit " ><form><textarea data-module_id= " {} " class= " {} " > {} </textarea></form></span> """
tag_edit = tag_mk . format (
mod [ " module_id " ] ,
tag_cls ,
" , " . join ( sco_tag_module . module_tag_list ( mod [ " module_id " ] ) ) ,
)
2022-02-01 11:37:05 +01:00
if ue [ " semestre_idx " ] is not None and mod [ " semestre_id " ] != ue [ " semestre_idx " ] :
warning_semestre = ' <span class= " red " >incohérent ?</span> '
else :
warning_semestre = " "
2021-10-22 23:09:15 +02:00
H . append (
2022-02-01 11:37:05 +01:00
" %s %s %s " % ( parcours . SESSION_NAME , mod [ " semestre_id " ] , warning_semestre )
2021-10-22 23:09:15 +02:00
+ " ( %s ) " % heurescoef
+ tag_edit
)
H . append ( " </li> " )
if not modules :
2021-11-08 19:44:25 +01:00
H . append ( f " <li> { empty_list_msg } ! " )
if editable and add_suppress_link :
2021-10-22 23:09:15 +02:00
H . append (
f """ <a class= " stdlink " href= " {
2023-12-15 01:07:08 +01:00
url_for ( " notes.matiere_delete " ,
2021-10-22 23:09:15 +02:00
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] ) } "
> la supprimer < / a >
"""
)
H . append ( " </li> " )
if editable : # and ((not parcours.UE_IS_MODULE) or len(Modlist) == 0):
H . append (
f """ <li> <a class= " stdlink " href= " {
2023-12-15 01:07:08 +01:00
url_for ( " notes.module_create " ,
2021-10-22 23:09:15 +02:00
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] ) } "
2021-11-08 19:44:25 +01:00
> { create_element_msg } < / a > < / li >
2021-10-22 23:09:15 +02:00
"""
)
H . append ( " </ul> " )
return " \n " . join ( H )
2023-06-25 11:49:11 +02:00
def ue_sharing_code ( ue_code : str = " " , ue_id : int = None , hide_ue_id : int = None ) :
2020-09-26 16:19:37 +02:00
""" HTML list of UE sharing this code
Either ue_code or ue_id may be specified .
2021-08-09 07:43:41 +02:00
hide_ue_id spécifie un id à retirer de la liste .
2020-09-26 16:19:37 +02:00
"""
2023-06-25 11:49:11 +02:00
if ue_id is not None :
2022-08-31 09:16:00 +02:00
ue = UniteEns . query . get_or_404 ( ue_id )
2020-09-26 16:19:37 +02:00
if not ue_code :
2022-08-31 09:16:00 +02:00
ue_code = ue . ue_code
formation_code = ue . formation . formation_code
2021-09-27 17:18:43 +02:00
# UE du même code, code formation et departement:
2021-09-26 11:28:13 +02:00
q_ues = (
2021-11-12 22:17:46 +01:00
UniteEns . query . filter_by ( ue_code = ue_code )
2023-08-27 11:16:06 +02:00
. join ( UniteEns . formation )
2021-09-27 17:18:43 +02:00
. filter_by ( dept_id = g . scodoc_dept_id , formation_code = formation_code )
2021-09-26 11:28:13 +02:00
)
2020-09-26 16:19:37 +02:00
else :
2021-09-27 17:18:43 +02:00
# Toutes les UE du departement avec ce code:
2021-09-26 11:28:13 +02:00
q_ues = (
2021-11-12 22:17:46 +01:00
UniteEns . query . filter_by ( ue_code = ue_code )
2023-08-27 11:16:06 +02:00
. join ( UniteEns . formation )
2021-09-27 17:18:43 +02:00
. filter_by ( dept_id = g . scodoc_dept_id )
2021-09-26 11:28:13 +02:00
)
2020-09-26 16:19:37 +02:00
2023-06-25 11:49:11 +02:00
if hide_ue_id is not None : # enlève l'ue de depart
2021-11-12 22:17:46 +01:00
q_ues = q_ues . filter ( UniteEns . id != hide_ue_id )
2020-09-26 16:19:37 +02:00
2021-09-26 11:28:13 +02:00
ues = q_ues . all ( )
2023-06-25 11:49:11 +02:00
msg = " dans les formations du département "
2021-09-26 11:28:13 +02:00
if not ues :
2023-06-25 11:49:11 +02:00
if ue_id is not None :
return f """ <span class= " ue_share " >Seule UE avec code {
ue_code if ue_code is not None else ' - ' } { msg } < / span > """
2020-09-26 16:19:37 +02:00
else :
2023-06-25 11:49:11 +02:00
return f """ <span class= " ue_share " >Aucune UE avec code {
ue_code if ue_code is not None else ' - ' } { msg } < / span > """
2020-09-26 16:19:37 +02:00
H = [ ]
if ue_id :
2022-08-31 09:16:00 +02:00
H . append (
2023-06-25 11:49:11 +02:00
f """ <span class= " ue_share " >Pour information, autres UEs avec le code {
ue_code if ue_code is not None else ' - ' } { msg } : < / span > """
2022-08-31 09:16:00 +02:00
)
2020-09-26 16:19:37 +02:00
else :
2023-06-25 11:49:11 +02:00
H . append (
f """ <span class= " ue_share " >UE avec le code {
ue_code if ue_code is not None else ' - ' } { msg } : < / span > """
)
2020-09-26 16:19:37 +02:00
H . append ( " <ul> " )
2021-09-26 11:28:13 +02:00
for ue in ues :
2020-09-26 16:19:37 +02:00
H . append (
2024-02-13 13:55:16 +01:00
f """ <li> { ue . acronyme } ( { ue . titre or ' ' } ) dans
2023-06-25 11:49:11 +02:00
< a class = " stdlink " href = " {
url_for ( " notes.ue_table " ,
scodoc_dept = g . scodoc_dept , formation_id = ue . formation . id ) } "
2021-09-26 11:28:13 +02:00
> { ue . formation . acronyme } ( { ue . formation . titre } ) < / a > , version { ue . formation . version }
< / li >
"""
2020-09-26 16:19:37 +02:00
)
H . append ( " </ul> " )
return " \n " . join ( H )
2021-08-20 01:09:55 +02:00
def do_ue_edit ( args , bypass_lock = False , dont_invalidate_cache = False ) :
2020-09-26 16:19:37 +02:00
" edit an UE "
# check
ue_id = args [ " ue_id " ]
2021-10-17 23:19:26 +02:00
ue = ue_list ( { " ue_id " : ue_id } ) [ 0 ]
2021-08-20 01:09:55 +02:00
if ( not bypass_lock ) and ue_is_locked ( ue [ " ue_id " ] ) :
2020-09-26 16:19:37 +02:00
raise ScoLockedFormError ( )
# check: acronyme unique dans cette formation
2021-07-09 17:47:06 +02:00
if " acronyme " in args :
2020-09-26 16:19:37 +02:00
new_acro = args [ " acronyme " ]
2021-10-17 23:19:26 +02:00
ues = ue_list ( { " formation_id " : ue [ " formation_id " ] , " acronyme " : new_acro } )
2020-09-26 16:19:37 +02:00
if ues and ues [ 0 ] [ " ue_id " ] != ue_id :
2021-12-18 17:39:03 +01:00
raise ScoValueError (
2023-12-15 01:07:08 +01:00
f """ Acronyme d ' UE " { args [ ' acronyme ' ] } " déjà utilisé !
2023-04-10 11:25:46 +02:00
( chaque UE doit avoir un acronyme unique dans la formation . ) """
2021-12-18 17:39:03 +01:00
)
2020-09-26 16:19:37 +02:00
# On ne peut pas supprimer le code UE:
2021-07-09 17:47:06 +02:00
if " ue_code " in args and not args [ " ue_code " ] :
2020-09-26 16:19:37 +02:00
del args [ " ue_code " ]
2021-06-15 13:59:56 +02:00
cnx = ndb . GetDBConnexion ( )
2021-06-17 00:08:37 +02:00
_ueEditor . edit ( cnx , args )
2020-09-26 16:19:37 +02:00
2023-07-11 06:57:38 +02:00
formation = db . session . get ( Formation , ue [ " formation_id " ] )
2020-09-26 16:19:37 +02:00
if not dont_invalidate_cache :
2022-06-24 03:34:52 +02:00
# Invalide les semestres utilisant cette formation
# ainsi que les poids et coefs
formation . invalidate_module_coefs ( )
2020-09-26 16:19:37 +02:00
2021-08-20 01:09:55 +02:00
def ue_is_locked ( ue_id ) :
2021-06-13 18:29:53 +02:00
""" True if UE should not be modified
( contains modules used in a locked formsemestre )
"""
r = ndb . SimpleDictFetch (
2021-08-08 17:38:46 +02:00
""" SELECT ue.id
FROM notes_ue ue , notes_modules mod , notes_formsemestre sem , notes_moduleimpl mi
WHERE ue . id = mod . ue_id
AND mi . module_id = mod . id AND mi . formsemestre_id = sem . id
AND ue . id = % ( ue_id ) s AND sem . etat = false
2021-06-13 18:29:53 +02:00
""" ,
{ " ue_id " : ue_id } ,
)
return len ( r ) > 0
2022-02-02 22:04:18 +01:00
UE_PALETTE = [
2022-02-10 23:14:33 +01:00
" #B80004 " , # rouge
" #F97B3D " , # Orange Crayola
" #FEB40B " , # Honey Yellow
" #80CB3F " , # Yellow Green
" #05162E " , # Oxford Blue
" #548687 " , # Steel Teal
" #444054 " , # Independence
" #889696 " , # Spanish Gray
" #0CA4A5 " , # Viridian Green
2022-02-02 22:04:18 +01:00
]
def colorie_anciennes_ues ( ues : list [ UniteEns ] ) - > None :
""" Avant ScoDoc 9.2, les ue n ' avaient pas de couleurs
Met des défauts raisonnables
"""
nb_colors = len ( UE_PALETTE )
index = 0
last_sem_idx = 0
for ue in ues :
if ue . semestre_idx != last_sem_idx :
index = 0
2022-02-10 23:14:33 +01:00
last_sem_idx = ue . semestre_idx
2022-02-02 22:04:18 +01:00
if ue . color is None :
ue . color = UE_PALETTE [ index % nb_colors ]
index + = 1
db . session . add ( ue )
def ue_guess_color_default ( formation_id : int , default_semestre_idx : int ) - > str :
""" Un code couleur pour une nouvelle UE dans ce semestre """
nb_colors = len ( UE_PALETTE )
# UE existantes dans ce semestre:
nb_ues = UniteEns . query . filter (
UniteEns . formation_id == formation_id ,
UniteEns . semestre_idx == default_semestre_idx ,
) . count ( )
index = nb_ues
return UE_PALETTE [ index % nb_colors ]