forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -5,6 +5,7 @@ from flask import g
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from app import db, log
|
from app import db, log
|
||||||
|
from app import models
|
||||||
from app.models import APO_CODE_STR_LEN
|
from app.models import APO_CODE_STR_LEN
|
||||||
from app.models import SHORT_STR_LEN
|
from app.models import SHORT_STR_LEN
|
||||||
from app.models.but_refcomp import ApcNiveau, ApcParcours
|
from app.models.but_refcomp import ApcNiveau, ApcParcours
|
||||||
@ -12,7 +13,7 @@ from app.models.modules import Module
|
|||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
class UniteEns(db.Model):
|
class UniteEns(models.ScoDocModel):
|
||||||
"""Unité d'Enseignement (UE)"""
|
"""Unité d'Enseignement (UE)"""
|
||||||
|
|
||||||
__tablename__ = "notes_ue"
|
__tablename__ = "notes_ue"
|
||||||
@ -81,7 +82,7 @@ class UniteEns(db.Model):
|
|||||||
'EXTERNE' if self.is_external else ''})>"""
|
'EXTERNE' if self.is_external else ''})>"""
|
||||||
|
|
||||||
def clone(self):
|
def clone(self):
|
||||||
"""Create a new copy of this ue.
|
"""Create a new copy of this ue, add to session.
|
||||||
Ne copie pas le code, ni le code Apogée, ni les liens au réf. de comp.
|
Ne copie pas le code, ni le code Apogée, ni les liens au réf. de comp.
|
||||||
(parcours et niveau).
|
(parcours et niveau).
|
||||||
"""
|
"""
|
||||||
@ -100,8 +101,26 @@ class UniteEns(db.Model):
|
|||||||
coef_rcue=self.coef_rcue,
|
coef_rcue=self.coef_rcue,
|
||||||
color=self.color,
|
color=self.color,
|
||||||
)
|
)
|
||||||
|
db.session.add(ue)
|
||||||
return ue
|
return ue
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def convert_dict_fields(cls, args: dict) -> dict:
|
||||||
|
"""Convert fields from the given dict to model's attributes values. No side effect.
|
||||||
|
|
||||||
|
args: dict with args in application.
|
||||||
|
returns: dict to store in model's db.
|
||||||
|
"""
|
||||||
|
args = args.copy()
|
||||||
|
if "type" in args:
|
||||||
|
args["type"] = int(args["type"] or 0)
|
||||||
|
if "is_external" in args:
|
||||||
|
args["is_external"] = scu.to_bool(args["is_external"])
|
||||||
|
if "ects" in args:
|
||||||
|
args["ects"] = float(args["ects"])
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
def to_dict(self, convert_objects=False, with_module_ue_coefs=True):
|
def to_dict(self, convert_objects=False, with_module_ue_coefs=True):
|
||||||
"""as a dict, with the same conversions as in ScoDoc7.
|
"""as a dict, with the same conversions as in ScoDoc7.
|
||||||
If convert_objects, convert all attributes to native types
|
If convert_objects, convert all attributes to native types
|
||||||
|
@ -300,6 +300,7 @@ class EditableTable(object):
|
|||||||
output_formators={},
|
output_formators={},
|
||||||
input_formators={},
|
input_formators={},
|
||||||
aux_tables=[],
|
aux_tables=[],
|
||||||
|
convert_empty_to_nulls=True, # les arguments vides sont traduits en NULL
|
||||||
convert_null_outputs_to_empty=True,
|
convert_null_outputs_to_empty=True,
|
||||||
html_quote=False, # changed in 9.0.10
|
html_quote=False, # changed in 9.0.10
|
||||||
fields_creators={}, # { field : [ sql_command_to_create_it ] }
|
fields_creators={}, # { field : [ sql_command_to_create_it ] }
|
||||||
@ -321,6 +322,7 @@ class EditableTable(object):
|
|||||||
self.output_formators = output_formators
|
self.output_formators = output_formators
|
||||||
self.input_formators = input_formators
|
self.input_formators = input_formators
|
||||||
self.convert_null_outputs_to_empty = convert_null_outputs_to_empty
|
self.convert_null_outputs_to_empty = convert_null_outputs_to_empty
|
||||||
|
self.convert_empty_to_nulls = convert_empty_to_nulls
|
||||||
self.html_quote = html_quote
|
self.html_quote = html_quote
|
||||||
self.fields_creators = fields_creators
|
self.fields_creators = fields_creators
|
||||||
self.filter_nulls = filter_nulls
|
self.filter_nulls = filter_nulls
|
||||||
@ -351,6 +353,7 @@ class EditableTable(object):
|
|||||||
self.table_name,
|
self.table_name,
|
||||||
vals,
|
vals,
|
||||||
commit=True,
|
commit=True,
|
||||||
|
convert_empty_to_nulls=self.convert_empty_to_nulls,
|
||||||
return_id=(self.id_name is not None),
|
return_id=(self.id_name is not None),
|
||||||
ignore_conflicts=self.insert_ignore_conflicts,
|
ignore_conflicts=self.insert_ignore_conflicts,
|
||||||
)
|
)
|
||||||
@ -444,7 +447,7 @@ def dictfilter(d, fields, filter_nulls=True):
|
|||||||
"""returns a copy of d with only keys listed in "fields" and non null values"""
|
"""returns a copy of d with only keys listed in "fields" and non null values"""
|
||||||
r = {}
|
r = {}
|
||||||
for f in fields:
|
for f in fields:
|
||||||
if f in d and (d[f] != None or not filter_nulls):
|
if f in d and (d[f] is not None or not filter_nulls):
|
||||||
try:
|
try:
|
||||||
val = d[f].strip()
|
val = d[f].strip()
|
||||||
except:
|
except:
|
||||||
|
@ -89,6 +89,7 @@ _ueEditor = ndb.EditableTable(
|
|||||||
"color",
|
"color",
|
||||||
"niveau_competence_id",
|
"niveau_competence_id",
|
||||||
),
|
),
|
||||||
|
convert_empty_to_nulls=False, # necessaire pour ue_code == ""
|
||||||
sortkey="numero",
|
sortkey="numero",
|
||||||
input_formators={
|
input_formators={
|
||||||
"type": ndb.int_null_is_zero,
|
"type": ndb.int_null_is_zero,
|
||||||
@ -110,7 +111,7 @@ def ue_list(*args, **kw):
|
|||||||
return _ueEditor.list(cnx, *args, **kw)
|
return _ueEditor.list(cnx, *args, **kw)
|
||||||
|
|
||||||
|
|
||||||
def do_ue_create(args):
|
def do_ue_create(args, allow_empty_ue_code=False):
|
||||||
"create an ue"
|
"create an ue"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# check duplicates
|
# check duplicates
|
||||||
@ -120,18 +121,18 @@ def do_ue_create(args):
|
|||||||
f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé !
|
f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé !
|
||||||
(chaque UE doit avoir un acronyme unique dans la formation)"""
|
(chaque UE doit avoir un acronyme unique dans la formation)"""
|
||||||
)
|
)
|
||||||
if (
|
if "ue_code" not in args or args["ue_code"] is None or not args["ue_code"].strip():
|
||||||
(not "ue_code" in args)
|
if allow_empty_ue_code:
|
||||||
or (args["ue_code"] is None)
|
args["ue_code"] = ""
|
||||||
or (not args["ue_code"].strip())
|
else:
|
||||||
):
|
# évite les conflits: génère nouveau ue_code
|
||||||
# évite les conflits de code
|
|
||||||
while True:
|
while True:
|
||||||
cursor = db.session.execute(sa.text("select notes_newid_ucod();"))
|
cursor = db.session.execute(sa.text("select notes_newid_ucod();"))
|
||||||
code = cursor.fetchone()[0]
|
code = cursor.fetchone()[0]
|
||||||
if UniteEns.query.filter_by(ue_code=code).count() == 0:
|
if UniteEns.query.filter_by(ue_code=code).count() == 0:
|
||||||
break
|
break
|
||||||
args["ue_code"] = code
|
args["ue_code"] = code
|
||||||
|
|
||||||
# create
|
# create
|
||||||
ue_id = _ueEditor.create(cnx, args)
|
ue_id = _ueEditor.create(cnx, args)
|
||||||
log(f"do_ue_create: created {ue_id} with {args}")
|
log(f"do_ue_create: created {ue_id} with {args}")
|
||||||
|
@ -168,7 +168,6 @@ def formsemestre_associate_new_version(
|
|||||||
formation_id=new_formation_id,
|
formation_id=new_formation_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.formsemestre_status",
|
"notes.formsemestre_status",
|
||||||
@ -176,7 +175,6 @@ def formsemestre_associate_new_version(
|
|||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
raise ScoValueError("Méthode invalide")
|
raise ScoValueError("Méthode invalide")
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ def formation_export_dict(
|
|||||||
ues = ues.all()
|
ues = ues.all()
|
||||||
ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
|
ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
|
||||||
f_dict["ue"] = []
|
f_dict["ue"] = []
|
||||||
|
ue: UniteEns
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_dict = ue.to_dict()
|
ue_dict = ue.to_dict()
|
||||||
f_dict["ue"].append(ue_dict)
|
f_dict["ue"].append(ue_dict)
|
||||||
@ -363,7 +364,9 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||||||
ue_info[1]["niveau_competence_id"] = _formation_retreive_apc_niveau(
|
ue_info[1]["niveau_competence_id"] = _formation_retreive_apc_niveau(
|
||||||
referentiel_competence_id, ue_info[1]
|
referentiel_competence_id, ue_info[1]
|
||||||
)
|
)
|
||||||
ue_id = sco_edit_ue.do_ue_create(ue_info[1])
|
# Note: si le code est indiqué "" dans le xml, il faut le conserver vide
|
||||||
|
# pour la comparaison ultérieure des formations XXX
|
||||||
|
ue_id = sco_edit_ue.do_ue_create(ue_info[1], allow_empty_ue_code=True)
|
||||||
ue: UniteEns = db.session.get(UniteEns, ue_id)
|
ue: UniteEns = db.session.get(UniteEns, ue_id)
|
||||||
assert ue
|
assert ue
|
||||||
if xml_ue_id:
|
if xml_ue_id:
|
||||||
|
@ -824,7 +824,6 @@ def ue_clone():
|
|||||||
ue_id = int(request.form.get("ue_id"))
|
ue_id = int(request.form.get("ue_id"))
|
||||||
ue = UniteEns.query.get_or_404(ue_id)
|
ue = UniteEns.query.get_or_404(ue_id)
|
||||||
ue2 = ue.clone()
|
ue2 = ue.clone()
|
||||||
db.session.add(ue2)
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(f"UE {ue.acronyme} dupliquée")
|
flash(f"UE {ue.acronyme} dupliquée")
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
|
Loading…
Reference in New Issue
Block a user