diff --git a/app/models/but_refcomp.py b/app/models/but_refcomp.py
index 425ff1923ca2682e8a942d08b188293f9104df5c..84dd2e1ca105fe79fca870ecc932434c9c4e87fc 100644
--- a/app/models/but_refcomp.py
+++ b/app/models/but_refcomp.py
@@ -53,7 +53,9 @@ class XMLModel:
class ApcReferentielCompetences(db.Model, XMLModel):
"Référentiel de compétence d'une spécialité"
id = db.Column(db.Integer, primary_key=True)
- dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
+ dept_id = db.Column(
+ db.Integer, db.ForeignKey("departement.id", ondelete="CASCADE"), index=True
+ )
annexe = db.Column(db.Text()) # '1', '22', ...
specialite = db.Column(db.Text()) # 'CJ', 'RT', 'INFO', ...
specialite_long = db.Column(
@@ -207,7 +209,9 @@ class ApcCompetence(db.Model, XMLModel):
"Compétence"
id = db.Column(db.Integer, primary_key=True)
referentiel_id = db.Column(
- db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False
+ db.Integer,
+ db.ForeignKey("apc_referentiel_competences.id", ondelete="CASCADE"),
+ nullable=False,
)
# les compétences dans Orébut sont identifiées par leur id unique
# (mais id_orebut n'est pas unique car le même ref. pourra être chargé dans plusieurs depts)
@@ -276,7 +280,9 @@ class ApcSituationPro(db.Model, XMLModel):
"Situation professionnelle"
id = db.Column(db.Integer, primary_key=True)
competence_id = db.Column(
- db.Integer, db.ForeignKey("apc_competence.id"), nullable=False
+ db.Integer,
+ db.ForeignKey("apc_competence.id", ondelete="CASCADE"),
+ nullable=False,
)
libelle = db.Column(db.Text(), nullable=False)
# aucun attribut (le text devient le libellé)
@@ -288,7 +294,9 @@ class ApcComposanteEssentielle(db.Model, XMLModel):
"Composante essentielle"
id = db.Column(db.Integer, primary_key=True)
competence_id = db.Column(
- db.Integer, db.ForeignKey("apc_competence.id"), nullable=False
+ db.Integer,
+ db.ForeignKey("apc_competence.id", ondelete="CASCADE"),
+ nullable=False,
)
libelle = db.Column(db.Text(), nullable=False)
@@ -306,7 +314,9 @@ class ApcNiveau(db.Model, XMLModel):
id = db.Column(db.Integer, primary_key=True)
competence_id = db.Column(
- db.Integer, db.ForeignKey("apc_competence.id"), nullable=False
+ db.Integer,
+ db.ForeignKey("apc_competence.id", ondelete="CASCADE"),
+ nullable=False,
)
libelle = db.Column(db.Text(), nullable=False)
annee = db.Column(db.Text(), nullable=False) # "BUT1", "BUT2", "BUT3"
@@ -387,7 +397,7 @@ app_critiques_modules = db.Table(
),
db.Column(
"app_crit_id",
- db.ForeignKey("apc_app_critique.id"),
+ db.ForeignKey("apc_app_critique.id", ondelete="CASCADE"),
primary_key=True,
),
)
@@ -396,7 +406,9 @@ app_critiques_modules = db.Table(
class ApcAppCritique(db.Model, XMLModel):
"Apprentissage Critique BUT"
id = db.Column(db.Integer, primary_key=True)
- niveau_id = db.Column(db.Integer, db.ForeignKey("apc_niveau.id"), nullable=False)
+ niveau_id = db.Column(
+ db.Integer, db.ForeignKey("apc_niveau.id", ondelete="CASCADE"), nullable=False
+ )
code = db.Column(db.Text(), nullable=False, index=True)
libelle = db.Column(db.Text())
@@ -445,7 +457,10 @@ class ApcAppCritique(db.Model, XMLModel):
parcours_modules = db.Table(
"parcours_modules",
db.Column(
- "parcours_id", db.Integer, db.ForeignKey("apc_parcours.id"), primary_key=True
+ "parcours_id",
+ db.Integer,
+ db.ForeignKey("apc_parcours.id", ondelete="CASCADE"),
+ primary_key=True,
),
db.Column(
"module_id",
@@ -459,7 +474,10 @@ parcours_modules = db.Table(
parcours_formsemestre = db.Table(
"parcours_formsemestre",
db.Column(
- "parcours_id", db.Integer, db.ForeignKey("apc_parcours.id"), primary_key=True
+ "parcours_id",
+ db.Integer,
+ db.ForeignKey("apc_parcours.id", ondelete="CASCADE"),
+ primary_key=True,
),
db.Column(
"formsemestre_id",
@@ -475,7 +493,9 @@ class ApcParcours(db.Model, XMLModel):
"Un parcours BUT"
id = db.Column(db.Integer, primary_key=True)
referentiel_id = db.Column(
- db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False
+ db.Integer,
+ db.ForeignKey("apc_referentiel_competences.id", ondelete="CASCADE"),
+ nullable=False,
)
numero = db.Column(db.Integer) # ordre de présentation
code = db.Column(db.Text(), nullable=False)
@@ -516,7 +536,7 @@ class ApcParcours(db.Model, XMLModel):
class ApcAnneeParcours(db.Model, XMLModel):
id = db.Column(db.Integer, primary_key=True)
parcours_id = db.Column(
- db.Integer, db.ForeignKey("apc_parcours.id"), nullable=False
+ db.Integer, db.ForeignKey("apc_parcours.id", ondelete="CASCADE"), nullable=False
)
ordre = db.Column(db.Integer)
"numéro de l'année: 1, 2, 3"
diff --git a/app/models/but_validations.py b/app/models/but_validations.py
index ccef89cd4d5d63eb9aad4d5ea8d7d5e62a93283b..9625d1e46918581cf5611c57269a68559ad41195 100644
--- a/app/models/but_validations.py
+++ b/app/models/but_validations.py
@@ -46,7 +46,9 @@ class ApcValidationRCUE(db.Model):
ue1_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)
ue2_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)
# optionnel, le parcours dans lequel se trouve la compétence:
- parcours_id = db.Column(db.Integer, db.ForeignKey("apc_parcours.id"), nullable=True)
+ parcours_id = db.Column(
+ db.Integer, db.ForeignKey("apc_parcours.id", ondelete="set null"), nullable=True
+ )
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
code = db.Column(db.String(CODE_STR_LEN), nullable=False, index=True)
diff --git a/app/models/formations.py b/app/models/formations.py
index d4aac9ad29273a93c92fd90eeab505b140445c50..8264fa81d3bab31beaa0fcbf9efa3b648cca06c3 100644
--- a/app/models/formations.py
+++ b/app/models/formations.py
@@ -48,7 +48,7 @@ class Formation(db.Model):
# Optionnel, pour les formations type BUT
referentiel_competence_id = db.Column(
- db.Integer, db.ForeignKey("apc_referentiel_competences.id")
+ db.Integer, db.ForeignKey("apc_referentiel_competences.id", ondelete="SET NULL")
)
ues = db.relationship("UniteEns", backref="formation", lazy="dynamic")
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index bafad116e7f1810a58df2cc623800ab078802bcc..f58a38b7215db8d3664f035180b49d39b47655b7 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -1037,7 +1037,9 @@ class FormSemestreInscription(db.Model):
# Etape Apogée d'inscription (ajout 2020)
etape = db.Column(db.String(APO_CODE_STR_LEN))
# Parcours (pour les BUT)
- parcour_id = db.Column(db.Integer, db.ForeignKey("apc_parcours.id"), index=True)
+ parcour_id = db.Column(
+ db.Integer, db.ForeignKey("apc_parcours.id", ondelete="SET NULL"), index=True
+ )
parcour = db.relationship(ApcParcours)
def __repr__(self):
diff --git a/app/models/ues.py b/app/models/ues.py
index 596e0bef6e378775670ae4193df0e8373a8f2bba..faa5df208acd9a69d1da02319f61c7efbeffe559 100644
--- a/app/models/ues.py
+++ b/app/models/ues.py
@@ -51,11 +51,15 @@ class UniteEns(db.Model):
color = db.Column(db.Text())
# BUT
- niveau_competence_id = db.Column(db.Integer, db.ForeignKey("apc_niveau.id"))
+ niveau_competence_id = db.Column(
+ db.Integer, db.ForeignKey("apc_niveau.id", ondelete="SET NULL")
+ )
niveau_competence = db.relationship("ApcNiveau", back_populates="ues")
# Une ue appartient soit à tous les parcours (tronc commun), soit à un seul:
- parcour_id = db.Column(db.Integer, db.ForeignKey("apc_parcours.id"), index=True)
+ parcour_id = db.Column(
+ db.Integer, db.ForeignKey("apc_parcours.id", ondelete="SET NULL"), index=True
+ )
parcour = db.relationship("ApcParcours", back_populates="ues")
# relations
diff --git a/app/models/validations.py b/app/models/validations.py
index f0ec9749ef994c5a257258688de9ca5f17ef7f66..20a4bb5871ebc8c041355a198ba5b8e20636ea64 100644
--- a/app/models/validations.py
+++ b/app/models/validations.py
@@ -160,11 +160,11 @@ class ScolarEvent(db.Model):
event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
formsemestre_id = db.Column(
db.Integer,
- db.ForeignKey("notes_formsemestre.id"),
+ db.ForeignKey("notes_formsemestre.id", ondelete="SET NULL"),
)
ue_id = db.Column(
db.Integer,
- db.ForeignKey("notes_ue.id"),
+ db.ForeignKey("notes_ue.id", ondelete="SET NULL"),
)
# 'CREATION', 'INSCRIPTION', 'DEMISSION',
# 'AUT_RED', 'EXCLUS', 'VALID_UE', 'VALID_SEM'
diff --git a/app/scodoc/sco_dept.py b/app/scodoc/sco_dept.py
index 6fdf92e4ae99b216a382ab47e421b40b32c19bfd..110a764ccbb42c40e44dc020ef93e816c73c9961 100644
--- a/app/scodoc/sco_dept.py
+++ b/app/scodoc/sco_dept.py
@@ -317,7 +317,7 @@ def _style_sems(sems):
] = f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['elt_sem_apo']}" """
-def delete_dept(dept_id: int):
+def delete_dept(dept_id: int) -> str:
"""Suppression irréversible d'un département et de tous les objets rattachés"""
assert isinstance(dept_id, int)
@@ -361,6 +361,7 @@ def delete_dept(dept_id: int):
)
reqs = [
+ "delete from apc_referentiel_competences where dept_id = %(dept_id)s",
"delete from identite where dept_id = %(dept_id)s",
"delete from sco_prefs where dept_id = %(dept_id)s",
"delete from notes_semset_formsemestre where formsemestre_id in (select id from formsemestres_temp)",
@@ -392,8 +393,10 @@ def delete_dept(dept_id: int):
]
for r in reqs:
cursor.execute(r, {"dept_id": dept_id})
- except:
+ except Exception as e:
cnx.rollback()
+ return str(e)
finally:
cnx.commit()
app.clear_scodoc_cache()
+ return ""
diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py
index 80a0b9c44a2d27ea95658f51a1f3ebeed049fb89..ad038ffe56097be6aeaa02c0867a2952bd61a0d7 100644
--- a/app/scodoc/sco_dump_db.py
+++ b/app/scodoc/sco_dump_db.py
@@ -28,8 +28,8 @@
"""Dump base de données pour debug et support technique
Le principe est le suivant:
- 1- S'il existe une base en cours d'anonymisation, s'arrête et affiche un msg d'erreur l'utilisateur,
- qui peut décider de la supprimer.
+ 1- S'il existe une base en cours d'anonymisation, s'arrête et affiche un msg
+ d'erreur à l'utilisateur, qui peut décider de la supprimer.
2- ScoDoc lance un script qui duplique la base (la copie de SCORT devient ANORT)
- (si elle existe deja, s'arrête)
@@ -49,9 +49,9 @@ pg_dump SCORT | psql ANORT
import base64
import fcntl
import os
-import requests
import subprocess
-import traceback
+
+import requests
from flask import g, request
from flask_login import current_user
@@ -59,9 +59,8 @@ from flask_login import current_user
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import log
-from app.scodoc import sco_users
-import sco_version
from app.scodoc.sco_exceptions import ScoValueError
+import sco_version
SCO_DUMP_LOCK = "/tmp/scodump.lock"
@@ -81,12 +80,10 @@ def sco_dump_and_send_db(
try:
x = open(SCO_DUMP_LOCK, "w+")
fcntl.flock(x, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except (IOError, OSError):
+ except (IOError, OSError) as e:
raise ScoValueError(
- "Un envoi de la base "
- + db_name
- + " est déjà en cours, re-essayer plus tard"
- )
+ "Un envoi de la base {db_name} est déjà en cours, re-essayer plus tard"
+ ) from e
try:
# Drop if exists
@@ -96,7 +93,7 @@ def sco_dump_and_send_db(
_duplicate_db(db_name, ano_db_name)
# Anonymisation
- _anonymize_db(ano_db_name)
+ anonymize_db(ano_db_name)
# Send
r = _send_db(ano_db_name, message, request_url, traceback_str=traceback_str)
@@ -116,44 +113,44 @@ def sco_dump_and_send_db(
def _duplicate_db(db_name, ano_db_name):
"""Create new database, and copy old one into"""
cmd = ["createdb", "-E", "UTF-8", ano_db_name]
- log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
+ log(f"sco_dump_and_send_db/_duplicate_db: {cmd}")
try:
_ = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
- log("sco_dump_and_send_db: exception createdb {}".format(e))
+ log(f"sco_dump_and_send_db: exception createdb {e}")
raise ScoValueError(
- "erreur lors de la creation de la base {}".format(ano_db_name)
- )
+ f"erreur lors de la creation de la base {ano_db_name}"
+ ) from e
- cmd = "pg_dump {} | psql {}".format(db_name, ano_db_name)
+ cmd = f"pg_dump {db_name} | psql {ano_db_name}"
log("sco_dump_and_send_db/_duplicate_db: {}".format(cmd))
try:
_ = subprocess.check_output(cmd, shell=1)
except subprocess.CalledProcessError as e:
log("sco_dump_and_send_db: exception {}".format(e))
raise ScoValueError(
- "erreur lors de la duplication de la base {} vers {}".format(
- db_name, ano_db_name
- )
- )
+ f"erreur lors de la duplication de la base {db_name} vers {ano_db_name}"
+ ) from e
-def _anonymize_db(ano_db_name):
- """Anonymize a departement database"""
+def anonymize_db(ano_db_name):
+ """Anonymize a ScoDoc database"""
cmd = os.path.join(scu.SCO_TOOLS_DIR, "anonymize_db.py")
- log("_anonymize_db: {}".format(cmd))
+ log(f"anonymize_db: {cmd}")
try:
_ = subprocess.check_output([cmd, ano_db_name])
except subprocess.CalledProcessError as e:
- log("sco_dump_and_send_db: exception in anonymisation: {}".format(e))
+ log(f"sco_dump_and_send_db: exception in anonymisation: {e}")
raise ScoValueError(
- "erreur lors de l'anonymisation de la base {}".format(ano_db_name)
- )
+ f"erreur lors de l'anonymisation de la base {ano_db_name}"
+ ) from e
def _get_scodoc_serial():
try:
- with open(os.path.join(scu.SCODOC_VERSION_DIR, "scodoc.sn")) as f:
+ with open(
+ os.path.join(scu.SCODOC_VERSION_DIR, "scodoc.sn"), encoding=scu.SCO_ENCODING
+ ) as f:
return int(f.read())
except:
return 0
diff --git a/migrations/versions/d8288b7f0a3e_cascades_ref_comp.py b/migrations/versions/d8288b7f0a3e_cascades_ref_comp.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e8e15ff51650fd4456b4b7e6ec2b7f9f5aafa90
--- /dev/null
+++ b/migrations/versions/d8288b7f0a3e_cascades_ref_comp.py
@@ -0,0 +1,415 @@
+"""cascades ref. comp.
+
+Revision ID: d8288b7f0a3e
+Revises: 5c7b208355df
+Create Date: 2023-02-09 11:25:28.879434
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = "d8288b7f0a3e"
+down_revision = "5c7b208355df"
+branch_labels = ""
+depends_on = ""
+
+
+def upgrade():
+ # EVENTS
+ op.drop_constraint(
+ "scolar_events_formsemestre_id_fkey", "scolar_events", type_="foreignkey"
+ )
+ op.drop_constraint("scolar_events_ue_id_fkey", "scolar_events", type_="foreignkey")
+ op.create_foreign_key(
+ "scolar_events_ue_id_fkey",
+ "scolar_events",
+ "notes_ue",
+ ["ue_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ op.create_foreign_key(
+ "scolar_events_formsemestre_id_fkey",
+ "scolar_events",
+ "notes_formsemestre",
+ ["formsemestre_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ # REF COMP
+ op.drop_constraint(
+ "apc_annee_parcours_parcours_id_fkey", "apc_annee_parcours", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_annee_parcours_parcours_id_fkey",
+ "apc_annee_parcours",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_app_critique_niveau_id_fkey", "apc_app_critique", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_app_critique_niveau_id_fkey",
+ "apc_app_critique",
+ "apc_niveau",
+ ["niveau_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_competence_referentiel_id_fkey", "apc_competence", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_competence_referentiel_id_fkey",
+ "apc_competence",
+ "apc_referentiel_competences",
+ ["referentiel_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_composante_essentielle_competence_id_fkey",
+ "apc_composante_essentielle",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_composante_essentielle_competence_id_fkey",
+ "apc_composante_essentielle",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_modules_acs_app_crit_id_fkey", "apc_modules_acs", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_modules_acs_app_crit_id_fkey",
+ "apc_modules_acs",
+ "apc_app_critique",
+ ["app_crit_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_niveau_competence_id_fkey", "apc_niveau", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_niveau_competence_id_fkey",
+ "apc_niveau",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_parcours_referentiel_id_fkey", "apc_parcours", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_parcours_referentiel_id_fkey",
+ "apc_parcours",
+ "apc_referentiel_competences",
+ ["referentiel_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_referentiel_competences_dept_id_fkey",
+ "apc_referentiel_competences",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_referentiel_competences_dept_id_fkey",
+ "apc_referentiel_competences",
+ "departement",
+ ["dept_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_situation_pro_competence_id_fkey", "apc_situation_pro", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_situation_pro_competence_id_fkey",
+ "apc_situation_pro",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "apc_validation_rcue_parcours_id_fkey",
+ "apc_validation_rcue",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_validation_rcue_parcours_id_fkey",
+ "apc_validation_rcue",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ ondelete="set null",
+ )
+ op.drop_constraint(
+ "notes_formations_referentiel_competence_id_fkey",
+ "notes_formations",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "notes_formations_referentiel_competence_id_fkey",
+ "notes_formations",
+ "apc_referentiel_competences",
+ ["referentiel_competence_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ op.drop_constraint(
+ "notes_formsemestre_inscription_parcour_id_fkey",
+ "notes_formsemestre_inscription",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "notes_formsemestre_inscription_parcour_id_fkey",
+ "notes_formsemestre_inscription",
+ "apc_parcours",
+ ["parcour_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ op.drop_constraint(
+ "notes_ue_niveau_competence_id_fkey", "notes_ue", type_="foreignkey"
+ )
+ op.drop_constraint("notes_ue_parcour_id_fkey", "notes_ue", type_="foreignkey")
+ op.create_foreign_key(
+ "notes_ue_niveau_competence_id_fkey",
+ "notes_ue",
+ "apc_niveau",
+ ["niveau_competence_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ op.create_foreign_key(
+ "notes_ue_parcour_id_fkey",
+ "notes_ue",
+ "apc_parcours",
+ ["parcour_id"],
+ ["id"],
+ ondelete="SET NULL",
+ )
+ op.drop_constraint(
+ "parcours_formsemestre_parcours_id_fkey",
+ "parcours_formsemestre",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "parcours_formsemestre_parcours_id_fkey",
+ "parcours_formsemestre",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ op.drop_constraint(
+ "parcours_modules_parcours_id_fkey", "parcours_modules", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "parcours_modules_parcours_id_fkey",
+ "parcours_modules",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_constraint(
+ "parcours_modules_parcours_id_fkey", "parcours_modules", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "parcours_modules_parcours_id_fkey",
+ "parcours_modules",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "parcours_formsemestre_parcours_id_fkey",
+ "parcours_formsemestre",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "parcours_formsemestre_parcours_id_fkey",
+ "parcours_formsemestre",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ )
+ op.drop_constraint("notes_ue_parcour_id_fkey", "notes_ue", type_="foreignkey")
+ op.drop_constraint(
+ "notes_ue_niveau_competence_id_fkey", "notes_ue", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "notes_ue_parcour_id_fkey", "notes_ue", "apc_parcours", ["parcour_id"], ["id"]
+ )
+ op.create_foreign_key(
+ "notes_ue_niveau_competence_id_fkey",
+ "notes_ue",
+ "apc_niveau",
+ ["niveau_competence_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "notes_formsemestre_inscription_parcour_id_fkey",
+ "notes_formsemestre_inscription",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "notes_formsemestre_inscription_parcour_id_fkey",
+ "notes_formsemestre_inscription",
+ "apc_parcours",
+ ["parcour_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "notes_formations_referentiel_competence_id_fkey",
+ "notes_formations",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "notes_formations_referentiel_competence_id_fkey",
+ "notes_formations",
+ "apc_referentiel_competences",
+ ["referentiel_competence_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_validation_rcue_parcours_id_fkey",
+ "apc_validation_rcue",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_validation_rcue_parcours_id_fkey",
+ "apc_validation_rcue",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_situation_pro_competence_id_fkey", "apc_situation_pro", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_situation_pro_competence_id_fkey",
+ "apc_situation_pro",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_referentiel_competences_dept_id_fkey",
+ "apc_referentiel_competences",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_referentiel_competences_dept_id_fkey",
+ "apc_referentiel_competences",
+ "departement",
+ ["dept_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_parcours_referentiel_id_fkey", "apc_parcours", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_parcours_referentiel_id_fkey",
+ "apc_parcours",
+ "apc_referentiel_competences",
+ ["referentiel_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_niveau_competence_id_fkey", "apc_niveau", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_niveau_competence_id_fkey",
+ "apc_niveau",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_modules_acs_app_crit_id_fkey", "apc_modules_acs", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_modules_acs_app_crit_id_fkey",
+ "apc_modules_acs",
+ "apc_app_critique",
+ ["app_crit_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_composante_essentielle_competence_id_fkey",
+ "apc_composante_essentielle",
+ type_="foreignkey",
+ )
+ op.create_foreign_key(
+ "apc_composante_essentielle_competence_id_fkey",
+ "apc_composante_essentielle",
+ "apc_competence",
+ ["competence_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_competence_referentiel_id_fkey", "apc_competence", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_competence_referentiel_id_fkey",
+ "apc_competence",
+ "apc_referentiel_competences",
+ ["referentiel_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_app_critique_niveau_id_fkey", "apc_app_critique", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_app_critique_niveau_id_fkey",
+ "apc_app_critique",
+ "apc_niveau",
+ ["niveau_id"],
+ ["id"],
+ )
+ op.drop_constraint(
+ "apc_annee_parcours_parcours_id_fkey", "apc_annee_parcours", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_annee_parcours_parcours_id_fkey",
+ "apc_annee_parcours",
+ "apc_parcours",
+ ["parcours_id"],
+ ["id"],
+ )
+ # EVENTS
+ op.drop_constraint("scolar_events_ue_id_fkey", "scolar_events", type_="foreignkey")
+ op.drop_constraint(
+ "scolar_events_formsemestre_id_fkey", "scolar_events", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "scolar_events_ue_id_fkey", "scolar_events", "notes_ue", ["ue_id"], ["id"]
+ )
+ op.create_foreign_key(
+ "scolar_events_formsemestre_id_fkey",
+ "scolar_events",
+ "notes_formsemestre",
+ ["formsemestre_id"],
+ ["id"],
+ )
+
+ # ### end Alembic commands ###
diff --git a/scodoc.py b/scodoc.py
index 12556c2c20c6a7659a273311b2c226437b711527..ec197aa73eedad8132c62c55d10ba4e521b87613 100755
--- a/scodoc.py
+++ b/scodoc.py
@@ -41,6 +41,7 @@ from app.models.but_refcomp import (
)
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
from app.models.evaluations import Evaluation
+from app.scodoc import sco_dump_db
from app.scodoc.sco_logos import make_logo_local
from app.scodoc.sco_permissions import Permission
from app.views import notes, scolar
@@ -131,6 +132,18 @@ def sco_db_init(erase=False): # sco-db-init
initialize_scodoc_database(erase=erase)
+@app.cli.command()
+@click.argument("database")
+def anonymize_db(database): # anonymize-db
+ """Anonymise la base de nom indiqué (et non pas la base courante!)"""
+ click.confirm(
+ f"L'anonymisation va affecter la base {database} et PERDRE beaucoup de données.\nContinuer ?",
+ abort=True,
+ )
+ sco_dump_db.anonymize_db(database)
+ click.echo(f"Base {database} pseudonymisée")
+
+
@app.cli.command()
def user_db_clear():
"""Erase all users and roles from the database !"""
@@ -397,9 +410,11 @@ def delete_dept(dept, force=False): # delete-dept
sys.stderr.write(f"Erreur: le departement {dept} n'existe pas !\n")
return 2
elif d:
- sco_dept.delete_dept(d.id)
+ msg = sco_dept.delete_dept(d.id)
db.session.commit()
- return 0
+ if msg:
+ print(f"Erreur:\n {msg}")
+ return 0 if not msg else 1
@app.cli.command()
diff --git a/tools/anonymize_db.py b/tools/anonymize_db.py
index a68250985f5a543ade20c5427601abcff8d11172..2e5040a255e66722b280279498f2336bd87cc6cd 100755
--- a/tools/anonymize_db.py
+++ b/tools/anonymize_db.py
@@ -26,8 +26,6 @@
#
##############################################################################
-# TODO à tester avec ScoDoc9, devrait fonctionner sans problème majeur ?
-
"""Anonymize une base de données ScoDoc
Runned as user "scodoc" with scodoc and postgresql up.