forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -1,6 +1,6 @@
|
|||||||
"""ScoDoc 9 models : Modules
|
"""ScoDoc 9 models : Modules
|
||||||
"""
|
"""
|
||||||
from flask import current_app
|
from flask import current_app, g
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import APO_CODE_STR_LEN
|
from app.models import APO_CODE_STR_LEN
|
||||||
@ -310,6 +310,14 @@ class Module(db.Model):
|
|||||||
return []
|
return []
|
||||||
return self.parcours
|
return self.parcours
|
||||||
|
|
||||||
|
def add_tag(self, tag: "NotesTag"):
|
||||||
|
"""Add tag to module. Check if already has it."""
|
||||||
|
if tag.id in {t.id for t in self.tags}:
|
||||||
|
return
|
||||||
|
self.tags.append(tag)
|
||||||
|
db.session.add(self)
|
||||||
|
db.session.flush()
|
||||||
|
|
||||||
|
|
||||||
class ModuleUECoef(db.Model):
|
class ModuleUECoef(db.Model):
|
||||||
"""Coefficients des modules vers les UE (APC, BUT)
|
"""Coefficients des modules vers les UE (APC, BUT)
|
||||||
@ -372,6 +380,19 @@ class NotesTag(db.Model):
|
|||||||
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
||||||
title = db.Column(db.Text(), nullable=False)
|
title = db.Column(db.Text(), nullable=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create(cls, title: str, dept_id: int | None = None) -> "NotesTag":
|
||||||
|
"""Get tag, or create it if it doesn't yet exists.
|
||||||
|
If dept_id unspecified, use current dept.
|
||||||
|
"""
|
||||||
|
dept_id = dept_id if dept_id is not None else g.scodoc_dept_id
|
||||||
|
tag = NotesTag.query.filter_by(dept_id=dept_id, title=title).first()
|
||||||
|
if tag is None:
|
||||||
|
tag = NotesTag(dept_id=dept_id, title=title)
|
||||||
|
db.session.add(tag)
|
||||||
|
db.session.flush()
|
||||||
|
return tag
|
||||||
|
|
||||||
|
|
||||||
# Association tag <-> module
|
# Association tag <-> module
|
||||||
notes_modules_tags = db.Table(
|
notes_modules_tags = db.Table(
|
||||||
|
@ -670,6 +670,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
|||||||
semestre_idx = None
|
semestre_idx = None
|
||||||
else:
|
else:
|
||||||
semestre_idx = int(semestre_idx)
|
semestre_idx = int(semestre_idx)
|
||||||
|
show_tags = scu.to_bool(request.args.get("show_tags", 0))
|
||||||
locked = formation.has_locked_sems(semestre_idx)
|
locked = formation.has_locked_sems(semestre_idx)
|
||||||
semestre_ids = range(1, parcours.NB_SEM + 1)
|
semestre_ids = range(1, parcours.NB_SEM + 1)
|
||||||
# transition: on requete ici via l'ORM mais on utilise les fonctions ScoDoc7
|
# transition: on requete ici via l'ORM mais on utilise les fonctions ScoDoc7
|
||||||
@ -875,11 +876,13 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
)
|
)
|
||||||
# Description des UE/matières/modules
|
# Description des UE/matières/modules
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
f"""
|
||||||
<div class="formation_ue_list">
|
<div class="formation_ue_list">
|
||||||
<div class="ue_list_tit">Programme pédagogique:</div>
|
<div class="ue_list_tit">Programme pédagogique:</div>
|
||||||
<form>
|
<form>
|
||||||
<input type="checkbox" class="sco_tag_checkbox">montrer les tags des modules</input>
|
<input type="checkbox" class="sco_tag_checkbox"
|
||||||
|
{'checked' if show_tags else ''}
|
||||||
|
>montrer les tags des modules</input>
|
||||||
</form>
|
</form>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@ -978,6 +981,11 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
formation_id=formation_id)
|
formation_id=formation_id)
|
||||||
}">Table récapitulative de la formation</a>
|
}">Table récapitulative de la formation</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formation_tag_modules_by_type', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id, semestre_idx=semestre_idx)
|
||||||
|
}">Tagguer tous les modules par leur type</a> (tag <tt>res</tt>, <tt>sae</tt>).
|
||||||
|
</li>
|
||||||
<li><a class="stdlink" href="{
|
<li><a class="stdlink" href="{
|
||||||
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=formation_id, fmt='xml')
|
formation_id=formation_id, fmt='xml')
|
||||||
@ -1061,6 +1069,7 @@ def _html_select_semestre_idx(formation_id, semestre_ids, semestre_idx):
|
|||||||
htm += f"""
|
htm += f"""
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" name="formation_id" value="{formation_id}"></input>
|
<input type="hidden" name="formation_id" value="{formation_id}"></input>
|
||||||
|
<input type="hidden" name="show_tags" value="0"></input>
|
||||||
</form>"""
|
</form>"""
|
||||||
return htm
|
return htm
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ def formation_table_recap(formation_id, fmt="html") -> Response:
|
|||||||
"heures_cours": mod.heures_cours,
|
"heures_cours": mod.heures_cours,
|
||||||
"heures_td": mod.heures_td,
|
"heures_td": mod.heures_td,
|
||||||
"heures_tp": mod.heures_tp,
|
"heures_tp": mod.heures_tp,
|
||||||
|
"tags": ", ".join(t.title for t in mod.tags if t.title),
|
||||||
"_css_row_class": f"mod {mod.type_abbrv()}",
|
"_css_row_class": f"mod {mod.type_abbrv()}",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -117,6 +118,7 @@ def formation_table_recap(formation_id, fmt="html") -> Response:
|
|||||||
"heures_cours",
|
"heures_cours",
|
||||||
"heures_td",
|
"heures_td",
|
||||||
"heures_tp",
|
"heures_tp",
|
||||||
|
"tags",
|
||||||
]
|
]
|
||||||
if not formation.is_apc():
|
if not formation.is_apc():
|
||||||
columns_ids.insert(columns_ids.index("ects"), "coef")
|
columns_ids.insert(columns_ids.index("ects"), "coef")
|
||||||
@ -132,6 +134,7 @@ def formation_table_recap(formation_id, fmt="html") -> Response:
|
|||||||
"heures_cours": "Cours (h)",
|
"heures_cours": "Cours (h)",
|
||||||
"heures_td": "TD (h)",
|
"heures_td": "TD (h)",
|
||||||
"heures_tp": "TP (h)",
|
"heures_tp": "TP (h)",
|
||||||
|
"tags": "Tags",
|
||||||
"ects": "ECTS",
|
"ects": "ECTS",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,17 +38,14 @@ import re
|
|||||||
|
|
||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
from app.comp import res_sem
|
from app import db, log
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.models import Formation, NotesTag
|
||||||
from app.models import FormSemestre
|
from app.scodoc import sco_edit_module
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
|
||||||
from app.scodoc import sco_edit_module
|
|
||||||
from app.scodoc import sco_etud
|
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
|
|
||||||
# Opérations à implementer:
|
# Opérations implementées:
|
||||||
# + liste des modules des formations de code donné (formation_code) avec ce tag
|
# + liste des modules des formations de code donné (formation_code) avec ce tag
|
||||||
# + liste de tous les noms de tag
|
# + liste de tous les noms de tag
|
||||||
# + tag pour un nom
|
# + tag pour un nom
|
||||||
@ -62,6 +59,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
|||||||
# module_tag_set( module_id, taglist ) -> modifie les tags
|
# module_tag_set( module_id, taglist ) -> modifie les tags
|
||||||
|
|
||||||
|
|
||||||
|
# NOTA: ancien code, n'utile pas de modèles SQLAlchemy
|
||||||
class ScoTag(object):
|
class ScoTag(object):
|
||||||
"""Generic tags for ScoDoc"""
|
"""Generic tags for ScoDoc"""
|
||||||
|
|
||||||
@ -232,7 +230,7 @@ def module_tag_search(term: str | int):
|
|||||||
return scu.sendJSON(data)
|
return scu.sendJSON(data)
|
||||||
|
|
||||||
|
|
||||||
def module_tag_list(module_id=""):
|
def module_tag_list(module_id="") -> list[str]:
|
||||||
"""les noms de tags associés à ce module"""
|
"""les noms de tags associés à ce module"""
|
||||||
r = ndb.SimpleDictFetch(
|
r = ndb.SimpleDictFetch(
|
||||||
"""SELECT t.title
|
"""SELECT t.title
|
||||||
@ -249,6 +247,7 @@ def module_tag_set(module_id="", taglist=None):
|
|||||||
"""taglist may either be:
|
"""taglist may either be:
|
||||||
a string with tag names separated by commas ("un,deux")
|
a string with tag names separated by commas ("un,deux")
|
||||||
or a list of strings (["un", "deux"])
|
or a list of strings (["un", "deux"])
|
||||||
|
Remplace les tags existants
|
||||||
"""
|
"""
|
||||||
if not taglist:
|
if not taglist:
|
||||||
taglist = []
|
taglist = []
|
||||||
@ -284,34 +283,6 @@ def module_tag_set(module_id="", taglist=None):
|
|||||||
return "", http.HTTPStatus.NO_CONTENT
|
return "", http.HTTPStatus.NO_CONTENT
|
||||||
|
|
||||||
|
|
||||||
def get_etud_tagged_modules(etudid, tagname):
|
|
||||||
"""Liste d'infos sur les modules de ce semestre avec ce tag.
|
|
||||||
Cherche dans tous les semestres dans lesquel l'étudiant est ou a été inscrit.
|
|
||||||
Construit la liste des modules avec le tag donné par tagname
|
|
||||||
"""
|
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
|
||||||
R = []
|
|
||||||
for sem in etud["sems"]:
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
|
||||||
modimpls = nt.get_modimpls_dict()
|
|
||||||
for modimpl in modimpls:
|
|
||||||
tags = module_tag_list(module_id=modimpl["module_id"])
|
|
||||||
if tagname in tags:
|
|
||||||
moy = nt.get_etud_mod_moy(
|
|
||||||
modimpl["moduleimpl_id"], etudid
|
|
||||||
) # ou NI si non inscrit
|
|
||||||
R.append(
|
|
||||||
{
|
|
||||||
"sem": sem,
|
|
||||||
"moy": moy, # valeur réelle, ou NI (non inscrit au module ou NA (pas de note)
|
|
||||||
"moduleimpl": modimpl,
|
|
||||||
"tags": tags,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return R
|
|
||||||
|
|
||||||
|
|
||||||
def split_tagname_coeff(tag: str, separateur=":") -> tuple[str, float]:
|
def split_tagname_coeff(tag: str, separateur=":") -> tuple[str, float]:
|
||||||
"""Découpage d'un tag, tel que saisi par un utilisateur dans le programme,
|
"""Découpage d'un tag, tel que saisi par un utilisateur dans le programme,
|
||||||
pour en extraire :
|
pour en extraire :
|
||||||
@ -335,42 +306,27 @@ def split_tagname_coeff(tag: str, separateur=":") -> tuple[str, float]:
|
|||||||
try:
|
try:
|
||||||
pond = float(temp[1])
|
pond = float(temp[1])
|
||||||
return (temp[0], pond)
|
return (temp[0], pond)
|
||||||
except:
|
except (IndexError, ValueError, TypeError):
|
||||||
"""Renvoie tout le tag si le découpage à échouer"""
|
# Renvoie tout le tag si le découpage a échoué
|
||||||
return (tag, 1.0)
|
return (tag, 1.0)
|
||||||
else:
|
else:
|
||||||
"""initialise le coeff de pondération à 1 lorsqu'aucun coeff de pondération n'est indiqué dans le tag"""
|
# initialise le coeff de pondération à 1 lorsqu'aucun coeff de pondération
|
||||||
|
# n'ait indiqué dans le tag
|
||||||
return (tag, 1.0)
|
return (tag, 1.0)
|
||||||
|
|
||||||
|
|
||||||
"""Tests:
|
def formation_tag_modules_by_type(formation: Formation):
|
||||||
from debug import *
|
"""Taggue tous les modules de la formation en fonction de leur type : 'res', 'sae', 'malus'
|
||||||
from app.scodoc.sco_tag_module import *
|
Ne taggue pas les modules standards.
|
||||||
_ = go_dept(app, 'RT').Notes
|
"""
|
||||||
|
tag_titles = {
|
||||||
t = ModuleTag( 'essai')
|
m.type_abbrv() for m in formation.modules
|
||||||
t.tag_module('totoro') # error (module invalide)
|
} # usually {'res', 'mod', 'sae'}
|
||||||
t.tag_module('MOD21460')
|
tag_by_type = {
|
||||||
t.delete() # detruit tag et assoc
|
tag_title: NotesTag.get_or_create(title=tag_title, dept_id=formation.dept_id)
|
||||||
t = ModuleTag( 'essai2')
|
for tag_title in tag_titles
|
||||||
t.tag_module('MOD21460')
|
}
|
||||||
t.tag_module('MOD21464')
|
for module in formation.modules:
|
||||||
t.list_modules()
|
if module.module_type != scu.ModuleType.STANDARD:
|
||||||
t.list_modules(formation_code='ccc') # empty list
|
module.add_tag(tag_by_type[module.type_abbrv()])
|
||||||
t.list_modules(formation_code='FCOD2')
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
Un essai de get_etud_tagged_modules:
|
|
||||||
from debug import *
|
|
||||||
from app.scodoc.sco_tag_module import *
|
|
||||||
_ = go_dept(app, 'GEA').Notes
|
|
||||||
|
|
||||||
etudid='GEAEID80687'
|
|
||||||
etud = sco_etud.get_etud_info( etudid=etudid, filled=True)[0]
|
|
||||||
sem = etud['sems'][0]
|
|
||||||
|
|
||||||
[ tm['moy'] for tm in get_etud_tagged_modules( etudid, 'allo') ]
|
|
||||||
|
|
||||||
# si besoin après modif par le Web:
|
|
||||||
# sco_cache.invalidate_formsemestre()
|
|
||||||
"""
|
|
||||||
|
@ -23,11 +23,36 @@ $(function () {
|
|||||||
// version readonly
|
// version readonly
|
||||||
readOnlyTags($(".module_tag_editor_ro"));
|
readOnlyTags($(".module_tag_editor_ro"));
|
||||||
|
|
||||||
$(".sco_tag_checkbox").click(function () {
|
// $(".sco_tag_checkbox").click(function () {
|
||||||
if ($(this).is(":checked")) {
|
// if ($(this).is(":checked")) {
|
||||||
$(".sco_tag_edit").show();
|
// $(".sco_tag_edit").show();
|
||||||
} else {
|
// } else {
|
||||||
$(".sco_tag_edit").hide();
|
// $(".sco_tag_edit").hide();
|
||||||
}
|
// }
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
// tags
|
||||||
|
function toggleEditDisplay(checkbox) {
|
||||||
|
const isChecked = checkbox.checked;
|
||||||
|
document.querySelectorAll('.sco_tag_edit').forEach(el => {
|
||||||
|
el.style.display = isChecked ? 'block' : 'none';
|
||||||
|
});
|
||||||
|
// form semection de semestres:
|
||||||
|
const showTagsInput = document.querySelector('input[name="show_tags"]');
|
||||||
|
if (showTagsInput) {
|
||||||
|
showTagsInput.value = isChecked ? '1' : '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('.sco_tag_checkbox').forEach(checkbox => {
|
||||||
|
// Set up initial state for each checkbox
|
||||||
|
toggleEditDisplay(checkbox);
|
||||||
|
|
||||||
|
// Add click event listener to each checkbox
|
||||||
|
checkbox.addEventListener('click', function() {
|
||||||
|
toggleEditDisplay(this);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -623,6 +623,29 @@ sco_publish("/module_list", sco_edit_module.module_table, Permission.ScoView)
|
|||||||
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/formation_tag_modules_by_type/<int:formation_id>/<int:semestre_idx>")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.EditFormationTags)
|
||||||
|
def formation_tag_modules_by_type(formation_id: int, semestre_idx: int):
|
||||||
|
"""Taggue tous les modules de la formation en fonction de leur type : 'res', 'sae', 'malus'
|
||||||
|
Ne taggue pas les modules standards.
|
||||||
|
"""
|
||||||
|
formation = Formation.query.filter_by(
|
||||||
|
id=formation_id, dept_id=g.scodoc_dept_id
|
||||||
|
).first_or_404()
|
||||||
|
sco_tag_module.formation_tag_modules_by_type(formation)
|
||||||
|
flash("Formation tagguée")
|
||||||
|
return flask.redirect(
|
||||||
|
url_for(
|
||||||
|
"notes.ue_table",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
semestre_idx=semestre_idx,
|
||||||
|
formation_id=formation.id,
|
||||||
|
show_tags=1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/module_tag_set", methods=["POST"])
|
@bp.route("/module_tag_set", methods=["POST"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.EditFormationTags)
|
@permission_required(Permission.EditFormationTags)
|
||||||
|
Loading…
Reference in New Issue
Block a user