2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-01-02 13:16:27 +01:00
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
""" ScoDoc : gestion des archives des PV et bulletins, et des dossiers etudiants (admission)
2022-12-27 00:13:34 +01:00
Archives are plain files , stored in
2021-09-17 10:02:27 +02:00
< SCODOC_VAR_DIR > / archives / < dept_id >
( where < SCODOC_VAR_DIR > is usually / opt / scodoc - data , and < dept_id > a departement id ( int ) )
2020-09-26 16:19:37 +02:00
Les PV de jurys et documents associés sont stockées dans un sous - repertoire de la forme
< archivedir > / < dept > / < formsemestre_id > / < YYYY - MM - DD - HH - MM - SS >
2021-09-16 21:42:45 +02:00
( formsemestre_id est ici FormSemestre . id )
2020-09-26 16:19:37 +02:00
Les documents liés à l ' étudiant sont dans
2021-09-17 10:02:27 +02:00
< archivedir > / docetuds / < dept_id > / < etudid > / < YYYY - MM - DD - HH - MM - SS >
2021-09-16 21:42:45 +02:00
( etudid est ici Identite . id )
2020-09-26 16:19:37 +02:00
Les maquettes Apogée pour l ' export des notes sont dans
2021-09-17 10:02:27 +02:00
< archivedir > / apo_csv / < dept_id > / < annee_scolaire > - < sem_id > / < YYYY - MM - DD - HH - MM - SS > / < code_etape > . csv
2022-12-27 00:13:34 +01:00
2020-09-26 16:19:37 +02:00
Un répertoire d ' archive contient des fichiers quelconques, et un fichier texte nommé _description.txt
qui est une description ( humaine , format libre ) de l ' archive.
"""
2023-02-12 01:13:43 +01:00
from typing import Union
2021-02-05 18:21:34 +01:00
import datetime
2021-09-16 00:15:10 +02:00
import glob
2022-04-06 18:51:01 +02:00
import json
2021-09-16 00:15:10 +02:00
import mimetypes
import os
2021-02-04 20:02:44 +01:00
import re
2020-09-26 16:19:37 +02:00
import shutil
2021-09-16 00:15:10 +02:00
import time
2023-02-12 01:13:43 +01:00
import chardet
2020-09-26 16:19:37 +02:00
2021-08-01 10:16:16 +02:00
import flask
2023-02-12 01:13:43 +01:00
from flask import flash , g , request , url_for
2021-09-18 13:42:19 +02:00
from flask_login import current_user
2021-08-01 10:16:16 +02:00
2021-06-19 23:21:37 +02:00
import app . scodoc . sco_utils as scu
2021-05-29 18:22:51 +02:00
from config import Config
2021-08-29 19:57:32 +02:00
from app import log
2022-07-17 15:15:24 +02:00
from app . but import jury_but_pv
2022-04-06 18:51:01 +02:00
from app . comp import res_sem
from app . comp . res_compat import NotesTableCompat
2023-02-02 22:20:25 +01:00
from app . models import FormSemestre
2021-06-19 23:21:37 +02:00
from app . scodoc . TrivialFormulator import TrivialFormulator
2023-02-12 01:13:43 +01:00
from app . scodoc . sco_exceptions import AccessDenied , ScoPermissionDenied
2021-06-19 23:21:37 +02:00
from app . scodoc import html_sco_header
from app . scodoc import sco_bulletins_pdf
from app . scodoc import sco_formsemestre
from app . scodoc import sco_groups
from app . scodoc import sco_groups_view
from app . scodoc import sco_permissions_check
from app . scodoc import sco_pvjury
from app . scodoc import sco_pvpdf
2022-03-04 18:55:45 +01:00
from app . scodoc . sco_exceptions import ScoValueError
2020-09-26 16:19:37 +02:00
2021-07-09 23:31:16 +02:00
class BaseArchiver ( object ) :
2020-09-26 16:19:37 +02:00
def __init__ ( self , archive_type = " " ) :
2021-08-29 19:57:32 +02:00
self . archive_type = archive_type
self . initialized = False
self . root = None
2023-02-02 22:20:25 +01:00
self . dept_id = None
def set_dept_id ( self , dept_id : int ) :
" set dept "
self . dept_id = dept_id
2021-08-29 19:57:32 +02:00
def initialize ( self ) :
if self . initialized :
return
2021-07-25 09:51:09 +02:00
dirs = [ Config . SCODOC_VAR_DIR , " archives " ]
2021-08-29 19:57:32 +02:00
if self . archive_type :
dirs . append ( self . archive_type )
2020-09-26 16:19:37 +02:00
self . root = os . path . join ( * dirs )
log ( " initialized archiver, path= " + self . root )
path = dirs [ 0 ]
2022-04-06 18:51:01 +02:00
for directory in dirs [ 1 : ] :
path = os . path . join ( path , directory )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2020-09-26 16:19:37 +02:00
if not os . path . isdir ( path ) :
2022-12-27 00:13:34 +01:00
log ( f " creating directory { path } " )
2020-09-26 16:19:37 +02:00
os . mkdir ( path )
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2021-08-29 19:57:32 +02:00
self . initialized = True
2023-02-02 22:20:25 +01:00
if self . dept_id is None :
self . dept_id = getattr ( g , " scodoc_dept_id " )
2020-09-26 16:19:37 +02:00
2022-12-27 00:13:34 +01:00
def get_obj_dir ( self , oid : int ) :
2020-09-26 16:19:37 +02:00
"""
: return : path to directory of archives for this object ( eg formsemestre_id or etudid ) .
If directory does not yet exist , create it .
"""
2021-08-29 19:57:32 +02:00
self . initialize ( )
2023-02-02 22:20:25 +01:00
dept_dir = os . path . join ( self . root , str ( self . dept_id ) )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2020-09-26 16:19:37 +02:00
if not os . path . isdir ( dept_dir ) :
2022-04-06 18:51:01 +02:00
log ( f " creating directory { dept_dir } " )
2020-09-26 16:19:37 +02:00
os . mkdir ( dept_dir )
2021-08-10 17:12:10 +02:00
obj_dir = os . path . join ( dept_dir , str ( oid ) )
2020-09-26 16:19:37 +02:00
if not os . path . isdir ( obj_dir ) :
2022-04-06 18:51:01 +02:00
log ( f " creating directory { obj_dir } " )
2020-09-26 16:19:37 +02:00
os . mkdir ( obj_dir )
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2020-09-26 16:19:37 +02:00
return obj_dir
2021-08-21 00:24:51 +02:00
def list_oids ( self ) :
2020-09-26 16:19:37 +02:00
"""
: return : list of archive oids
"""
2021-08-29 19:57:32 +02:00
self . initialize ( )
2023-02-02 22:20:25 +01:00
base = os . path . join ( self . root , str ( self . dept_id ) ) + os . path . sep
2020-09-26 16:19:37 +02:00
dirs = glob . glob ( base + " * " )
return [ os . path . split ( x ) [ 1 ] for x in dirs ]
2022-12-27 00:13:34 +01:00
def list_obj_archives ( self , oid : int ) :
2020-09-26 16:19:37 +02:00
""" Returns
: return : list of archive identifiers for this object ( paths to non empty dirs )
"""
2021-08-29 19:57:32 +02:00
self . initialize ( )
2021-08-20 10:51:42 +02:00
base = self . get_obj_dir ( oid ) + os . path . sep
2020-09-26 16:19:37 +02:00
dirs = glob . glob (
base
+ " [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9] "
)
2021-07-12 15:13:10 +02:00
dirs = [ os . path . join ( base , d ) for d in dirs ]
2020-09-26 16:19:37 +02:00
dirs = [ d for d in dirs if os . path . isdir ( d ) and os . listdir ( d ) ] # non empty dirs
dirs . sort ( )
return dirs
2022-12-27 00:13:34 +01:00
def delete_archive ( self , archive_id : str ) :
2020-09-26 16:19:37 +02:00
""" Delete (forever) this archive """
2021-08-29 19:57:32 +02:00
self . initialize ( )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2020-09-26 16:19:37 +02:00
shutil . rmtree ( archive_id , ignore_errors = True )
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2020-09-26 16:19:37 +02:00
2022-12-27 00:13:34 +01:00
def get_archive_date ( self , archive_id : str ) :
2020-09-26 16:19:37 +02:00
""" Returns date (as a DateTime object) of an archive """
2022-04-06 18:51:01 +02:00
return datetime . datetime (
* [ int ( x ) for x in os . path . split ( archive_id ) [ 1 ] . split ( " - " ) ]
)
2020-09-26 16:19:37 +02:00
2021-08-10 17:12:10 +02:00
def list_archive ( self , archive_id : str ) - > str :
2020-09-26 16:19:37 +02:00
""" Return list of filenames (without path) in archive """
2021-08-29 19:57:32 +02:00
self . initialize ( )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2020-09-26 16:19:37 +02:00
files = os . listdir ( archive_id )
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2020-09-26 16:19:37 +02:00
files . sort ( )
2021-08-10 17:12:10 +02:00
return [ f for f in files if f and f [ 0 ] != " _ " ]
2020-09-26 16:19:37 +02:00
2022-12-27 00:13:34 +01:00
def get_archive_name ( self , archive_id : str ) :
2020-09-26 16:19:37 +02:00
""" name identifying archive, to be used in web URLs """
return os . path . split ( archive_id ) [ 1 ]
2022-12-27 00:13:34 +01:00
def is_valid_archive_name ( self , archive_name : str ) :
2020-09-26 16:19:37 +02:00
""" check if name is valid. """
return re . match (
" ^[0-9] {4} -[0-9] {2} -[0-9] {2} -[0-9] {2} -[0-9] {2} -[0-9] {2} $ " , archive_name
)
2022-12-27 00:13:34 +01:00
def get_id_from_name ( self , oid , archive_name : str ) :
2020-09-26 16:19:37 +02:00
""" returns archive id (check that name is valid) """
2021-08-29 19:57:32 +02:00
self . initialize ( )
2020-09-26 16:19:37 +02:00
if not self . is_valid_archive_name ( archive_name ) :
2022-09-14 22:47:31 +02:00
raise ScoValueError ( f " Archive { archive_name } introuvable " )
2021-08-20 10:51:42 +02:00
archive_id = os . path . join ( self . get_obj_dir ( oid ) , archive_name )
2020-09-26 16:19:37 +02:00
if not os . path . isdir ( archive_id ) :
log (
2022-04-06 18:51:01 +02:00
f " invalid archive name: { archive_name } , oid= { oid } , archive_id= { archive_id } "
2020-09-26 16:19:37 +02:00
)
2022-09-13 10:50:13 +02:00
raise ScoValueError ( f " Archive { archive_name } introuvable " )
2020-09-26 16:19:37 +02:00
return archive_id
2022-12-27 00:13:34 +01:00
def get_archive_description ( self , archive_id : str ) - > str :
2020-09-26 16:19:37 +02:00
""" Return description of archive """
2021-08-29 19:57:32 +02:00
self . initialize ( )
2021-12-12 16:53:52 +01:00
filename = os . path . join ( archive_id , " _description.txt " )
try :
with open ( filename ) as f :
descr = f . read ( )
except UnicodeDecodeError :
# some (old) files may have saved under exotic encodings
with open ( filename , " rb " ) as f :
data = f . read ( )
descr = data . decode ( chardet . detect ( data ) [ " encoding " ] )
2021-10-11 22:22:42 +02:00
return descr
2020-09-26 16:19:37 +02:00
2021-08-20 10:51:42 +02:00
def create_obj_archive ( self , oid : int , description : str ) :
2020-09-26 16:19:37 +02:00
""" Creates a new archive for this object and returns its id. """
archive_id = (
2021-08-20 10:51:42 +02:00
self . get_obj_dir ( oid )
2020-09-26 16:19:37 +02:00
+ os . path . sep
+ " - " . join ( [ " %02d " % x for x in time . localtime ( ) [ : 6 ] ] )
)
2022-04-06 18:51:01 +02:00
log ( f " creating archive: { archive_id } " )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2022-09-21 11:35:02 +02:00
os . mkdir ( archive_id ) # if exists, raises FileExistsError
2020-09-26 16:19:37 +02:00
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2022-06-30 09:27:46 +02:00
self . store ( archive_id , " _description.txt " , description )
2020-09-26 16:19:37 +02:00
return archive_id
2022-06-30 09:27:46 +02:00
def store ( self , archive_id : str , filename : str , data : Union [ str , bytes ] ) :
2020-10-14 15:28:09 +02:00
""" Store data in archive, under given filename.
2020-09-26 16:19:37 +02:00
Filename may be modified ( sanitized ) : return used filename
The file is created or replaced .
2022-06-30 09:27:46 +02:00
data may be str or bytes
2020-09-26 16:19:37 +02:00
"""
2022-06-30 09:27:46 +02:00
if isinstance ( data , str ) :
data = data . encode ( scu . SCO_ENCODING )
2021-08-29 19:57:32 +02:00
self . initialize ( )
2021-02-04 20:02:44 +01:00
filename = scu . sanitize_filename ( filename )
2022-12-27 00:13:34 +01:00
log ( f " storing { filename } ( { len ( data ) } bytes) in { archive_id } " )
2020-09-26 16:19:37 +02:00
try :
2021-02-04 20:02:44 +01:00
scu . GSL . acquire ( )
2020-09-26 16:19:37 +02:00
fname = os . path . join ( archive_id , filename )
2021-10-11 22:22:42 +02:00
with open ( fname , " wb " ) as f :
f . write ( data )
2020-09-26 16:19:37 +02:00
finally :
2021-02-04 20:02:44 +01:00
scu . GSL . release ( )
2020-09-26 16:19:37 +02:00
return filename
2021-08-10 17:12:10 +02:00
def get ( self , archive_id : str , filename : str ) :
2020-09-26 16:19:37 +02:00
""" Retreive data """
2021-08-29 19:57:32 +02:00
self . initialize ( )
2021-02-04 20:02:44 +01:00
if not scu . is_valid_filename ( filename ) :
2022-12-27 00:13:34 +01:00
log ( f """ Archiver.get: invalid filename ' { filename } ' """ )
2022-03-04 18:55:45 +01:00
raise ScoValueError ( " archive introuvable (déjà supprimée ?) " )
2020-09-26 16:19:37 +02:00
fname = os . path . join ( archive_id , filename )
2022-12-27 00:13:34 +01:00
log ( f " reading archive file { fname } " )
2021-10-11 22:22:42 +02:00
with open ( fname , " rb " ) as f :
data = f . read ( )
return data
2020-09-26 16:19:37 +02:00
2021-09-16 14:58:56 +02:00
def get_archived_file ( self , oid , archive_name , filename ) :
2022-12-27 00:13:34 +01:00
""" Recupère les donnees du fichier indiqué et envoie au client.
Returns : Response
"""
2021-08-20 10:51:42 +02:00
archive_id = self . get_id_from_name ( oid , archive_name )
2020-09-26 16:19:37 +02:00
data = self . get ( archive_id , filename )
2021-09-16 00:15:10 +02:00
mime = mimetypes . guess_type ( filename ) [ 0 ]
if mime is None :
mime = " application/octet-stream "
return scu . send_file ( data , filename , mime = mime )
2020-09-26 16:19:37 +02:00
class SemsArchiver ( BaseArchiver ) :
def __init__ ( self ) :
BaseArchiver . __init__ ( self , archive_type = " " )
PVArchive = SemsArchiver ( )
# ----------------------------------------------------------------------------
def do_formsemestre_archive (
formsemestre_id ,
group_ids = [ ] , # si indiqué, ne prend que ces groupes
description = " " ,
date_jury = " " ,
signature = None , # pour lettres indiv
date_commission = None ,
numeroArrete = None ,
VDICode = None ,
showTitle = False ,
2020-12-02 10:01:07 +01:00
pv_title = None ,
2020-10-14 15:28:09 +02:00
with_paragraph_nom = False ,
2020-09-26 16:19:37 +02:00
anonymous = False ,
bulVersion = " long " ,
) :
""" Make and store new archive for this formsemestre.
Store :
- tableau recap ( xls ) , pv jury ( xls et pdf ) , bulletins ( xml et pdf ) , lettres individuelles ( pdf )
"""
2022-04-06 18:51:01 +02:00
from app . scodoc . sco_recapcomplet import (
gen_formsemestre_recapcomplet_excel ,
2023-02-12 01:13:43 +01:00
gen_formsemestre_recapcomplet_html_table ,
2022-04-06 18:51:01 +02:00
gen_formsemestre_recapcomplet_json ,
)
2021-06-19 23:21:37 +02:00
2022-04-06 18:51:01 +02:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
res : NotesTableCompat = res_sem . load_formsemestre_results ( formsemestre )
2021-09-16 21:42:45 +02:00
sem_archive_id = formsemestre_id
2021-08-27 22:16:10 +02:00
archive_id = PVArchive . create_obj_archive ( sem_archive_id , description )
2020-09-26 16:19:37 +02:00
date = PVArchive . get_archive_date ( archive_id ) . strftime ( " %d / % m/ % Y à % H: % M " )
if not group_ids :
# tous les inscrits du semestre
2021-07-29 16:31:15 +02:00
group_ids = [ sco_groups . get_default_group ( formsemestre_id ) ]
2020-09-26 16:19:37 +02:00
groups_infos = sco_groups_view . DisplayedGroupsInfos (
2021-09-08 00:34:45 +02:00
group_ids , formsemestre_id = formsemestre_id
2020-09-26 16:19:37 +02:00
)
groups_filename = " - " + groups_infos . groups_filename
etudids = [ m [ " etudid " ] for m in groups_infos . members ]
# Tableau recap notes en XLS (pour tous les etudiants, n'utilise pas les groupes)
2023-02-06 10:58:36 +01:00
data , _ = gen_formsemestre_recapcomplet_excel ( res , include_evaluations = True )
2020-09-26 16:19:37 +02:00
if data :
2021-08-12 14:49:53 +02:00
PVArchive . store ( archive_id , " Tableau_moyennes " + scu . XLSX_SUFFIX , data )
2020-09-26 16:19:37 +02:00
# Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
2023-02-12 01:13:43 +01:00
table_html , _ = gen_formsemestre_recapcomplet_html_table (
2022-04-06 18:51:01 +02:00
formsemestre , res , include_evaluations = True
2020-09-26 16:19:37 +02:00
)
2022-04-06 18:51:01 +02:00
if table_html :
2020-09-26 16:19:37 +02:00
data = " \n " . join (
[
2021-06-13 23:37:14 +02:00
html_sco_header . sco_header (
2022-04-06 18:51:01 +02:00
page_title = f " Moyennes archivées le { date } " ,
head_message = f " Moyennes archivées le { date } " ,
2020-09-26 16:19:37 +02:00
no_side_bar = True ,
) ,
2022-04-06 18:51:01 +02:00
f ' <h2 class= " fontorange " >Valeurs archivées le { date } </h2> ' ,
2020-09-26 16:19:37 +02:00
' <style type= " text/css " >table.notes_recapcomplet tr { color: rgb(185,70,0); }</style> ' ,
2022-04-06 18:51:01 +02:00
table_html ,
2021-07-29 10:19:00 +02:00
html_sco_header . sco_footer ( ) ,
2020-09-26 16:19:37 +02:00
]
)
PVArchive . store ( archive_id , " Tableau_moyennes.html " , data )
2022-04-06 18:51:01 +02:00
# Bulletins en JSON
data = gen_formsemestre_recapcomplet_json ( formsemestre_id , xml_with_decisions = True )
data_js = json . dumps ( data , indent = 1 , cls = scu . ScoDocJSONEncoder )
2020-09-26 16:19:37 +02:00
if data :
2022-04-06 18:51:01 +02:00
PVArchive . store ( archive_id , " Bulletins.json " , data_js )
2022-07-17 15:15:24 +02:00
# Décisions de jury, en XLS
if formsemestre . formation . is_apc ( ) :
response = jury_but_pv . pvjury_table_but ( formsemestre_id , format = " xls " )
data = response . get_data ( )
else : # formations classiques
data = sco_pvjury . formsemestre_pvjury (
formsemestre_id , format = " xls " , publish = False
)
2020-09-26 16:19:37 +02:00
if data :
2022-06-27 19:20:26 +02:00
PVArchive . store (
archive_id ,
" Decisions_Jury " + scu . XLSX_SUFFIX ,
2022-06-30 09:27:46 +02:00
data ,
2022-06-27 19:20:26 +02:00
)
2020-09-26 16:19:37 +02:00
# Classeur bulletins (PDF)
2021-02-16 15:16:57 +01:00
data , _ = sco_bulletins_pdf . get_formsemestre_bulletins_pdf (
2021-09-27 10:20:10 +02:00
formsemestre_id , version = bulVersion
2020-09-26 16:19:37 +02:00
)
if data :
PVArchive . store ( archive_id , " Bulletins.pdf " , data )
# Lettres individuelles (PDF):
data = sco_pvpdf . pdf_lettres_individuelles (
formsemestre_id ,
etudids = etudids ,
date_jury = date_jury ,
date_commission = date_commission ,
signature = signature ,
)
if data :
PVArchive . store ( archive_id , " CourriersDecisions %s .pdf " % groups_filename , data )
2022-07-17 15:15:24 +02:00
# PV de jury (PDF): disponible seulement en classique
# en BUT, le PV est sous forme excel (Decisions_Jury.xlsx ci-dessus)
if not formsemestre . formation . is_apc ( ) :
dpv = sco_pvjury . dict_pvjury ( formsemestre_id , etudids = etudids , with_prev = True )
data = sco_pvpdf . pvjury_pdf (
dpv ,
date_commission = date_commission ,
date_jury = date_jury ,
numeroArrete = numeroArrete ,
VDICode = VDICode ,
showTitle = showTitle ,
pv_title = pv_title ,
with_paragraph_nom = with_paragraph_nom ,
anonymous = anonymous ,
)
if data :
PVArchive . store ( archive_id , " PV_Jury %s .pdf " % groups_filename , data )
2020-09-26 16:19:37 +02:00
2021-09-27 10:20:10 +02:00
def formsemestre_archive ( formsemestre_id , group_ids = [ ] ) :
2020-09-26 16:19:37 +02:00
""" Make and store new archive for this formsemestre.
( all students or only selected groups )
"""
2023-02-12 01:13:43 +01:00
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
if not formsemestre . can_edit_pv ( ) :
raise ScoPermissionDenied (
dest_url = url_for (
" notes.formsemestre_status " ,
scodoc_dept = g . scodoc_dept ,
formsemestre_id = formsemestre_id ,
)
)
2020-09-26 16:19:37 +02:00
2021-08-19 10:28:35 +02:00
sem = sco_formsemestre . get_formsemestre ( formsemestre_id )
2020-09-26 16:19:37 +02:00
if not group_ids :
# tous les inscrits du semestre
2021-07-29 16:31:15 +02:00
group_ids = [ sco_groups . get_default_group ( formsemestre_id ) ]
2020-09-26 16:19:37 +02:00
groups_infos = sco_groups_view . DisplayedGroupsInfos (
2021-09-08 00:34:45 +02:00
group_ids , formsemestre_id = formsemestre_id
2020-09-26 16:19:37 +02:00
)
H = [
2021-06-13 23:37:14 +02:00
html_sco_header . html_sem_header (
2020-09-26 16:19:37 +02:00
" Archiver les PV et résultats du semestre " ,
javascripts = sco_groups_view . JAVASCRIPTS ,
cssstyles = sco_groups_view . CSSSTYLES ,
init_qtip = True ,
) ,
""" <p class= " help " >Cette page permet de générer et d ' archiver tous
2021-08-27 22:16:10 +02:00
les documents résultant de ce semestre : PV de jury , lettres individuelles ,
tableaux récapitulatifs . < / p > < p class = " help " > Les documents archivés sont
2020-09-26 16:19:37 +02:00
enregistrés et non modifiables , on peut les retrouver ultérieurement .
2021-08-29 19:57:32 +02:00
< / p > < p class = " help " > On peut archiver plusieurs versions des documents
2021-08-27 22:16:10 +02:00
( avant et après le jury par exemple ) .
2020-09-26 16:19:37 +02:00
< / p >
""" ,
]
F = [
""" <p><em>Note: les documents sont aussi affectés par les réglages sur la page " <a href= " edit_preferences " >Paramétrage</a> " (accessible à l ' administrateur du département).</em>
< / p > """ ,
2021-07-29 10:19:00 +02:00
html_sco_header . sco_footer ( ) ,
2020-09-26 16:19:37 +02:00
]
descr = [
(
" description " ,
{ " input_type " : " textarea " , " rows " : 4 , " cols " : 77 , " title " : " Description " } ,
) ,
( " sep " , { " input_type " : " separator " , " title " : " Informations sur PV de jury " } ) ,
]
2021-08-20 10:51:42 +02:00
descr + = sco_pvjury . descrform_pvjury ( sem )
2020-09-26 16:19:37 +02:00
descr + = [
(
" signature " ,
{
" input_type " : " file " ,
" size " : 30 ,
" explanation " : " optionnel: image scannée de la signature pour les lettres individuelles " ,
} ,
) ,
(
" bulVersion " ,
{
" input_type " : " menu " ,
" title " : " Version des bulletins archivés " ,
" labels " : [
" Version courte " ,
" Version intermédiaire " ,
" Version complète " ,
] ,
2021-07-19 19:53:01 +02:00
" allowed_values " : scu . BULLETINS_VERSIONS ,
2020-09-26 16:19:37 +02:00
" default " : " long " ,
} ,
) ,
]
menu_choix_groupe = (
""" <div class= " group_ids_sel_menu " >Groupes d ' étudiants à lister: """
2021-08-20 10:51:42 +02:00
+ sco_groups_view . menu_groups_choice ( groups_infos )
2020-09-26 16:19:37 +02:00
+ """ (pour les PV et lettres)</div> """
)
tf = TrivialFormulator (
2021-09-18 10:10:02 +02:00
request . base_url ,
2021-09-27 16:42:14 +02:00
scu . get_request_args ( ) ,
2020-09-26 16:19:37 +02:00
descr ,
cancelbutton = " Annuler " ,
method = " POST " ,
submitlabel = " Générer et archiver les documents " ,
name = " tf " ,
formid = " group_selector " ,
html_foot_markup = menu_choix_groupe ,
)
if tf [ 0 ] == 0 :
return " \n " . join ( H ) + " \n " + tf [ 1 ] + " \n " . join ( F )
elif tf [ 0 ] == - 1 :
msg = " Opération %20a nnulée "
else :
# submit
sf = tf [ 2 ] [ " signature " ]
signature = sf . read ( ) # image of signature
if tf [ 2 ] [ " anonymous " ] :
tf [ 2 ] [ " anonymous " ] = True
else :
tf [ 2 ] [ " anonymous " ] = False
do_formsemestre_archive (
formsemestre_id ,
group_ids = group_ids ,
description = tf [ 2 ] [ " description " ] ,
date_jury = tf [ 2 ] [ " date_jury " ] ,
date_commission = tf [ 2 ] [ " date_commission " ] ,
signature = signature ,
numeroArrete = tf [ 2 ] [ " numeroArrete " ] ,
VDICode = tf [ 2 ] [ " VDICode " ] ,
2020-12-02 10:01:07 +01:00
pv_title = tf [ 2 ] [ " pv_title " ] ,
2020-09-26 16:19:37 +02:00
showTitle = tf [ 2 ] [ " showTitle " ] ,
2020-10-14 15:28:09 +02:00
with_paragraph_nom = tf [ 2 ] [ " with_paragraph_nom " ] ,
2020-09-26 16:19:37 +02:00
anonymous = tf [ 2 ] [ " anonymous " ] ,
bulVersion = tf [ 2 ] [ " bulVersion " ] ,
)
msg = " Nouvelle %20a rchive %20c réée "
# submitted or cancelled:
2021-07-31 18:01:10 +02:00
return flask . redirect (
2021-05-11 11:48:32 +02:00
" formsemestre_list_archives?formsemestre_id= %s &head_message= %s "
2020-09-26 16:19:37 +02:00
% ( formsemestre_id , msg )
)
2021-09-27 10:20:10 +02:00
def formsemestre_list_archives ( formsemestre_id ) :
2020-10-14 15:28:09 +02:00
""" Page listing archives """
2021-08-27 22:16:10 +02:00
sem = sco_formsemestre . get_formsemestre ( formsemestre_id )
2021-09-16 21:42:45 +02:00
sem_archive_id = formsemestre_id
2020-09-26 16:19:37 +02:00
L = [ ]
2021-08-27 22:16:10 +02:00
for archive_id in PVArchive . list_obj_archives ( sem_archive_id ) :
2020-09-26 16:19:37 +02:00
a = {
" archive_id " : archive_id ,
" description " : PVArchive . get_archive_description ( archive_id ) ,
" date " : PVArchive . get_archive_date ( archive_id ) ,
" content " : PVArchive . list_archive ( archive_id ) ,
}
L . append ( a )
2022-01-07 15:11:24 +01:00
H = [ html_sco_header . html_sem_header ( " Archive des PV et résultats " ) ]
2020-09-26 16:19:37 +02:00
if not L :
H . append ( " <p>aucune archive enregistrée</p> " )
else :
H . append ( " <ul> " )
for a in L :
archive_name = PVArchive . get_archive_name ( a [ " archive_id " ] )
H . append (
2021-05-11 11:48:32 +02:00
' <li> %s : <em> %s </em> (<a href= " formsemestre_delete_archive?formsemestre_id= %s &archive_name= %s " >supprimer</a>)<ul> '
2020-09-26 16:19:37 +02:00
% (
a [ " date " ] . strftime ( " %d / % m/ % Y % H: % M " ) ,
a [ " description " ] ,
formsemestre_id ,
archive_name ,
)
)
for filename in a [ " content " ] :
H . append (
2021-05-11 11:48:32 +02:00
' <li><a href= " formsemestre_get_archived_file?formsemestre_id= %s &archive_name= %s &filename= %s " > %s </a></li> '
2020-09-26 16:19:37 +02:00
% ( formsemestre_id , archive_name , filename , filename )
)
if not a [ " content " ] :
H . append ( " <li><em>aucun fichier !</em></li> " )
H . append ( " </ul></li> " )
H . append ( " </ul> " )
2021-07-29 10:19:00 +02:00
return " \n " . join ( H ) + html_sco_header . sco_footer ( )
2020-09-26 16:19:37 +02:00
2021-09-16 14:58:56 +02:00
def formsemestre_get_archived_file ( formsemestre_id , archive_name , filename ) :
2020-10-14 15:28:09 +02:00
""" Send file to client. """
2023-02-12 01:13:43 +01:00
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
sem_archive_id = formsemestre . id
2021-09-16 14:58:56 +02:00
return PVArchive . get_archived_file ( sem_archive_id , archive_name , filename )
2020-09-26 16:19:37 +02:00
2021-09-27 10:20:10 +02:00
def formsemestre_delete_archive ( formsemestre_id , archive_name , dialog_confirmed = False ) :
2020-10-14 15:28:09 +02:00
""" Delete an archive """
2023-02-12 01:13:43 +01:00
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
if not formsemestre . can_edit_pv ( ) :
raise ScoPermissionDenied (
dest_url = url_for (
" notes.formsemestre_status " ,
scodoc_dept = g . scodoc_dept ,
formsemestre_id = formsemestre_id ,
)
)
2021-09-16 21:42:45 +02:00
sem_archive_id = formsemestre_id
2021-08-27 22:16:10 +02:00
archive_id = PVArchive . get_id_from_name ( sem_archive_id , archive_name )
2020-09-26 16:19:37 +02:00
2023-02-12 01:13:43 +01:00
dest_url = url_for (
" notes.formsemestre_list_archives " ,
scodoc_dept = g . scodoc_dept ,
formsemestre_id = formsemestre_id ,
)
2020-09-26 16:19:37 +02:00
if not dialog_confirmed :
2021-06-02 22:40:34 +02:00
return scu . confirm_dialog (
2023-02-12 01:13:43 +01:00
f """ <h2>Confirmer la suppression de l ' archive du {
PVArchive . get_archive_date ( archive_id ) . strftime ( " %d / % m/ % Y % H: % M " )
} ? < / h2 >
< p > La suppression sera définitive . < / p >
""" ,
2020-09-26 16:19:37 +02:00
dest_url = " " ,
cancel_url = dest_url ,
parameters = {
" formsemestre_id " : formsemestre_id ,
" archive_name " : archive_name ,
} ,
)
PVArchive . delete_archive ( archive_id )
2023-02-12 01:13:43 +01:00
flash ( " Archive supprimée " )
return flask . redirect ( dest_url )