Merge pull request 'scodoc9_placement_PR' (#126) from jmplace/ScoDoc-Lille:scodoc9_placement_PR into master

Reviewed-on: https://scodoc.org/git/viennet/ScoDoc/pulls/126
This commit is contained in:
Emmanuel Viennet 2021-09-18 13:43:11 +02:00
commit 11ba73d264
14 changed files with 1748 additions and 1808 deletions

1
.gitignore vendored
View File

@ -170,3 +170,4 @@ Thumbs.db
*.code-workspace *.code-workspace
copy

View File

@ -482,9 +482,9 @@ class GenTable(object):
ses.append_blank_row() # empty line ses.append_blank_row() # empty line
ses.append_single_cell_row(self.origin, style_base) ses.append_single_cell_row(self.origin, style_base)
if wb is None: if wb is None:
return ses.generate_standalone() return ses.generate()
else: else:
ses.generate_embeded() ses.generate()
def text(self): def text(self):
"raw text representation of the table" "raw text representation of the table"

View File

@ -269,9 +269,14 @@ def etudarchive_generate_excel_sample(group_id=None, REQUEST=None):
], ],
extra_cols=["fichier_a_charger"], extra_cols=["fichier_a_charger"],
) )
return sco_excel.send_excel_file( return scu.send_file(
REQUEST, data, "ImportFichiersEtudiants" + scu.XLSX_SUFFIX data,
"ImportFichiersEtudiants",
scu.XLSX_SUFFIX,
scu.XLSX_MIMETYPE,
attached=True,
) )
# return sco_excel.send_excel_file(REQUEST, data, "ImportFichiersEtudiants" + scu.XLSX_SUFFIX)
def etudarchive_import_files_form(group_id, REQUEST=None): def etudarchive_import_files_form(group_id, REQUEST=None):

View File

@ -35,11 +35,11 @@ from enum import Enum
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import openpyxl.utils.datetime import openpyxl.utils.datetime
from openpyxl.styles.numbers import FORMAT_NUMBER_00, FORMAT_GENERAL
from openpyxl.comments import Comment
from openpyxl import Workbook, load_workbook from openpyxl import Workbook, load_workbook
from openpyxl.cell import WriteOnlyCell from openpyxl.cell import WriteOnlyCell
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
from openpyxl.styles.numbers import FORMAT_NUMBER_00, FORMAT_GENERAL
from openpyxl.comments import Comment
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import notesdb from app.scodoc import notesdb
@ -59,24 +59,9 @@ class COLORS(Enum):
LIGHT_YELLOW = "FFFFFF99" LIGHT_YELLOW = "FFFFFF99"
def send_excel_file(request, data, filename, mime=scu.XLSX_MIMETYPE):
"""publication fichier.
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
"""
filename = (
scu.unescape_html(scu.suppress_accents(filename))
.replace("&", "")
.replace(" ", "_")
)
request.RESPONSE.setHeader("content-type", mime)
request.RESPONSE.setHeader(
"content-disposition", 'attachment; filename="%s"' % filename
)
return data
# Un style est enregistré comme un dictionnaire qui précise la valeur d'un attributdans la liste suivante: # Un style est enregistré comme un dictionnaire qui précise la valeur d'un attributdans la liste suivante:
# font, border, number_format, fill, .. (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles) # font, border, number_format, fill,...
# (cf https://openpyxl.readthedocs.io/en/stable/styles.html#working-with-styles)
def xldate_as_datetime(xldate, datemode=0): def xldate_as_datetime(xldate, datemode=0):
@ -86,6 +71,12 @@ def xldate_as_datetime(xldate, datemode=0):
return openpyxl.utils.datetime.from_ISO8601(xldate) return openpyxl.utils.datetime.from_ISO8601(xldate)
def adjust_sheetname(sheet_name):
# Le nom de la feuille ne peut faire plus de 31 caractères.
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
return sheet_name[:31]
class ScoExcelBook: class ScoExcelBook:
"""Permet la génération d'un classeur xlsx composé de plusieurs feuilles. """Permet la génération d'un classeur xlsx composé de plusieurs feuilles.
usage: usage:
@ -98,13 +89,16 @@ class ScoExcelBook:
def __init__(self): def __init__(self):
self.sheets = [] # list of sheets self.sheets = [] # list of sheets
self.wb = Workbook(write_only=True)
def create_sheet(self, sheet_name="feuille", default_style=None): def create_sheet(self, sheet_name="feuille", default_style=None):
"""Crée une nouvelle feuille dans ce classeur """Crée une nouvelle feuille dans ce classeur
sheet_name -- le nom de la feuille sheet_name -- le nom de la feuille
default_style -- le style par défaut default_style -- le style par défaut
""" """
sheet = ScoExcelSheet(sheet_name, default_style) sheet_name = adjust_sheetname(sheet_name)
ws = self.wb.create_sheet(sheet_name)
sheet = ScoExcelSheet(sheet_name, default_style, ws)
self.sheets.append(sheet) self.sheets.append(sheet)
return sheet return sheet
@ -112,12 +106,12 @@ class ScoExcelBook:
"""génération d'un stream binaire représentant la totalité du classeur. """génération d'un stream binaire représentant la totalité du classeur.
retourne le flux retourne le flux
""" """
wb = Workbook(write_only=True)
for sheet in self.sheets: for sheet in self.sheets:
sheet.generate(self) sheet.prepare()
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream) # construction d'un flux
# (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
with NamedTemporaryFile() as tmp: with NamedTemporaryFile() as tmp:
wb.save(tmp.name) self.wb.save(tmp.name)
tmp.seek(0) tmp.seek(0)
return tmp.read() return tmp.read()
@ -125,6 +119,7 @@ class ScoExcelBook:
def excel_make_style( def excel_make_style(
bold=False, bold=False,
italic=False, italic=False,
outline=False,
color: COLORS = COLORS.BLACK, color: COLORS = COLORS.BLACK,
bgcolor: COLORS = None, bgcolor: COLORS = None,
halign=None, halign=None,
@ -145,7 +140,14 @@ def excel_make_style(
size -- taille de police size -- taille de police
""" """
style = {} style = {}
font = Font(name=font_name, bold=bold, italic=italic, color=color.value, size=size) font = Font(
name=font_name,
bold=bold,
italic=italic,
outline=outline,
color=color.value,
size=size,
)
style["font"] = font style["font"] = font
if bgcolor: if bgcolor:
style["fill"] = PatternFill(fill_type="solid", fgColor=bgcolor.value) style["fill"] = PatternFill(fill_type="solid", fgColor=bgcolor.value)
@ -182,41 +184,93 @@ class ScoExcelSheet:
""" """
def __init__(self, sheet_name="feuille", default_style=None, wb=None): def __init__(self, sheet_name="feuille", default_style=None, wb=None):
"""Création de la feuille. """Création de la feuille. sheet_name
sheet_name -- le nom de la feuille -- le nom de la feuille default_style
default_style -- le style par défaut des cellules -- le style par défaut des cellules ws
wb -- le WorkBook dans laquelle se trouve la feuille. Si wb est None (cas d'un classeur mono-feuille), -- None si la feuille est autonome (dans ce cas ell crée son propre wb), sinon c'est la worksheet
un workbook est crée et associé à cette feuille. créée par le workbook propriétaire un workbook est crée et associé à cette feuille.
""" """
# Le nom de la feuille ne peut faire plus de 31 caractères. # Le nom de la feuille ne peut faire plus de 31 caractères.
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?) # si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
self.sheet_name = sheet_name[ self.sheet_name = adjust_sheetname(sheet_name)
:31
] # if len(sheet_name) > 31: sheet_name = 'Feuille' ?
self.rows = [] # list of list of cells
# self.cells_styles_lico = {} # { (li,co) : style }
# self.cells_styles_li = {} # { li : style }
# self.cells_styles_co = {} # { co : style }
if default_style is None: if default_style is None:
default_style = excel_make_style() default_style = excel_make_style()
self.default_style = default_style self.default_style = default_style
self.wb = wb or Workbook(write_only=True) # Création de workbook si nécessaire if wb is None:
self.ws = self.wb.create_sheet(title=self.sheet_name) self.wb = Workbook()
self.ws = self.wb.active
self.ws.title = self.sheet_name
else:
self.wb = None
self.ws = wb
# internal data
self.rows = [] # list of list of cells
self.column_dimensions = {} self.column_dimensions = {}
self.row_dimensions = {}
def set_column_dimension_width(self, cle, value): def excel_make_composite_style(
"""Détermine la largeur d'une colonne. self,
cle -- identifie la colonne ("A"n "B", ...) alignment=None,
value -- la dimension (unité : 7 pixels comme affiché dans Excel) border=None,
fill=None,
number_format=None,
font=None,
):
style = {}
if font is not None:
style["font"] = font
if alignment is not None:
style["alignment"] = alignment
if border is not None:
style["border"] = border
if fill is not None:
style["fill"] = fill
if number_format is None:
style["number_format"] = FORMAT_GENERAL
else:
style["number_format"] = number_format
return style
@staticmethod
def i2col(idx):
if idx < 26: # one letter key
return chr(idx + 65)
else: # two letters AA..ZZ
first = (idx // 26) + 66
second = (idx % 26) + 65
return "" + chr(first) + chr(second)
def set_column_dimension_width(self, cle=None, value=21):
"""Détermine la largeur d'une colonne. cle -- identifie la colonne ("A" "B", ... ou 0, 1, 2, ...) si None,
value donne la liste des largeurs de colonnes depuis A, B, C, ... value -- la dimension (unité : 7 pixels
comme affiché dans Excel)
""" """
self.ws.column_dimensions[cle].width = value if cle is None:
for i, val in enumerate(value):
self.ws.column_dimensions[self.i2col(i)].width = val
# No keys: value is a list of widths
elif type(cle) == str: # accepts set_column_with("D", ...)
self.ws.column_dimensions[cle].width = value
else:
self.ws.column_dimensions[self.i2col(cle)].width = value
def set_column_dimension_hidden(self, cle, value): def set_row_dimension_height(self, cle=None, value=21):
"""Masque ou affiche une colonne. """Détermine la hauteur d'une ligne. cle -- identifie la ligne (1, 2, ...) si None,
cle -- identifie la colonne ("A"n "B", ...) value donne la liste des hauteurs de colonnes depuis 1, 2, 3, ... value -- la dimension
"""
if cle is None:
for i, val in enumerate(value, start=1):
self.ws.row_dimensions[i].height = val
# No keys: value is a list of widths
else:
self.ws.row_dimensions[cle].height = value
def set_row_dimension_hidden(self, cle, value):
"""Masque ou affiche une ligne.
cle -- identifie la colonne (1...)
value -- boolean (vrai = colonne cachée) value -- boolean (vrai = colonne cachée)
""" """
self.ws.column_dimensions[cle].hidden = value self.ws.row_dimensions[cle].hidden = value
def make_cell(self, value: any = None, style=None, comment=None): def make_cell(self, value: any = None, style=None, comment=None):
"""Construit une cellule. """Construit une cellule.
@ -232,8 +286,12 @@ class ScoExcelSheet:
style = self.default_style style = self.default_style
if "font" in style: if "font" in style:
cell.font = style["font"] cell.font = style["font"]
if "alignment" in style:
cell.alignment = style["alignment"]
if "border" in style: if "border" in style:
cell.border = style["border"] cell.border = style["border"]
if "fill" in style:
cell.fill = style["fill"]
if "number_format" in style: if "number_format" in style:
cell.number_format = style["number_format"] cell.number_format = style["number_format"]
if "fill" in style: if "fill" in style:
@ -272,73 +330,31 @@ class ScoExcelSheet:
"""ajoute une ligne déjà construite à la feuille.""" """ajoute une ligne déjà construite à la feuille."""
self.rows.append(row) self.rows.append(row)
# def set_style(self, style=None, li=None, co=None): def prepare(self):
# if li is not None and co is not None:
# self.cells_styles_lico[(li, co)] = style
# elif li is None:
# self.cells_styles_li[li] = style
# elif co is None:
# self.cells_styles_co[co] = style
#
# def get_cell_style(self, li, co):
# """Get style for specified cell"""
# return (
# self.cells_styles_lico.get((li, co), None)
# or self.cells_styles_li.get(li, None)
# or self.cells_styles_co.get(co, None)
# or self.default_style
# )
def _generate_ws(self):
"""génére un flux décrivant la feuille. """génére un flux décrivant la feuille.
Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille) Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille)
ou pour la génération d'un classeur multi-feuilles ou pour la génération d'un classeur multi-feuilles
""" """
for col in self.column_dimensions.keys(): for row in self.column_dimensions.keys():
self.ws.column_dimensions[col] = self.column_dimensions[col] self.ws.column_dimensions[row] = self.column_dimensions[row]
for row in self.row_dimensions.keys():
self.ws.row_dimensions[row] = self.row_dimensions[row]
for row in self.rows: for row in self.rows:
self.ws.append(row) self.ws.append(row)
def generate_standalone(self): def generate(self):
"""génération d'un classeur mono-feuille""" """génération d'un classeur mono-feuille"""
self._generate_ws() # this method makes sense only if it is a standalone worksheet (else call workbook.generate()
if self.wb is None: # embeded sheet
raise ScoValueError("can't generate a single sheet from a ScoWorkbook")
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream) # construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
self.prepare()
with NamedTemporaryFile() as tmp: with NamedTemporaryFile() as tmp:
self.wb.save(tmp.name) self.wb.save(tmp.name)
tmp.seek(0) tmp.seek(0)
return tmp.read() return tmp.read()
def generate_embeded(self):
"""generation d'une feuille include dans un classeur multi-feuilles"""
self._generate_ws()
def gen_workbook(self, wb=None):
"""TODO: à remplacer"""
"""Generates and returns a workbook from stored data.
If wb, add a sheet (tab) to the existing workbook (in this case, returns None).
"""
if wb is None:
wb = Workbook() # Création du fichier
sauvegarde = True
else:
sauvegarde = False
ws0 = wb.add_sheet(self.sheet_name)
li = 0
for row in self.rows:
co = 0
for c in row:
# safety net: allow only str, int and float
# #py3 #sco8 A revoir lors de la ré-écriture de ce module
# XXX if type(c) not in (IntType, FloatType):
# c = str(c).decode(scu.SCO_ENCODING)
ws0.write(li, co, c, self.get_cell_style(li, co))
co += 1
li += 1
if sauvegarde:
return wb.savetostr()
else:
return None
def excel_simple_table( def excel_simple_table(
titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None
@ -377,7 +393,7 @@ def excel_simple_table(
cell_style = text_style cell_style = text_style
cells.append(ws.make_cell(it, cell_style)) cells.append(ws.make_cell(it, cell_style))
ws.append_row(cells) ws.append_row(cells)
return ws.generate_standalone() return ws.generate()
def excel_feuille_saisie(e, titreannee, description, lines): def excel_feuille_saisie(e, titreannee, description, lines):
@ -538,7 +554,7 @@ def excel_feuille_saisie(e, titreannee, description, lines):
ws.make_cell("cellule vide -> note non modifiée", style_expl), ws.make_cell("cellule vide -> note non modifiée", style_expl),
] ]
) )
return ws.generate_standalone() return ws.generate()
def excel_bytes_to_list(bytes_content): def excel_bytes_to_list(bytes_content):
@ -758,4 +774,4 @@ def excel_feuille_listeappel(
cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i) cell_2 = ws.make_cell(("Liste éditée le " + dt), style1i)
ws.append_row([None, cell_2]) ws.append_row([None, cell_2])
return ws.generate_standalone() return ws.generate()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -324,5 +324,12 @@ def feuille_preparation_jury(formsemestre_id, REQUEST):
REQUEST.AUTHENTICATED_USER, REQUEST.AUTHENTICATED_USER,
) )
) )
xls = ws.generate_standalone() xls = ws.generate()
return sco_excel.send_excel_file(REQUEST, xls, f"PrepaJury{sn}{scu.XLSX_SUFFIX}") return scu.send_file(
xls,
f"PrepaJury{sn}{scu.XLSX_SUFFIX}",
scu.XLSX_SUFFIX,
scu.XLSX_MIMETYPE,
attached=True,
)
# return sco_excel.send_excel_file(REQUEST, xls, f"PrepaJury{sn}{scu.XLSX_SUFFIX}")

View File

@ -829,7 +829,10 @@ def feuille_saisie_notes(evaluation_id, group_ids=[], REQUEST=None):
filename = "notes_%s_%s.xlsx" % (evalname, gr_title_filename) filename = "notes_%s_%s.xlsx" % (evalname, gr_title_filename)
xls = sco_excel.excel_feuille_saisie(E, sem["titreannee"], description, lines=L) xls = sco_excel.excel_feuille_saisie(E, sem["titreannee"], description, lines=L)
return sco_excel.send_excel_file(REQUEST, xls, filename) return scu.send_file(
xls, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
)
# return sco_excel.send_excel_file(REQUEST, xls, filename)
def has_existing_decision(M, E, etudid): def has_existing_decision(M, E, etudid):

View File

@ -486,7 +486,10 @@ def photos_generate_excel_sample(group_ids=[], REQUEST=None):
], ],
extra_cols=["fichier_photo"], extra_cols=["fichier_photo"],
) )
return sco_excel.send_excel_file(REQUEST, data, "ImportPhotos" + scu.XLSX_SUFFIX) return scu.send_file(
data, "ImportPhotos", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
)
# return sco_excel.send_excel_file(REQUEST, data, "ImportPhotos" + scu.XLSX_SUFFIX)
def photos_import_files_form(group_ids=[], REQUEST=None): def photos_import_files_form(group_ids=[], REQUEST=None):

View File

@ -1092,13 +1092,11 @@ h2.formsemestre, .gtrcontent h2 {
#formnotes td.tf-fieldlabel { #formnotes td.tf-fieldlabel {
border-bottom: 1px dotted #fdcaca; border-bottom: 1px dotted #fdcaca;
} }
.wtf-field li {
/* Formulaires ScoDoc 9 */ display: inline;
form.sco-form {
margin-top: 1em;
} }
div.sco-submit { .wtf-field .errors {
margin-top: 2em; color: red ; font-weight: bold;
} }
/* /*
.formsemestre_menubar { .formsemestre_menubar {

View File

@ -0,0 +1,77 @@
{% import 'bootstrap/wtf.html' as wtf %}
{% macro render_field(field) %}
<tr>
<td class="wtf-field">{{ field.label }}</td>
<td class="wtf-field">{{ field()|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</td>
</tr>
{% endmacro %}
<div class="saisienote_etape1 form_placement">
<form method=post>
{{ form.evaluation_id }}
{{ form.csrf_token }}
<table class="tf">
<tbody>
{{ render_field(form.surveillants) }}
{{ render_field(form.batiment) }}
{{ render_field(form.salle) }}
{{ render_field(form.nb_rangs) }}
{{ render_field(form.etiquetage) }}
{% if form.has_groups %}
{{ render_field(form.groups) }}
<!-- Tentative de recréer le choix des groupes sous forme de cases à cocher // demande à créer des champs wtf dynamiquement
{% for partition in form.groups_tree %}
<tr>
{% if partition == 'Tous' %}
<td rowspan="{{ form.nb_groups }}">Groupes</td>
{% endif %}
<td>{{ partition }}</td>
<td>
{% for groupe in form.groups_tree[partition] %}
{{ groupe }}{{ form[form.groups_tree[partition][groupe]] }}
{% endfor %}
</td>
</tr>
{% endfor %}
-->
{% endif %}
{{ render_field(form.file_format) }}
</tbody>
</table>
<p>
<input id="gr_submit" type=submit value="Ok">
<input id="gr_cancel" type=submit value="Annuler">
</script>
</form>
<h3>Explications</h3>
<ul>
<li>préciser les surveillants et la localisation (bâtiment et salle) et indiquer le nombre de colonnes;</li>
<li>deux types de placements sont possibles :
<ul>
<li>continue suppose que les tables ont toutes un numéro unique;</li>
<li>coordonnées localise chaque table via un numéro de colonne et un numéro de ligne (ou rangée).</li>
</ul></li>
<li>il est possible de choisir un ou plusieurs groupes (shift/ctrl click) ou de choisir 'tous'.</li>
<li>Choisir le format du fichier résultat :
<ul>
<li>le format pdf consiste en un tableau précisant pour chaque étudiant la localisation de sa table;</li>
<li>le format xls produit un classeur avec deux onglets:
<ul>
<li>le premier onglet donne une vue de la salle avec la localisation des étudiants et
peut servir de feuille d'émargement;</li>
<li>le second onglet est un tableau similaire à celui du fichier pdf;</li>
</ul></li>
</ul> </li>
</ul>
</div>

View File

@ -1645,8 +1645,8 @@ sco_publish(
"/placement_eval_selectetuds", "/placement_eval_selectetuds",
sco_placement.placement_eval_selectetuds, sco_placement.placement_eval_selectetuds,
Permission.ScoEnsView, Permission.ScoEnsView,
methods=["GET", "POST"],
) )
sco_publish("/do_placement", sco_placement.do_placement, Permission.ScoEnsView)
# --- Saisie des notes # --- Saisie des notes
sco_publish( sco_publish(

View File

@ -1937,7 +1937,10 @@ def import_generate_excel_sample(REQUEST, with_codesemestre="1"):
data = sco_import_etuds.sco_import_generate_excel_sample( data = sco_import_etuds.sco_import_generate_excel_sample(
format, with_codesemestre, exclude_cols=["photo_filename"] format, with_codesemestre, exclude_cols=["photo_filename"]
) )
return sco_excel.send_excel_file(REQUEST, data, "ImportEtudiants" + scu.XLSX_SUFFIX) return scu.send_file(
data, "ImportEtudiants", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
)
# return sco_excel.send_excel_file(REQUEST, data, "ImportEtudiants" + scu.XLSX_SUFFIX)
# --- Données admission # --- Données admission
@ -1955,9 +1958,10 @@ def import_generate_admission_sample(REQUEST, formsemestre_id):
exclude_cols=["nationalite", "foto", "photo_filename"], exclude_cols=["nationalite", "foto", "photo_filename"],
group_ids=[group["group_id"]], group_ids=[group["group_id"]],
) )
return sco_excel.send_excel_file( return scu.send_file(
REQUEST, data, "AdmissionEtudiants" + scu.XLSX_SUFFIX data, "AdmissionEtudiants", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
) )
# return sco_excel.send_excel_file(REQUEST, data, "AdmissionEtudiants" + scu.XLSX_SUFFIX)
# --- Données admission depuis fichier excel (version nov 2016) # --- Données admission depuis fichier excel (version nov 2016)

View File

@ -65,8 +65,6 @@ from app import log
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc.sco_permissions_check import can_handle_passwd from app.scodoc.sco_permissions_check import can_handle_passwd
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
from app.scodoc.sco_excel import send_excel_file
from app.scodoc.sco_import_users import generate_excel_sample
from app.views import users_bp as bp from app.views import users_bp as bp
@ -490,9 +488,10 @@ def create_user_form(REQUEST, user_name=None, edit=0, all_roles=1):
def import_users_generate_excel_sample(REQUEST): def import_users_generate_excel_sample(REQUEST):
"une feuille excel pour importation utilisateurs" "une feuille excel pour importation utilisateurs"
data = sco_import_users.generate_excel_sample() data = sco_import_users.generate_excel_sample()
return sco_excel.send_excel_file( return scu.send_file(
REQUEST, data, "ImportUtilisateurs" + scu.XLSX_SUFFIX data, "ImportUtilisateurs", scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE, attached=True
) )
# return sco_excel.send_excel_file(REQUEST, data, "ImportUtilisateurs" + scu.XLSX_SUFFIX)
@bp.route("/import_users_form", methods=["GET", "POST"]) @bp.route("/import_users_form", methods=["GET", "POST"])