diff --git a/app/__init__.py b/app/__init__.py index a1862aaa70..66c6effd1c 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -205,6 +205,10 @@ def create_app(config_class=DevConfig): app = Flask(__name__, static_url_path="/ScoDoc/static", static_folder="static") app.wsgi_app = ReverseProxied(app.wsgi_app) app.logger.setLevel(logging.DEBUG) + + # Evite de logguer toutes les requetes dans notre log + logging.getLogger("werkzeug").disabled = True + app.config.from_object(config_class) db.init_app(app) diff --git a/app/models/formations.py b/app/models/formations.py index f35a48ce67..7db99a1fb5 100644 --- a/app/models/formations.py +++ b/app/models/formations.py @@ -14,6 +14,7 @@ from app.models.but_refcomp import ( ApcParcoursNiveauCompetence, ) from app.models.modules import Module +from app.models.moduleimpls import ModuleImpl from app.models.ues import UniteEns from app.scodoc import sco_cache from app.scodoc import sco_codes_parcours @@ -109,6 +110,13 @@ class Formation(db.Model): else: keys = f"{self.id}.{semestre_idx}" df_cache.ModuleCoefsCache.delete_many(keys | {f"{self.id}"}) + # Invalidate aussi les poids de toutes les évals de la formation + for modimpl in ModuleImpl.query.filter( + ModuleImpl.module_id == Module.id, + Module.formation_id == self.id, + ): + modimpl.invalidate_evaluations_poids() + sco_cache.invalidate_formsemestre() def invalidate_cached_sems(self): diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index df790649a6..daf4a9419d 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -158,9 +158,24 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): I["server_name"] = request.url_root # Formation et parcours - I["formation"] = sco_formations.formation_list( - args={"formation_id": I["sem"]["formation_id"]} - )[0] + if I["sem"]["formation_id"]: + I["formation"] = sco_formations.formation_list( + args={"formation_id": I["sem"]["formation_id"]} + )[0] + else: # what's the fuck ? + I["formation"] = { + "acronyme": "?", + "code_specialite": "", + "dept_id": 1, + "formation_code": "?", + "formation_id": -1, + "id": -1, + "referentiel_competence_id": None, + "titre": "?", + "titre_officiel": "?", + "type_parcours": 0, + "version": 0, + } I["parcours"] = sco_codes_parcours.get_parcours_from_code( I["formation"]["type_parcours"] ) diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py index 8fcc6f7efe..7975e3b2cf 100644 --- a/app/scodoc/sco_cache.py +++ b/app/scodoc/sco_cache.py @@ -67,6 +67,7 @@ class ScoDocCache: timeout = None # ttl, infinite by default prefix = "" + verbose = False # if true, verbose logging (debug) @classmethod def _get_key(cls, oid): @@ -87,7 +88,10 @@ class ScoDocCache: def set(cls, oid, value): """Store value""" key = cls._get_key(oid) - # log(f"CACHE key={key}, type={type(value)}, timeout={cls.timeout}") + if cls.verbose: + log( + f"{cls.__name__}.set key={key}, type={type(value).__name__}, timeout={cls.timeout}" + ) try: status = CACHE.set(key, value, timeout=cls.timeout) if not status: @@ -101,11 +105,15 @@ class ScoDocCache: @classmethod def delete(cls, oid): """Remove from cache""" + # if cls.verbose: + # log(f"{cls.__name__}.delete({oid})") CACHE.delete(cls._get_key(oid)) @classmethod def delete_many(cls, oids): """Remove multiple keys at once""" + if cls.verbose: + log(f"{cls.__name__}.delete_many({oids})") # delete_many seems bugged: # CACHE.delete_many([cls._get_key(oid) for oid in oids]) for oid in oids: diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index a2a6c05c8d..fd40ac2b85 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -122,12 +122,7 @@ def do_ue_create(args): # create ue_id = _ueEditor.create(cnx, args) - # Invalidate cache: vire les poids de toutes les évals de la formation - for modimpl in ModuleImpl.query.filter( - ModuleImpl.module_id == Module.id, Module.formation_id == args["formation_id"] - ): - modimpl.invalidate_evaluations_poids() - formation = Formation.query.get(args["formation_id"]) + formation: Formation = Formation.query.get(args["formation_id"]) formation.invalidate_module_coefs() # news ue = UniteEns.query.get(ue_id) @@ -145,11 +140,10 @@ def do_ue_create(args): def do_ue_delete(ue_id, delete_validations=False, force=False): "delete UE and attached matieres (but not modules)" - from app.scodoc import sco_formations from app.scodoc import sco_parcours_dut ue = UniteEns.query.get_or_404(ue_id) - formation_id = ue.formation_id + formation = ue.formation semestre_idx = ue.semestre_idx if not ue.can_be_deleted(): raise ScoNonEmptyFormationObject( @@ -158,7 +152,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False): dest_url=url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, - formation_id=formation_id, + formation_id=formation.id, semestre_idx=semestre_idx, ), ) @@ -182,7 +176,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False): cancel_url=url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, - formation_id=formation_id, + formation_id=formation.id, semestre_idx=semestre_idx, ), parameters={"ue_id": ue.id, "dialog_confirmed": 1}, @@ -208,13 +202,13 @@ def do_ue_delete(ue_id, delete_validations=False, force=False): _ueEditor.delete(cnx, ue.id) # > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement # utilisé: acceptable de tout invalider): - sco_cache.invalidate_formsemestre() + formation.invalidate_module_coefs() + # -> invalide aussi .invalidate_formsemestre() # news - F = sco_formations.formation_list(args={"formation_id": formation_id})[0] ScolarNews.add( typ=ScolarNews.NEWS_FORM, - obj=formation_id, - text=f"Modification de la formation {F['acronyme']}", + obj=formation.id, + text=f"Modification de la formation {formation.acronyme}", max_frequency=10 * 60, ) # @@ -223,7 +217,7 @@ def do_ue_delete(ue_id, delete_validations=False, force=False): url_for( "notes.ue_table", scodoc_dept=g.scodoc_dept, - formation_id=formation_id, + formation_id=formation.id, semestre_idx=semestre_idx, ) ) @@ -1317,8 +1311,9 @@ def do_ue_edit(args, bypass_lock=False, dont_invalidate_cache=False): formation = Formation.query.get(ue["formation_id"]) if not dont_invalidate_cache: - # Invalide les semestres utilisant cette formation: - formation.invalidate_cached_sems() + # Invalide les semestres utilisant cette formation + # ainsi que les poids et coefs + formation.invalidate_module_coefs() # essai edition en ligne: diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py index 1084314d6a..c49ef080a9 100644 --- a/app/scodoc/sco_moduleimpl_status.py +++ b/app/scodoc/sco_moduleimpl_status.py @@ -192,7 +192,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None): """Tableau de bord module (liste des evaluations etc)""" if not isinstance(moduleimpl_id, int): raise ScoInvalidIdType("moduleimpl_id must be an integer !") - modimpl = ModuleImpl.query.get_or_404(moduleimpl_id) + modimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id) M = modimpl.to_dict() formsemestre_id = modimpl.formsemestre_id Mod = sco_edit_module.module_list(args={"module_id": modimpl.module_id})[0]