migration abs : fusion + cmd downgrade

This commit is contained in:
iziram 2023-02-11 14:26:08 +01:00
parent 21f57aab8f
commit aa956f4530
5 changed files with 217 additions and 126 deletions

View File

@ -1,7 +1,8 @@
from app.scodoc.sco_archives import BaseArchiver
from app.scodoc.sco_exceptions import ScoValueError
from app.models import Identite, Departement
from flask import g
from shutil import rmtree
import os
@ -106,3 +107,12 @@ class JustificatifArchiver(BaseArchiver):
"""
etud: Identite = Identite.query.filter_by(id=etudid).first()
self.set_dept_id(etud.dept_id)
def remove_dept_archive(self, dept_id: int = None):
self.set_dept_id(1)
self.initialize()
if dept_id is None:
rmtree(self.root, ignore_errors=True)
else:
rmtree(os.path.join(self.root, str(dept_id)), ignore_errors=True)

View File

@ -503,6 +503,30 @@ def migrate_abs_to_assiduites(
tools.migrate_abs_to_assiduites(dept, morning, noon, evening)
@app.cli.command()
@click.option(
"-d", "--dept", help="Restreint la suppression au dept sélectionné (ACRONYME)"
)
@click.option(
"-a",
"--assiduites",
is_flag=True,
help="Supprime les assiduités de scodoc",
)
@click.option(
"-j",
"--justificatifs",
is_flag=True,
help="Supprime les justificatifs de scodoc",
)
@with_appcontext
def downgrade_assiduites_module(
dept: str = None, assiduites: bool = False, justificatifs: bool = False
):
"""Supprime les assiduites et/ou les justificatifs de tous les départements ou du département sélectionné"""
tools.downgrade_module(dept, assiduites, justificatifs)
@app.cli.command()
@click.argument("dept", default="")
@with_appcontext

View File

@ -9,3 +9,4 @@ from tools.import_scodoc7_dept import import_scodoc7_dept
from tools.migrate_scodoc7_archives import migrate_scodoc7_dept_archives
from tools.migrate_scodoc7_logos import migrate_scodoc7_dept_logos
from tools.migrate_abs_to_assiduites import migrate_abs_to_assiduites
from tools.downgrade_assiduites import downgrade_module

View File

@ -0,0 +1,50 @@
from app import db
from app.models import Justificatif, Assiduite, Departement
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
from app.scodoc.sco_utils import ProgressBarColors
def downgrade_module(
dept: str = None, assiduites: bool = False, justificatifs: bool = False
):
dept_etudid: list[int] = None
dept_id: int = None
if dept is not None:
departement: Departement = Departement.query.filter_by(acronym=dept).first()
assert departement is not None, "Le département n'existe pas."
dept_etudid = [etud.id for etud in departement.etudiants]
dept_id = departement.id
if assiduites:
_remove_assiduites(dept_etudid)
if justificatifs:
_remove_justificatifs(dept_etudid)
_remove_justificatifs_archive(dept_id)
db.session.commit()
print(
f"{ProgressBarColors.GREEN}Le module assiduité a bien été remis à zero.{ProgressBarColors.RESET}"
)
def _remove_assiduites(dept_etudid: str = None):
if dept_etudid is None:
Assiduite.query.delete()
else:
Assiduite.query.filter(Assiduite.etudid.in_(dept_etudid)).delete()
def _remove_justificatifs(dept_etudid: str = None):
if dept_etudid is None:
Justificatif.query.delete()
else:
Justificatif.query.filter(Justificatif.etudid.in_(dept_etudid)).delete()
def _remove_justificatifs_archive(dept_id: int = None):
JustificatifArchiver().remove_dept_archive(dept_id)

View File

@ -16,19 +16,113 @@ from app.scodoc.sco_utils import (
ProgressBarColors,
printProgressBar,
)
from datetime import time, datetime, date
from datetime import time, datetime, date, timedelta
from json import dump, dumps
from sqlalchemy import not_
class _Merger:
""""""
class _glob:
DUPLICATIONS_ASSIDUITES: dict[tuple[date, bool, int], Assiduite] = {}
DUPLICATIONS_JUSTIFICATIFS: dict[tuple[date, bool, int], Justificatif] = {}
DUPLICATED: list[Justificatif] = []
PROBLEMS: dict[int, list[str]] = {}
CURRENT_ETU: list = []
MODULES: list[tuple[int, int]] = []
COMPTE: list[int, int] = []
ERR_ETU: list[int] = []
MERGER: _Merger = None
MORNING: time = None
NOON: time = None
EVENING: time = None
class _Merger:
def __init__(self, abs: Absence) -> None:
self.deb = (abs.jour, abs.matin)
self.fin = (abs.jour, abs.matin)
self.moduleimpl = abs.moduleimpl_id
self.etudid = abs.etudid
self.est_abs = abs.estabs
self.est_just = abs.estjust
self.raison = abs.description
def merge(self, abs: Absence) -> bool:
if self.etudid != abs.etudid:
return False
# Cas d'une même absence enregistrée plusieurs fois
if self.fin == (abs.jour, abs.matin):
self.est_abs |= abs.estabs
self.est_just |= abs.estjust
self.moduleimpl = None
else:
if self.est_abs != abs.estabs or self.est_just != abs.estjust:
return False
if self.fin[1]:
if abs.jour != self.fin[0]:
return False
else:
if abs.jour - timedelta(days=1) != self.fin[0]:
return False
self.fin = (abs.jour, abs.matin)
return True
@staticmethod
def _tuple_to_date(tuple, end=False):
if tuple[1]:
time_ = _glob.NOON if end else _glob.MORNING
date_ = datetime.combine(tuple[0], time_)
else:
time_ = _glob.EVENING if end else _glob.NOON
date_ = datetime.combine(tuple[0], time_)
d = localize_datetime(date_)
return d
def _to_justif(self):
date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True)
retour = Justificatif.fast_create_justificatif(
etudid=self.etudid,
date_debut=date_deb,
date_fin=date_fin,
etat=EtatJustificatif.VALIDE,
raison=self.raison,
)
return retour
def _to_assi(self):
date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True)
retour = Assiduite.fast_create_assiduite(
etudid=self.etudid,
date_debut=date_deb,
date_fin=date_fin,
etat=EtatAssiduite.ABSENT,
moduleimpl_id=self.moduleimpl,
description=self.raison,
)
return retour
def export(self):
objects = []
if self.est_abs:
_glob.COMPTE[0] += 1
objects.append(self._to_assi())
if self.est_just:
_glob.COMPTE[1] += 1
objects.append(self._to_justif())
db.session.add_all(objects)
class _Statistics:
@ -116,22 +210,22 @@ def migrate_abs_to_assiduites(
time_elapsed.start()
if morning is None:
pref_time_morning = time(8, 0)
_glob.MORNING = time(8, 0)
else:
morning: list[str] = morning.split("h")
pref_time_morning = time(int(morning[0]), int(morning[1]))
_glob.MORNING = time(int(morning[0]), int(morning[1]))
if noon is None:
pref_time_noon = time(12, 0)
_glob.NOON = time(12, 0)
else:
noon: list[str] = noon.split("h")
pref_time_noon = time(int(noon[0]), int(noon[1]))
_glob.NOON = time(int(noon[0]), int(noon[1]))
if evening is None:
pref_time_evening = time(18, 0)
_glob.EVENING = time(18, 0)
else:
evening: list[str] = evening.split("h")
pref_time_evening = time(int(evening[0]), int(evening[1]))
_glob.EVENING = time(int(evening[0]), int(evening[1]))
absences_query = Absence.query
if dept is not None:
@ -140,7 +234,9 @@ def migrate_abs_to_assiduites(
if dept is not None:
etuds_id: list[int] = [etud.id for etud in dept.etudiants]
absences_query = absences_query.filter(Absence.etudid.in_(etuds_id))
absences: Absence = absences_query.order_by(Absence.etudid)
absences: Absence = absences_query.order_by(
Absence.etudid, Absence.jour, not_(Absence.matin)
)
_glob.DUPLICATED = []
_glob.DUPLICATIONS_ASSIDUITES = {}
@ -160,25 +256,7 @@ def migrate_abs_to_assiduites(
for i, abs in enumerate(absences):
try:
if abs.estabs:
generated = _from_abs_to_assiduite(
abs, pref_time_morning, pref_time_noon, pref_time_evening
)
if not isinstance(generated, str):
db.session.add(generated)
_glob.COMPTE[0] += 1
except Exception as e:
stats.add_problem(abs, e.args[0])
try:
if abs.estjust:
generated = _from_abs_to_justificatif(
abs, pref_time_morning, pref_time_noon, pref_time_evening
)
if not isinstance(generated, str):
db.session.add(generated)
_glob.COMPTE[1] += 1
_from_abs_to_assiduite_justificatif(abs)
except Exception as e:
stats.add_problem(abs, e.args[0])
@ -225,12 +303,14 @@ def migrate_abs_to_assiduites(
)
print(
f"{ProgressBarColors.RED}{statistiques['total']} absences qui n'ont pas pu être migrée."
f"{ProgressBarColors.RED}{statistiques['total']} absences qui n'ont pas pu être migrées."
)
print(
f"Vous retrouverez un fichier json {ProgressBarColors.GREEN}/tmp/scodoc_migration_abs.json{ProgressBarColors.RED} contenant les problèmes de migrations"
f"Vous retrouverez un fichier json {ProgressBarColors.GREEN}/opt/scodoc-data/log/scodoc_migration_abs.json{ProgressBarColors.RED} contenant les problèmes de migrations"
)
with open("/tmp/scodoc_migration_abs.json", "w", encoding="utf-8") as file:
with open(
"/opt/scodoc-data/log/scodoc_migration_abs.json", "w", encoding="utf-8"
) as file:
stats.export(file)
print(
@ -240,32 +320,7 @@ def migrate_abs_to_assiduites(
print(dumps(statistiques, indent=2))
def _from_abs_to_assiduite(
_abs: Absence, morning: time, noon: time, evening: time
) -> Assiduite:
etat = EtatAssiduite.ABSENT
date_deb: datetime = None
date_fin: datetime = None
if _abs.matin:
date_deb = datetime.combine(_abs.jour, morning)
date_fin = datetime.combine(_abs.jour, noon)
else:
date_deb = datetime.combine(_abs.jour, noon)
date_fin = datetime.combine(_abs.jour, evening)
date_deb = localize_datetime(date_deb)
date_fin = localize_datetime(date_fin)
duplicata: Assiduite = _glob.DUPLICATIONS_ASSIDUITES.get(
(_abs.jour, _abs.matin, _abs.etudid)
)
if duplicata is not None:
_glob.DUPLICATED.append(duplicata)
return "Duplicata"
desc: str = _abs.description
entry_date: datetime = _abs.entry_date
def _from_abs_to_assiduite_justificatif(_abs: Absence):
if _abs.etudid not in _glob.CURRENT_ETU:
etud: Identite = Identite.query.filter_by(id=_abs.etudid).first()
@ -273,73 +328,24 @@ def _from_abs_to_assiduite(
raise Exception("Etudiant inexistant")
_glob.CURRENT_ETU.append(_abs.etudid)
moduleimpl_id: int = _abs.moduleimpl_id
if _abs.estabs:
moduleimpl_id: int = _abs.moduleimpl_id
if (
moduleimpl_id is not None
and (_abs.etudid, _abs.moduleimpl_id) not in _glob.MODULES
):
moduleimpl_inscription: ModuleImplInscription = (
ModuleImplInscription.query.filter_by(
moduleimpl_id=_abs.moduleimpl_id, etudid=_abs.etudid
).first()
)
if moduleimpl_inscription is None:
raise Exception("Moduleimpl_id incorrect ou étudiant non inscrit")
if (
moduleimpl_id is not None
and (_abs.etudid, _abs.moduleimpl_id) not in _glob.MODULES
):
moduleimpl_inscription: ModuleImplInscription = (
ModuleImplInscription.query.filter_by(
moduleimpl_id=_abs.moduleimpl_id, etudid=_abs.etudid
).first()
)
if moduleimpl_inscription is None:
raise Exception("Moduleimpl_id incorrect ou étudiant non inscrit")
retour = Assiduite.fast_create_assiduite(
etudid=_abs.etudid,
date_debut=date_deb,
date_fin=date_fin,
etat=etat,
moduleimpl_id=moduleimpl_id,
description=desc,
entry_date=entry_date,
)
_glob.DUPLICATIONS_ASSIDUITES[(_abs.jour, _abs.matin, _abs.etudid)] = retour
return retour
def _from_abs_to_justificatif(
_abs: Absence, morning: time, noon: time, evening: time
) -> Justificatif:
etat = EtatJustificatif.VALIDE
date_deb: datetime = None
date_fin: datetime = None
if _abs.matin:
date_deb = datetime.combine(_abs.jour, morning)
date_fin = datetime.combine(_abs.jour, noon)
if _glob.MERGER is None:
_glob.MERGER = _Merger(_abs)
elif _glob.MERGER.merge(_abs):
return True
else:
date_deb = datetime.combine(_abs.jour, noon)
date_fin = datetime.combine(_abs.jour, evening)
date_deb = localize_datetime(date_deb)
date_fin = localize_datetime(date_fin)
duplicata: Justificatif = _glob.DUPLICATIONS_JUSTIFICATIFS.get(
(_abs.jour, _abs.matin, _abs.etudid)
)
if duplicata is not None:
return "Duplicated"
desc: str = _abs.description
entry_date: datetime = _abs.entry_date
if _abs.etudid not in _glob.CURRENT_ETU:
etud: Identite = Identite.query.filter_by(id=_abs.etudid).first()
if etud is None:
raise Exception("Etudiant inexistant")
_glob.CURRENT_ETU.append(_abs.etudid)
retour = Justificatif.fast_create_justificatif(
etudid=_abs.etudid,
date_debut=date_deb,
date_fin=date_fin,
etat=etat,
raison=desc,
entry_date=entry_date,
)
_glob.DUPLICATIONS_JUSTIFICATIFS[(_abs.jour, _abs.matin, _abs.etudid)] = retour
return retour
_glob.MERGER.export()
_glob.MERGER = _Merger(_abs)