Les partitions sont des découpages de l'ensemble des étudiants. Par exemple, les "groupes de TD" sont une partition. On peut créer autant de partitions que nécessaire.
Les groupes %s de cette partition seront supprimés
""" % (partition["partition_name"], grnames), dest_url="", cancel_url="editPartitionForm?formsemestre_id=%s" % formsemestre_id, parameters={"redirect": redirect, "partition_id": partition_id}, ) log("partition_delete: partition_id=%s" % partition_id) # 1- groups for group in groups: group_delete(context, group, force=force) # 2- partition partitionEditor.delete(cnx, partition_id) # redirect to partition edit page: if redirect: return flask.redirect( "editPartitionForm?formsemestre_id=" + str(formsemestre_id) ) def partition_move(context, partition_id, after=0, REQUEST=None, redirect=1): """Move before/after previous one (decrement/increment numero)""" partition = get_partition(context, partition_id) 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 !") # redirect = int(redirect) after = int(after) # 0: deplace avant, 1 deplace apres if after not in (0, 1): raise ValueError('invalid value for "after"') others = get_partitions_list(context, formsemestre_id) if len(others) > 1: pidx = [p["partition_id"] for p in others].index(partition_id) log("partition_move: after=%s pidx=%s" % (after, pidx)) neigh = None # partition to swap with if after == 0 and pidx > 0: neigh = others[pidx - 1] elif after == 1 and pidx < len(others) - 1: neigh = others[pidx + 1] if neigh: # # swap numero between partition and its neighbor log("moving partition %s" % partition_id) cnx = ndb.GetDBConnexion() partition["numero"], neigh["numero"] = neigh["numero"], partition["numero"] partitionEditor.edit(cnx, partition) partitionEditor.edit(cnx, neigh) # redirect to partition edit page: if redirect: return flask.redirect( "editPartitionForm?formsemestre_id=" + str(formsemestre_id) ) def partition_rename(context, partition_id, REQUEST=None): """Form to rename a partition""" partition = get_partition(context, partition_id) 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 !") H = ["Semestre %s
" % sem["titreannee"], """Les groupes existants seront effacés et remplacés par ceux créés ici. La répartition aléatoire tente d'uniformiser le niveau des groupes (en utilisant la dernière moyenne générale disponible pour chaque étudiant) et de maximiser la mixité de chaque groupe.
""", ] tf = TrivialFormulator( REQUEST.URL0, REQUEST.form, descr, {}, cancelbutton="Annuler", method="GET", submitlabel="Créer et peupler les groupes", name="tf", ) if tf[0] == 0: return "\n".join(H) + "\n" + tf[1] + html_sco_header.sco_footer() elif tf[0] == -1: return flask.redirect(dest_url) else: # form submission log( "groups_auto_repartition( partition_id=%s partition_name=%s" % (partition_id, partition["partition_name"]) ) groupNames = tf[2]["groupNames"] group_names = sorted(set([x.strip() for x in groupNames.split(",")])) # Détruit les groupes existant de cette partition for old_group in get_partition_groups(context, partition): group_delete(context, old_group) # Crée les nouveaux groupes group_ids = [] for group_name in group_names: # try: # checkGroupName(group_name) # except: # H.append('Nom de groupe invalide: %s
'%group_name) # return '\n'.join(H) + tf[1] + html_sco_header.sco_footer( REQUEST) group_ids.append(createGroup(context, partition_id, group_name)) # nt = sco_cache.NotesTableCache.get(formsemestre_id) # > identdict identdict = nt.identdict # build: { civilite : liste etudids trie par niveau croissant } civilites = set([x["civilite"] for x in identdict.values()]) listes = {} for civilite in civilites: listes[civilite] = [ (get_prev_moy(context, x["etudid"], formsemestre_id), x["etudid"]) for x in identdict.values() if x["civilite"] == civilite ] listes[civilite].sort() log("listes[%s] = %s" % (civilite, listes[civilite])) # affect aux groupes: n = len(identdict) igroup = 0 nbgroups = len(group_ids) while n > 0: for civilite in civilites: if len(listes[civilite]): n -= 1 etudid = listes[civilite].pop()[1] group_id = group_ids[igroup] igroup = (igroup + 1) % nbgroups change_etud_group_in_partition( context, etudid, group_id, partition, REQUEST=REQUEST ) log("%s in group %s" % (etudid, group_id)) return flask.redirect(dest_url) def get_prev_moy(context, etudid, formsemestre_id): """Donne la derniere moyenne generale calculee pour cette étudiant, ou 0 si on n'en trouve pas (nouvel inscrit,...). """ from app.scodoc import sco_parcours_dut info = sco_etud.get_etud_info(etudid=etudid, filled=True) if not info: raise ScoValueError("etudiant invalide: etudid=%s" % etudid) etud = info[0] Se = sco_parcours_dut.SituationEtudParcours(context, etud, formsemestre_id) if Se.prev: nt = sco_cache.NotesTableCache.get( Se.prev["formsemestre_id"] ) # > get_etud_moy_gen return nt.get_etud_moy_gen(etudid) else: return 0.0 def create_etapes_partition(context, formsemestre_id, partition_name="apo_etapes"): """Crée une partition "apo_etapes" avec un groupe par étape Apogée. Cette partition n'est crée que si plusieurs étapes différentes existent dans ce semestre. Si la partition existe déjà, ses groupes sont mis à jour (les groupes devenant vides ne sont pas supprimés). """ from app.scodoc import sco_formsemestre_inscriptions log("create_etapes_partition(%s)" % formsemestre_id) ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( context, args={"formsemestre_id": formsemestre_id} ) etapes = {i["etape"] for i in ins if i["etape"]} partitions = get_partitions_list(context, formsemestre_id, with_default=False) partition = None for p in partitions: if p["partition_name"] == partition_name: partition = p break if len(etapes) < 2 and not partition: return # moins de deux étapes, pas de création if partition: pid = partition["partition_id"] else: pid = partition_create( context, formsemestre_id, partition_name=partition_name, redirect=False ) partition = get_partition(context, pid) groups = get_partition_groups(context, partition) groups_by_names = {g["group_name"]: g for g in groups} for etape in etapes: if not (etape in groups_by_names): gid = createGroup(context, pid, etape) g = get_group(context, gid) groups_by_names[etape] = g # Place les etudiants dans les groupes for i in ins: if i["etape"]: change_etud_group_in_partition( context, i["etudid"], groups_by_names[i["etape"]]["group_id"], partition ) def do_evaluation_listeetuds_groups( evaluation_id, groups=None, getallstudents=False, include_dems=False ): """Donne la liste des etudids inscrits a cette evaluation dans les groupes indiqués. Si getallstudents==True, donne tous les etudiants inscrits a cette evaluation. Si include_dems, compte aussi les etudiants démissionnaires (sinon, par défaut, seulement les 'I') """ fromtables = [ "notes_moduleimpl_inscription Im", "notes_formsemestre_inscription Isem", "notes_moduleimpl M", "notes_evaluation E", ] # construit condition sur les groupes if not getallstudents: if not groups: return [] # no groups, so no students rg = ["gm.group_id = '%(group_id)s'" % g for g in groups] rq = "and Isem.etudid = gm.etudid and gd.partition_id = p.partition_id and p.formsemestre_id = Isem.formsemestre_id" r = rq + " AND (" + " or ".join(rg) + " )" fromtables += ["group_membership gm", "group_descr gd", "partition p"] else: r = "" # requete complete req = ( "SELECT distinct Im.etudid FROM " + ", ".join(fromtables) + """ WHERE Isem.etudid = Im.etudid and Im.moduleimpl_id = M.id and Isem.formsemestre_id = M.formsemestre_id and E.moduleimpl_id = M.id and E.id = %(evaluation_id)s """ ) if not include_dems: req += " and Isem.etat='I'" req += r cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor.execute(req, {"evaluation_id": evaluation_id}) res = cursor.fetchall() return [x[0] for x in res] def do_evaluation_listegroupes(context, evaluation_id, include_default=False): """Donne la liste des groupes dans lesquels figurent des etudiants inscrits au module/semestre auquel appartient cette evaluation. Si include_default, inclue aussi le groupe par defaut ('tous') [ group ] """ if include_default: c = "" else: c = " AND p.partition_name is not NULL" cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor.execute( "SELECT DISTINCT gd.group_id FROM group_descr gd, group_membership gm, partition p, notes_moduleimpl m, notes_evaluation e WHERE gm.group_id = gd.group_id and gd.partition_id = p.partition_id and p.formsemestre_id = m.formsemestre_id and m.moduleimpl_id = e.moduleimpl_id and e.evaluation_id = %(evaluation_id)s" + c, {"evaluation_id": evaluation_id}, ) res = cursor.fetchall() group_ids = [x[0] for x in res] return listgroups(context, group_ids) def listgroups(context, group_ids): cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) groups = [] for group_id in group_ids: cursor.execute( """SELECT gd.*, p.* FROM group_descr gd, partition p WHERE p.id = gd.partition_id AND gd.id = %(group_id)s """, {"group_id": group_id}, ) r = cursor.dictfetchall() if r: groups.append(r[0]) return _sortgroups(groups) def _sortgroups(groups): # Tri: place 'all' en tête, puis groupe par partition / nom de groupe R = [g for g in groups if g["partition_name"] is None] o = [g for g in groups if g["partition_name"] != None] o.sort(key=lambda x: (x["numero"], x["group_name"])) return R + o def listgroups_filename(groups): """Build a filename representing groups""" return "gr" + "+".join([g["group_name"] or "tous" for g in groups]) def listgroups_abbrev(groups): """Human readable abbreviation descring groups (eg "A / AB / B3") Ne retient que les partitions avec show_in_lists """ return " / ".join( [g["group_name"] for g in groups if g["group_name"] and g["show_in_lists"]] ) # form_group_choice replaces formChoixGroupe def form_group_choice( context, formsemestre_id, allow_none=True, # offre un choix vide dans chaque partition select_default=True, # Le groupe par defaut est mentionné (hidden). display_sem_title=False, ): """Partie de formulaire pour le choix d'un ou plusieurs groupes. Variable : group_ids """ from app.scodoc import sco_formsemestre sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) if display_sem_title: sem_title = "%s: " % sem["titremois"] else: sem_title = "" # H = ["""Groupe de %(partition_name)s | " % p) H.append(' |