diff --git a/app/scodoc/sco_placement.py b/app/scodoc/sco_placement.py index 9f63a6ec..7e5b68b7 100644 --- a/app/scodoc/sco_placement.py +++ b/app/scodoc/sco_placement.py @@ -141,14 +141,15 @@ class PlacementForm(FlaskForm): self.groups.choices = choices -def placement_eval_selectetuds(evaluation_id, REQUEST=None): +def placement_eval_selectetuds(evaluation_id): + """Creation de l'écran de placement""" form = PlacementForm( request.form, data={"evaluation_id": int(evaluation_id), "groups": PlacementForm.TOUS}, ) form.set_evaluation_infos(evaluation_id) if form.validate_on_submit(): - exec_placement(form) + exec_placement(form) # calcul et generation du fichier return flask.redirect(titi()) H = [html_sco_header.sco_header(init_jquery_ui=True)] H.append(sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)) @@ -158,238 +159,227 @@ def placement_eval_selectetuds(evaluation_id, REQUEST=None): return "\n".join(H) + "

" + F -def do_placement_selectetuds(): - """ - Choisi les étudiants et les infos sur la salle pour leur placement. - """ - # M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0] - # description de l'evaluation - H = [ - sco_evaluations.evaluation_describe(evaluation_id=evaluation_id), - "

Placement et émargement des étudiants

", - ] - # - descr = [ - ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), - ( - "placement_method", - { - "input_type": "radio", - "default": "xls", - "allow_null": False, - "allowed_values": ["pdf", "xls"], - "labels": ["fichier pdf", "fichier xls"], - "title": "Format de fichier :", - }, - ), - ("teachers", {"size": 25, "title": "Surveillants :"}), - ("building", {"size": 25, "title": "Batiment :"}), - ("room", {"size": 10, "title": "Salle :"}), - ( - "columns", - { - "input_type": "radio", - "default": "5", - "allow_null": False, - "allowed_values": ["3", "4", "5", "6", "7", "8"], - "labels": [ - "3 colonnes", - "4 colonnes", - "5 colonnes", - "6 colonnes", - "7 colonnes", - "8 colonnes", - ], - "title": "Nombre de colonnes :", - }, - ), - ( - "numbering", - { - "input_type": "radio", - "default": "coordinate", - "allow_null": False, - "allowed_values": ["continuous", "coordinate"], - "labels": ["continue", "coordonnées"], - "title": "Numérotation :", - }, - ), - ] - if no_groups: - submitbuttonattributes = [] - descr += [ - ( - "group_ids", - { - "default": [ - g["group_id"] # pylint: disable=invalid-sequence-index - for g in groups - ], - "input_type": "hidden", - "type": "list", - }, - ) - ] - else: - descr += [ - ( - "group_ids", - { - "input_type": "checkbox", - "title": "Choix groupe(s) d'étudiants :", - "allowed_values": grnams, - "labels": grlabs, - "attributes": ['onchange="gr_change(this);"'], - }, - ) - ] - - if not ("group_ids" in REQUEST.form and REQUEST.form["group_ids"]): - submitbuttonattributes = ['disabled="1"'] - else: - submitbuttonattributes = [] # groupe(s) preselectionnés - H.append( - # JS pour desactiver le bouton OK si aucun groupe selectionné - """ - """ - ) - - tf = TrivialFormulator( - REQUEST.URL0, - REQUEST.form, - descr, - cancelbutton="Annuler", - submitbuttonattributes=submitbuttonattributes, - submitlabel="OK", - formid="gr", - ) - if tf[0] == 0: - # H.append( """
- # Choix du groupe et de la localisation - # """) - H.append("""
""") - return "\n".join(H) + "\n" + tf[1] + "\n
" - elif tf[0] == -1: - return flask.redirect( - "%s/Notes/moduleimpl_status?moduleimpl_id=%s" - % (scu.ScoURL(), E["moduleimpl_id"]) - ) - else: - placement_method = tf[2]["placement_method"] - teachers = tf[2]["teachers"] - building = tf[2]["building"] - room = tf[2]["room"] - group_ids = tf[2]["group_ids"] - columns = tf[2]["columns"] - numbering = tf[2]["numbering"] - if columns in ("3", "4", "5", "6", "7", "8"): - gs = [ - ("group_ids%3Alist=" + six.moves.urllib.parse.quote_plus(x)) - for x in group_ids - ] - query = ( - "evaluation_id=%s&placement_method=%s&teachers=%s&building=%s&room=%s&columns=%s&numbering=%s&" - % ( - evaluation_id, - placement_method, - teachers, - building, - room, - columns, - numbering, - ) - + "&".join(gs) - ) - return flask.redirect(scu.NotesURL() + "/do_placement?" + query) - else: - raise ValueError( - "invalid placement_method (%s)" % tf[2]["placement_method"] - ) +# def do_placement_selectetuds(): +# """ +# Choisi les étudiants et les infos sur la salle pour leur placement. +# """ +# # M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0] +# # description de l'evaluation +# H = [ +# sco_evaluations.evaluation_describe(evaluation_id=evaluation_id), +# "

Placement et émargement des étudiants

", +# ] +# # +# descr = [ +# ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), +# ( +# "placement_method", +# { +# "input_type": "radio", +# "default": "xls", +# "allow_null": False, +# "allowed_values": ["pdf", "xls"], +# "labels": ["fichier pdf", "fichier xls"], +# "title": "Format de fichier :", +# }, +# ), +# ("teachers", {"size": 25, "title": "Surveillants :"}), +# ("building", {"size": 25, "title": "Batiment :"}), +# ("room", {"size": 10, "title": "Salle :"}), +# ( +# "columns", +# { +# "input_type": "radio", +# "default": "5", +# "allow_null": False, +# "allowed_values": ["3", "4", "5", "6", "7", "8"], +# "labels": [ +# "3 colonnes", +# "4 colonnes", +# "5 colonnes", +# "6 colonnes", +# "7 colonnes", +# "8 colonnes", +# ], +# "title": "Nombre de colonnes :", +# }, +# ), +# ( +# "numbering", +# { +# "input_type": "radio", +# "default": "coordinate", +# "allow_null": False, +# "allowed_values": ["continuous", "coordinate"], +# "labels": ["continue", "coordonnées"], +# "title": "Numérotation :", +# }, +# ), +# ] +# if no_groups: +# submitbuttonattributes = [] +# descr += [ +# ( +# "group_ids", +# { +# "default": [ +# g["group_id"] # pylint: disable=invalid-sequence-index +# for g in groups +# ], +# "input_type": "hidden", +# "type": "list", +# }, +# ) +# ] +# else: +# descr += [ +# ( +# "group_ids", +# { +# "input_type": "checkbox", +# "title": "Choix groupe(s) d'étudiants :", +# "allowed_values": grnams, +# "labels": grlabs, +# "attributes": ['onchange="gr_change(this);"'], +# }, +# ) +# ] +# +# if not ("group_ids" in REQUEST.form and REQUEST.form["group_ids"]): +# submitbuttonattributes = ['disabled="1"'] +# else: +# submitbuttonattributes = [] # groupe(s) preselectionnés +# H.append( +# # JS pour desactiver le bouton OK si aucun groupe selectionné +# """ +# """ +# ) +# +# tf = TrivialFormulator( +# REQUEST.URL0, +# REQUEST.form, +# descr, +# cancelbutton="Annuler", +# submitbuttonattributes=submitbuttonattributes, +# submitlabel="OK", +# formid="gr", +# ) +# if tf[0] == 0: +# # H.append( """
+# # Choix du groupe et de la localisation +# # """) +# H.append("""
""") +# return "\n".join(H) + "\n" + tf[1] + "\n
" +# elif tf[0] == -1: +# return flask.redirect( +# "%s/Notes/moduleimpl_status?moduleimpl_id=%s" +# % (scu.ScoURL(), E["moduleimpl_id"]) +# ) +# else: +# placement_method = tf[2]["placement_method"] +# teachers = tf[2]["teachers"] +# building = tf[2]["building"] +# room = tf[2]["room"] +# group_ids = tf[2]["group_ids"] +# columns = tf[2]["columns"] +# numbering = tf[2]["numbering"] +# if columns in ("3", "4", "5", "6", "7", "8"): +# gs = [ +# ("group_ids%3Alist=" + six.moves.urllib.parse.quote_plus(x)) +# for x in group_ids +# ] +# query = ( +# "evaluation_id=%s&placement_method=%s&teachers=%s&building=%s&room=%s&columns=%s&numbering=%s&" +# % ( +# evaluation_id, +# placement_method, +# teachers, +# building, +# room, +# columns, +# numbering, +# ) +# + "&".join(gs) +# ) +# return flask.redirect(scu.NotesURL() + "/do_placement?" + query) +# else: +# raise ValueError( +# "invalid placement_method (%s)" % tf[2]["placement_method"] +# ) def exec_placement(form): - try: - evaluation_id = int(form["evaluation_id"].data) - except: - raise ScoValueError( - "Formulaire incomplet ! Vous avez sans doute attendu trop longtemps, veuillez vous reconnecter. Si le problème persiste, contacter l'administrateur. Merci." - ) - eval_data = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0] - # Check access - # (admin, respformation, and responsable_id) - if not sco_permissions_check.can_edit_notes( - current_user, eval_data["moduleimpl_id"] - ): - return ( - "

Génération du placement impossible pour %s

" % authusername - + """

(vérifiez que le semestre n'est pas verrouillé et que vous - avez l'autorisation d'effectuer cette opération)

-

Continuer

- """ - % E["moduleimpl_id"] - ) - plan = repartition(form, eval_data) + """Calcul et génération du fichier sur la base des données du formulaire""" breakpoint() - sem_preferences = sco_preferences.SemPreferences() - space = sem_preferences.get("feuille_placement_emargement") - maxlines = sem_preferences.get("feuille_placement_positions") + d = { + "evaluation_id": form["evaluation_id"].data, + "etiquetage": form["etiquetage"].data, + "surveillants": form["surveillants"].data, + "batiment": form["batiment"].data, + "salle": form["salle"].data, + "nb_rangs": form["nb_rangs"].data, + "groups": form["groups"].data, + } + d["eval_data"] = sco_evaluations.do_evaluation_list(d)[0] + # Check access (admin, respformation, and responsable_id) + d["current_user"] = current_user + d["moduleimpl_id"] = d["eval_data"]["moduleimpl_id"] + if not sco_permissions_check.can_edit_notes(d["current_user"], d["moduleimpl_id"]): + return ( + """

Génération du placement impossible pour %(current_user)s

+

(vérifiez que le semestre n'est pas verrouillé et que vous +avez l'autorisation d'effectuer cette opération)

+

Continuer

+""" + % d + ) + d["cnx"] = ndb.GetDBConnexion() + d["plan"] = repartition(d) + d["gr_title_filename"] = sco_groups.listgroups_filename(d['groups']) + # gr_title = sco_groups.listgroups_abbrev(d['groups']) + d["moduleimpl_data"] = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=d["moduleimpl_id"]) + d["Mod"] = sco_edit_module.do_module_list(args={"module_id": d["moduleimpl_id"]})[0] + d["sem"] = sco_formsemestre.get_formsemestre(d["moduleimpl_data"]["formsemestre_id"]) + d["evalname"] = "%s-%s" % (d["Mod"]["code"], ndb.DateDMYtoISO(eval_data["jour"])) + if d["eval_data"]["description"]: + d["evaltitre"] = d["eval_data"]["description"] + else: + d["evaltitre"] = "évaluation du %s" % eval_data["jour"] + d["desceval"] = [ + ["%s" % d["sem"]["titreannee"]], + ["Module : %s - %s" % (d["Mod"]["code"], d["Mod"]["abbrev"])], + ["Surveillants : %(surveillant)s" % d], + ["Batiment : %(batiment)s - Salle : %(salle)s" % d], + ["Controle : %s (coef. %g)" % (d["evaltitre"], d["eval_data"]["coefficient"])], + ] # une liste de liste de chaines: description de l'evaluation + if form["file_format"].data == "xls": + production_xls(d) + else: + production_pdf(d) -def repartition(form, eval_data): +def repartition(d): """ Calcule le placement. retourne une liste de couples ((nom, prenom), position) """ - cnx = ndb.GetDBConnexion() - # Infos transmises - evaluation_id = form["evaluation_id"].data - etiquetage = form["etiquetage"].data - teachers = form["surveillants"].data - building = form["batiment"].data - room = form["salle"].data - nb_rangs = form["nb_rangs"].data - group_ids = form["groups"].data - # Construit liste des etudiants - groups = sco_groups.listgroups(group_ids) - gr_title_filename = sco_groups.listgroups_filename(groups) - # gr_title = sco_groups.listgroups_abbrev(groups) - - moduleimpl_data = sco_moduleimpl.do_moduleimpl_list( - moduleimpl_id=eval_data["moduleimpl_id"] - )[0] - Mod = sco_edit_module.do_module_list( - args={"module_id": moduleimpl_data["module_id"]} - )[0] - sem = sco_formsemestre.get_formsemestre(moduleimpl_data["formsemestre_id"]) - evalname = "%s-%s" % (Mod["code"], ndb.DateDMYtoISO(eval_data["jour"])) - if eval_data["description"]: - evaltitre = eval_data["description"] - else: - evaltitre = "évaluation du %s" % eval_data["jour"] - - desceval = [ - ["%s" % sem["titreannee"]], - ["Module : %s - %s" % (Mod["code"], Mod["abbrev"])], - ["Surveillants : %s" % teachers], - ["Batiment : %s - Salle : %s" % (building, room)], - ["Controle : %s (coef. %g)" % (evaltitre, eval_data["coefficient"])] - ] # une liste de liste de chaines: description de l'evaluation - listetud = build_listetud(cnx, groups, evaluation_id, moduleimpl_data) - return affectation_places(listetud, etiquetage, nb_rangs) + groups = sco_groups.listgroups(d["groups"]) + d["listetud"] = build_listetud(d) + return affectation_places(d) def build_listetud(cnx, groups, evaluation_id, moduleimpl_data): @@ -446,99 +436,96 @@ class Distributeur2D: return retour -def affectation_places(listetud, etiquetage, nb_rangs=1): - affectation = [] - if etiquetage == "continu": +def affectation_places(d): + plan = [] + if d["etiquetage"] == "continu": distributeur = DistributeurContinu() else: - distributeur = Distributeur2D(nb_rangs) - for etud in listetud: - affectation.append((etud, distributeur.suivant())) - return affectation + distributeur = Distributeur2D(d["nb_rangs"]) + for etud in d["listetud"]: + plan.append((etud, distributeur.suivant())) + return plan -def production_xls(file_format, eval_dat, plan): +def production_xls(d): + filename = f"placement_{evalname}_{gr_title_filename}{scu.XLSX_SUFFIX}" + xls = _excel_feuille_placement( + d["eval_data"], + d["desceval"], + d["listetud"], + d["nb_rangs"], + d["batiment"], + d["salle"], + d["etiquetage"], + ) + return sco_excel.send_excel_file(REQUEST, xls, filename) -def production(file_format, eval_dat, plan): - if file_format == "xls": - filename = f"placement_{evalname}_{gr_title_filename}{scu.XLSX_SUFFIX}" - xls = _excel_feuille_placement( - eval_data, desceval, listetud, columns, space, maxlines, building, room, numbering - ) - return sco_excel.send_excel_file(REQUEST, xls, filename) +def production_pdf(d): + pdf_title = d["desceval"] + pdf_title += ( + "Date : %(jour)s - Horaire : %(heure_debut)s à %(heure_fin)s" % d["eval_data"] + ) + + filename = "placement_%(evalname)s_%(gr_title_filename)s.pdf" % d + titles = { + "nom": "Nom", + "prenom": "Prenom", + "colonne": "Colonne", + "ligne": "Ligne", + "place": "Place", + } + nbcolumns = int(columns) + if numbering == "coordinate": + columns_ids = ["nom", "prenom", "colonne", "ligne"] else: - nbcolumns = int(columns) + columns_ids = ["nom", "prenom", "place"] - pdf_title = "%s
" % sem["titreannee"] - pdf_title += "Module : %s - %s
" % (Mod["code"], Mod["abbrev"]) - pdf_title += "Surveillants : %s
" % teachers - pdf_title += "Batiment : %s - Salle : %s
" % (building, room) - pdf_title += "Controle : %s (coef. %g)
" % (evaltitre, E["coefficient"]) - pdf_title += "Date : %s - Horaire : %s à %s" % ( - E["jour"], - E["heure_debut"], - E["heure_fin"], - ) - - filename = "placement_%s_%s.pdf" % (evalname, gr_title_filename) - titles = { - "nom": "Nom", - "prenom": "Prenom", - "colonne": "Colonne", - "ligne": "Ligne", - "place": "Place", - } + # etudiants + line = 1 + col = 1 + orderetud = [] + for etudid in listetud: if numbering == "coordinate": - columns_ids = ["nom", "prenom", "colonne", "ligne"] + orderetud.append((etudid[0], etudid[1], col, line)) else: - columns_ids = ["nom", "prenom", "place"] + orderetud.append((etudid[0], etudid[1], col + (line - 1) * nbcolumns)) - # etudiants - line = 1 - col = 1 - orderetud = [] - for etudid in listetud: - if numbering == "coordinate": - orderetud.append((etudid[0], etudid[1], col, line)) - else: - orderetud.append((etudid[0], etudid[1], col + (line - 1) * nbcolumns)) + if col == nbcolumns: + col = 0 + line += 1 + col += 1 - if col == nbcolumns: - col = 0 - line += 1 - col += 1 + rows = [] + orderetud.sort() + for etudid in orderetud: + if numbering == "coordinate": + rows.append( + { + "nom": etudid[0], + "prenom": etudid[1], + "colonne": etudid[2], + "ligne": etudid[3], + } + ) + else: + rows.append({"nom": etudid[0], "prenom": etudid[1], "place": etudid[2]}) - rows = [] - orderetud.sort() - for etudid in orderetud: - if numbering == "coordinate": - rows.append( - { - "nom": etudid[0], - "prenom": etudid[1], - "colonne": etudid[2], - "ligne": etudid[3], - } - ) - else: - rows.append({"nom": etudid[0], "prenom": etudid[1], "place": etudid[2]}) - - tab = GenTable( - titles=titles, - columns_ids=columns_ids, - rows=rows, - filename=filename, - origin="Généré par %s le " % sco_version.SCONAME - + scu.timedate_human_repr() - + "", - pdf_title=pdf_title, - # pdf_shorttitle = '', - preferences=sco_preferences.SemPreferences(M["formsemestre_id"]), - # html_generate_cells=False # la derniere ligne (moyennes) est incomplete - ) - t = tab.make_page(format="pdf", with_html_headers=False, REQUEST=REQUEST) - return t + tab = GenTable( + titles=titles, + columns_ids=columns_ids, + rows=rows, + filename=filename, + origin="Généré par %s le " % sco_version.SCONAME + + scu.timedate_human_repr() + + "", + pdf_title=pdf_title, + # pdf_shorttitle = '', + preferences=sco_preferences.SemPreferences(M["formsemestre_id"]), + # html_generate_cells=False # la derniere ligne (moyennes) est incomplete + ) + t = tab.make_page(format="pdf", with_html_headers=False, REQUEST=REQUEST) + return t def placement_eval_selectetuds_old(evaluation_id, REQUEST=None): @@ -704,16 +691,16 @@ def _titres(ws, description, evaluation, building, room, styles): def _feuille0( - ws0, - description, - evaluation, - styles, - numbering, - listetud, - nbcolumns, - building, - room, - space, + ws0, + description, + evaluation, + styles, + numbering, + listetud, + nbcolumns, + building, + room, + space, ): _titres(ws0, description, evaluation, building, room, styles) # entetes colonnes - feuille0 @@ -801,16 +788,16 @@ def _next_page(ws): def _feuille1( - ws, - description, - evaluation, - styles, - numbering, - maxlines, - nbcolumns, - building, - room, - listetud, + ws, + description, + evaluation, + styles, + numbering, + maxlines, + nbcolumns, + building, + room, + listetud, ): # etudiants - feuille1 # structuration: @@ -867,21 +854,24 @@ def _feuille1( def _excel_feuille_placement( - evaluation, - description, - listetud, - columns, - space, - maxlines, - building, - room, - numbering, + evaluation, + description, + listetud, + columns, + space, + maxlines, + building, + room, + numbering, ): """Genere feuille excel pour placement des etudiants. E: evaluation (dict) lines: liste de tuples (etudid, nom, prenom, etat, groupe, val, explanation) """ + sem_preferences = sco_preferences.SemPreferences() + space = sem_preferences.get("feuille_placement_emargement") + maxlines = sem_preferences.get("feuille_placement_positions") nbcolumns = int(columns) column_width_ratio = 1 / 250 # changement d unités entre pyExcelerator et openpyxl @@ -897,7 +887,7 @@ def _excel_feuille_placement( ws0.set_column_dimension_width("A", 750 * column_width_ratio) for col in range(nbcolumns): ws0.set_column_dimension_width( - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[col + 1: col + 2], width + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[col + 1 : col + 2], width ) SheetName1 = "Positions"