diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py index 88beeb76..b49ab5da 100644 --- a/app/scodoc/gen_tables.py +++ b/app/scodoc/gen_tables.py @@ -185,6 +185,9 @@ class GenTable(object): else: self.preferences = DEFAULT_TABLE_PREFERENCES() + def __repr__(self): + return f"" + def get_nb_cols(self): return len(self.columns_ids) diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index 364ecce6..034a2f41 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -81,6 +81,7 @@ def list_authorized_etuds_by_sem(sem, delai=274): "title": src["titreannee"], "title_target": "formsemestre_status?formsemestre_id=%s" % src["formsemestre_id"], + "filename": "etud_autorises", }, } # ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest. @@ -99,6 +100,7 @@ def list_authorized_etuds_by_sem(sem, delai=274): % sem["formsemestre_id"], "comment": " actuellement inscrits dans ce semestre", "help": "Ces étudiants sont actuellement inscrits dans ce semestre. Si vous les décochez, il seront désinscrits.", + "filename": "etud_inscrits", }, } @@ -506,7 +508,12 @@ def etuds_select_boxes(
""" ] # " - + # Élimine les boites vides: + auth_etuds_by_cat = { + k: auth_etuds_by_cat[k] + for k in auth_etuds_by_cat + if auth_etuds_by_cat[k]["etuds"] + } for src_cat in auth_etuds_by_cat.keys(): infos = auth_etuds_by_cat[src_cat]["infos"] infos["comment"] = infos.get("comment", "") # commentaire dans sous-titre boite @@ -549,10 +556,8 @@ def etuds_select_boxes( if with_checkbox or sel_inscrits: H.append(")") if base_url and etuds: - H.append( - '%s ' - % (base_url, src_cat, scu.ICON_XLS) - ) + url = scu.build_url_query(base_url, export_cat_xls=src_cat) + H.append(f'{scu.ICON_XLS} ') H.append("
") for etud in etuds: if etud.get("inscrit", False): @@ -632,4 +637,4 @@ def etuds_select_box_xls(src_cat): caption="%(title)s. %(help)s" % src_cat["infos"], preferences=sco_preferences.SemPreferences(), ) - return tab.excel() + return tab.excel() # tab.make_page(filename=src_cat["infos"]["filename"]) diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index b788702f..9521b53c 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -231,7 +231,7 @@ def do_formsemestre_recapcomplet( return data elif format == "csv": return scu.send_file(data, filename=filename, mime=scu.CSV_MIMETYPE) - elif format[:3] == "xls" or format[:4] == "xlsx": + elif format.startswith("xls") or format.startswith("xlsx"): return scu.send_file(data, filename=filename, mime=scu.XLSX_MIMETYPE) elif format == "json": js = json.dumps(data, indent=1, cls=scu.ScoDocJSONEncoder) diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index f3d928cb..2ac4ade4 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -32,7 +32,7 @@ import time import pprint from operator import itemgetter -from flask import g, url_for, send_file +from flask import g, url_for from flask_login import current_user import app.scodoc.sco_utils as scu @@ -112,6 +112,7 @@ def formsemestre_synchro_etuds( base_url = url_for( "notes.formsemestre_synchro_etuds", scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre_id, anneeapogee=anneeapogee or None, # si None, le param n'est pas dans l'URL ) @@ -146,11 +147,11 @@ def formsemestre_synchro_etuds( base_url=base_url, read_only=read_only, ) - return send_file( + return scu.send_file( xls, - mimetype=scu.XLS_MIMETYPE, - download_name=scu.sanitize_filename(filename + scu.XLSX_SUFFIX), - as_attachment=True, + mime=scu.XLS_MIMETYPE, + filename=filename, + suffix=scu.XLSX_SUFFIX, ) H = [header] @@ -317,7 +318,8 @@ def build_page( """ % sem, """ - Année Apogée: """ % (sem["formsemestre_id"]), "\n".join(options), """ @@ -430,17 +432,20 @@ def list_synch(sem, anneeapogee=None): return etuds # - r = { - "etuds_ok": { - "etuds": set_to_sorted_list(etuds_ok, is_inscrit=True), + boites = { + "etuds_a_importer": { + "etuds": set_to_sorted_list(a_importer, is_inscrit=True, etud_apo=True), "infos": { - "id": "etuds_ok", - "title": "Etudiants dans Apogée et déjà inscrits", - "help": "Ces etudiants sont inscrits dans le semestre ScoDoc et sont présents dans Apogée: tout est donc correct. Décocher les étudiants que vous souhaitez désinscrire.", + "id": "etuds_a_importer", + "title": "Etudiants dans Apogée à importer", + "help": """Ces étudiants sont inscrits dans cette étape Apogée mais ne sont pas connus par ScoDoc: + cocher les noms à importer et inscrire puis appuyer sur le bouton "Appliquer".""", "title_target": "", "with_checkbox": True, - "etud_key": EKEY_SCO, + "etud_key": EKEY_APO, # clé à stocker dans le formulaire html + "filename": "etuds_a_importer", }, + "nomprenoms": etudsapo_ident, }, "etuds_noninscrits": { "etuds": set_to_sorted_list(etuds_noninscrits, is_inscrit=True), @@ -453,20 +458,9 @@ def list_synch(sem, anneeapogee=None): "title_target": "", "with_checkbox": True, "etud_key": EKEY_SCO, + "filename": "etuds_non_inscrits", }, }, - "etuds_a_importer": { - "etuds": set_to_sorted_list(a_importer, is_inscrit=True, etud_apo=True), - "infos": { - "id": "etuds_a_importer", - "title": "Etudiants dans Apogée à importer", - "help": """Ces étudiants sont inscrits dans cette étape Apogée mais ne sont pas connus par ScoDoc: cocher les noms à importer et inscrire puis appuyer sur le bouton "Appliquer".""", - "title_target": "", - "with_checkbox": True, - "etud_key": EKEY_APO, # clé à stocker dans le formulaire html - }, - "nomprenoms": etudsapo_ident, - }, "etuds_nonapogee": { "etuds": set_to_sorted_list(etuds_nonapogee, is_inscrit=True), "infos": { @@ -478,6 +472,7 @@ def list_synch(sem, anneeapogee=None): "title_target": "", "with_checkbox": True, "etud_key": EKEY_SCO, + "filename": "etuds_non_apogee", }, }, "inscrits_without_key": { @@ -489,11 +484,25 @@ def list_synch(sem, anneeapogee=None): "title_target": "", "with_checkbox": True, "checkbox_name": "inscrits_without_key", + "filename": "inscrits_without_key", + }, + }, + "etuds_ok": { + "etuds": set_to_sorted_list(etuds_ok, is_inscrit=True), + "infos": { + "id": "etuds_ok", + "title": "Etudiants dans Apogée et déjà inscrits", + "help": """Ces etudiants sont inscrits dans le semestre ScoDoc et sont présents dans Apogée: + tout est donc correct. Décocher les étudiants que vous souhaitez désinscrire.""", + "title_target": "", + "with_checkbox": True, + "etud_key": EKEY_SCO, + "filename": "etuds_inscrits_ok_apo", }, }, } return ( - r, + boites, a_importer, etuds_noninscrits, inscrits_set, diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 63e63878..ec4e2dd5 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -39,15 +39,11 @@ import os import pydot import re import requests -import six -import six.moves._thread -import sys +import _thread import time -import traceback -import types import unicodedata import urllib -from xml.etree import ElementTree +from urllib.parse import urlparse, parse_qsl, urlunparse, urlencode from flask import g, current_app @@ -218,7 +214,7 @@ def group_by_key(d, key): # ----- Global lock for critical sections (except notes_tables caches) -GSL = six.moves._thread.allocate_lock() # Global ScoDoc Lock +GSL = _thread.allocate_lock() # Global ScoDoc Lock SCODOC_DIR = Config.SCODOC_DIR @@ -308,6 +304,7 @@ JSON_SUFFIX = ".json" PDF_MIMETYPE = "application/pdf" PDF_SUFFIX = ".pdf" XLS_MIMETYPE = "application/vnd.ms-excel" +XLS_SUFFIX = ".xls" XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" XLSX_SUFFIX = ".xlsx" XML_MIMETYPE = "text/xml" @@ -411,6 +408,18 @@ def unescape_html(s): return s +def build_url_query(url: str, **params) -> str: + """Add parameters to existing url, as a query string""" + url_parse = urlparse(url) + query = url_parse.query + url_dict = dict(parse_qsl(query)) + url_dict.update(params) + url_new_query = urlencode(url_dict) + url_parse = url_parse._replace(query=url_new_query) + new_url = urlunparse(url_parse) + return new_url + + # test if obj is iterable (but not a string) isiterable = lambda obj: getattr(obj, "__iter__", False)