Merge pull request 'master' (#5) from ScoDoc/ScoDoc:master into master
Reviewed-on: lehmann/ScoDoc-Front#5
This commit is contained in:
commit
12e92b0c19
|
@ -190,6 +190,7 @@ def create_app(config_class=DevConfig):
|
|||
|
||||
app.register_error_handler(ScoGenError, handle_sco_value_error)
|
||||
app.register_error_handler(ScoValueError, handle_sco_value_error)
|
||||
|
||||
app.register_error_handler(AccessDenied, handle_access_denied)
|
||||
app.register_error_handler(500, internal_server_error)
|
||||
app.register_error_handler(503, postgresql_server_error)
|
||||
|
|
|
@ -72,10 +72,10 @@ def bulletin_but_xml_compat(
|
|||
etud = Identite.query.get_or_404(etudid)
|
||||
results = bulletin_but.ResultatsSemestreBUT(sem)
|
||||
nb_inscrits = len(results.etuds)
|
||||
if sem.bul_hide_xml or force_publishing:
|
||||
published = "1"
|
||||
if (not sem.bul_hide_xml) or force_publishing:
|
||||
published = 1
|
||||
else:
|
||||
published = "0"
|
||||
published = 0
|
||||
if xml_nodate:
|
||||
docdate = ""
|
||||
else:
|
||||
|
@ -84,7 +84,7 @@ def bulletin_but_xml_compat(
|
|||
"etudid": str(etudid),
|
||||
"formsemestre_id": str(formsemestre_id),
|
||||
"date": docdate,
|
||||
"publie": published,
|
||||
"publie": str(published),
|
||||
}
|
||||
if sem.etapes:
|
||||
el["etape_apo"] = sem.etapes[0].etape_apo or ""
|
||||
|
@ -117,7 +117,9 @@ def bulletin_but_xml_compat(
|
|||
)
|
||||
# Disponible pour publication ?
|
||||
if not published:
|
||||
return doc # stop !
|
||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(
|
||||
scu.SCO_ENCODING
|
||||
) # stop !
|
||||
# Moyenne générale:
|
||||
doc.append(
|
||||
Element(
|
||||
|
@ -218,7 +220,8 @@ def bulletin_but_xml_compat(
|
|||
value=scu.fmt_note(
|
||||
results.modimpls_evals_notes[e.moduleimpl_id][
|
||||
e.id
|
||||
][etud.id]
|
||||
][etud.id],
|
||||
note_max=e.note_max,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -36,6 +36,7 @@ import pandas as pd
|
|||
from pandas.core.frame import DataFrame
|
||||
|
||||
from app import db
|
||||
from app import log
|
||||
from app import models
|
||||
from app.models import ModuleImpl, Evaluation, EvaluationUEPoids
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
@ -79,7 +80,11 @@ def check_moduleimpl_conformity(
|
|||
if nb_ues == 0:
|
||||
return False # situation absurde (pas d'UE)
|
||||
if len(modules_coefficients) != nb_ues:
|
||||
raise ValueError("check_moduleimpl_conformity: nb ue incoherent")
|
||||
# bug ?
|
||||
log(
|
||||
"check_moduleimpl_conformity: nb ue incoherent (moduleimpl.id={moduleimpl.id})"
|
||||
)
|
||||
return False
|
||||
module_evals_poids = evals_poids.transpose().sum(axis=1).to_numpy() != 0
|
||||
check = all(
|
||||
(modules_coefficients[moduleimpl.module.id].to_numpy() != 0)
|
||||
|
|
|
@ -245,7 +245,7 @@ class DeptForm(FlaskForm):
|
|||
|
||||
|
||||
def _make_dept_id_name():
|
||||
"""Cette section assute que tous les départements sont traités (y compris ceux qu'ont pas de logo au départ)
|
||||
"""Cette section assure que tous les départements sont traités (y compris ceux qu'ont pas de logo au départ)
|
||||
et détermine l'ordre d'affichage des DeptForm (GLOBAL d'abord, puis par ordre alpha de nom de département)
|
||||
-> [ (None, None), (dept_id, dept_name)... ]"""
|
||||
depts = [(None, GLOBAL)]
|
||||
|
|
|
@ -31,16 +31,10 @@ Formulaires création département
|
|||
|
||||
from flask import flash, url_for, redirect, render_template
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SelectField, SubmitField, FormField, validators, FieldList
|
||||
from wtforms.fields.simple import StringField, HiddenField
|
||||
from wtforms import SubmitField, validators
|
||||
from wtforms.fields.simple import StringField, BooleanField
|
||||
|
||||
from app import AccessDenied
|
||||
from app.models import Departement
|
||||
from app.models import ScoPreference
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
from flask_login import current_user
|
||||
|
||||
|
||||
class CreateDeptForm(FlaskForm):
|
||||
|
@ -60,5 +54,10 @@ class CreateDeptForm(FlaskForm):
|
|||
validators.DataRequired("acronyme du département requis"),
|
||||
],
|
||||
)
|
||||
# description = StringField(label="Description")
|
||||
visible = BooleanField(
|
||||
"Visible sur page d'accueil",
|
||||
default=True,
|
||||
)
|
||||
submit = SubmitField("Valider")
|
||||
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
|
||||
|
|
|
@ -12,8 +12,10 @@ class Departement(db.Model):
|
|||
"""Un département ScoDoc"""
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
acronym = db.Column(db.String(SHORT_STR_LEN), nullable=False, index=True)
|
||||
description = db.Column(db.Text())
|
||||
acronym = db.Column(
|
||||
db.String(SHORT_STR_LEN), nullable=False, index=True
|
||||
) # ne change jamais, voir la pref. DeptName
|
||||
description = db.Column(db.Text()) # pas utilisé par ScoDoc : voir DeptFullName
|
||||
date_creation = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||
visible = db.Column(
|
||||
db.Boolean(), nullable=False, default=True, server_default="true"
|
||||
|
@ -49,11 +51,11 @@ class Departement(db.Model):
|
|||
return dept
|
||||
|
||||
|
||||
def create_dept(acronym: str) -> Departement:
|
||||
def create_dept(acronym: str, visible=True) -> Departement:
|
||||
"Create new departement"
|
||||
from app.models import ScoPreference
|
||||
|
||||
departement = Departement(acronym=acronym)
|
||||
departement = Departement(acronym=acronym, visible=visible)
|
||||
p1 = ScoPreference(name="DeptName", value=acronym, departement=departement)
|
||||
db.session.add(p1)
|
||||
db.session.add(departement)
|
||||
|
|
|
@ -97,14 +97,18 @@ class Formation(db.Model):
|
|||
for sem in self.formsemestres:
|
||||
sco_cache.invalidate_formsemestre(formsemestre_id=sem.id)
|
||||
|
||||
def force_semestre_modules_aux_ues(self) -> None:
|
||||
def sanitize_old_formation(self) -> None:
|
||||
"""
|
||||
Affecte à chaque module de cette formation le semestre de son UE de rattachement,
|
||||
Corrige si nécessaire certains champs issus d'anciennes versions de ScoDoc:
|
||||
- affecte à chaque module de cette formation le semestre de son UE de rattachement,
|
||||
si elle en a une.
|
||||
- si le module_type n'est pas renseigné, le met à STANDARD.
|
||||
|
||||
Devrait être appelé lorsqu'on change le type de formation vers le BUT, et aussi
|
||||
lorsqu'on change le semestre d'une UE BUT.
|
||||
Utile pour la migration des anciennes formations vers le BUT.
|
||||
Invalide les caches coefs/poids.
|
||||
|
||||
En cas de changement, invalide les caches coefs/poids.
|
||||
"""
|
||||
if not self.is_apc():
|
||||
return
|
||||
|
@ -118,6 +122,10 @@ class Formation(db.Model):
|
|||
mod.semestre_id = mod.ue.semestre_idx
|
||||
db.session.add(mod)
|
||||
change = True
|
||||
if mod.module_type is None:
|
||||
mod.module_type = scu.ModuleType.STANDARD
|
||||
db.session.add(mod)
|
||||
change = True
|
||||
db.session.commit()
|
||||
if change:
|
||||
self.invalidate_module_coefs()
|
||||
|
|
|
@ -49,9 +49,7 @@ class Module(db.Model):
|
|||
super(Module, self).__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"<Module{ModuleType(self.module_type).name} id={self.id} code={self.code}>"
|
||||
)
|
||||
return f"<Module{ModuleType(self.module_type or ModuleType.STANDARD).name} id={self.id} code={self.code}>"
|
||||
|
||||
def to_dict(self):
|
||||
e = dict(self.__dict__)
|
||||
|
|
|
@ -46,7 +46,10 @@ class UniteEns(db.Model):
|
|||
modules = db.relationship("Module", lazy="dynamic", backref="ue")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
||||
return f"""<{self.__class__.__name__}(id={self.id}, formation_id={
|
||||
self.formation_id}, acronyme='{self.acronyme}', semestre_idx={
|
||||
self.semestre_idx} {
|
||||
'EXTERNE' if self.is_external else ''})>"""
|
||||
|
||||
def to_dict(self):
|
||||
"""as a dict, with the same conversions as in ScoDoc7"""
|
||||
|
|
|
@ -416,6 +416,20 @@ def bonus_iutbeziers(notes_sport, coefs, infos=None):
|
|||
return bonus
|
||||
|
||||
|
||||
def bonus_iutlr(notes_sport, coefs, infos=None):
|
||||
"""Calcul bonus modules optionels (sport, culture), règle IUT La Rochelle
|
||||
Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point
|
||||
Si la note de sport est comprise entre 10.1 et 20 : ajout de 1% de cette note sur la moyenne générale du semestre
|
||||
"""
|
||||
# les coefs sont ignorés
|
||||
# une seule note
|
||||
note_sport = notes_sport[0]
|
||||
if note_sport <= 10:
|
||||
return 0
|
||||
bonus = note_sport * 0.01 # 1%
|
||||
return bonus
|
||||
|
||||
|
||||
def bonus_demo(notes_sport, coefs, infos=None):
|
||||
"""Fausse fonction "bonus" pour afficher les informations disponibles
|
||||
et aider les développeurs.
|
||||
|
|
|
@ -108,13 +108,14 @@ def apo_compare_csv(A_file, B_file, autodetect=True):
|
|||
|
||||
def _load_apo_data(csvfile, autodetect=True):
|
||||
"Read data from request variable and build ApoData"
|
||||
data = csvfile.read()
|
||||
data_b = csvfile.read()
|
||||
if autodetect:
|
||||
data, message = sco_apogee_csv.fix_data_encoding(data)
|
||||
data_b, message = sco_apogee_csv.fix_data_encoding(data_b)
|
||||
if message:
|
||||
log("apo_compare_csv: %s" % message)
|
||||
if not data:
|
||||
if not data_b:
|
||||
raise ScoValueError("apo_compare_csv: no data")
|
||||
data = data_b.decode(sco_apogee_csv.APO_INPUT_ENCODING)
|
||||
apo_data = sco_apogee_csv.ApoData(data, orig_filename=csvfile.filename)
|
||||
return apo_data
|
||||
|
||||
|
|
|
@ -173,8 +173,10 @@ def guess_data_encoding(text, threshold=0.6):
|
|||
|
||||
|
||||
def fix_data_encoding(
|
||||
text, default_source_encoding=APO_INPUT_ENCODING, dest_encoding=APO_INPUT_ENCODING
|
||||
):
|
||||
text: bytes,
|
||||
default_source_encoding=APO_INPUT_ENCODING,
|
||||
dest_encoding=APO_INPUT_ENCODING,
|
||||
) -> bytes:
|
||||
"""Try to ensure that text is using dest_encoding
|
||||
returns converted text, and a message describing the conversion.
|
||||
"""
|
||||
|
@ -200,7 +202,7 @@ def fix_data_encoding(
|
|||
|
||||
|
||||
class StringIOFileLineWrapper(object):
|
||||
def __init__(self, data):
|
||||
def __init__(self, data: str):
|
||||
self.f = io.StringIO(data)
|
||||
self.lineno = 0
|
||||
|
||||
|
@ -655,7 +657,7 @@ class ApoEtud(dict):
|
|||
class ApoData(object):
|
||||
def __init__(
|
||||
self,
|
||||
data,
|
||||
data: str,
|
||||
periode=None,
|
||||
export_res_etape=True,
|
||||
export_res_sem=True,
|
||||
|
@ -693,7 +695,7 @@ class ApoData(object):
|
|||
"<h3>Erreur lecture du fichier Apogée <tt>%s</tt></h3><p>" % filename
|
||||
+ e.args[0]
|
||||
+ "</p>"
|
||||
)
|
||||
) from e
|
||||
self.etape_apogee = self.get_etape_apogee() # 'V1RT'
|
||||
self.vdi_apogee = self.get_vdi_apogee() # '111'
|
||||
self.etape = ApoEtapeVDI(etape=self.etape_apogee, vdi=self.vdi_apogee)
|
||||
|
@ -760,7 +762,6 @@ class ApoData(object):
|
|||
def read_csv(self, data: str):
|
||||
if not data:
|
||||
raise ScoFormatError("Fichier Apogée vide !")
|
||||
|
||||
f = StringIOFileLineWrapper(data) # pour traiter comme un fichier
|
||||
# check that we are at the begining of Apogee CSV
|
||||
line = f.readline().strip()
|
||||
|
@ -768,7 +769,10 @@ class ApoData(object):
|
|||
raise ScoFormatError("format incorrect: pas de XX-APO_TITRES-XX")
|
||||
|
||||
# 1-- En-tête: du début jusqu'à la balise XX-APO_VALEURS-XX
|
||||
idx = data.index("XX-APO_VALEURS-XX")
|
||||
try:
|
||||
idx = data.index("XX-APO_VALEURS-XX")
|
||||
except ValueError as exc:
|
||||
raise ScoFormatError("format incorrect: pas de XX-APO_VALEURS-XX") from exc
|
||||
self.header = data[:idx]
|
||||
|
||||
# 2-- Titres:
|
||||
|
@ -1178,7 +1182,7 @@ def nar_etuds_table(apo_data, NAR_Etuds):
|
|||
|
||||
|
||||
def export_csv_to_apogee(
|
||||
apo_csv_data,
|
||||
apo_csv_data: str,
|
||||
periode=None,
|
||||
dest_zip=None,
|
||||
export_res_etape=True,
|
||||
|
|
|
@ -93,9 +93,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||
)
|
||||
|
||||
if (not sem["bul_hide_xml"]) or force_publishing:
|
||||
published = "1"
|
||||
published = 1
|
||||
else:
|
||||
published = "0"
|
||||
published = 0
|
||||
if xml_nodate:
|
||||
docdate = ""
|
||||
else:
|
||||
|
@ -105,7 +105,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||
"etudid": str(etudid),
|
||||
"formsemestre_id": str(formsemestre_id),
|
||||
"date": docdate,
|
||||
"publie": published,
|
||||
"publie": str(published),
|
||||
}
|
||||
if sem["etapes"]:
|
||||
el["etape_apo"] = str(sem["etapes"][0]) or ""
|
||||
|
@ -141,7 +141,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||
|
||||
# Disponible pour publication ?
|
||||
if not published:
|
||||
return doc # stop !
|
||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(
|
||||
scu.SCO_ENCODING
|
||||
) # stop !
|
||||
|
||||
# Groupes:
|
||||
partitions = sco_groups.get_partitions_list(formsemestre_id, with_default=False)
|
||||
|
|
|
@ -62,7 +62,8 @@ def html_edit_formation_apc(
|
|||
else:
|
||||
semestre_ids = [semestre_idx]
|
||||
other_modules = formation.modules.filter(
|
||||
Module.module_type != ModuleType.SAE, Module.module_type != ModuleType.RESSOURCE
|
||||
Module.module_type.is_distinct_from(ModuleType.SAE),
|
||||
Module.module_type.is_distinct_from(ModuleType.RESSOURCE),
|
||||
).order_by(
|
||||
Module.semestre_id, Module.module_type.desc(), Module.numero, Module.code
|
||||
)
|
||||
|
@ -78,7 +79,8 @@ def html_edit_formation_apc(
|
|||
alt="supprimer",
|
||||
),
|
||||
"delete_disabled": scu.icontag(
|
||||
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
|
||||
"delete_small_dis_img",
|
||||
title="Suppression impossible (utilisé dans des semestres)",
|
||||
),
|
||||
}
|
||||
|
||||
|
|
|
@ -304,9 +304,9 @@ def do_formation_edit(args):
|
|||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
sco_formations._formationEditor.edit(cnx, args)
|
||||
formation = Formation.query.get(args["formation_id"])
|
||||
formation: Formation = Formation.query.get(args["formation_id"])
|
||||
formation.invalidate_cached_sems()
|
||||
formation.force_semestre_modules_aux_ues()
|
||||
formation.sanitize_old_formation()
|
||||
|
||||
|
||||
def module_move(module_id, after=0, redirect=True):
|
||||
|
|
|
@ -30,13 +30,18 @@
|
|||
"""
|
||||
import flask
|
||||
from flask import g, url_for, request
|
||||
from app.models.formations import Matiere
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app import log
|
||||
from app.models import Formation
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
|
||||
from app.scodoc.sco_exceptions import (
|
||||
ScoValueError,
|
||||
ScoLockedFormError,
|
||||
ScoNonEmptyFormationObject,
|
||||
)
|
||||
from app.scodoc import html_sco_header
|
||||
|
||||
_matiereEditor = ndb.EditableTable(
|
||||
|
@ -156,6 +161,16 @@ associé.
|
|||
return flask.redirect(dest_url)
|
||||
|
||||
|
||||
def can_delete_matiere(matiere: Matiere) -> tuple[bool, str]:
|
||||
"True si la matiere n'est pas utilisée dans des formsemestre"
|
||||
locked = matiere_is_locked(matiere.id)
|
||||
if locked:
|
||||
return False
|
||||
if any(m.modimpls.all() for m in matiere.modules):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def do_matiere_delete(oid):
|
||||
"delete matiere and attached modules"
|
||||
from app.scodoc import sco_formations
|
||||
|
@ -165,17 +180,16 @@ def do_matiere_delete(oid):
|
|||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
# check
|
||||
mat = matiere_list({"matiere_id": oid})[0]
|
||||
matiere = Matiere.query.get_or_404(oid)
|
||||
mat = matiere_list({"matiere_id": oid})[0] # compat sco7
|
||||
ue = sco_edit_ue.ue_list({"ue_id": mat["ue_id"]})[0]
|
||||
locked = matiere_is_locked(mat["matiere_id"])
|
||||
if locked:
|
||||
log("do_matiere_delete: mat=%s" % mat)
|
||||
log("do_matiere_delete: ue=%s" % ue)
|
||||
log("do_matiere_delete: locked sems: %s" % locked)
|
||||
raise ScoLockedFormError()
|
||||
log("do_matiere_delete: matiere_id=%s" % oid)
|
||||
if not can_delete_matiere(matiere):
|
||||
# il y a au moins un modimpl dans un module de cette matière
|
||||
raise ScoNonEmptyFormationObject("Matière", matiere.titre)
|
||||
|
||||
log("do_matiere_delete: matiere_id=%s" % matiere.id)
|
||||
# delete all modules in this matiere
|
||||
mods = sco_edit_module.module_list({"matiere_id": oid})
|
||||
mods = sco_edit_module.module_list({"matiere_id": matiere.id})
|
||||
for mod in mods:
|
||||
sco_edit_module.do_module_delete(mod["module_id"])
|
||||
_matiereEditor.delete(cnx, oid)
|
||||
|
@ -194,11 +208,25 @@ def matiere_delete(matiere_id=None):
|
|||
"""Delete matière"""
|
||||
from app.scodoc import sco_edit_ue
|
||||
|
||||
M = matiere_list(args={"matiere_id": matiere_id})[0]
|
||||
UE = sco_edit_ue.ue_list(args={"ue_id": M["ue_id"]})[0]
|
||||
matiere = Matiere.query.get_or_404(matiere_id)
|
||||
if not can_delete_matiere(matiere):
|
||||
# il y a au moins un modimpl dans un module de cette matière
|
||||
raise ScoNonEmptyFormationObject(
|
||||
"Matière",
|
||||
matiere.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table",
|
||||
formation_id=matiere.ue.formation_id,
|
||||
semestre_idx=matiere.ue.semestre_idx,
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
),
|
||||
)
|
||||
|
||||
mat = matiere_list(args={"matiere_id": matiere_id})[0]
|
||||
UE = sco_edit_ue.ue_list(args={"ue_id": mat["ue_id"]})[0]
|
||||
H = [
|
||||
html_sco_header.sco_header(page_title="Suppression d'une matière"),
|
||||
"<h2>Suppression de la matière %(titre)s" % M,
|
||||
"<h2>Suppression de la matière %(titre)s" % mat,
|
||||
" dans l'UE (%(acronyme)s))</h2>" % UE,
|
||||
]
|
||||
dest_url = url_for(
|
||||
|
@ -210,7 +238,7 @@ def matiere_delete(matiere_id=None):
|
|||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
(("matiere_id", {"input_type": "hidden"}),),
|
||||
initvalues=M,
|
||||
initvalues=mat,
|
||||
submitlabel="Confirmer la suppression",
|
||||
cancelbutton="Annuler",
|
||||
)
|
||||
|
|
|
@ -43,7 +43,12 @@ from app import models
|
|||
from app.models import Formation
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError, ScoGenError
|
||||
from app.scodoc.sco_exceptions import (
|
||||
ScoValueError,
|
||||
ScoLockedFormError,
|
||||
ScoGenError,
|
||||
ScoNonEmptyFormationObject,
|
||||
)
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_edit_matiere
|
||||
|
@ -330,20 +335,37 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||
)
|
||||
|
||||
|
||||
def can_delete_module(module):
|
||||
"True si le module n'est pas utilisée dans des formsemestre"
|
||||
return len(module.modimpls.all()) == 0
|
||||
|
||||
|
||||
def do_module_delete(oid):
|
||||
"delete module"
|
||||
from app.scodoc import sco_formations
|
||||
|
||||
mod = module_list({"module_id": oid})[0]
|
||||
if module_is_locked(mod["module_id"]):
|
||||
module = Module.query.get_or_404(oid)
|
||||
mod = module_list({"module_id": oid})[0] # sco7
|
||||
if module_is_locked(module.id):
|
||||
raise ScoLockedFormError()
|
||||
if not can_delete_module(module):
|
||||
raise ScoNonEmptyFormationObject(
|
||||
"Module",
|
||||
msg=module.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=module.formation_id,
|
||||
semestre_idx=module.ue.semestre_idx,
|
||||
),
|
||||
)
|
||||
|
||||
# S'il y a des moduleimpls, on ne peut pas detruire le module !
|
||||
mods = sco_moduleimpl.moduleimpl_list(module_id=oid)
|
||||
if mods:
|
||||
err_page = f"""<h3>Destruction du module impossible car il est utilisé dans des semestres existants !</h3>
|
||||
<p class="help">Il faut d'abord supprimer le semestre. Mais il est peut être préférable de
|
||||
laisser ce programme intact et d'en créer une nouvelle version pour la modifier.
|
||||
<p class="help">Il faut d'abord supprimer le semestre (ou en retirer ce module). Mais il est peut être préférable de
|
||||
laisser ce programme intact et d'en créer une nouvelle version pour la modifier sans affecter les semestres déjà en place.
|
||||
</p>
|
||||
<a href="{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
|
||||
formation_id=mod["formation_id"])}">reprendre</a>
|
||||
|
@ -365,12 +387,21 @@ def do_module_delete(oid):
|
|||
|
||||
def module_delete(module_id=None):
|
||||
"""Delete a module"""
|
||||
if not module_id:
|
||||
raise ScoValueError("invalid module !")
|
||||
modules = module_list(args={"module_id": module_id})
|
||||
if not modules:
|
||||
raise ScoValueError("Module inexistant !")
|
||||
mod = modules[0]
|
||||
module = Module.query.get_or_404(module_id)
|
||||
mod = module_list(args={"module_id": module_id})[0] # sco7
|
||||
|
||||
if not can_delete_module(module):
|
||||
raise ScoNonEmptyFormationObject(
|
||||
"Module",
|
||||
msg=module.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=module.formation_id,
|
||||
semestre_idx=module.ue.semestre_idx,
|
||||
),
|
||||
)
|
||||
|
||||
H = [
|
||||
html_sco_header.sco_header(page_title="Suppression d'un module"),
|
||||
"""<h2>Suppression du module %(titre)s (%(code)s)</h2>""" % mod,
|
||||
|
|
|
@ -42,7 +42,12 @@ from app import log
|
|||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
|
||||
from app.scodoc.sco_exceptions import (
|
||||
ScoGenError,
|
||||
ScoValueError,
|
||||
ScoLockedFormError,
|
||||
ScoNonEmptyFormationObject,
|
||||
)
|
||||
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_cache
|
||||
|
@ -130,64 +135,83 @@ def do_ue_create(args):
|
|||
return ue_id
|
||||
|
||||
|
||||
def can_delete_ue(ue: UniteEns) -> bool:
|
||||
"""True si l'UE n'est pas utilisée dans des formsemestre
|
||||
et n'a pas de module rattachés
|
||||
"""
|
||||
# "pas un seul module de cette UE n'a de modimpl...""
|
||||
return (not len(ue.modules.all())) and not any(m.modimpls.all() for m in ue.modules)
|
||||
|
||||
|
||||
def do_ue_delete(ue_id, delete_validations=False, force=False):
|
||||
"delete UE and attached matieres (but not modules)"
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_parcours_dut
|
||||
|
||||
ue = UniteEns.query.get_or_404(ue_id)
|
||||
if not can_delete_ue(ue):
|
||||
raise ScoNonEmptyFormationObject(
|
||||
"UE",
|
||||
msg=ue.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=ue.formation_id,
|
||||
semestre_idx=ue.semestre_idx,
|
||||
),
|
||||
)
|
||||
|
||||
cnx = ndb.GetDBConnexion()
|
||||
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue_id, delete_validations))
|
||||
log("do_ue_delete: ue_id=%s, delete_validations=%s" % (ue.id, delete_validations))
|
||||
# check
|
||||
ue = ue_list({"ue_id": ue_id})
|
||||
if not ue:
|
||||
raise ScoValueError("UE inexistante !")
|
||||
ue = ue[0]
|
||||
if ue_is_locked(ue["ue_id"]):
|
||||
raise ScoLockedFormError()
|
||||
# if ue_is_locked(ue.id):
|
||||
# raise ScoLockedFormError()
|
||||
# Il y a-t-il des etudiants ayant validé cette UE ?
|
||||
# si oui, propose de supprimer les validations
|
||||
validations = sco_parcours_dut.scolar_formsemestre_validation_list(
|
||||
cnx, args={"ue_id": ue_id}
|
||||
cnx, args={"ue_id": ue.id}
|
||||
)
|
||||
if validations and not delete_validations and not force:
|
||||
return scu.confirm_dialog(
|
||||
"<p>%d étudiants ont validé l'UE %s (%s)</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p>"
|
||||
% (len(validations), ue["acronyme"], ue["titre"]),
|
||||
% (len(validations), ue.acronyme, ue.titre),
|
||||
dest_url="",
|
||||
target_variable="delete_validations",
|
||||
cancel_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=str(ue["formation_id"]),
|
||||
formation_id=ue.formation_id,
|
||||
semestre_idx=ue.semestre_idx,
|
||||
),
|
||||
parameters={"ue_id": ue_id, "dialog_confirmed": 1},
|
||||
parameters={"ue_id": ue.id, "dialog_confirmed": 1},
|
||||
)
|
||||
if delete_validations:
|
||||
log("deleting all validations of UE %s" % ue_id)
|
||||
log("deleting all validations of UE %s" % ue.id)
|
||||
ndb.SimpleQuery(
|
||||
"DELETE FROM scolar_formsemestre_validation WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue_id},
|
||||
{"ue_id": ue.id},
|
||||
)
|
||||
|
||||
# delete all matiere in this UE
|
||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
|
||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
|
||||
for mat in mats:
|
||||
sco_edit_matiere.do_matiere_delete(mat["matiere_id"])
|
||||
# delete uecoef and events
|
||||
ndb.SimpleQuery(
|
||||
"DELETE FROM notes_formsemestre_uecoef WHERE ue_id=%(ue_id)s",
|
||||
{"ue_id": ue_id},
|
||||
{"ue_id": ue.id},
|
||||
)
|
||||
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue_id})
|
||||
ndb.SimpleQuery("DELETE FROM scolar_events WHERE ue_id=%(ue_id)s", {"ue_id": ue.id})
|
||||
cnx = ndb.GetDBConnexion()
|
||||
_ueEditor.delete(cnx, ue_id)
|
||||
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement utilisé: acceptable de tout invalider ?):
|
||||
_ueEditor.delete(cnx, ue.id)
|
||||
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement
|
||||
# utilisé: acceptable de tout invalider):
|
||||
sco_cache.invalidate_formsemestre()
|
||||
# news
|
||||
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
|
||||
F = sco_formations.formation_list(args={"formation_id": ue.formation_id})[0]
|
||||
sco_news.add(
|
||||
typ=sco_news.NEWS_FORM,
|
||||
object=ue["formation_id"],
|
||||
object=ue.formation_id,
|
||||
text="Modification de la formation %(acronyme)s" % F,
|
||||
max_frequency=3,
|
||||
)
|
||||
|
@ -197,11 +221,11 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||
url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=ue["formation_id"],
|
||||
formation_id=ue.formation_id,
|
||||
semestre_idx=ue.semestre_idx,
|
||||
)
|
||||
)
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def ue_create(formation_id=None):
|
||||
|
@ -211,8 +235,6 @@ def ue_create(formation_id=None):
|
|||
|
||||
def ue_edit(ue_id=None, create=False, formation_id=None):
|
||||
"""Modification ou création d'une UE"""
|
||||
from app.scodoc import sco_formations
|
||||
|
||||
create = int(create)
|
||||
if not create:
|
||||
U = ue_list(args={"ue_id": ue_id})
|
||||
|
@ -444,36 +466,50 @@ def next_ue_numero(formation_id, semestre_id=None):
|
|||
|
||||
def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
|
||||
"""Delete an UE"""
|
||||
ues = ue_list(args={"ue_id": ue_id})
|
||||
if not ues:
|
||||
raise ScoValueError("UE inexistante !")
|
||||
ue = ues[0]
|
||||
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
"<h2>Suppression de l'UE %(titre)s (%(acronyme)s))</h2>" % ue,
|
||||
dest_url="",
|
||||
parameters={"ue_id": ue_id},
|
||||
cancel_url=url_for(
|
||||
ue = UniteEns.query.get_or_404(ue_id)
|
||||
if ue.modules.all():
|
||||
raise ScoValueError(
|
||||
f"""Suppression de l'UE {ue.titre} impossible car
|
||||
des modules (ou SAÉ ou ressources) lui sont rattachés."""
|
||||
)
|
||||
if not can_delete_ue(ue):
|
||||
raise ScoNonEmptyFormationObject(
|
||||
"UE",
|
||||
msg=ue.titre,
|
||||
dest_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=str(ue["formation_id"]),
|
||||
formation_id=ue.formation_id,
|
||||
semestre_idx=ue.semestre_idx,
|
||||
),
|
||||
)
|
||||
|
||||
return do_ue_delete(ue_id, delete_validations=delete_validations)
|
||||
if not dialog_confirmed:
|
||||
return scu.confirm_dialog(
|
||||
f"<h2>Suppression de l'UE {ue.titre} ({ue.acronyme})</h2>",
|
||||
dest_url="",
|
||||
parameters={"ue_id": ue.id},
|
||||
cancel_url=url_for(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=ue.formation_id,
|
||||
semestre_idx=ue.semestre_idx,
|
||||
),
|
||||
)
|
||||
|
||||
return do_ue_delete(ue.id, delete_validations=delete_validations)
|
||||
|
||||
|
||||
def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
||||
"""Liste des matières et modules d'une formation, avec liens pour
|
||||
éditer (si non verrouillée).
|
||||
"""
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_formsemestre_validation
|
||||
|
||||
formation = Formation.query.get(formation_id)
|
||||
formation: Formation = Formation.query.get(formation_id)
|
||||
if not formation:
|
||||
raise ScoValueError("invalid formation_id")
|
||||
formation.sanitize_old_formation()
|
||||
parcours = formation.get_parcours()
|
||||
is_apc = parcours.APC_SAE
|
||||
locked = formation.has_locked_sems()
|
||||
|
@ -1010,12 +1046,14 @@ def _ue_table_modules(
|
|||
H.append(arrow_none)
|
||||
im += 1
|
||||
if mod["nb_moduleimpls"] == 0 and editable:
|
||||
H.append(
|
||||
'<a class="smallbutton" href="module_delete?module_id=%s">%s</a>'
|
||||
% (mod["module_id"], delete_icon)
|
||||
)
|
||||
icon = delete_icon
|
||||
else:
|
||||
H.append(delete_disabled_icon)
|
||||
icon = delete_disabled_icon
|
||||
H.append(
|
||||
'<a class="smallbutton" href="module_delete?module_id=%s">%s</a>'
|
||||
% (mod["module_id"], icon)
|
||||
)
|
||||
|
||||
H.append("</span>")
|
||||
|
||||
mod_editable = (
|
||||
|
@ -1167,7 +1205,7 @@ def do_ue_edit(args, bypass_lock=False, dont_invalidate_cache=False):
|
|||
if not dont_invalidate_cache:
|
||||
# Invalide les semestres utilisant cette formation:
|
||||
formation.invalidate_cached_sems()
|
||||
formation.force_semestre_modules_aux_ues()
|
||||
formation.sanitize_old_formation()
|
||||
|
||||
|
||||
# essai edition en ligne:
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
apo_csv_get()
|
||||
|
||||
API:
|
||||
apo_csv_store( annee_scolaire, sem_id)
|
||||
# apo_csv_store(csv_data, annee_scolaire, sem_id)
|
||||
store maq file (archive)
|
||||
|
||||
apo_csv_get(etape_apo, annee_scolaire, sem_id, vdi_apo=None)
|
||||
|
@ -101,7 +101,7 @@ ApoCSVArchive = ApoCSVArchiver()
|
|||
|
||||
def apo_csv_store(csv_data: str, annee_scolaire, sem_id):
|
||||
"""
|
||||
csv_data: maquette content (string)
|
||||
csv_data: maquette content (str))
|
||||
annee_scolaire: int (2016)
|
||||
sem_id: 0 (année ?), 1 (premier semestre de l'année) ou 2 (deuxième semestre)
|
||||
:return: etape_apo du fichier CSV stocké
|
||||
|
@ -378,7 +378,7 @@ e.associate_sco( apo_data)
|
|||
print apo_csv_list_stored_archives()
|
||||
|
||||
|
||||
apo_csv_store(csv_data, annee_scolaire, sem_id)
|
||||
# apo_csv_store(csv_data, annee_scolaire, sem_id)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ from app.scodoc import sco_preferences
|
|||
from app.scodoc import sco_semset
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc.sco_apogee_csv import APO_PORTAL_ENCODING, APO_INPUT_ENCODING
|
||||
from app.scodoc.sco_apogee_csv import APO_INPUT_ENCODING, APO_OUTPUT_ENCODING
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
|
@ -585,7 +585,7 @@ def _view_etuds_page(semset_id, title="", etuds=[], keys=(), format="html"):
|
|||
return "\n".join(H) + html_sco_header.sco_footer()
|
||||
|
||||
|
||||
def view_apo_csv_store(semset_id="", csvfile=None, data="", autodetect=False):
|
||||
def view_apo_csv_store(semset_id="", csvfile=None, data: bytes = "", autodetect=False):
|
||||
"""Store CSV data
|
||||
Le semset identifie l'annee scolaire et le semestre
|
||||
Si csvfile, lit depuis FILE, sinon utilise data
|
||||
|
@ -593,9 +593,8 @@ def view_apo_csv_store(semset_id="", csvfile=None, data="", autodetect=False):
|
|||
if not semset_id:
|
||||
raise ValueError("invalid null semset_id")
|
||||
semset = sco_semset.SemSet(semset_id=semset_id)
|
||||
|
||||
if csvfile:
|
||||
data = csvfile.read()
|
||||
data = csvfile.read() # bytes
|
||||
if autodetect:
|
||||
# check encoding (although documentation states that users SHOULD upload LATIN1)
|
||||
data, message = sco_apogee_csv.fix_data_encoding(data)
|
||||
|
@ -605,19 +604,26 @@ def view_apo_csv_store(semset_id="", csvfile=None, data="", autodetect=False):
|
|||
log("view_apo_csv_store: autodetection of encoding disabled by user")
|
||||
if not data:
|
||||
raise ScoValueError("view_apo_csv_store: no data")
|
||||
|
||||
# data est du bytes, encodé en APO_INPUT_ENCODING
|
||||
data_str = data.decode(APO_INPUT_ENCODING)
|
||||
# check si etape maquette appartient bien au semset
|
||||
apo_data = sco_apogee_csv.ApoData(
|
||||
data, periode=semset["sem_id"]
|
||||
data_str, periode=semset["sem_id"]
|
||||
) # parse le fichier -> exceptions
|
||||
if apo_data.etape not in semset["etapes"]:
|
||||
raise ScoValueError(
|
||||
"Le code étape de ce fichier ne correspond pas à ceux de cet ensemble"
|
||||
)
|
||||
|
||||
sco_etape_apogee.apo_csv_store(data, semset["annee_scolaire"], semset["sem_id"])
|
||||
sco_etape_apogee.apo_csv_store(data_str, semset["annee_scolaire"], semset["sem_id"])
|
||||
|
||||
return flask.redirect("apo_semset_maq_status?semset_id=" + semset_id)
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.apo_semset_maq_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
semset_id=semset_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def view_apo_csv_download_and_store(etape_apo="", semset_id=""):
|
||||
|
@ -629,9 +635,9 @@ def view_apo_csv_download_and_store(etape_apo="", semset_id=""):
|
|||
data = sco_portal_apogee.get_maquette_apogee(
|
||||
etape=etape_apo, annee_scolaire=semset["annee_scolaire"]
|
||||
)
|
||||
# here, data is utf8
|
||||
# here, data is str
|
||||
# but we store and generate latin1 files, to ease further import in Apogée
|
||||
data = data.decode(APO_PORTAL_ENCODING).encode(APO_INPUT_ENCODING) # XXX #py3
|
||||
data = data.encode(APO_OUTPUT_ENCODING)
|
||||
return view_apo_csv_store(semset_id, data=data, autodetect=False)
|
||||
|
||||
|
||||
|
@ -669,7 +675,7 @@ def view_apo_csv(etape_apo="", semset_id="", format="html"):
|
|||
sem_id = semset["sem_id"]
|
||||
csv_data = sco_etape_apogee.apo_csv_get(etape_apo, annee_scolaire, sem_id)
|
||||
if format == "raw":
|
||||
scu.send_file(csv_data, etape_apo, suffix=".txt", mime=scu.CSV_MIMETYPE)
|
||||
return scu.send_file(csv_data, etape_apo, suffix=".txt", mime=scu.CSV_MIMETYPE)
|
||||
|
||||
apo_data = sco_apogee_csv.ApoData(csv_data, periode=semset["sem_id"])
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class InvalidNoteValue(ScoException):
|
|||
# Exception qui stoque dest_url, utilisee dans Zope standard_error_message
|
||||
class ScoValueError(ScoException):
|
||||
def __init__(self, msg, dest_url=None):
|
||||
ScoException.__init__(self, msg)
|
||||
super().__init__(msg)
|
||||
self.dest_url = dest_url
|
||||
|
||||
|
||||
|
@ -72,20 +72,35 @@ class ScoConfigurationError(ScoValueError):
|
|||
pass
|
||||
|
||||
|
||||
class ScoLockedFormError(ScoException):
|
||||
def __init__(self, msg=""):
|
||||
class ScoLockedFormError(ScoValueError):
|
||||
"Modification d'une formation verrouillée"
|
||||
|
||||
def __init__(self, msg="", dest_url=None):
|
||||
msg = (
|
||||
"Cette formation est verrouillée (car il y a un semestre verrouillé qui s'y réfère). "
|
||||
+ str(msg)
|
||||
)
|
||||
ScoException.__init__(self, msg)
|
||||
super().__init__(msg=msg, dest_url=dest_url)
|
||||
|
||||
|
||||
class ScoNonEmptyFormationObject(ScoValueError):
|
||||
"""On ne peut pas supprimer un module/matiere ou UE si des formsemestre s'y réfèrent"""
|
||||
|
||||
def __init__(self, type_objet="objet'", msg="", dest_url=None):
|
||||
msg = f"""<h3>{type_objet} "{msg}" utilisé dans des semestres: suppression impossible.</h3>
|
||||
<p class="help">Il faut d'abord supprimer le semestre (ou en retirer ce {type_objet}).
|
||||
Mais il est peut-être préférable de laisser ce programme intact et d'en créer une
|
||||
nouvelle version pour la modifier sans affecter les semestres déjà en place.
|
||||
</p>
|
||||
"""
|
||||
super().__init__(msg=msg, dest_url=dest_url)
|
||||
|
||||
|
||||
class ScoGenError(ScoException):
|
||||
"exception avec affichage d'une page explicative ad-hoc"
|
||||
|
||||
def __init__(self, msg=""):
|
||||
ScoException.__init__(self, msg)
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
class AccessDenied(ScoGenError):
|
||||
|
@ -101,7 +116,7 @@ class APIInvalidParams(Exception):
|
|||
status_code = 400
|
||||
|
||||
def __init__(self, message, status_code=None, payload=None):
|
||||
Exception.__init__(self)
|
||||
super().__init__()
|
||||
self.message = message
|
||||
if status_code is not None:
|
||||
self.status_code = status_code
|
||||
|
|
|
@ -198,10 +198,13 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||
NB_SEM = parcours.NB_SEM
|
||||
else:
|
||||
NB_SEM = 10 # fallback, max 10 semestres
|
||||
semestre_id_list = [-1] + list(range(1, NB_SEM + 1))
|
||||
if NB_SEM == 1:
|
||||
semestre_id_list = [-1]
|
||||
else:
|
||||
semestre_id_list = [-1] + list(range(1, NB_SEM + 1))
|
||||
semestre_id_labels = []
|
||||
for sid in semestre_id_list:
|
||||
if sid == "-1":
|
||||
if sid == -1:
|
||||
semestre_id_labels.append("pas de semestres")
|
||||
else:
|
||||
semestre_id_labels.append(f"S{sid}")
|
||||
|
@ -329,6 +332,8 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||
"labels": modalites_titles,
|
||||
},
|
||||
),
|
||||
]
|
||||
modform.append(
|
||||
(
|
||||
"semestre_id",
|
||||
{
|
||||
|
@ -338,7 +343,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||
"labels": semestre_id_labels,
|
||||
},
|
||||
),
|
||||
]
|
||||
)
|
||||
etapes = sco_portal_apogee.get_etapes_apogee_dept()
|
||||
# Propose les etapes renvoyées par le portail
|
||||
# et ajoute les étapes du semestre qui ne sont pas dans la liste (soit la liste a changé, soit l'étape a été ajoutée manuellement)
|
||||
|
|
|
@ -292,6 +292,8 @@ def formsemestre_inscr_passage(
|
|||
etuds = [int(x) for x in etuds.split(",") if x]
|
||||
elif isinstance(etuds, int):
|
||||
etuds = [etuds]
|
||||
elif etuds and isinstance(etuds[0], str):
|
||||
etuds = [int(x) for x in etuds]
|
||||
|
||||
auth_etuds_by_sem, inscrits, candidats = list_authorized_etuds_by_sem(sem)
|
||||
etuds_set = set(etuds)
|
||||
|
|
|
@ -544,7 +544,7 @@ def check_paiement_etuds(etuds):
|
|||
etud["paiementinscription_str"] = "(pb cnx Apogée)"
|
||||
|
||||
|
||||
def get_maquette_apogee(etape="", annee_scolaire=""):
|
||||
def get_maquette_apogee(etape="", annee_scolaire="") -> str:
|
||||
"""Maquette CSV Apogee pour une étape et une annee scolaire"""
|
||||
maquette_url = get_maquette_url()
|
||||
if not maquette_url:
|
||||
|
|
|
@ -279,6 +279,7 @@ class BasePreferences(object):
|
|||
{
|
||||
"initvalue": "Dept",
|
||||
"title": "Nom abrégé du département",
|
||||
"explanation": "acronyme: par exemple R&T, ORTF, HAL",
|
||||
"size": 12,
|
||||
"category": "general",
|
||||
"only_global": True,
|
||||
|
@ -289,7 +290,7 @@ class BasePreferences(object):
|
|||
{
|
||||
"initvalue": "nom du département",
|
||||
"title": "Nom complet du département",
|
||||
"explanation": "inutilisé par défaut",
|
||||
"explanation": "apparaît sur la page d'accueil",
|
||||
"size": 40,
|
||||
"category": "general",
|
||||
"only_global": True,
|
||||
|
|
|
@ -49,16 +49,12 @@ from app.scodoc import sco_etud
|
|||
from app.scodoc import sco_excel
|
||||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc import sco_formsemestre_inscriptions
|
||||
from app.scodoc import sco_formsemestre_status
|
||||
from app.scodoc import sco_parcours_dut
|
||||
from app.scodoc import sco_pdf
|
||||
from app.scodoc import sco_preferences
|
||||
import sco_version
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app import log
|
||||
from app.scodoc.sco_codes_parcours import code_semestre_validant
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_pdf import SU
|
||||
|
||||
MAX_ETUD_IN_DESCR = 20
|
||||
|
||||
|
@ -121,9 +117,9 @@ def _categories_and_results(etuds, category, result):
|
|||
categories[etud[category]] = True
|
||||
results[etud[result]] = True
|
||||
categories = list(categories.keys())
|
||||
categories.sort()
|
||||
categories.sort(key=scu.heterogeneous_sorting_key)
|
||||
results = list(results.keys())
|
||||
results.sort()
|
||||
results.sort(key=scu.heterogeneous_sorting_key)
|
||||
return categories, results
|
||||
|
||||
|
||||
|
@ -166,7 +162,7 @@ def _results_by_category(
|
|||
l["sumpercent"] = "%2.1f%%" % ((100.0 * l["sum"]) / tot)
|
||||
#
|
||||
codes = list(results.keys())
|
||||
codes.sort()
|
||||
codes.sort(key=scu.heterogeneous_sorting_key)
|
||||
|
||||
bottom_titles = []
|
||||
if C: # ligne du bas avec totaux:
|
||||
|
@ -314,7 +310,7 @@ def formsemestre_report_counts(
|
|||
"type_admission",
|
||||
"boursier_prec",
|
||||
]
|
||||
keys.sort()
|
||||
keys.sort(key=scu.heterogeneous_sorting_key)
|
||||
F = [
|
||||
"""<form name="f" method="get" action="%s"><p>
|
||||
Colonnes: <select name="result" onchange="document.f.submit()">"""
|
||||
|
@ -497,7 +493,7 @@ def table_suivi_cohorte(
|
|||
P.append(p)
|
||||
|
||||
# 4-- regroupe par indice de semestre S_i
|
||||
indices_sems = list(set([s["semestre_id"] for s in sems]))
|
||||
indices_sems = list({s["semestre_id"] for s in sems})
|
||||
indices_sems.sort()
|
||||
for p in P:
|
||||
p.nb_etuds = 0 # nombre total d'etudiants dans la periode
|
||||
|
@ -788,9 +784,9 @@ def _gen_form_selectetuds(
|
|||
):
|
||||
"""HTML form pour choix criteres selection etudiants"""
|
||||
bacs = list(bacs)
|
||||
bacs.sort()
|
||||
bacs.sort(key=scu.heterogeneous_sorting_key)
|
||||
bacspecialites = list(bacspecialites)
|
||||
bacspecialites.sort()
|
||||
bacspecialites.sort(key=scu.heterogeneous_sorting_key)
|
||||
# on peut avoir un mix de chaines vides et d'entiers:
|
||||
annee_bacs = [int(x) if x else 0 for x in annee_bacs]
|
||||
annee_bacs.sort()
|
||||
|
|
|
@ -395,6 +395,8 @@ def do_semset_add_sem(semset_id, formsemestre_id):
|
|||
"""Add a sem to a semset"""
|
||||
if not semset_id:
|
||||
raise ScoValueError("empty semset_id")
|
||||
if formsemestre_id == "":
|
||||
raise ScoValueError("pas de semestre choisi !")
|
||||
s = SemSet(semset_id=semset_id)
|
||||
# check for valid formsemestre_id
|
||||
_ = sco_formsemestre.get_formsemestre(formsemestre_id) # raise exc
|
||||
|
|
|
@ -93,6 +93,7 @@ MODULE_TYPE_NAMES = {
|
|||
ModuleType.MALUS: "Malus",
|
||||
ModuleType.RESSOURCE: "Ressource",
|
||||
ModuleType.SAE: "SAÉ",
|
||||
None: "Module",
|
||||
}
|
||||
|
||||
MALUS_MAX = 20.0
|
||||
|
@ -897,6 +898,11 @@ def sort_dates(L, reverse=False):
|
|||
raise
|
||||
|
||||
|
||||
def heterogeneous_sorting_key(x):
|
||||
"key to sort non homogeneous sequences"
|
||||
return (float(x), "") if isinstance(x, (bool, float, int)) else (-1e34, str(x))
|
||||
|
||||
|
||||
def query_portal(req, msg="Portail Apogee", timeout=3):
|
||||
"""Retreives external data using HTTP request
|
||||
(used to connect to Apogee portal, or ScoDoc server)
|
||||
|
|
|
@ -239,6 +239,17 @@ div.box-chercheetud {
|
|||
margin-top: 12px;
|
||||
}
|
||||
|
||||
/* Page accueil général */
|
||||
span.dept_full_name {
|
||||
font-style: italic;
|
||||
}
|
||||
span.dept_visible {
|
||||
color: rgb(6, 158, 6);
|
||||
}
|
||||
span.dept_cache {
|
||||
color: rgb(194, 5, 5);
|
||||
}
|
||||
|
||||
div.table_etud_in_accessible_depts {
|
||||
margin-left: 3em;
|
||||
margin-bottom: 2em;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
{% block app_content %}
|
||||
<h1>Modification du compte ScoDoc <tt>{{form.user_name.data}}</tt></h1>
|
||||
<div class="help">
|
||||
<p>Identifiez-vous avez votre mot de passe actuel</p>
|
||||
<p>Identifiez-vous avec votre mot de passe actuel</p>
|
||||
</div>
|
||||
<form method=post>
|
||||
{{ form.user_name }}
|
||||
|
|
|
@ -23,14 +23,11 @@
|
|||
{{icons.arrow_none|safe}}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if editable and not ue.modules.count() %}
|
||||
|
||||
<a class="smallbutton" href="{{ url_for('notes.ue_delete',
|
||||
scodoc_dept=g.scodoc_dept, ue_id=ue.id)
|
||||
}}">{{icons.delete|safe}}</a>
|
||||
{% else %}
|
||||
{{icons.delete_disabled|safe}}
|
||||
{% endif %}
|
||||
|
||||
}}">{% if editable and not ue.modules.count() %}{{icons.delete|safe}}{% else %}{{icons.delete_disabled|safe}}{% endif %}</a>
|
||||
|
||||
<b>{{ue.acronyme}}</b> <a class="discretelink" href="{{
|
||||
url_for('notes.ue_infos', scodoc_dept=g.scodoc_dept, ue_id=ue.id)}}"
|
||||
>{{ue.titre}}</a>
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
|
||||
{{ exc | safe }}
|
||||
|
||||
<p class="footer">
|
||||
<p>
|
||||
{% if g.scodoc_dept %}
|
||||
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">retour page d'accueil
|
||||
departement {{ g.scodoc_dept }}</a>
|
||||
<a href="{{ exc.dest_url or url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">continuer</a>
|
||||
{% else %}
|
||||
<a href="{{ exc.dest_url or url_for('scodoc.index') }}">retour page d'accueil</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -12,11 +12,25 @@
|
|||
|
||||
<ul class="main">
|
||||
{% for dept in depts %}
|
||||
{% if dept.visible or current_user.is_administrator() %}
|
||||
<li>
|
||||
<a class="stdlink {{'link_accessible' if current_user.has_permission(Permission.ScoView, dept=dept.acronym) else 'link_unauthorized'}}"
|
||||
href="{{url_for('scolar.index_html', scodoc_dept=dept.acronym)}}">Département
|
||||
{{dept.preferences.filter_by(name="DeptName").first().value}}</a>
|
||||
{{dept.preferences.filter_by(name="DeptName").first().value}}
|
||||
</a>
|
||||
<span class="dept_full_name">
|
||||
{{ dept.preferences.filter_by( name="DeptFullName" ).first().value or "" }}
|
||||
</span>
|
||||
{% if current_user.is_administrator() %}
|
||||
<span {% if dept.visible %}class="dept_visible">visible{% else %}class="dept_cache">caché aux utilisateurs{% endif %}
|
||||
</span>
|
||||
<a href="{{ url_for('scodoc.toggle_dept_vis', dept_id=dept.id) }}">
|
||||
{% if dept.visible %}cacher{% else %}rendre visible{% endif %}
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<li>
|
||||
<b>Aucun département défini !</b>
|
||||
|
|
|
@ -53,6 +53,7 @@ from wtforms.fields.simple import BooleanField, StringField, TextAreaField, Hidd
|
|||
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
||||
|
||||
import app
|
||||
from app import db
|
||||
from app.forms.main import config_forms
|
||||
from app.forms.main.create_dept import CreateDeptForm
|
||||
from app.models import Departement, Identite
|
||||
|
@ -82,9 +83,7 @@ from PIL import Image as PILImage
|
|||
@bp.route("/ScoDoc/index")
|
||||
def index():
|
||||
"Page d'accueil: liste des départements"
|
||||
depts = (
|
||||
Departement.query.filter_by(visible=True).order_by(Departement.acronym).all()
|
||||
)
|
||||
depts = Departement.query.filter_by().order_by(Departement.acronym).all()
|
||||
return render_template(
|
||||
"scodoc.html",
|
||||
title=sco_version.SCONAME,
|
||||
|
@ -108,7 +107,11 @@ def create_dept():
|
|||
if request.method == "POST" and form.cancel.data: # cancel button
|
||||
return redirect(url_for("scodoc.index"))
|
||||
if form.validate_on_submit():
|
||||
departements.create_dept(form.acronym.data)
|
||||
departements.create_dept(
|
||||
form.acronym.data,
|
||||
visible=form.visible.data,
|
||||
# description=form.description.data,
|
||||
)
|
||||
flash(f"Département {form.acronym.data} créé.")
|
||||
return redirect(url_for("scodoc.index"))
|
||||
return render_template(
|
||||
|
@ -118,6 +121,17 @@ def create_dept():
|
|||
)
|
||||
|
||||
|
||||
@bp.route("/ScoDoc/toggle_dept_vis/<dept_id>", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def toggle_dept_vis(dept_id):
|
||||
"""Cache ou rend visible un dept"""
|
||||
dept = Departement.query.get_or_404(dept_id)
|
||||
dept.visible = not dept.visible
|
||||
db.session.add(dept)
|
||||
db.session.commit()
|
||||
return redirect(url_for("scodoc.index"))
|
||||
|
||||
|
||||
@bp.route("/ScoDoc/table_etud_in_accessible_depts", methods=["POST"])
|
||||
@login_required
|
||||
def table_etud_in_accessible_depts():
|
||||
|
|
|
@ -152,7 +152,6 @@ def user_info(user_name, format="json"):
|
|||
def create_user_form(user_name=None, edit=0, all_roles=1):
|
||||
"form. création ou edition utilisateur"
|
||||
auth_dept = current_user.dept
|
||||
auth_username = current_user.user_name
|
||||
from_mail = current_user.email
|
||||
initvalues = {}
|
||||
edit = int(edit)
|
||||
|
@ -204,7 +203,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
administrable_dept_acronyms = sorted(
|
||||
set(
|
||||
[
|
||||
x.dept
|
||||
x.dept or ""
|
||||
for x in UserRole.query.filter_by(user=current_user)
|
||||
if x.role.has_permission(Permission.ScoUsersAdmin) and x.dept
|
||||
]
|
||||
|
@ -249,7 +248,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
r.name + "_" + (dept or "") for (r, dept) in displayed_roles
|
||||
]
|
||||
displayed_roles_labels = [f"{dept}: {r.name}" for (r, dept) in displayed_roles]
|
||||
disabled_roles = {} # pour desactiver les roles que l'on ne peut pas editer
|
||||
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
|
||||
for i in range(len(displayed_roles_strings)):
|
||||
if displayed_roles_strings[i] not in editable_roles_strings:
|
||||
disabled_roles[i] = True
|
||||
|
@ -375,7 +374,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
can_choose_dept = True
|
||||
else:
|
||||
selectable_dept_acronyms = set(administrable_dept_acronyms)
|
||||
if edit: # ajoute dept actuel de l'utilisateur
|
||||
if edit and the_user.dept is not None: # ajoute dept actuel de l'utilisateur
|
||||
selectable_dept_acronyms |= {the_user.dept}
|
||||
if len(selectable_dept_acronyms) > 1:
|
||||
can_choose_dept = True
|
||||
|
@ -389,6 +388,9 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
"explanation": """département de rattachement de l'utilisateur""",
|
||||
"labels": selectable_dept_acronyms,
|
||||
"allowed_values": selectable_dept_acronyms,
|
||||
"default": g.scodoc_dept
|
||||
if g.scodoc_dept in selectable_dept_acronyms
|
||||
else "",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
@ -541,10 +543,10 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
vals["active"] = vals["status"] == ""
|
||||
# Département:
|
||||
if auth_dept: # pas super-admin
|
||||
if vals["dept"] not in selectable_dept_acronyms:
|
||||
if ("dept" in vals) and (vals["dept"] not in selectable_dept_acronyms):
|
||||
del vals["dept"] # ne change pas de dept
|
||||
# traitement des roles: ne doit pas affecter les roles
|
||||
# que l'on en controle pas:
|
||||
# Traitement des roles: ne doit pas affecter les rôles
|
||||
# que l'on en contrôle pas:
|
||||
for role in orig_roles_strings: # { "Ens_RT", "Secr_CJ", ... }
|
||||
if role and not role in editable_roles_strings:
|
||||
roles.add(role)
|
||||
|
@ -573,7 +575,7 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||
# A: envoi de welcome + procedure de reset
|
||||
# B: envoi de welcome seulement (mot de passe saisie dans le formulaire)
|
||||
# C: Aucun envoi (mot de passe saisi dans le formulaire)
|
||||
if vals["welcome:list"] == "1":
|
||||
if vals["welcome"] == "1":
|
||||
if vals["reset_password:list"] == "1":
|
||||
mode = Mode.WELCOME_AND_CHANGE_PASSWORD
|
||||
else:
|
||||
|
@ -751,7 +753,7 @@ def user_info_page(user_name=None):
|
|||
if not user_name:
|
||||
user = current_user
|
||||
else:
|
||||
user = User.query.filter_by(user_name=user_name).first()
|
||||
user = User.query.filter_by(user_name=str(user_name)).first()
|
||||
if not user:
|
||||
raise ScoValueError("invalid user_name")
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.1.16"
|
||||
SCOVERSION = "9.1.19"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
|
|
@ -42,17 +42,17 @@
|
|||
# - do_formation_delete
|
||||
|
||||
import json
|
||||
import xml.dom.minidom
|
||||
|
||||
import flask
|
||||
from flask import g
|
||||
|
||||
import pytest
|
||||
from tests.unit import sco_fake_gen
|
||||
|
||||
from app.scodoc import sco_edit_formation
|
||||
from app.scodoc import sco_edit_matiere
|
||||
from app.scodoc import sco_edit_module
|
||||
from app.scodoc import sco_edit_ue
|
||||
from app.scodoc import sco_exceptions
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_formsemestre_edit
|
||||
from app.scodoc import sco_moduleimpl
|
||||
|
@ -273,31 +273,31 @@ def test_formations(test_client):
|
|||
|
||||
# --- Suppression du module, matiere et ue test du semestre 2
|
||||
|
||||
# on doit d'abbord supprimer le semestre
|
||||
|
||||
# sco_formsemestre_edit.formsemestre_delete( formsemestre_id=sem2["formsemestre_id"])
|
||||
# sco_formsemestre_edit.formsemestre_createwithmodules( formsemestre_id=sem2["formsemestre_id"])
|
||||
|
||||
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
||||
# on doit d'abord supprimer le semestre:
|
||||
|
||||
sco_formsemestre_edit.do_formsemestre_delete(
|
||||
formsemestre_id=sem2["formsemestre_id"]
|
||||
)
|
||||
|
||||
# sco_edit_module.module_delete( module_id=modt["module_id"])
|
||||
# sco_edit_matiere.matiere_delete( matiere_id=matt["matiere_id"])
|
||||
# sco_edit_ue.ue_delete( ue_id=uet["ue_id"])
|
||||
|
||||
# RIEN NE SE PASSE AVEC CES FONCTIONS
|
||||
|
||||
li_module = sco_edit_module.module_list()
|
||||
assert len(li_module) == 4
|
||||
sco_edit_module.do_module_delete(oid=modt["module_id"]) # on supprime le semestre
|
||||
# sco_formsemestre_edit.formsemestre_delete_moduleimpls( formsemestre_id=sem2["formsemestre_id"], module_ids_to_del=[modt["module_id"]])
|
||||
# deuxieme methode de supression d'un module
|
||||
li_module2 = sco_edit_module.module_list()
|
||||
# Suppression impossible car utilisé dans le semestre semt:
|
||||
with pytest.raises(sco_exceptions.ScoNonEmptyFormationObject):
|
||||
sco_edit_module.module_delete(module_id=mi3["module_id"])
|
||||
|
||||
assert len(li_module2) == 3 # verification de la suppression du module
|
||||
sco_formsemestre_edit.do_formsemestre_delete(semt["formsemestre_id"])
|
||||
|
||||
li_module2_before = sco_edit_module.module_list()
|
||||
|
||||
sco_edit_module.do_module_delete(mi3["module_id"])
|
||||
sco_edit_module.do_module_delete(modt["module_id"])
|
||||
|
||||
# deuxieme methode de supression d'un module
|
||||
li_module2_after = sco_edit_module.module_list()
|
||||
|
||||
assert (
|
||||
len(li_module2_after) == len(li_module2_before) - 2
|
||||
) # verification de la suppression
|
||||
|
||||
lim_sem2 = sco_moduleimpl.moduleimpl_list(formsemestre_id=sem2["formsemestre_id"])
|
||||
|
||||
|
@ -316,10 +316,6 @@ def test_formations(test_client):
|
|||
assert len(li_ue2) == 3 # verification de la suppression de l'UE
|
||||
|
||||
# --- Suppression d'une formation
|
||||
# Il faut d'abbord supprimer le semestre aussi.
|
||||
sco_formsemestre_edit.do_formsemestre_delete(
|
||||
formsemestre_id=semt["formsemestre_id"]
|
||||
)
|
||||
|
||||
sco_edit_formation.do_formation_delete(oid=f2["formation_id"])
|
||||
lif3 = notes.formation_list(format="json").get_data(as_text=True)
|
||||
|
|
|
@ -24,53 +24,74 @@ usage() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
# analyse de la ligne de commande
|
||||
# calcule:
|
||||
# SRC = fichier source de la restauration
|
||||
# DB_DEST = base de données destination
|
||||
# KEEP_ENV = vide si restauration à l'identique (i.e. production)
|
||||
if (($# < 1 || $# > 2))
|
||||
then
|
||||
usage
|
||||
elif [ $# -eq 2 -a $1 != '--keep-env' -a $2 != '--keep-env' ] ; then
|
||||
elif [ $# -eq 2 ] && [ "$1" != "--keep-env" ] && [ "$2" != "--keep-env" ]
|
||||
then
|
||||
usage
|
||||
elif [ $# -eq 1 ] ; then
|
||||
elif [ $# -eq 1 ]
|
||||
then
|
||||
echo "restauration des données et de la configuration originale (production)"
|
||||
SRC=$1
|
||||
SRC="$1"
|
||||
DB_DEST="SCODOC"
|
||||
else
|
||||
echo "restauration des données dans la configuration actuelle"
|
||||
DB_CURRENT=$(su -c "(cd $SCODOC_DIR && source venv/bin/activate && flask scodoc-database -n)")
|
||||
DB_DEST="$DB_CURRENT"
|
||||
KEEP=1
|
||||
if [ $1 = '--keep-env' ]; then
|
||||
SRC=$2
|
||||
KEEP_ENV="Y"
|
||||
if [ "$1" = "--keep-env" ]
|
||||
then
|
||||
SRC="$2"
|
||||
else
|
||||
SRC=$1
|
||||
SRC="$1"
|
||||
fi
|
||||
fi
|
||||
DB_DUMP="${SCODOC_VAR_DIR}"/SCODOC.dump
|
||||
|
||||
# Safety check
|
||||
echo "Ce script va remplacer les donnees de votre installation ScoDoc par celles"
|
||||
echo "Ce script va remplacer les données de votre installation ScoDoc par celles"
|
||||
echo "enregistrées dans le fichier fourni."
|
||||
echo "Ce fichier doit avoir ete cree par le script save_scodoc9_data.sh."
|
||||
echo "Ce fichier doit avoir été créé par le script save_scodoc9_data.sh."
|
||||
echo
|
||||
echo "Attention: TOUTES LES DONNEES DE CE SCODOC SERONT REMPLACEES !"
|
||||
echo "Notamment, tous les utilisateurs et departements existants seront effaces !"
|
||||
echo "Notamment, tous les utilisateurs et départements existants seront effacés !"
|
||||
echo
|
||||
echo "La base SQL $DB_CURRENT sera effacée et remplacée !!!"
|
||||
echo
|
||||
echo -n "Voulez vous poursuivre cette operation ? (y/n) [n]"
|
||||
read -r ans
|
||||
if [ ! "$(norm_ans "$ans")" = 'Y' ]
|
||||
# Préparation si une copie 'antique' doit être effacée, demander confirmation, puis effacer
|
||||
SCODOC_VAR_OLD=${SCODOC_VAR_DIR}.old
|
||||
if [ -e "$SCODOC_VAR_DIR" ] && [ -e "$SCODOC_VAR_OLD" ]
|
||||
then
|
||||
echo "Annulation"
|
||||
echo "Une ancienne sauvegarde (\"$SCODOC_VAR_OLD\" en date du $(stat -c %w "$SCODOC_VAR_OLD") ) va être effacée."
|
||||
echo
|
||||
fi
|
||||
if [ -n "$KEEP_ENV" ]
|
||||
then
|
||||
echo -n "Restauration des données sans changement de configuration: Assurez-vous d'avoir arrêté le serveur scodoc."
|
||||
echo
|
||||
fi
|
||||
|
||||
echo -n "Voulez-vous poursuivre la restauration ? (y/n) [n]"
|
||||
read -r ans
|
||||
if [ ! "$(norm_ans "$ans")" = "Y" ]
|
||||
then
|
||||
echo "Annulation de la restauration par l\'utilisateur"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$SCODOC_VAR_OLD" || die "Erreur suppression $SCODOC_VAR_OLD"
|
||||
|
||||
# -- Stop ScoDoc
|
||||
if [ $KEEP -ne 1 ]; then
|
||||
if [ -z "$KEEP_ENV" ]
|
||||
then
|
||||
echo "Arrêt de scodoc9..."
|
||||
systemctl stop scodoc9
|
||||
else
|
||||
echo -n "Assurez-vous d'avoir arrété le serveur scodoc (validez pour continuer)"
|
||||
read ans
|
||||
fi
|
||||
|
||||
# Clear caches
|
||||
|
@ -86,7 +107,7 @@ fi
|
|||
|
||||
# -- Ouverture archive
|
||||
echo "Ouverture archive $SRC..."
|
||||
(cd $(dirname "$SCODOC_VAR_DIR"); tar xfz "$SRC") || die "Error opening archive"
|
||||
(cd "$(dirname "$SCODOC_VAR_DIR")"; tar xfz "$SRC") || die "Error opening archive"
|
||||
|
||||
# -- Ckeck/fix owner
|
||||
echo "Vérification du propriétaire..."
|
||||
|
@ -103,7 +124,7 @@ su -c "createdb $DB_DEST" "$SCODOC_USER" || die "Erreur création db"
|
|||
|
||||
if [ ! -z $KEEP_ENV ] ; then
|
||||
echo "conservation de la configuration actuelle"
|
||||
cp "$SCODOC_VAR_DIR".old/.env "$SCODOC_VAR_DIR"/.env
|
||||
cp -p "$SCODOC_VAR_OLD"/.env "$SCODOC_VAR_DIR"/.env
|
||||
echo "récupération des données..."
|
||||
su -c "pg_restore -f - $DB_DUMP | psql -q $DB_DEST" "$SCODOC_USER" >/dev/null || die "Erreur chargement/renommage de la base SQL"
|
||||
su -c "(cd $SCODOC_DIR && source venv/bin/activate && flask db upgrade)" "$SCODOC_USER"
|
||||
|
@ -119,5 +140,4 @@ else
|
|||
systemctl start scodoc9
|
||||
fi
|
||||
|
||||
|
||||
echo "Terminé."
|
||||
|
|
Loading…
Reference in New Issue