Update
This commit is contained in:
parent
2c470cfdeb
commit
4e9c35b9e6
@ -5,6 +5,7 @@
|
|||||||
pip install flask-wtf
|
pip install flask-wtf
|
||||||
pip install flask-sqlalchemy
|
pip install flask-sqlalchemy
|
||||||
pip install flask-migrate
|
pip install flask-migrate
|
||||||
|
pip install wtforms-alchemy
|
||||||
|
|
||||||
### Pour lancer l'app
|
### Pour lancer l'app
|
||||||
|
|
||||||
|
280
app/forms.py
280
app/forms.py
@ -1,8 +1,11 @@
|
|||||||
from flask import redirect, url_for
|
from flask import redirect, url_for
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from flask_wtf.file import FileAllowed
|
from flask_wtf.file import FileAllowed
|
||||||
from wtforms import StringField, SubmitField, FileField, TextAreaField, RadioField
|
from wtforms import StringField, SubmitField, FileField, TextAreaField, RadioField, SelectMultipleField, widgets, FieldList, FormField, HiddenField
|
||||||
from wtforms.validators import DataRequired, Regexp, Optional, ValidationError
|
from wtforms.validators import DataRequired, Regexp, Optional, ValidationError
|
||||||
|
from wtforms_alchemy import model_form_factory, ClassMap
|
||||||
|
from wtforms_alchemy.fields import QuerySelectMultipleField
|
||||||
|
from sqlalchemy_utils import ChoiceType
|
||||||
from app import db
|
from app import db
|
||||||
import app.models as models
|
import app.models as models
|
||||||
|
|
||||||
@ -15,14 +18,40 @@ REPERTOIRE_YAML = "./export/"
|
|||||||
if not os.path.exists(REPERTOIRE_YAML):
|
if not os.path.exists(REPERTOIRE_YAML):
|
||||||
os.makedirs(REPERTOIRE_YAML)
|
os.makedirs(REPERTOIRE_YAML)
|
||||||
|
|
||||||
def validate_ref_list(regex, message):
|
categorie_liste = ["saes","ressources","acs"]
|
||||||
def _validate_ref_list(form, field):
|
categorie_to_model = {"saes": "SAE", "ressources": "Ressource", "acs": "AC"}
|
||||||
refs = field.data.strip() + " "
|
separateur = None
|
||||||
if re.match(regex, refs) == None:
|
|
||||||
raise ValidationError(message)
|
|
||||||
return _validate_ref_list
|
|
||||||
|
|
||||||
class Form(FlaskForm):
|
BaseModelForm = model_form_factory(FlaskForm, include_primary_keys=True)
|
||||||
|
|
||||||
|
class ModelForm(BaseModelForm):
|
||||||
|
@classmethod
|
||||||
|
def get_session(self):
|
||||||
|
return db.session
|
||||||
|
|
||||||
|
class RefListField(QuerySelectMultipleField):
|
||||||
|
option_widget=widgets.CheckboxInput()
|
||||||
|
|
||||||
|
class AccueilForm(FlaskForm):
|
||||||
|
ajouter = SubmitField("Ajouter")
|
||||||
|
reset = SubmitField("Reset")
|
||||||
|
exporter = SubmitField("Exporter")
|
||||||
|
importer = SubmitField("Importer")
|
||||||
|
|
||||||
|
class UEForm(FlaskForm):
|
||||||
|
ue = HiddenField("Competence")
|
||||||
|
acs = RefListField("Liste des ACs", query_factory=lambda: models.AC.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
ressources = RefListField("Liste des Ressources inclus dans les ACs", query_factory=lambda: [], get_label=lambda ref: ref.getLabel())
|
||||||
|
saes = RefListField("Liste des SAEs inclus dans les ACs", query_factory=lambda: [], get_label=lambda ref: ref.getLabel())
|
||||||
|
|
||||||
|
class SemestreForm(FlaskForm):
|
||||||
|
ues = RefListField("Liste des UEs", query_factory=lambda: models.Competence.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
ueform = FieldList(FormField(UEForm))
|
||||||
|
update = SubmitField("Update")
|
||||||
|
|
||||||
|
class Form(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
not_null_validator_type_map = ClassMap({db.String: [DataRequired()]})
|
||||||
|
|
||||||
sauvegarder = SubmitField("Sauvegarder")
|
sauvegarder = SubmitField("Sauvegarder")
|
||||||
charger = SubmitField("Charger")
|
charger = SubmitField("Charger")
|
||||||
@ -32,154 +61,105 @@ class Form(FlaskForm):
|
|||||||
importer = SubmitField("Importer")
|
importer = SubmitField("Importer")
|
||||||
referentiel = RadioField("Liste des référentiels", validators=[Optional()])
|
referentiel = RadioField("Liste des référentiels", validators=[Optional()])
|
||||||
|
|
||||||
class PNForm(Form):
|
def chargerRef(self):
|
||||||
regex = "^PN\d$"
|
if self.referentiel.data == None:
|
||||||
|
self.referentiel.errors.append("Aucun référentiel n'a été selectionné!")
|
||||||
code = StringField("Code", validators=[DataRequired(), Regexp("^PN\d$", message="Le code doit être de la forme PN0.")])
|
return False
|
||||||
nom = StringField("Nom", validators=[DataRequired()] )
|
|
||||||
diminutif = StringField("Diminutif", validators=[DataRequired()] )
|
|
||||||
description = TextAreaField("Description", validators=[DataRequired()] )
|
|
||||||
type = RadioField("Type", choices=["1","2","3"], validators=[DataRequired()])
|
|
||||||
|
|
||||||
class ACForm(Form):
|
|
||||||
regex = "^AC\d{4}$"
|
|
||||||
|
|
||||||
code = StringField("Code", validators=[DataRequired(), Regexp("^AC\d{4}$", message="Le code doit être de la forme AC0000.")])
|
|
||||||
titre = StringField("Titre", validators=[DataRequired()] )
|
|
||||||
saes = StringField("SAEs", validators=[DataRequired(), validate_ref_list("^(\s*(SAE\d{2}\s+)*)$", message="Les saes doit être de la forme SAE00.")] )
|
|
||||||
ressources = StringField("Ressources", validators=[DataRequired(), validate_ref_list("^(\s*(R\d{3}\s+)*)$", message="Les ressources doit être de la forme R000.")] )
|
|
||||||
|
|
||||||
class SAEForm(Form):
|
|
||||||
regex = "^SAE\d{2}$"
|
|
||||||
|
|
||||||
code = StringField("Code", validators=[DataRequired(), Regexp("^SAE\d{2}$", message="Le code doit être de la forme SAE00.")])
|
|
||||||
titre = StringField("Titre", validators=[DataRequired()] )
|
|
||||||
semestre = StringField("Semestre", validators=[DataRequired()] )
|
|
||||||
heures_encadrees = StringField("Heures encadrées", validators=[DataRequired()] )
|
|
||||||
heures_tp = StringField("Heures TP", validators=[DataRequired()] )
|
|
||||||
projet = StringField("Projet", validators=[DataRequired()] )
|
|
||||||
description = TextAreaField("Description", validators=[DataRequired()] )
|
|
||||||
coef = StringField("Coef.", validators=[DataRequired()] )
|
|
||||||
acs = StringField("ACs", validators=[DataRequired(), validate_ref_list("^(\s*(AC\d{4}\s+)*)$", message="Les acs être de la forme AC0000.")] )
|
|
||||||
ressources = StringField("Ressources", validators=[DataRequired(), validate_ref_list("^(\s*(R\d{3}\s+)*)$", message="Les ressources doit être de la forme R000.")] )
|
|
||||||
livrables = TextAreaField("Livrables", validators=[DataRequired()] )
|
|
||||||
motscles = StringField("Mots clés", validators=[DataRequired()] )
|
|
||||||
|
|
||||||
class RessourceForm(Form):
|
|
||||||
regex = "^R\{3}$"
|
|
||||||
|
|
||||||
code = StringField("Code", validators=[DataRequired(), Regexp("^R\{3}$", message="Le code doit être de la forme R000.")])
|
|
||||||
nom = StringField("Nom", validators=[DataRequired()] )
|
|
||||||
semestre = StringField("Semestre", validators=[DataRequired()] )
|
|
||||||
heures_formation = StringField("Heures formation", validators=[DataRequired()] )
|
|
||||||
heures_tp = StringField("Heures TP", validators=[DataRequired()] )
|
|
||||||
coef = StringField("Coef.", validators=[DataRequired()] )
|
|
||||||
acs = StringField("ACs", validators=[DataRequired(), validate_ref_list("^(\s*(AC\d{4}\s+)*)$", message="Les acs doit être de la forme AC0000.")] )
|
|
||||||
saes = StringField("SAEs", validators=[DataRequired(), validate_ref_list("^(\s*(SAE\d{2}\s+)*)$", message="Les saes doit être de la forme SAE00.")] )
|
|
||||||
prerequis = StringField("Prérequis", validators=[DataRequired()] )
|
|
||||||
contexte = TextAreaField("Contexte", validators=[DataRequired()] )
|
|
||||||
contenu = TextAreaField("Contenu", validators=[DataRequired()] )
|
|
||||||
motscles = StringField("Mots clés", validators=[DataRequired()] )
|
|
||||||
|
|
||||||
class CompetenceForm(Form):
|
|
||||||
regex = "^RT\d$"
|
|
||||||
|
|
||||||
code = StringField("Code", validators=[DataRequired(), Regexp("^RT\d$", message="Le code doit être de la forme RT0.")])
|
|
||||||
nom = StringField("Nom", validators=[DataRequired()] )
|
|
||||||
diminutif = StringField("Diminutif", validators=[DataRequired()] )
|
|
||||||
description = TextAreaField("Description", validators=[DataRequired()] )
|
|
||||||
composantes = TextAreaField("Composantes", validators=[DataRequired()] )
|
|
||||||
situations = TextAreaField("Situations", validators=[DataRequired()] )
|
|
||||||
niveaux = TextAreaField("Niveaux", validators=[DataRequired()] )
|
|
||||||
|
|
||||||
categorie_liste = ["saes","ressources","acs"]
|
|
||||||
categorie_to_model = {"saes": "SAE", "ressources": "Ressource", "acs": "AC"}
|
|
||||||
separateur = None
|
|
||||||
|
|
||||||
def form_import(form):
|
|
||||||
""" Si le bouton import a été appuyé et qu'il n'y a pas d'erreur d'import => importe le fichier yaml"""
|
|
||||||
# Bouton import appuyé et fichier yaml selectionné
|
|
||||||
if form.importer.data and len(form.fichier.errors) == 0:
|
|
||||||
if form.fichier.data.filename == "":
|
|
||||||
form.fichier.errors.append("Aucun fichier selectioné.")
|
|
||||||
return form
|
|
||||||
if re.match(form.regex, form.fichier.data.filename[:-4]) == None:
|
|
||||||
form.fichier.errors.append("Mauvais type de référentiel!")
|
|
||||||
return form
|
|
||||||
fichier_Yaml = yaml.safe_load(form.fichier.data.read())
|
|
||||||
for categorie, valeur in fichier_Yaml.items():
|
|
||||||
if categorie in categorie_liste:
|
|
||||||
form[categorie].process_data(" ".join(valeur))
|
|
||||||
else:
|
|
||||||
form[categorie].process_data(valeur)
|
|
||||||
form.validate_on_submit() # Réinitialise les messages d'erreur
|
|
||||||
return form
|
|
||||||
|
|
||||||
def form_export(form):
|
|
||||||
""" Si le formulaire est valide => exporte dans un fichier yaml avec les informations du formulaire """
|
|
||||||
output = {}
|
|
||||||
for categorie, valeur in list(form.data.items())[7:-1]:
|
|
||||||
if categorie in categorie_liste:
|
|
||||||
output[categorie] = [ referentiel for referentiel in valeur.split(separateur) ]
|
|
||||||
else:
|
else:
|
||||||
output[categorie] = valeur
|
return True
|
||||||
fichier = REPERTOIRE_YAML + form.code.data + ".yml"
|
|
||||||
|
def chargerBDD(self, referentiel):
|
||||||
|
for categorie in list(self.data.keys())[7:-1]:
|
||||||
|
self[categorie].process_data(referentiel.__dict__[categorie])
|
||||||
|
self.referentiel.process_data(referentiel)
|
||||||
|
|
||||||
|
def importerRef(self):
|
||||||
|
if len(self.fichier.errors) == 0:
|
||||||
|
if self.fichier.data.filename == "":
|
||||||
|
self.fichier.errors.append("Aucun fichier selectioné.")
|
||||||
|
return
|
||||||
|
if re.match(self.regex, self.fichier.data.filename[:-4]) == None:
|
||||||
|
self.fichier.errors.append("Mauvais type de référentiel!")
|
||||||
|
return
|
||||||
|
fichier_Yaml = yaml.safe_load(self.fichier.data.read())
|
||||||
|
for categorie, valeur in fichier_Yaml.items():
|
||||||
|
if categorie in categorie_liste:
|
||||||
|
model = getattr(models, categorie_to_model[categorie])
|
||||||
|
self[categorie].process_data([model.query.filter_by(code=ref).first() for ref in valeur])
|
||||||
|
else:
|
||||||
|
self[categorie].process_data(valeur)
|
||||||
|
self.validate()
|
||||||
|
|
||||||
|
def exporterRef(self):
|
||||||
|
""" Exporte dans un fichier yaml les informations du formulaire rempli """
|
||||||
|
output = {}
|
||||||
|
for categorie, valeur in list(self.data.items())[7:-1]:
|
||||||
|
if categorie in categorie_liste:
|
||||||
|
output[categorie] = [ referentiel.code for referentiel in valeur ]
|
||||||
|
else:
|
||||||
|
output[categorie] = valeur
|
||||||
|
fichier = REPERTOIRE_YAML + self.code.data + ".yml"
|
||||||
with open(fichier, "w", encoding="utf8") as fid:
|
with open(fichier, "w", encoding="utf8") as fid:
|
||||||
fid.write(yaml.dump(output))
|
fid.write(yaml.dump(output))
|
||||||
|
print(yaml.dump(output))
|
||||||
|
|
||||||
def form_charger(form):
|
def supprimerRef(self):
|
||||||
""" Si le bouton charger est appuyé et qu'un référentiel du BDD a été selectionné => remplie le formulaire avec ses informations """
|
if self.referentiel.data == None:
|
||||||
if form.charger.data:
|
self.referentiel.erros.append("Aucun référentiel n'a été selectionné!")
|
||||||
if form.referentiel.data == None:
|
return False
|
||||||
form.referentiel.errors.append("Aucun référentiel n'a été selectionné!")
|
|
||||||
else:
|
else:
|
||||||
temp = form.referentiel.data[1:-1].split()
|
temp = self.referentiel.data[1:-1].split()
|
||||||
model = getattr(models, temp[0])
|
|
||||||
referentiel = model.query.filter_by(code=temp[1]).first()
|
|
||||||
for categorie in list(referentiel.__dict__)[1:]:
|
|
||||||
if categorie in categorie_liste:
|
|
||||||
form[categorie].process_data(" ".join(ref.code for ref in referentiel.__dict__[categorie]))
|
|
||||||
else:
|
|
||||||
form[categorie].process_data(referentiel.__dict__[categorie])
|
|
||||||
form.validate_on_submit()
|
|
||||||
return form
|
|
||||||
|
|
||||||
def form_sauvegarder(form):
|
|
||||||
""" Si le bouton sauvegarder est appuyé et que le formulaire est valide => ajoute le référentiel dans la table respectif du base de données """
|
|
||||||
if form.sauvegarder.data:
|
|
||||||
model = getattr(models, "".join( c for c in form.code.data if not c.isdigit()))
|
|
||||||
referentiel = model.query.filter_by(code=form.code.data).first()
|
|
||||||
if referentiel == None:
|
|
||||||
referentiel = model()
|
|
||||||
# Si le référentiel contient une catégorie avec une liste de référentiels
|
|
||||||
for categorie, valeur in list(form.data.items())[7:-1]:
|
|
||||||
if categorie in categorie_liste:
|
|
||||||
resultat = []
|
|
||||||
refs = [ ref for ref in form[categorie].data.split(separateur) ]
|
|
||||||
ref_model = getattr(models, categorie_to_model[categorie])
|
|
||||||
for ref in refs:
|
|
||||||
ref_bdd = ref_model.query.filter_by(code=ref).first()
|
|
||||||
if ref_bdd == None:
|
|
||||||
ref_new = ref_model(code=ref)
|
|
||||||
resultat.append(ref_new)
|
|
||||||
db.session.add(ref_new)
|
|
||||||
else:
|
|
||||||
resultat.append(ref_bdd)
|
|
||||||
form[categorie].process_data(resultat)
|
|
||||||
|
|
||||||
form.populate_obj(referentiel)
|
|
||||||
db.session.add(referentiel)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
def form_supprimer(form):
|
|
||||||
if form.supprimer.data:
|
|
||||||
if form.referentiel.data == None:
|
|
||||||
form.referentiel.errors.append("Aucun référentiel n'a été selectionné!")
|
|
||||||
else:
|
|
||||||
temp = form.referentiel.data[1:-1].split()
|
|
||||||
model = getattr(models, temp[0])
|
model = getattr(models, temp[0])
|
||||||
referentiel = model.query.filter_by(code=temp[1]).first()
|
referentiel = model.query.filter_by(code=temp[1]).first()
|
||||||
db.session.delete(referentiel)
|
db.session.delete(referentiel)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return True, redirect(url_for(temp[0]))
|
return True
|
||||||
return False, form
|
|
||||||
|
def sauvegarderRef(self):
|
||||||
|
model = getattr(models, self.__class__.__name__[:-4])
|
||||||
|
referentiel = model.query.filter_by(code=self.code.data).first()
|
||||||
|
if referentiel == None: referentiel = model()
|
||||||
|
self.populate_obj(referentiel)
|
||||||
|
db.session.add(referentiel)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
class PNForm(Form):
|
||||||
|
regex = "^PN\d$"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.PN
|
||||||
|
type_map = ClassMap({ChoiceType: RadioField})
|
||||||
|
|
||||||
|
|
||||||
|
class ACForm(Form):
|
||||||
|
regex = "^AC\d{4}$"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.AC
|
||||||
|
|
||||||
|
saes = RefListField("Liste des SAEs", query_factory=lambda: models.SAE.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
ressources = RefListField("Liste des Ressources", query_factory=lambda: models.Ressource.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
|
||||||
|
class SAEForm(Form):
|
||||||
|
regex = "^SAE\d{2}$"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.SAE
|
||||||
|
|
||||||
|
acs = RefListField("Liste des ACs", query_factory=lambda: models.AC.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
ressources = RefListField("Liste des Ressources", query_factory=lambda: models.Ressource.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
|
||||||
|
class RessourceForm(Form):
|
||||||
|
regex = "^R\d{3}$"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Ressource
|
||||||
|
|
||||||
|
acs = RefListField("Liste des ACs", query_factory=lambda: models.AC.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
saes = RefListField("Liste des SAEs", query_factory=lambda: models.SAE.query.all(), get_label=lambda ref: ref.getLabel())
|
||||||
|
|
||||||
|
class CompetenceForm(Form):
|
||||||
|
regex = "^RT\d$"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Competence
|
133
app/models.py
133
app/models.py
@ -1,4 +1,25 @@
|
|||||||
from app import db
|
from app import db
|
||||||
|
from sqlalchemy_utils import ChoiceType
|
||||||
|
|
||||||
|
Semestres_Competences = db.Table("Semestres_Competences",
|
||||||
|
db.Column("Semestre_num", db.String(1), db.ForeignKey("semestre.num")),
|
||||||
|
db.Column("Competence_code", db.String(3), db.ForeignKey("competence.code"))
|
||||||
|
)
|
||||||
|
|
||||||
|
ACs_Competences = db.Table("ACs_Competences",
|
||||||
|
db.Column("AC_code", db.String(6), db.ForeignKey("AC.code")),
|
||||||
|
db.Column("Competence_code", db.String(3), db.ForeignKey("competence.code"))
|
||||||
|
)
|
||||||
|
|
||||||
|
SAEs_Competences = db.Table("SAEs_Competences",
|
||||||
|
db.Column("SAE_code", db.String(6), db.ForeignKey("SAE.code")),
|
||||||
|
db.Column("Competence_code", db.String(3), db.ForeignKey("competence.code"))
|
||||||
|
)
|
||||||
|
|
||||||
|
Ressources_Competences = db.Table("Ressources_Competences",
|
||||||
|
db.Column("Ressource_code", db.String(6), db.ForeignKey("ressource.code")),
|
||||||
|
db.Column("Competence_code", db.String(3), db.ForeignKey("competence.code"))
|
||||||
|
)
|
||||||
|
|
||||||
Ressources_ACs = db.Table("Ressources_ACs",
|
Ressources_ACs = db.Table("Ressources_ACs",
|
||||||
db.Column("Ressource_code", db.String(4), db.ForeignKey("ressource.code")),
|
db.Column("Ressource_code", db.String(4), db.ForeignKey("ressource.code")),
|
||||||
@ -15,64 +36,90 @@ SAEs_ACs = db.Table("SAEs_ACs",
|
|||||||
db.Column("AC_code", db.String(6), db.ForeignKey("AC.code"))
|
db.Column("AC_code", db.String(6), db.ForeignKey("AC.code"))
|
||||||
)
|
)
|
||||||
|
|
||||||
class PN(db.Model):
|
class Semestre(db.Model):
|
||||||
code = db.Column(db.String(3), primary_key = True)
|
num = db.Column(db.String(1), primary_key = True)
|
||||||
nom = db.Column(db.String(255))
|
ues = db.relationship("Competence", order_by="Competence.code", secondary=Semestres_Competences, lazy=False, backref=db.backref("semestres", lazy=False))
|
||||||
diminutif = db.Column(db.String(30))
|
|
||||||
description = db.Column(db.Text())
|
|
||||||
type = db.Column(db.String(1))
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<PN {}>".format(self.code)
|
return "<Semestre {}>".format(self.num)
|
||||||
|
|
||||||
|
class Competence(db.Model):
|
||||||
|
code = db.Column(db.String(3), primary_key = True, info={'label': 'Code'})
|
||||||
|
nom = db.Column(db.String(255), info={'label': 'Nom'})
|
||||||
|
diminutif = db.Column(db.String(30), info={'label': 'Diminutif'})
|
||||||
|
description = db.Column(db.Text(), info={'label': 'Description'})
|
||||||
|
composantes = db.Column(db.Text(), info={'label': 'Composantes'})
|
||||||
|
situations = db.Column(db.Text(), info={'label': 'Situations'})
|
||||||
|
niveaux = db.Column(db.Text(), info={'label': 'Niveaux'})
|
||||||
|
acs = db.relationship("AC", order_by="AC.code", secondary=ACs_Competences, lazy=False, backref=db.backref("competences", lazy=False))
|
||||||
|
#objets de formation
|
||||||
|
saes = db.relationship("SAE", secondary=SAEs_Competences, lazy=False, backref=db.backref("competences", lazy=False))
|
||||||
|
ressources = db.relationship("Ressource", secondary=Ressources_Competences, lazy=False, backref=db.backref("competences", lazy=False))
|
||||||
|
|
||||||
|
def getLabel(self):
|
||||||
|
return self.code + " - " + self.nom
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Competence {}>".format(self.code)
|
||||||
|
|
||||||
class AC(db.Model):
|
class AC(db.Model):
|
||||||
code = db.Column(db.String(6), primary_key = True)
|
code = db.Column(db.String(6), primary_key = True, info={'label': 'Code'})
|
||||||
titre = db.Column(db.String(255))
|
titre = db.Column(db.String(255), info={'label': 'Titre'})
|
||||||
saes = db.relationship("SAE", secondary=SAEs_ACs, cascade="all, delete", lazy=False, backref=db.backref("acs", lazy=False))
|
saes = db.relationship("SAE", secondary=SAEs_ACs, lazy=False, backref=db.backref("acs", lazy=False))
|
||||||
ressources = db.relationship("Ressource", secondary=Ressources_ACs, cascade="all, delete", lazy=False, backref=db.backref("acs", lazy=False))
|
ressources = db.relationship("Ressource", order_by="Ressource.code", secondary=Ressources_ACs, lazy=False, backref=db.backref("acs", lazy=False))
|
||||||
|
|
||||||
|
def getLabel(self):
|
||||||
|
return self.code + " - " + self.titre
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<AC {}>".format(self.code)
|
return "<AC {}>".format(self.code)
|
||||||
|
|
||||||
|
class PN(db.Model):
|
||||||
|
code = db.Column(db.String(3), primary_key = True, info={'label': 'Code'})
|
||||||
|
nom = db.Column(db.String(255), info={'label': 'Nom'})
|
||||||
|
diminutif = db.Column(db.String(30), info={'label': 'Diminutif'})
|
||||||
|
description = db.Column(db.Text(), info={'label': 'Description'})
|
||||||
|
|
||||||
|
TYPES = [("1","1"),("2","2"),("3","3")]
|
||||||
|
type = db.Column(ChoiceType(TYPES))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<PN {}>".format(self.code)
|
||||||
|
|
||||||
class SAE(db.Model):
|
class SAE(db.Model):
|
||||||
code = db.Column(db.String(5), primary_key = True)
|
code = db.Column(db.String(5), primary_key = True, info={'label': 'Code'})
|
||||||
titre = db.Column(db.String(255))
|
titre = db.Column(db.String(255), info={'label': 'Titre'})
|
||||||
semestre = db.Column(db.String(255))
|
semestre = db.Column(db.String(255), info={'label': 'Semestre'})
|
||||||
heures_encadrees = db.Column(db.String(3))
|
heures_encadrees = db.Column(db.String(3), info={'label': 'Heures Encadrées'})
|
||||||
heures_tp = db.Column(db.String(3))
|
heures_tp = db.Column(db.String(3), info={'label': 'Heures TP'})
|
||||||
projet = db.Column(db.String(3))
|
projet = db.Column(db.String(3), info={'label': 'Projet'})
|
||||||
description = db.Column(db.Text())
|
description = db.Column(db.Text(), info={'label': 'Description'})
|
||||||
coef = db.Column(db.String(255))
|
coef = db.Column(db.String(255), info={'label': 'Coef.'})
|
||||||
ressources = db.relationship("Ressource", secondary=Ressources_SAEs, cascade="all, delete", lazy=False, backref=db.backref("saes", lazy=False))
|
ressources = db.relationship("Ressource", order_by="Ressource.code", secondary=Ressources_SAEs, lazy=False, backref=db.backref("saes", lazy=False))
|
||||||
livrables = db.Column(db.Text())
|
livrables = db.Column(db.Text(), info={'label': 'Livrables'})
|
||||||
motscles = db.Column(db.String(255))
|
motscles = db.Column(db.String(255), info={'label': 'Mots Clés'})
|
||||||
|
|
||||||
|
def getLabel(self):
|
||||||
|
return self.code + " - " + self.titre
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<SAE {}>".format(self.code)
|
return "<SAE {}>".format(self.code)
|
||||||
|
|
||||||
class Ressource(db.Model):
|
class Ressource(db.Model):
|
||||||
code = db.Column(db.String(4), primary_key = True)
|
code = db.Column(db.String(4), primary_key = True, info={'label': 'Code'})
|
||||||
nom = db.Column(db.String(255))
|
nom = db.Column(db.String(255), info={'label': 'Nom'})
|
||||||
semestre = db.Column(db.String(255))
|
semestre = db.Column(db.String(255), info={'label': 'Semestre'})
|
||||||
heures_formation = db.Column(db.String(3))
|
heures_formation = db.Column(db.String(3), info={'label': 'Heures Formation'})
|
||||||
heures_tp = db.Column(db.String(3))
|
heures_tp = db.Column(db.String(3), info={'label': 'Heures TP'})
|
||||||
coef = db.Column(db.String(255))
|
coef = db.Column(db.String(255), info={'label': 'Coef.'})
|
||||||
prerequis = db.Column(db.String(255))
|
prerequis = db.Column(db.String(255), info={'label': 'Prerequis'})
|
||||||
contexte = db.Column(db.Text())
|
contexte = db.Column(db.Text(), info={'label': 'Contexte'})
|
||||||
contenu = db.Column(db.Text())
|
contenu = db.Column(db.Text(), info={'label': 'Contenu'})
|
||||||
motscles = db.Column(db.String(255))
|
motscles = db.Column(db.String(255), info={'label': 'Mots Clés'})
|
||||||
|
|
||||||
|
def getLabel(self):
|
||||||
|
return self.code + " - " + self.nom
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Ressource {}>".format(self.code)
|
return "<Ressource {}>".format(self.code)
|
||||||
|
|
||||||
class Competence(db.Model):
|
|
||||||
code = db.Column(db.String(3), primary_key = True)
|
|
||||||
nom = db.Column(db.String(255))
|
|
||||||
diminutif = db.Column(db.String(30))
|
|
||||||
description = db.Column(db.Text())
|
|
||||||
composantes = db.Column(db.Text())
|
|
||||||
situations = db.Column(db.Text())
|
|
||||||
niveaux = db.Column(db.Text())
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<Compétence {}>".format(self.code)
|
|
206
app/routes.py
206
app/routes.py
@ -6,96 +6,178 @@ import app.models as models
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@app.route("/index")
|
@app.route("/index", methods=["GET","POST"])
|
||||||
def index():
|
def index():
|
||||||
return render_template("base.html")
|
form = AccueilForm()
|
||||||
|
if form.ajouter.data:
|
||||||
|
for i in range(1,7):
|
||||||
|
semestre = models.Semestre(num=i)
|
||||||
|
db.session.add(semestre)
|
||||||
|
db.session.commit()
|
||||||
|
elif form.reset.data:
|
||||||
|
for semestre in models.Semestre.query.all():
|
||||||
|
db.session.delete(semestre)
|
||||||
|
db.session.commit()
|
||||||
|
semestres = sorted(models.Semestre.query.all(), key=lambda semestre: semestre.num)
|
||||||
|
return render_template("index.html", semestres=semestres, form=form)
|
||||||
|
|
||||||
@app.route("/PN", methods=["GET","POST"])
|
@app.route("/Semestre<num>", methods=["GET","POST"])
|
||||||
def PN():
|
def Semestre(num):
|
||||||
|
form = SemestreForm()
|
||||||
|
semestre = models.Semestre.query.filter_by(num=num).first()
|
||||||
|
for i, ue in enumerate(semestre.ues):
|
||||||
|
if form.ueform.__len__() < len(semestre.ues): form.ueform.append_entry(data={"ue": ue.code})
|
||||||
|
# Donne aux dropdowns la liste des objets de formations que les ACs possèdent sans doublons
|
||||||
|
querySAE = []
|
||||||
|
queryRessource = []
|
||||||
|
for ac in ue.acs:
|
||||||
|
for sae in ac.saes:
|
||||||
|
if sae not in querySAE: querySAE.append(sae)
|
||||||
|
for ressource in ac.ressources:
|
||||||
|
if ressource not in queryRessource: queryRessource.append(ressource)
|
||||||
|
form.ueform.__getitem__(i).saes.query=querySAE
|
||||||
|
form.ueform.__getitem__(i).ressources.query=queryRessource
|
||||||
|
# Appuie sur Update
|
||||||
|
if form.update.data:
|
||||||
|
semestre.ues = [ue for ue in form.ues.data]
|
||||||
|
for i, field in enumerate(form.ueform):
|
||||||
|
ue = models.Competence.query.filter_by(code=field.ue.data).first()
|
||||||
|
ue.acs = field.acs.data
|
||||||
|
ue.saes = field.saes.data
|
||||||
|
ue.ressources = field.ressources.data
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for("Semestre", num=num))
|
||||||
|
# Coche les référentiels que l'ue possède
|
||||||
|
for i, ue in enumerate(semestre.ues):
|
||||||
|
form.ueform.__getitem__(i).acs.process_data(ue.acs)
|
||||||
|
form.ueform.__getitem__(i).saes.process_data(ue.saes)
|
||||||
|
form.ueform.__getitem__(i).ressources.process_data(ue.ressources)
|
||||||
|
# Coche les ues que le semestre possède
|
||||||
|
form.ues.process_data(semestre.ues)
|
||||||
|
|
||||||
|
return render_template("semestre.html", semestre=semestre, form=form)
|
||||||
|
|
||||||
|
@app.route("/PN", defaults={"code":None}, methods=["GET","POST"])
|
||||||
|
@app.route("/PN<code>", methods=["GET","POST"])
|
||||||
|
def PN(code):
|
||||||
form = PNForm()
|
form = PNForm()
|
||||||
form.referentiel.choices = [x for x in models.PN.query.all()]
|
form.referentiel.choices = [x for x in models.PN.query.all()]
|
||||||
form_validation = form.validate_on_submit()
|
form.validate_on_submit()
|
||||||
form = form_import(form)
|
if form.charger.data:
|
||||||
form = form_charger(form)
|
if form.chargerRef(): return redirect(url_for("PN", code=form.referentiel.data.split()[1][2:-1]))
|
||||||
temp = form_supprimer(form)
|
elif form.importer.data:
|
||||||
if temp[0] == True: return temp[1]
|
form.importerRef()
|
||||||
else: form = temp[1]
|
elif form.supprimer.data:
|
||||||
if form_validation and not form.charger.data:
|
if form.supprimerRef(): return redirect(url_for("PN"))
|
||||||
|
elif form.validate_on_submit() and not form.charger.data:
|
||||||
if form.exporter.data:
|
if form.exporter.data:
|
||||||
flash("Ajout du référentiel PN: {} ".format(form.code.data))
|
flash("Export du référentiel PN: {} ".format(form.code.data))
|
||||||
form_export(form)
|
form.exporterRef()
|
||||||
form_sauvegarder(form)
|
elif form.sauvegarder.data:
|
||||||
|
form.sauvegarderRef()
|
||||||
return redirect(url_for("PN"))
|
return redirect(url_for("PN"))
|
||||||
|
elif code:
|
||||||
|
referentiel = models.PN.query.filter_by(code="PN"+code).first()
|
||||||
|
if referentiel == None: return redirect(url_for("PN"))
|
||||||
|
else: form.chargerBDD(referentiel)
|
||||||
return render_template("PN.html", form = form)
|
return render_template("PN.html", form = form)
|
||||||
|
|
||||||
@app.route("/AC", methods=["GET","POST"])
|
@app.route("/AC", defaults={"code":None}, methods=["GET","POST"])
|
||||||
def AC():
|
@app.route("/AC<code>", methods=["GET","POST"])
|
||||||
|
def AC(code):
|
||||||
form = ACForm()
|
form = ACForm()
|
||||||
form.referentiel.choices = [x for x in models.AC.query.all()]
|
form.referentiel.choices = [x for x in models.AC.query.all()]
|
||||||
form_validation = form.validate_on_submit()
|
form.validate_on_submit()
|
||||||
form = form_import(form)
|
if form.charger.data:
|
||||||
form = form_charger(form)
|
if form.chargerRef(): return redirect(url_for("AC", code=form.referentiel.data.split()[1][2:-1]))
|
||||||
temp = form_supprimer(form)
|
elif form.importer.data:
|
||||||
if temp[0] == True: return temp[1]
|
form.importerRef()
|
||||||
else: form = temp[1]
|
elif form.supprimer.data:
|
||||||
if form_validation and not form.charger.data:
|
if form.supprimerRef(): return redirect(url_for("AC"))
|
||||||
|
elif form.validate_on_submit() and not form.charger.data:
|
||||||
if form.exporter.data:
|
if form.exporter.data:
|
||||||
flash("Ajout du référentiel AC: {} ".format(form.code.data))
|
flash("Export du référentiel AC: {} ".format(form.code.data))
|
||||||
form_export(form)
|
form.exporterRef()
|
||||||
form_sauvegarder(form)
|
elif form.sauvegarder.data:
|
||||||
|
form.sauvegarderRef()
|
||||||
return redirect(url_for("AC"))
|
return redirect(url_for("AC"))
|
||||||
|
elif code:
|
||||||
|
referentiel = models.AC.query.filter_by(code="AC"+code).first()
|
||||||
|
if referentiel == None: return redirect(url_for("AC"))
|
||||||
|
else: form.chargerBDD(referentiel)
|
||||||
return render_template("AC.html", form = form)
|
return render_template("AC.html", form = form)
|
||||||
|
|
||||||
@app.route("/SAE", methods=["GET","POST"])
|
@app.route("/SAE", defaults={"code":None}, methods=["GET","POST"])
|
||||||
def SAE():
|
@app.route("/SAE<code>", methods=["GET","POST"])
|
||||||
|
def SAE(code):
|
||||||
form = SAEForm()
|
form = SAEForm()
|
||||||
form.referentiel.choices = [x for x in models.SAE.query.all()]
|
form.referentiel.choices = [x for x in models.SAE.query.all()]
|
||||||
form_validation = form.validate_on_submit()
|
form.validate_on_submit()
|
||||||
form = form_import(form)
|
if form.charger.data:
|
||||||
form = form_charger(form)
|
if form.chargerRef(): return redirect(url_for("SAE", code=form.referentiel.data.split()[1][3:-1]))
|
||||||
temp = form_supprimer(form)
|
elif form.importer.data:
|
||||||
if temp[0] == True: return temp[1]
|
form.importerRef()
|
||||||
else: form = temp[1]
|
elif form.supprimer.data:
|
||||||
if form_validation and not form.charger.data:
|
if form.supprimerRef(): return redirect(url_for("SAE"))
|
||||||
|
elif form.validate_on_submit() and not form.charger.data:
|
||||||
if form.exporter.data:
|
if form.exporter.data:
|
||||||
flash("Ajout du référentiel SAE: {} ".format(form.code.data))
|
flash("Export du référentiel SAE: {} ".format(form.code.data))
|
||||||
form_export(form)
|
form.exporterRef()
|
||||||
form_sauvegarder(form)
|
elif form.sauvegarder.data:
|
||||||
|
form.sauvegarderRef()
|
||||||
return redirect(url_for("SAE"))
|
return redirect(url_for("SAE"))
|
||||||
|
elif code:
|
||||||
|
referentiel = models.SAE.query.filter_by(code="SAE"+code).first()
|
||||||
|
if referentiel == None: return redirect(url_for("SAE"))
|
||||||
|
else: form.chargerBDD(referentiel)
|
||||||
return render_template("SAE.html", form = form)
|
return render_template("SAE.html", form = form)
|
||||||
|
|
||||||
@app.route("/Ressource", methods=["GET","POST"])
|
@app.route("/Ressource", defaults={"code":None}, methods=["GET","POST"])
|
||||||
def Ressource():
|
@app.route("/Ressource<code>", methods=["GET","POST"])
|
||||||
|
def Ressource(code):
|
||||||
form = RessourceForm()
|
form = RessourceForm()
|
||||||
form.referentiel.choices = [x for x in models.Ressource.query.all()]
|
form.referentiel.choices = [x for x in models.Ressource.query.all()]
|
||||||
form_validation = form.validate_on_submit()
|
form.validate_on_submit()
|
||||||
form = form_import(form)
|
if form.charger.data:
|
||||||
form = form_charger(form)
|
if form.chargerRef(): return redirect(url_for("Ressource", code=form.referentiel.data.split()[1][1:-1]))
|
||||||
temp = form_supprimer(form)
|
elif form.importer.data:
|
||||||
if temp[0] == True: return temp[1]
|
form.importerRef()
|
||||||
else: form = temp[1]
|
elif form.supprimer.data:
|
||||||
if form_validation and not form.charger.data:
|
if form.supprimerRef(): return redirect(url_for("Ressource"))
|
||||||
|
elif form.validate_on_submit() and not form.charger.data:
|
||||||
if form.exporter.data:
|
if form.exporter.data:
|
||||||
flash("Ajout du référentiel Ressource: {} ".format(form.code.data))
|
flash("Export du référentiel Ressource: {} ".format(form.code.data))
|
||||||
form_export(form)
|
form.exporterRef()
|
||||||
form_sauvegarder(form)
|
elif form.sauvegarder.data:
|
||||||
|
form.sauvegarderRef()
|
||||||
return redirect(url_for("Ressource"))
|
return redirect(url_for("Ressource"))
|
||||||
|
elif code:
|
||||||
|
referentiel = models.Ressource.query.filter_by(code="R"+code).first()
|
||||||
|
if referentiel == None: return redirect(url_for("Ressource"))
|
||||||
|
else: form.chargerBDD(referentiel)
|
||||||
return render_template("Ressource.html", form = form)
|
return render_template("Ressource.html", form = form)
|
||||||
|
|
||||||
@app.route("/Competence", methods=["GET","POST"])
|
@app.route("/Competence", defaults={"code":None}, methods=["GET","POST"])
|
||||||
def Competence():
|
@app.route("/Competence<code>", methods=["GET","POST"])
|
||||||
|
def Competence(code):
|
||||||
form = CompetenceForm()
|
form = CompetenceForm()
|
||||||
form.referentiel.choices = [x for x in models.Competence.query.all()]
|
form.referentiel.choices = [x for x in models.Competence.query.all()]
|
||||||
form_validation = form.validate_on_submit()
|
form.validate_on_submit()
|
||||||
form = form_import(form)
|
if form.charger.data:
|
||||||
form = form_charger(form)
|
if form.chargerRef(): return redirect(url_for("Competence", code=form.referentiel.data.split()[1][2:-1]))
|
||||||
temp = form_supprimer(form)
|
elif form.importer.data:
|
||||||
if temp[0] == True: return temp[1]
|
form.importerRef()
|
||||||
else: form = temp[1]
|
elif form.supprimer.data:
|
||||||
if form_validation and not form.charger.data:
|
if form.supprimerRef(): return redirect(url_for("Compentence"))
|
||||||
|
elif form.validate_on_submit() and not form.charger.data:
|
||||||
if form.exporter.data:
|
if form.exporter.data:
|
||||||
flash("Ajout du référentielCompetence: {} ".format(form.code.data))
|
flash("Export du référentielCompetence: {} ".format(form.code.data))
|
||||||
form_export(form)
|
form.exporterRef()
|
||||||
form_sauvegarder(form)
|
if form.sauvegarder.data:
|
||||||
|
form.sauvegarderRef()
|
||||||
return redirect(url_for("Competence"))
|
return redirect(url_for("Competence"))
|
||||||
|
elif code:
|
||||||
|
referentiel = models.Competence.query.filter_by(code="RT"+code).first()
|
||||||
|
if referentiel == None: return redirect(url_for("Competence"))
|
||||||
|
else: form.chargerBDD(referentiel)
|
||||||
return render_template("Competence.html", form = form)
|
return render_template("Competence.html", form = form)
|
12
app/static/js/base.js
Normal file
12
app/static/js/base.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
$("document").ready(function() {
|
||||||
|
// Affichage mobile du menu | affiche/cache le menu contenant la liste des catégories
|
||||||
|
// en appuyant sur le burger/les trois traits
|
||||||
|
$(".navbar-burger").click(function() {
|
||||||
|
$(".navbar-burger").toggleClass("is-active");
|
||||||
|
$(".navbar-menu").toggleClass("is-active");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".navbar-item.has-dropdown").click(function() {
|
||||||
|
$(this).toggleClass("is-active");
|
||||||
|
});
|
||||||
|
});
|
@ -7,7 +7,9 @@
|
|||||||
|
|
||||||
{{ render_field(form.code,"input") }}
|
{{ render_field(form.code,"input") }}
|
||||||
{{ render_field(form.titre,"input") }}
|
{{ render_field(form.titre,"input") }}
|
||||||
{{ render_field(form.saes,"input") }}
|
{{ render_list(form.saes) }}
|
||||||
{{ render_field(form.ressources,"input") }}
|
<div class="field">{{ render_dropdown(form.saes) }}</div>
|
||||||
|
{{ render_list(form.ressources) }}
|
||||||
|
<div class="field">{{ render_dropdown(form.ressources) }}</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -11,8 +11,10 @@
|
|||||||
{{ render_field(form.heures_formation,"input") }}
|
{{ render_field(form.heures_formation,"input") }}
|
||||||
{{ render_field(form.heures_tp,"input") }}
|
{{ render_field(form.heures_tp,"input") }}
|
||||||
{{ render_field(form.coef,"input") }}
|
{{ render_field(form.coef,"input") }}
|
||||||
{{ render_field(form.acs,"input") }}
|
{{ render_list(form.acs) }}
|
||||||
{{ render_field(form.saes,"input") }}
|
<div class="field">{{ render_dropdown(form.acs) }}</div>
|
||||||
|
{{ render_list(form.saes) }}
|
||||||
|
<div class="field">{{ render_dropdown(form.saes) }}</div>
|
||||||
{{ render_field(form.prerequis,"input") }}
|
{{ render_field(form.prerequis,"input") }}
|
||||||
{{ render_field(form.contexte,"textarea") }}
|
{{ render_field(form.contexte,"textarea") }}
|
||||||
{{ render_field(form.contenu,"textarea") }}
|
{{ render_field(form.contenu,"textarea") }}
|
||||||
|
@ -13,8 +13,10 @@
|
|||||||
{{ render_field(form.projet,"input") }}
|
{{ render_field(form.projet,"input") }}
|
||||||
{{ render_field(form.description,"textarea") }}
|
{{ render_field(form.description,"textarea") }}
|
||||||
{{ render_field(form.coef,"input") }}
|
{{ render_field(form.coef,"input") }}
|
||||||
{{ render_field(form.acs,"input") }}
|
{{ render_list(form.acs) }}
|
||||||
{{ render_field(form.ressources,"input") }}
|
<div class="field">{{ render_dropdown(form.acs) }}</div>
|
||||||
|
{{ render_list(form.ressources) }}
|
||||||
|
<div class="field">{{ render_dropdown(form.ressources) }}</div>
|
||||||
{{ render_field(form.livrables,"textarea") }}
|
{{ render_field(form.livrables,"textarea") }}
|
||||||
{{ render_field(form.motscles,"input") }}
|
{{ render_field(form.motscles,"input") }}
|
||||||
|
|
||||||
|
@ -1,3 +1,47 @@
|
|||||||
|
{% macro render_dropdown(field) %}
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<div class="dropdown is-hoverable" style="width: 100%">
|
||||||
|
<div class="dropdown-trigger" style="width: 100%">
|
||||||
|
<span class="button is-fullwidth" aria-controls="dropdown-menu">
|
||||||
|
<span>{{ field.label }}</span>
|
||||||
|
<span class="icon is-small">
|
||||||
|
<i class="fas fa-angle-down"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" style="width: 100%">
|
||||||
|
<div class="dropdown-content">
|
||||||
|
{% for val in field %}
|
||||||
|
<div class="dropdown-item">
|
||||||
|
{{ val }} {{ val.label }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro render_field(field,class) %}
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ field.label }}</label>
|
||||||
|
<div class="control">
|
||||||
|
{{ field(class=class)}}
|
||||||
|
</div>
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<p class="help is-danger">{{error}}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro render_list(field) %}
|
||||||
|
<ul>
|
||||||
|
{% for ref in field.data %}
|
||||||
|
<li>{{ ref.code }} - {{ ref.titre }}{{ ref.nom }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="has-navbar-fixed-top">
|
<html class="has-navbar-fixed-top">
|
||||||
<head>
|
<head>
|
||||||
@ -7,6 +51,7 @@
|
|||||||
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
|
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
|
||||||
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
|
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/base.js') }}"></script>
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -25,6 +70,18 @@
|
|||||||
<div class="navbar-menu">
|
<div class="navbar-menu">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<!-- Liste des catégories -->
|
<!-- Liste des catégories -->
|
||||||
|
<a class="navbar-item" href="{{ url_for('index') }}">Accueil</a>
|
||||||
|
<div class="navbar-item has-dropdown">
|
||||||
|
<a class="navbar-link">Semestres</a>
|
||||||
|
<div class="navbar-dropdown">
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=1) }}">Semestre 1</a>
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=2) }}">Semestre 2</a>
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=3) }}">Semestre 3</a>
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=4) }}">Semestre 4</a>
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=5) }}">Semestre 5</a>
|
||||||
|
<a class="navbar-item" href="{{ url_for('Semestre', num=6) }}">Semestre 6</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<a class="navbar-item" href="{{ url_for('PN') }}">PN</a>
|
<a class="navbar-item" href="{{ url_for('PN') }}">PN</a>
|
||||||
<a class="navbar-item" href="{{ url_for('AC') }}">AC</a>
|
<a class="navbar-item" href="{{ url_for('AC') }}">AC</a>
|
||||||
<a class="navbar-item" href="{{ url_for('SAE') }}">SAÉ</a>
|
<a class="navbar-item" href="{{ url_for('SAE') }}">SAÉ</a>
|
||||||
@ -52,3 +109,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
@ -1,14 +1,3 @@
|
|||||||
{% macro render_field(field,class) %}
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">{{ field.label }}</label>
|
|
||||||
<div class="control">
|
|
||||||
{{ field(class=class)}}
|
|
||||||
</div>
|
|
||||||
{% for error in field.errors %}
|
|
||||||
<p class="help is-danger">{{error}}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -49,7 +38,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for error in form.charger.errors %}
|
{% for error in form.referentiel.errors %}
|
||||||
<p class="help is-danger">{{error}}</p>
|
<p class="help is-danger">{{error}}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if form.referentiel.choices|length != 0 %}
|
{% if form.referentiel.choices|length != 0 %}
|
||||||
|
35
app/templates/index.html
Normal file
35
app/templates/index.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Accueil{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content">
|
||||||
|
{% for semestre in semestres %}
|
||||||
|
<h1 class="title"><a style="color: inherit;" href="{{ url_for('Semestre', num=semestre.num) }}">Semestre {{ semestre.num }} <i class="far fa-edit fa-sm"></i></a></h1>
|
||||||
|
<ul>
|
||||||
|
{% for competence in semestre.ues %}
|
||||||
|
<li><h2 class="title is-4"><a style="color: inherit;" href="{{ url_for('Competence', code=competence.code[-1]) }}">UE{{ semestre.num }}.{{ competence.code[-1] }} - {{ competence.nom }} <i class="far fa-edit fa-sm"></i></a></h2></li>
|
||||||
|
<ul>
|
||||||
|
{% for ac in competence.acs %}
|
||||||
|
<li><a style="color: inherit;" href="{{ url_for('AC', code=ac.code[2:]) }}"><span class="tag is-info">{{ ac.code }}</span> - {{ ac.titre }} <i class="far fa-edit fa-sm"></i></a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<form action="" method="post" novalidate>
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
<div class="buttons">
|
||||||
|
{% if not semestres %}
|
||||||
|
{{ form.ajouter(class="button") }}
|
||||||
|
{{ form.reset(class="button is-static") }}
|
||||||
|
{% else %}
|
||||||
|
{{ form.ajouter(class="button is-static") }}
|
||||||
|
{{ form.reset(class="button") }}
|
||||||
|
{% endif %}
|
||||||
|
{{ form.exporter(class="button is-static") }}
|
||||||
|
{{ form.importer(class="button is-static") }}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
41
app/templates/semestre.html
Normal file
41
app/templates/semestre.html
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Semestre 1{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form action="" method="post" novalidate>
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
<div class="content">
|
||||||
|
{% for competence in semestre.ues %}
|
||||||
|
<h2 class="title"><a style="color: inherit;" href="{{ url_for('Competence', code=competence.code[-1]) }}">UE{{ semestre.num }}.{{ competence.code[-1] }} - {{ competence.nom }} <i class="far fa-edit fa-sm"></i></a></h2>
|
||||||
|
<ul>
|
||||||
|
{% for ac in competence.acs %}
|
||||||
|
<li><a style="color: inherit;" href="{{ url_for('AC', code=ac.code[2:]) }}"><span class="tag is-info">{{ ac.code }}</span> - {{ ac.titre }} <i class="far fa-edit fa-sm"></i></a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{{ form.ueform.__getitem__(loop.index0).ue }}
|
||||||
|
{{ render_dropdown(form.ueform.__getitem__(loop.index0).acs) }}
|
||||||
|
<p>Objets de formation</p>
|
||||||
|
<ul>
|
||||||
|
{% for sae in competence.saes %}
|
||||||
|
<li><a style="color: inherit;" href="{{ url_for('SAE', code=sae.code[3:]) }}"><span class="tag is-info">{{ sae.code }}</span> - {{ sae.titre }} <i class="far fa-edit fa-sm"></i></a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{{ render_dropdown(form.ueform.__getitem__(loop.index0).saes) }}
|
||||||
|
<ul>
|
||||||
|
{% for ressource in competence.ressources %}
|
||||||
|
<li><a style="color: inherit;" href="{{ url_for('Ressource', code=ressource.code[1:]) }}"><span class="tag is-info">{{ ressource.code }}</span> - {{ ressource.nom }} <i class="far fa-edit fa-sm"></i></a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{{ render_dropdown(form.ueform.__getitem__(loop.index0).ressources) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
{{ render_dropdown(form.ues) }}
|
||||||
|
<div class="control">
|
||||||
|
{{ form.update(class="button") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
38
migrations/versions/03ec797adcc8_.py
Normal file
38
migrations/versions/03ec797adcc8_.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 03ec797adcc8
|
||||||
|
Revises: 15feabeae315
|
||||||
|
Create Date: 2021-05-12 12:41:11.703242
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '03ec797adcc8'
|
||||||
|
down_revision = '15feabeae315'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('semestre',
|
||||||
|
sa.Column('num', sa.String(length=1), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('num')
|
||||||
|
)
|
||||||
|
op.create_table('Semestres_Competences',
|
||||||
|
sa.Column('Semestre_num', sa.String(length=1), nullable=True),
|
||||||
|
sa.Column('Competence_code', sa.String(length=3), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['Competence_code'], ['competence.code'], ),
|
||||||
|
sa.ForeignKeyConstraint(['Semestre_num'], ['semestre.num'], )
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('Semestres_Competences')
|
||||||
|
op.drop_table('semestre')
|
||||||
|
# ### end Alembic commands ###
|
40
migrations/versions/8b0862eb0856_.py
Normal file
40
migrations/versions/8b0862eb0856_.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 8b0862eb0856
|
||||||
|
Revises: cff96c022884
|
||||||
|
Create Date: 2021-06-01 18:50:16.604312
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '8b0862eb0856'
|
||||||
|
down_revision = 'cff96c022884'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('Ressources_Competences',
|
||||||
|
sa.Column('Ressource_code', sa.String(length=6), nullable=True),
|
||||||
|
sa.Column('Competence_code', sa.String(length=3), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['Competence_code'], ['competence.code'], ),
|
||||||
|
sa.ForeignKeyConstraint(['Ressource_code'], ['ressource.code'], )
|
||||||
|
)
|
||||||
|
op.create_table('SAEs_Competences',
|
||||||
|
sa.Column('SAE_code', sa.String(length=6), nullable=True),
|
||||||
|
sa.Column('Competence_code', sa.String(length=3), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['Competence_code'], ['competence.code'], ),
|
||||||
|
sa.ForeignKeyConstraint(['SAE_code'], ['SAE.code'], )
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('SAEs_Competences')
|
||||||
|
op.drop_table('Ressources_Competences')
|
||||||
|
# ### end Alembic commands ###
|
33
migrations/versions/cff96c022884_.py
Normal file
33
migrations/versions/cff96c022884_.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: cff96c022884
|
||||||
|
Revises: 03ec797adcc8
|
||||||
|
Create Date: 2021-05-13 15:30:50.203249
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cff96c022884'
|
||||||
|
down_revision = '03ec797adcc8'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('ACs_Competences',
|
||||||
|
sa.Column('AC_code', sa.String(length=6), nullable=True),
|
||||||
|
sa.Column('Competence_code', sa.String(length=3), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['AC_code'], ['AC.code'], ),
|
||||||
|
sa.ForeignKeyConstraint(['Competence_code'], ['competence.code'], )
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('ACs_Competences')
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Reference in New Issue
Block a user