1
0
forked from ScoDoc/ScoDoc

Conservation des anciens id de semestres et d'étudiants pour accès aux archives.

This commit is contained in:
Emmanuel Viennet 2021-08-27 22:16:10 +02:00
parent 41c4fdafa4
commit 58d6db57fa
9 changed files with 112 additions and 34 deletions

View File

@ -150,6 +150,8 @@ Mémo pour développeurs: séquence re-création d'une base:
# Paquet debian 11
Ce que le script d'installation/mise à jour du paquet ne fait pas encore:
Les scripts associés au paquet Debian (.deb) sont dans `tools/debian`.
La préparation d'une release se fait à l'aide du script
`tools/build_release.sh`.
- migrations flask (à faire)

View File

@ -40,6 +40,8 @@ class Identite(db.Model):
# Codes INE et NIP pas unique car le meme etud peut etre ds plusieurs dept
code_nip = db.Column(db.Text())
code_ine = db.Column(db.Text())
# Ancien id ScoDoc7 pour les migrations de bases anciennes
scodoc7_id = db.Column(db.Text(), nullable=True)
class Adresse(db.Model):

View File

@ -69,6 +69,8 @@ class FormSemestre(db.Model):
etapes = db.relationship(
"NotesFormsemestreEtape", cascade="all,delete", backref="notes_formsemestre"
)
# Ancien id ScoDoc7 pour les migrations de bases anciennes
scodoc7_id = db.Column(db.Text(), nullable=True)
def __init__(self, **kwargs):
super(FormSemestre, self).__init__(**kwargs)

View File

@ -34,9 +34,11 @@
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>
(formsemestre_id est ici FormSemestre.scodoc7_id ou à défaut FormSemestre.id)
Les documents liés à l'étudiant sont dans
<archivedir>/docetuds/<dept>/<etudid>/<YYYY-MM-DD-HH-MM-SS>
(etudid est ici soit Identite.scodoc7id, soit à défaut Identite.id)
Les maquettes Apogée pour l'export des notes sont dans
<archivedir>/apo_csv/<dept>/<annee_scolaire>-<sem_id>/<YYYY-MM-DD-HH-MM-SS>/<code_etape>.csv
@ -284,7 +286,9 @@ def do_formsemestre_archive(
"""
from app.scodoc.sco_recapcomplet import make_formsemestre_recapcomplet
archive_id = PVArchive.create_obj_archive(formsemestre_id, description)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
archive_id = PVArchive.create_obj_archive(sem_archive_id, description)
date = PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y à %H:%M")
if not group_ids:
@ -394,10 +398,11 @@ def formsemestre_archive(REQUEST, formsemestre_id, group_ids=[]):
init_qtip=True,
),
"""<p class="help">Cette page permet de générer et d'archiver tous
les documents résultant de ce semestre: PV de jury, lettres individuelles,
tableaux récapitulatifs.</p><p class="help">Les documents archivés sont
les documents résultant de ce semestre: PV de jury, lettres individuelles,
tableaux récapitulatifs.</p><p class="help">Les documents archivés sont
enregistrés et non modifiables, on peut les retrouver ultérieurement.
</p><p class="help">On peut archiver plusieurs versions des documents (avant et après le jury par exemple).
</p><p class="help">On peut archiver plusieurs versions des documents
(avant et après le jury par exemple).
</p>
""",
]
@ -495,8 +500,10 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
def formsemestre_list_archives(REQUEST, formsemestre_id):
"""Page listing archives"""
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
L = []
for archive_id in PVArchive.list_obj_archives(formsemestre_id):
for archive_id in PVArchive.list_obj_archives(sem_archive_id):
a = {
"archive_id": archive_id,
"description": PVArchive.get_archive_description(archive_id),
@ -505,7 +512,6 @@ def formsemestre_list_archives(REQUEST, formsemestre_id):
}
L.append(a)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
H = [html_sco_header.html_sem_header(REQUEST, "Archive des PV et résultats ", sem)]
if not L:
H.append("<p>aucune archive enregistrée</p>")
@ -537,7 +543,9 @@ def formsemestre_list_archives(REQUEST, formsemestre_id):
def formsemestre_get_archived_file(REQUEST, formsemestre_id, archive_name, filename):
"""Send file to client."""
return PVArchive.get_archived_file(REQUEST, formsemestre_id, archive_name, filename)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
return PVArchive.get_archived_file(REQUEST, sem_archive_id, archive_name, filename)
def formsemestre_delete_archive(
@ -548,8 +556,9 @@ def formsemestre_delete_archive(
raise AccessDenied(
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
)
_ = sco_formsemestre.get_formsemestre(formsemestre_id) # check formsemestre_id
archive_id = PVArchive.get_id_from_name(formsemestre_id, archive_name)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem_archive_id = sem["scodoc7_id"] or formsemestre_id
archive_id = PVArchive.get_id_from_name(sem_archive_id, archive_name)
dest_url = "formsemestre_list_archives?formsemestre_id=%s" % (formsemestre_id)

View File

@ -27,7 +27,7 @@
"""ScoDoc : gestion des fichiers archivés associés aux étudiants
Il s'agit de fichiers quelconques, généralement utilisés pour conserver
les dossiers d'admission et autres pièces utiles.
les dossiers d'admission et autres pièces utiles.
"""
import flask
from flask import url_for, g
@ -39,7 +39,7 @@ from app.scodoc import sco_trombino
from app.scodoc import sco_excel
from app.scodoc import sco_archives
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import html_sco_header
from app.scodoc import sco_etud
@ -61,8 +61,13 @@ def can_edit_etud_archive(authuser):
def etud_list_archives_html(REQUEST, etudid):
"""HTML snippet listing archives"""
can_edit = can_edit_etud_archive(REQUEST.AUTHENTICATED_USER)
etuds = sco_etud.get_etud_info(etudid=etudid)
if not etuds:
raise ScoValueError("étudiant inexistant")
etud = etuds[0]
etud_archive_id = etud["scodoc7_id"] or etudid
L = []
for archive_id in EtudsArchive.list_obj_archives(etudid):
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
a = {
"archive_id": archive_id,
"description": EtudsArchive.get_archive_description(archive_id),
@ -113,7 +118,8 @@ def add_archives_info_to_etud_list(etuds):
"""
for etud in etuds:
l = []
for archive_id in EtudsArchive.list_obj_archives(etud["etudid"]):
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
for archive_id in EtudsArchive.list_obj_archives(etud_archive_id):
l.append(
"%s (%s)"
% (
@ -129,9 +135,12 @@ def etud_upload_file_form(REQUEST, etudid):
# check permission
if not can_edit_etud_archive(REQUEST.AUTHENTICATED_USER):
raise AccessDenied(
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
"opération non autorisée pour %s" % REQUEST.AUTHENTICATED_USER
)
etud = sco_etud.get_etud_info(filled=True)[0]
etuds = sco_etud.get_etud_info(filled=True)
if not etuds:
raise ScoValueError("étudiant inexistant")
etud = etuds[0]
H = [
html_sco_header.sco_header(
page_title="Chargement d'un document associé à %(nomprenom)s" % etud,
@ -172,18 +181,21 @@ def etud_upload_file_form(REQUEST, etudid):
data = tf[2]["datafile"].read()
descr = tf[2]["description"]
filename = tf[2]["datafile"].filename
_store_etud_file_to_new_archive(etudid, data, filename, description=descr)
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
_store_etud_file_to_new_archive(
etud_archive_id, data, filename, description=descr
)
return flask.redirect(
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
)
def _store_etud_file_to_new_archive(etudid, data, filename, description=""):
def _store_etud_file_to_new_archive(etud_archive_id, data, filename, description=""):
"""Store data to new archive."""
filesize = len(data)
if filesize < 10 or filesize > scu.CONFIG.ETUD_MAX_FILE_SIZE:
return 0, "Fichier image de taille invalide ! (%d)" % filesize
archive_id = EtudsArchive.create_obj_archive(etudid, description)
archive_id = EtudsArchive.create_obj_archive(etud_archive_id, description)
EtudsArchive.store(archive_id, filename, data)
@ -194,8 +206,12 @@ def etud_delete_archive(REQUEST, etudid, archive_name, dialog_confirmed=False):
raise AccessDenied(
"opération non autorisée pour %s" % str(REQUEST.AUTHENTICATED_USER)
)
etud = sco_etud.get_etud_info(filled=True)[0]
archive_id = EtudsArchive.get_id_from_name(etudid, archive_name)
etuds = sco_etud.get_etud_info(filled=True)
if not etuds:
raise ScoValueError("étudiant inexistant")
etud = etuds[0]
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
archive_id = EtudsArchive.get_id_from_name(etud_archive_id, archive_name)
if not dialog_confirmed:
return scu.confirm_dialog(
"""<h2>Confirmer la suppression des fichiers ?</h2>
@ -228,7 +244,14 @@ def etud_delete_archive(REQUEST, etudid, archive_name, dialog_confirmed=False):
def etud_get_archived_file(REQUEST, etudid, archive_name, filename):
"""Send file to client."""
return EtudsArchive.get_archived_file(REQUEST, etudid, archive_name, filename)
etuds = sco_etud.get_etud_info(filled=True)
if not etuds:
raise ScoValueError("étudiant inexistant")
etud = etuds[0]
etud_archive_id = etud["scodoc7_id"] or etud["etudid"]
return EtudsArchive.get_archived_file(
REQUEST, etud_archive_id, archive_name, filename
)
# --- Upload d'un ensemble de fichiers (pour un groupe d'étudiants)
@ -260,17 +283,22 @@ def etudarchive_import_files_form(group_id, REQUEST=None):
page_title="Import de fichiers associés aux étudiants"
),
"""<h2 class="formsemestre">Téléchargement de fichier associés aux étudiants</h2>
<p>Les fichiers associés (dossiers d'admission, certificats, ...), de types quelconques (pdf, doc, images)
sont accessibles aux utilisateurs via la fiche individuelle de l'étudiant.
<p>Les fichiers associés (dossiers d'admission, certificats, ...), de
types quelconques (pdf, doc, images) sont accessibles aux utilisateurs via
la fiche individuelle de l'étudiant.
</p>
<p class="warning">Ne pas confondre avec les photos des étudiants, qui se chargent via l'onglet "Photos".</p>
<p><b>Vous pouvez aussi charger à tout moment de nouveaux fichiers, ou en supprimer, via la fiche de chaque étudiant.</b></p>
<p class="help">Cette page permet de charger en une seule fois les fichiers de plusieurs étudiants.<br/>
Il faut d'abord remplir une feuille excel donnant les noms
<p class="warning">Ne pas confondre avec les photos des étudiants, qui se
chargent via l'onglet "Photos".</p>
<p><b>Vous pouvez aussi charger à tout moment de nouveaux fichiers, ou en
supprimer, via la fiche de chaque étudiant.</b>
</p>
<p class="help">Cette page permet de charger en une seule fois les fichiers
de plusieurs étudiants.<br/>
Il faut d'abord remplir une feuille excel donnant les noms
des fichiers (un fichier par étudiant).
</p>
<p class="help">Ensuite, réunir vos fichiers dans un fichier zip, puis télécharger
simultanément le fichier excel et le fichier zip.
<p class="help">Ensuite, réunir vos fichiers dans un fichier zip, puis
télécharger simultanément le fichier excel et le fichier zip.
</p>
<ol>
<li><a class="stdlink" href="etudarchive_generate_excel_sample?group_id=%s">

View File

@ -256,6 +256,7 @@ _identiteEditor = ndb.EditableTable(
"photo_filename",
"code_ine",
"code_nip",
"scodoc7_id",
),
filter_dept=True,
sortkey="nom",
@ -655,9 +656,9 @@ def make_etud_args(etudid=None, code_nip=None, use_request=True, raise_exc=True)
return args
def get_etud_info(etudid=False, code_nip=False, filled=False):
"""infos sur un etudiant (API)
On peut specifier etudid ou conde_nip
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
"""infos sur un etudiant (API). If not foud, returns empty list.
On peut specifier etudid ou code_nip
ou bien cherche dans REQUEST.form: etudid, code_nip, code_ine
(dans cet ordre).
"""

View File

@ -67,6 +67,7 @@ _formsemestreEditor = ndb.EditableTable(
"ens_can_edit_eval",
"elt_sem_apo",
"elt_annee_apo",
"scodoc7_id",
),
filter_dept=True,
sortkey="date_debut",

View File

@ -0,0 +1,30 @@
"""ScoDoc 9.0.4: ajout id scodoc7 pour migrations (archives)
Revision ID: 017e32eb4773
Revises: 6b071b7947e5
Create Date: 2021-08-27 21:58:05.317092
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '017e32eb4773'
down_revision = '6b071b7947e5'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('identite', sa.Column('scodoc7_id', sa.Text(), nullable=True))
op.add_column('notes_formsemestre', sa.Column('scodoc7_id', sa.Text(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('notes_formsemestre', 'scodoc7_id')
op.drop_column('identite', 'scodoc7_id')
# ### end Alembic commands ###

View File

@ -260,6 +260,8 @@ def convert_object(
if id_name:
old_id = obj[id_name]
del obj[id_name]
if hasattr(klass, "scodoc7_id"):
obj["scodoc7_id"] = old_id
else:
old_id = None # tables ScoDoc7 sans id
if is_table:
@ -283,6 +285,7 @@ def convert_object(
if (k.endswith("id") or k == "object") and k not in USER_REFS | {
"semestre_id",
"sem_id",
"scodoc7_id",
}:
old_ref = obj[k]
if old_ref is not None: