Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
4 changed files with 68 additions and 56 deletions
Showing only changes of commit 7162d83f39 - Show all commits

View File

@ -5,7 +5,7 @@
import datetime import datetime
from operator import attrgetter from operator import attrgetter
from flask import g, url_for from flask import abort, g, url_for
from flask_login import current_user from flask_login import current_user
import sqlalchemy as sa import sqlalchemy as sa
@ -241,6 +241,25 @@ class Evaluation(db.Model):
if k != "_sa_instance_state" and k != "id" and k in data: if k != "_sa_instance_state" and k != "id" and k in data:
setattr(self, k, data[k]) setattr(self, k, data[k])
@classmethod
def get_evaluation(
cls, evaluation_id: int | str, dept_id: int = None
) -> "Evaluation":
"""Evaluation ou 404, cherche uniquement dans le département spécifié ou le courant."""
from app.models import FormSemestre, ModuleImpl
if not isinstance(evaluation_id, int):
try:
evaluation_id = int(evaluation_id)
except (TypeError, ValueError):
abort(404, "evaluation_id invalide")
if g.scodoc_dept:
dept_id = dept_id if dept_id is not None else g.scodoc_dept_id
query = cls.query.filter_by(id=evaluation_id)
if dept_id is not None:
query = query.join(ModuleImpl).join(FormSemestre).filter_by(dept_id=dept_id)
return query.first_or_404()
@classmethod @classmethod
def get_max_numero(cls, moduleimpl_id: int) -> int: def get_max_numero(cls, moduleimpl_id: int) -> int:
"""Return max numero among evaluations in this """Return max numero among evaluations in this
@ -265,7 +284,9 @@ class Evaluation(db.Model):
evaluations = moduleimpl.evaluations.order_by( evaluations = moduleimpl.evaluations.order_by(
Evaluation.date_debut, Evaluation.numero Evaluation.date_debut, Evaluation.numero
).all() ).all()
all_numbered = all(e.numero is not None for e in evaluations) numeros_distincts = {e.numero for e in evaluations if e.numero is not None}
# pas de None, pas de dupliqués
all_numbered = len(numeros_distincts) == len(evaluations)
if all_numbered and only_if_unumbered: if all_numbered and only_if_unumbered:
return # all ok return # all ok

View File

@ -162,50 +162,48 @@ def do_evaluation_get_all_notes(
return d return d
def moduleimpl_evaluation_move(evaluation_id: int, after=0, redirect=1): def moduleimpl_evaluation_move(evaluation_id: int, after=0):
"""Move before/after previous one (decrement/increment numero) """Move before/after previous one (decrement/increment numero)
(published) (published)
""" """
evaluation: Evaluation = Evaluation.query.get_or_404(evaluation_id) evaluation = Evaluation.get_evaluation(evaluation_id)
redirect = int(redirect)
# access: can change eval ? # access: can change eval ?
if not evaluation.moduleimpl.can_edit_evaluation(current_user): if not evaluation.moduleimpl.can_edit_evaluation(current_user):
raise AccessDenied( raise AccessDenied(
f"Modification évaluation impossible pour {current_user.get_nomplogin()}" f"Modification évaluation impossible pour {current_user.get_nomplogin()}"
) )
Evaluation.moduleimpl_evaluation_renumber(
evaluation.moduleimpl, only_if_unumbered=True
)
e = get_evaluations_dict(args={"evaluation_id": evaluation_id})[0]
after = int(after) # 0: deplace avant, 1 deplace apres after = int(after) # 0: deplace avant, 1 deplace apres
if after not in (0, 1): if after not in (0, 1):
raise ValueError('invalid value for "after"') raise ValueError('invalid value for "after"')
mod_evals = get_evaluations_dict({"moduleimpl_id": e["moduleimpl_id"]})
if len(mod_evals) > 1: Evaluation.moduleimpl_evaluation_renumber(
idx = [p["evaluation_id"] for p in mod_evals].index(evaluation_id) evaluation.moduleimpl, only_if_unumbered=True
)
mod_evaluations = evaluation.moduleimpl.evaluations.all()
if len(mod_evaluations) > 1:
idx = [e.id for e in mod_evaluations].index(evaluation.id)
neigh = None # object to swap with neigh = None # object to swap with
if after == 0 and idx > 0: if after == 0 and idx > 0:
neigh = mod_evals[idx - 1] neigh = mod_evaluations[idx - 1]
elif after == 1 and idx < len(mod_evals) - 1: elif after == 1 and idx < len(mod_evaluations) - 1:
neigh = mod_evals[idx + 1] neigh = mod_evaluations[idx + 1]
if neigh: # if neigh: #
if neigh["numero"] == e["numero"]: if neigh.numero == evaluation.numero:
log("Warning: moduleimpl_evaluation_move: forcing renumber") log("Warning: moduleimpl_evaluation_move: forcing renumber")
Evaluation.moduleimpl_evaluation_renumber( Evaluation.moduleimpl_evaluation_renumber(
evaluation.moduleimpl, only_if_unumbered=False evaluation.moduleimpl, only_if_unumbered=False
) )
else: else:
# swap numero with neighbor # swap numero with neighbor
e["numero"], neigh["numero"] = neigh["numero"], e["numero"] evaluation.numero, neigh.numero = neigh.numero, evaluation.numero
do_evaluation_edit(e) db.session.add(evaluation)
do_evaluation_edit(neigh) db.session.add(neigh)
db.session.commit()
# redirect to moduleimpl page: # redirect to moduleimpl page:
if redirect:
return flask.redirect( return flask.redirect(
url_for( url_for(
"notes.moduleimpl_status", "notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
moduleimpl_id=e["moduleimpl_id"], moduleimpl_id=evaluation.moduleimpl.id,
) )
) )

View File

@ -37,7 +37,7 @@ from flask_login import current_user
from flask import request from flask import request
from app import db from app import db
from app.models import Evaluation, FormSemestre, ModuleImpl from app.models import Evaluation, Module, ModuleImpl
from app.models.evaluations import heure_to_time from app.models.evaluations import heure_to_time
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -47,7 +47,6 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
@ -58,27 +57,20 @@ def evaluation_create_form(
page_title="Évaluation", page_title="Évaluation",
): ):
"Formulaire création/édition d'une évaluation (pas de ses notes)" "Formulaire création/édition d'une évaluation (pas de ses notes)"
evaluation: Evaluation
if evaluation_id is not None: if evaluation_id is not None:
evaluation: Evaluation = db.session.get(Evaluation, evaluation_id) evaluation = db.session.get(Evaluation, evaluation_id)
if evaluation is None: if evaluation is None:
raise ScoValueError("Cette évaluation n'existe pas ou plus !") raise ScoValueError("Cette évaluation n'existe pas ou plus !")
moduleimpl_id = evaluation.moduleimpl_id moduleimpl_id = evaluation.moduleimpl_id
# #
modimpl: ModuleImpl = ( modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
ModuleImpl.query.filter_by(id=moduleimpl_id) formsemestre_id = modimpl.formsemestre_id
.join(FormSemestre)
.filter_by(dept_id=g.scodoc_dept_id)
.first_or_404()
)
modimpl_o = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[
0
]
mod = modimpl_o["module"]
formsemestre_id = modimpl_o["formsemestre_id"]
formsemestre = modimpl.formsemestre formsemestre = modimpl.formsemestre
module: Module = modimpl.module
sem_ues = formsemestre.get_ues(with_sport=False) sem_ues = formsemestre.get_ues(with_sport=False)
is_malus = mod["module_type"] == ModuleType.MALUS is_malus = module.module_type == ModuleType.MALUS
is_apc = mod["module_type"] in (ModuleType.RESSOURCE, ModuleType.SAE) is_apc = module.module_type in (ModuleType.RESSOURCE, ModuleType.SAE)
preferences = sco_preferences.SemPreferences(formsemestre.id) preferences = sco_preferences.SemPreferences(formsemestre.id)
can_edit_poids = not preferences["but_disable_edit_poids_evaluations"] can_edit_poids = not preferences["but_disable_edit_poids_evaluations"]
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
@ -99,8 +91,9 @@ def evaluation_create_form(
if moduleimpl_id is None: if moduleimpl_id is None:
raise ValueError("missing moduleimpl_id parameter") raise ValueError("missing moduleimpl_id parameter")
initvalues = { initvalues = {
"note_max": 20,
"jour": time.strftime("%d/%m/%Y", time.localtime()), "jour": time.strftime("%d/%m/%Y", time.localtime()),
"note_max": 20,
"numero": max(e.numero or 0 for e in modimpl.evaluations) + 1,
"publish_incomplete": is_malus, "publish_incomplete": is_malus,
"visibulletin": 1, "visibulletin": 1,
} }
@ -128,18 +121,7 @@ def evaluation_create_form(
min_note_max_str = scu.fmt_note(min_note_max) min_note_max_str = scu.fmt_note(min_note_max)
else: else:
min_note_max_str = "0" min_note_max_str = "0"
#
H = [
f"""<h3>{action} en
{scu.MODULE_TYPE_NAMES[mod["module_type"]]} <a class="stdlink" href="{
url_for("notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id)
}">{mod["code"] or "module sans code"} {mod["titre"]}</a> {link}</h3>
"""
]
heures = [f"{h:02d}h{m:02d}" for h in range(8, 19) for m in (0, 30)]
#
initvalues["coefficient"] = initvalues.get("coefficient", 1.0) initvalues["coefficient"] = initvalues.get("coefficient", 1.0)
vals = scu.get_request_args() vals = scu.get_request_args()
# #
@ -164,6 +146,7 @@ def evaluation_create_form(
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}), ("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}),
("moduleimpl_id", {"default": moduleimpl_id, "input_type": "hidden"}), ("moduleimpl_id", {"default": moduleimpl_id, "input_type": "hidden"}),
("numero", {"default": initvalues["numero"], "input_type": "hidden"}),
( (
"jour", "jour",
{ {
@ -323,6 +306,16 @@ def evaluation_create_form(
dest_url = url_for( dest_url = url_for(
"notes.moduleimpl_status", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id "notes.moduleimpl_status", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id
) )
H = [
f"""<h3>{action} en
{scu.MODULE_TYPE_NAMES[module.module_type]} <a class="stdlink" href="{
url_for("notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id)
}">{module.code or "module sans code"} {
module.titre or module.abbrev or "(sans titre)"
}</a> {link}</h3>
"""
]
if tf[0] == 0: if tf[0] == 0:
head = html_sco_header.sco_header(page_title=page_title) head = html_sco_header.sco_header(page_title=page_title)
return ( return (

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.6.93" SCOVERSION = "9.6.931"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"