diff --git a/app/models/groups.py b/app/models/groups.py index 1d24b60c08..27b763d112 100644 --- a/app/models/groups.py +++ b/app/models/groups.py @@ -23,7 +23,7 @@ class Partition(db.Model): ) # "TD", "TP", ... (NULL for 'all') partition_name = db.Column(db.String(SHORT_STR_LEN)) - # numero = ordre de presentation) + # Numero = ordre de presentation) numero = db.Column(db.Integer) # Calculer le rang ? bul_show_rank = db.Column( @@ -33,6 +33,10 @@ class Partition(db.Model): show_in_lists = db.Column( db.Boolean(), nullable=False, default=True, server_default="true" ) + # Editable ? (faux pour les groupes de parcours) + groups_editable = db.Column( + db.Boolean(), nullable=False, default=True, server_default="true" + ) groups = db.relationship( "GroupDescr", backref=db.backref("partition", lazy=True), diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py index b3fe985327..394af3be57 100644 --- a/app/scodoc/sco_formsemestre_inscriptions.py +++ b/app/scodoc/sco_formsemestre_inscriptions.py @@ -35,6 +35,7 @@ from flask import url_for, g, request from app.comp import res_sem from app.comp.res_compat import NotesTableCompat from app.models import FormSemestre +from app.models.groups import GroupDescr, Partition import app.scodoc.sco_utils as scu from app import log from app.scodoc.scolog import logdb @@ -263,8 +264,7 @@ def do_formsemestre_inscription_with_modules( args["etat"] = etat do_formsemestre_inscription_create(args, method=method) log( - "do_formsemestre_inscription_with_modules: etudid=%s formsemestre_id=%s" - % (etudid, formsemestre_id) + f"do_formsemestre_inscription_with_modules: etudid={etudid} formsemestre_id={formsemestre_id}" ) # inscriptions aux groupes # 1- inscrit au groupe 'tous' @@ -275,8 +275,14 @@ def do_formsemestre_inscription_with_modules( # 2- inscrit aux groupes for group_id in group_ids: if group_id and not group_id in gdone: - sco_groups.set_group(etudid, group_id) - gdone[group_id] = 1 + group = GroupDescr.query.get_or_404(group_id) + if group.partition.groups_editable: + sco_groups.set_group(etudid, group_id) + gdone[group_id] = 1 + else: + log( + f"do_formsemestre_inscription_with_modules: group {group:r} belongs to non editable partition" + ) # inscription a tous les modules de ce semestre modimpls = sco_moduleimpl.moduleimpl_withmodule_list( @@ -534,11 +540,14 @@ def formsemestre_inscription_option(etudid, formsemestre_id): ue_status = nt.get_etud_ue_status(etudid, ue_id) if ue_status and ue_status["is_capitalized"]: sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"]) - ue_descr += ' (capitalisée le %s)' % ( - sem_origin["formsemestre_id"], - etudid, - sem_origin["titreannee"], - ndb.DateISOtoDMY(ue_status["event_date"]), + ue_descr += ( + ' (capitalisée le %s)' + % ( + sem_origin["formsemestre_id"], + etudid, + sem_origin["titreannee"], + ndb.DateISOtoDMY(ue_status["event_date"]), + ) ) descr.append( ( diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 10e5dbe932..5cc5c47a60 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -346,7 +346,7 @@ def formsemestre_status_menubar(sem): "title": "%s" % partition["partition_name"], "endpoint": "scolar.affect_groups", "args": {"partition_id": partition["partition_id"]}, - "enabled": enabled, + "enabled": enabled and partition["groups_editable"], } ) menuGroupes.append( diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index 8eae60e040..50e0e70ee0 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -76,10 +76,12 @@ partitionEditor = ndb.EditableTable( "numero", "bul_show_rank", "show_in_lists", + "editable", ), input_formators={ "bul_show_rank": bool, "show_in_lists": bool, + "editable": bool, }, ) @@ -621,10 +623,12 @@ def comp_origin(etud, cur_sem): return "" # parcours normal, ne le signale pas -def set_group(etudid, group_id): +def set_group(etudid: int, group_id: int) -> bool: """Inscrit l'étudiant au groupe. Return True if ok, False si deja inscrit. - Warning: don't check if group_id exists (the caller should check). + Warning: + - don't check if group_id exists (the caller should check). + - don't check if group's partition is editable """ cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) @@ -698,14 +702,28 @@ def setGroups( groupsToCreate="", # name and members of new groups groupsToDelete="", # groups to delete ): - """Affect groups (Ajax request) + """Affect groups (Ajax request): renvoie du XML groupsLists: lignes de la forme "group_id;etudid;...\n" groupsToCreate: lignes "group_name;etudid;...\n" groupsToDelete: group_id;group_id;... + + Ne peux pas modifier les groupes des partitions non éditables. """ from app.scodoc import sco_formsemestre + def xml_error(msg, code=404): + data = ( + f'Error: {msg}' + ) + response = make_response(data, code) + response.headers["Content-Type"] = scu.XML_MIMETYPE + return response + partition = get_partition(partition_id) + if not partition["group_editable"]: + msg = "setGroups: partition non editable" + log(msg) + return xml_error(msg, code=403) formsemestre_id = partition["formsemestre_id"] if not sco_permissions_check.can_change_groups(formsemestre_id): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") @@ -727,8 +745,8 @@ def setGroups( continue try: group_id = int(group_id) - except ValueError as exc: - log("setGroups: ignoring invalid group_id={group_id}") + except ValueError: + log(f"setGroups: ignoring invalid group_id={group_id}") continue group = get_group(group_id) # Anciens membres du groupe: @@ -967,14 +985,19 @@ def edit_partition_form(formsemestre_id=None): for group in get_partition_groups(p) ] H.append(", ".join(lg)) - H.append( - f"""répartir - """ - ) + H.append("""""") + if p["groups_editable"]: + H.append( + f"""répartir + """ + ) + else: + H.append("""non éditable""") + H.append("""""") H.append( 'renommer' % p["partition_id"] @@ -1334,6 +1357,8 @@ def groups_auto_repartition(partition_id=None): from app.scodoc import sco_formsemestre partition = get_partition(partition_id) + if not partition["groups_editable"]: + raise AccessDenied("Partition non éditable") formsemestre_id = partition["formsemestre_id"] formsemestre = FormSemestre.query.get(formsemestre_id) # renvoie sur page édition groupes diff --git a/app/scodoc/sco_import_etuds.py b/app/scodoc/sco_import_etuds.py index 32b2530d47..fcad66228d 100644 --- a/app/scodoc/sco_import_etuds.py +++ b/app/scodoc/sco_import_etuds.py @@ -33,14 +33,13 @@ import io import os import re import time -from datetime import date from flask import g, url_for import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app import log -from app.models import ScolarNews +from app.models import ScolarNews, GroupDescr from app.scodoc.sco_excel import COLORS from app.scodoc.sco_formsemestre_inscriptions import ( @@ -718,9 +717,17 @@ def scolars_import_admission(datafile, formsemestre_id=None, type_admission=None ) for group_id in group_ids: - sco_groups.change_etud_group_in_partition( - args["etudid"], group_id - ) + group = GroupDescr.query.get(group_id) + if group.partition.groups_editable: + sco_groups.change_etud_group_in_partition( + args["etudid"], group_id + ) + else: + log("scolars_import_admission: partition non editable") + diag.append( + f"Attention: partition {group.partition} non editable (ignorée)" + ) + # diag.append("import de %s" % (etud["nomprenom"])) n_import += 1 diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index 807792fb00..4f0146c1e1 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -219,11 +219,12 @@ def do_inscrit(sem, etudids, inscrit_groupes=False): # inscrit aux groupes for partition_group in partition_groups: - sco_groups.change_etud_group_in_partition( - etudid, - partition_group["group_id"], - partition_group, - ) + if partition_group["groups_editable"]: + sco_groups.change_etud_group_in_partition( + etudid, + partition_group["group_id"], + partition_group, + ) def do_desinscrit(sem, etudids): diff --git a/migrations/versions/a2771105c21c_parcours_inscriptions_casc.py b/migrations/versions/a2771105c21c_parcours_inscriptions_casc.py index 55d194e025..74da8acb93 100644 --- a/migrations/versions/a2771105c21c_parcours_inscriptions_casc.py +++ b/migrations/versions/a2771105c21c_parcours_inscriptions_casc.py @@ -102,6 +102,13 @@ def upgrade(): ["id"], ondelete="CASCADE", ) + # GROUPES + op.add_column( + "partition", + sa.Column( + "groups_editable", sa.Boolean(), server_default="true", nullable=False + ), + ) # INSCRIPTIONS op.drop_constraint( "notes_formsemestre_inscription_etudid_fkey", @@ -192,6 +199,7 @@ def upgrade(): # ### end Alembic commands ### +# -------------------------------------------------------------- def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_constraint( @@ -232,6 +240,8 @@ def downgrade(): op.create_foreign_key( "notes_notes_etudid_fkey", "notes_notes", "identite", ["etudid"], ["id"] ) + # GROUPES + op.drop_column("partition", "groups_editable") # INSCRIPTIONS op.drop_constraint( "notes_formsemestre_inscription_etudid_fkey",