diff --git a/app.db b/app.db index 4f8dc27..03108ca 100644 Binary files a/app.db and b/app.db differ diff --git a/app/forms.py b/app/forms.py index bb0146a..1948da5 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,9 +1,10 @@ from flask_wtf import FlaskForm from flask_wtf.file import FileAllowed from wtforms import StringField, SubmitField, FileField, TextAreaField, RadioField -from wtforms.validators import DataRequired, Regexp, Optional - +from wtforms.validators import DataRequired, Regexp, Optional, ValidationError +from app import db import app.models as models + import yaml import os import re @@ -13,6 +14,13 @@ REPERTOIRE_YAML = "./export/" if not os.path.exists(REPERTOIRE_YAML): os.makedirs(REPERTOIRE_YAML) +def validate_ref_list(regex, message): + def _validate_ref_list(form, field): + refs = field.data.strip() + " " + if re.match(regex, refs) == None: + raise ValidationError(message) + return _validate_ref_list + class Form(FlaskForm): sauvegarder = SubmitField("Sauvegarder") @@ -36,7 +44,7 @@ class ACForm(Form): 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()] ) + saes = StringField("SAEs", validators=[DataRequired(), validate_ref_list("^(\s*(SAE\d{2}\s+)*)$", message="Les saes doit être de la forme SAE00.")] ) class SAEForm(Form): regex = "^SAE\d{2}$" @@ -49,8 +57,8 @@ class SAEForm(Form): projet = StringField("Projet", validators=[DataRequired()] ) description = TextAreaField("Description", validators=[DataRequired()] ) coef = StringField("Coef.", validators=[DataRequired()] ) - acs = StringField("ACs", validators=[DataRequired()] ) - ressources = StringField("Ressources", 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()] ) @@ -63,8 +71,8 @@ class RessourceForm(Form): heures_formation = StringField("Heures formation", validators=[DataRequired()] ) heures_tp = StringField("Heures TP", validators=[DataRequired()] ) coef = StringField("Coef.", validators=[DataRequired()] ) - acs = StringField("ACs", validators=[DataRequired()] ) - saes = StringField("SAEs", 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()] ) @@ -81,6 +89,9 @@ class CompetenceForm(Form): situations = TextAreaField("Situations", validators=[DataRequired()] ) niveaux = TextAreaField("Niveaux", validators=[DataRequired()] ) +categorie_liste = ["saes","ressources","acs"] +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é @@ -93,7 +104,10 @@ def form_import(form): return form fichier_Yaml = yaml.safe_load(form.fichier.data.read()) for categorie, valeur in fichier_Yaml.items(): - form[categorie].process_data(valeur) + 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 @@ -101,7 +115,10 @@ 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())[6:-1]: - output[categorie] = valeur + if categorie in categorie_liste: + output[categorie] = [ referentiel for referentiel in valeur.split(separateur) ] + else: + output[categorie] = valeur fichier = REPERTOIRE_YAML + form.code.data + ".yml" with open(fichier, "w", encoding="utf8") as fid: fid.write(yaml.dump(output)) @@ -116,6 +133,36 @@ def form_charger(form): model = getattr(models, temp[0]) referentiel = model.query.filter_by(code=temp[1]).first() for categorie in list(referentiel.__dict__)[1:]: - form[categorie].process_data(referentiel.__dict__[categorie]) + 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 \ No newline at end of file + 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())[6:-1]: + if categorie in categorie_liste: + resultat = [] + refs = [ ref for ref in form[categorie].data.split(separateur) ] + ref_model = getattr(models, categorie.upper()[:-1]) + 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() \ No newline at end of file diff --git a/app/models.py b/app/models.py index eccd771..157a1bd 100644 --- a/app/models.py +++ b/app/models.py @@ -28,7 +28,7 @@ class PN(db.Model): class AC(db.Model): code = db.Column(db.String(6), primary_key = True) titre = db.Column(db.String(255)) - saes = db.relationship("SAE", secondary=SAEs_ACs, lazy=True, backref=db.backref("acs", lazy=True)) + saes = db.relationship("SAE", secondary=SAEs_ACs, lazy=False, backref=db.backref("acs", lazy=False)) def __repr__(self): return "".format(self.code) @@ -43,7 +43,7 @@ class SAE(db.Model): description = db.Column(db.Text()) coef = db.Column(db.String(255)) #acs = db.relationship("AC", secondary=SAEs_ACs, lazy=True, backref=db.backref("saes", lazy=True)) - ressources = db.relationship("Ressource", secondary=Ressources_SAEs, lazy=True, backref=db.backref("saes", lazy=True)) + ressources = db.relationship("Ressource", secondary=Ressources_SAEs, lazy=False, backref=db.backref("saes", lazy=False)) livrables = db.Column(db.Text()) motscles = db.Column(db.String(255)) diff --git a/app/routes.py b/app/routes.py index d969478..0fa32ef 100644 --- a/app/routes.py +++ b/app/routes.py @@ -21,13 +21,7 @@ def PN(): if form.exporter.data: flash("Ajout du référentiel PN: {} ".format(form.code.data)) form_export(form) - if form.sauvegarder.data: - pn = models.PN.query.filter_by(code=form.code.data).first() - if pn == None: - pn = models.PN() - form.populate_obj(pn) - db.session.add(pn) - db.session.commit() + form_sauvegarder(form) return redirect(url_for("PN")) return render_template("PN.html", form = form) @@ -42,13 +36,7 @@ def AC(): if form.exporter.data: flash("Ajout du référentiel AC: {} ".format(form.code.data)) form_export(form) - if form.sauvegarder.data: - ac = models.AC.query.filter_by(code=form.code.data).first() - if ac == None: - ac = models.AC() - form.populate_obj(ac) - db.session.add(ac) - db.session.commit() + form_sauvegarder(form) return redirect(url_for("AC")) return render_template("AC.html", form = form) @@ -63,13 +51,7 @@ def SAE(): if form.exporter.data: flash("Ajout du référentiel SAE: {} ".format(form.code.data)) form_export(form) - if form.sauvegarder.data: - sae = models.SAE.query.filter_by(code=form.code.data).first() - if sae == None: - sae = models.SAE() - form.populate_obj(sae) - db.session.add(sae) - db.session.commit() + form_sauvegarder(form) return redirect(url_for("SAE")) return render_template("SAE.html", form = form) @@ -84,13 +66,7 @@ def Ressource(): if form.exporter.data: flash("Ajout du référentiel Ressource: {} ".format(form.code.data)) form_export(form) - if form.sauvegarder.data: - ressource = models.Ressource.query.filter_by(code=form.code.data).first() - if ressource == None: - ressource = models.Ressource() - form.populate_obj(ressource) - db.session.add(ressource) - db.session.commit() + form_sauvegarder(form) return redirect(url_for("Ressource")) return render_template("Ressource.html", form = form) @@ -105,12 +81,6 @@ def Competence(): if form.exporter.data: flash("Ajout du référentielCompetence: {} ".format(form.code.data)) form_export(form) - if form.sauvegarder.data: - competence = models.Competence.query.filter_by(code=form.code.data).first() - if competence == None: - competence = models.Competence() - form.populate_obj(competence) - db.session.add(competence) - db.session.commit() + form_sauvegarder(form) return redirect(url_for("Competence")) return render_template("Competence.html", form = form) \ No newline at end of file diff --git a/app/templates/form.html b/app/templates/form.html index f67aab8..45ed6e0 100644 --- a/app/templates/form.html +++ b/app/templates/form.html @@ -51,7 +51,7 @@ diff --git a/migrations/versions/c000b3a8d714_.py b/migrations/versions/15feabeae315_.py similarity index 62% rename from migrations/versions/c000b3a8d714_.py rename to migrations/versions/15feabeae315_.py index 841af97..a9117ba 100644 --- a/migrations/versions/c000b3a8d714_.py +++ b/migrations/versions/15feabeae315_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: c000b3a8d714 -Revises: c1377d41bf27 -Create Date: 2021-05-06 17:50:35.360220 +Revision ID: 15feabeae315 +Revises: +Create Date: 2021-05-07 16:45:01.928258 """ from alembic import op @@ -10,8 +10,8 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = 'c000b3a8d714' -down_revision = 'c1377d41bf27' +revision = '15feabeae315' +down_revision = None branch_labels = None depends_on = None @@ -21,7 +21,14 @@ def upgrade(): op.create_table('AC', sa.Column('code', sa.String(length=6), nullable=False), sa.Column('titre', sa.String(length=255), nullable=True), - sa.Column('saes', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('code') + ) + op.create_table('PN', + sa.Column('code', sa.String(length=3), nullable=False), + sa.Column('nom', sa.String(length=255), nullable=True), + sa.Column('diminutif', sa.String(length=30), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('type', sa.String(length=1), nullable=True), sa.PrimaryKeyConstraint('code') ) op.create_table('SAE', @@ -33,8 +40,6 @@ def upgrade(): sa.Column('projet', sa.String(length=3), nullable=True), sa.Column('description', sa.Text(), nullable=True), sa.Column('coef', sa.String(length=255), nullable=True), - sa.Column('acs', sa.String(length=255), nullable=True), - sa.Column('ressources', sa.String(length=255), nullable=True), sa.Column('livrables', sa.Text(), nullable=True), sa.Column('motscles', sa.String(length=255), nullable=True), sa.PrimaryKeyConstraint('code') @@ -56,21 +61,41 @@ def upgrade(): sa.Column('heures_formation', sa.String(length=3), nullable=True), sa.Column('heures_tp', sa.String(length=3), nullable=True), sa.Column('coef', sa.String(length=255), nullable=True), - sa.Column('acs', sa.String(length=255), nullable=True), - sa.Column('saes', sa.String(length=255), nullable=True), sa.Column('prerequis', sa.String(length=255), nullable=True), sa.Column('contexte', sa.Text(), nullable=True), sa.Column('contenu', sa.Text(), nullable=True), sa.Column('motscles', sa.String(length=255), nullable=True), sa.PrimaryKeyConstraint('code') ) + op.create_table('Ressources_ACs', + sa.Column('Ressource_code', sa.String(length=4), nullable=True), + sa.Column('AC_code', sa.String(length=6), nullable=True), + sa.ForeignKeyConstraint(['AC_code'], ['AC.code'], ), + sa.ForeignKeyConstraint(['Ressource_code'], ['ressource.code'], ) + ) + op.create_table('Ressources_SAEs', + sa.Column('Ressource_code', sa.String(length=4), nullable=True), + sa.Column('SAE_code', sa.String(length=5), nullable=True), + sa.ForeignKeyConstraint(['Ressource_code'], ['ressource.code'], ), + sa.ForeignKeyConstraint(['SAE_code'], ['SAE.code'], ) + ) + op.create_table('SAEs_ACs', + sa.Column('SAE_code', sa.String(length=5), nullable=True), + sa.Column('AC_code', sa.String(length=6), nullable=True), + sa.ForeignKeyConstraint(['AC_code'], ['AC.code'], ), + sa.ForeignKeyConstraint(['SAE_code'], ['SAE.code'], ) + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('SAEs_ACs') + op.drop_table('Ressources_SAEs') + op.drop_table('Ressources_ACs') op.drop_table('ressource') op.drop_table('competence') op.drop_table('SAE') + op.drop_table('PN') op.drop_table('AC') # ### end Alembic commands ### diff --git a/migrations/versions/be67c6934c05_pn_table.py b/migrations/versions/be67c6934c05_pn_table.py deleted file mode 100644 index 88ae7b1..0000000 --- a/migrations/versions/be67c6934c05_pn_table.py +++ /dev/null @@ -1,34 +0,0 @@ -"""PN table - -Revision ID: be67c6934c05 -Revises: -Create Date: 2021-05-03 17:01:39.845539 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'be67c6934c05' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('PN', - sa.Column('code', sa.String(length=3), nullable=False), - sa.Column('nom', sa.String(length=255), nullable=True), - sa.Column('diminutif', sa.String(length=30), nullable=True), - sa.Column('description', sa.Text(), nullable=True), - sa.PrimaryKeyConstraint('code') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('PN') - # ### end Alembic commands ### diff --git a/migrations/versions/c1377d41bf27_pn_table.py b/migrations/versions/c1377d41bf27_pn_table.py deleted file mode 100644 index 448081a..0000000 --- a/migrations/versions/c1377d41bf27_pn_table.py +++ /dev/null @@ -1,28 +0,0 @@ -"""PN table - -Revision ID: c1377d41bf27 -Revises: be67c6934c05 -Create Date: 2021-05-03 17:20:44.055359 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'c1377d41bf27' -down_revision = 'be67c6934c05' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('PN', sa.Column('type', sa.Integer(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('PN', 'type') - # ### end Alembic commands ### diff --git a/migrations/versions/e52d97e91e29_.py b/migrations/versions/e52d97e91e29_.py deleted file mode 100644 index ec334ee..0000000 --- a/migrations/versions/e52d97e91e29_.py +++ /dev/null @@ -1,57 +0,0 @@ -"""empty message - -Revision ID: e52d97e91e29 -Revises: c000b3a8d714 -Create Date: 2021-05-07 14:03:45.369279 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'e52d97e91e29' -down_revision = 'c000b3a8d714' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('Ressources_ACs', - sa.Column('Ressource_code', sa.String(length=4), nullable=True), - sa.Column('AC_code', sa.String(length=6), nullable=True), - sa.ForeignKeyConstraint(['AC_code'], ['AC.code'], ), - sa.ForeignKeyConstraint(['Ressource_code'], ['ressource.code'], ) - ) - op.create_table('Ressources_SAEs', - sa.Column('Ressource_code', sa.String(length=4), nullable=True), - sa.Column('SAE_code', sa.String(length=5), nullable=True), - sa.ForeignKeyConstraint(['Ressource_code'], ['ressource.code'], ), - sa.ForeignKeyConstraint(['SAE_code'], ['SAE.code'], ) - ) - op.create_table('SAEs_ACs', - sa.Column('SAE_code', sa.String(length=5), nullable=True), - sa.Column('AC_code', sa.String(length=6), nullable=True), - sa.ForeignKeyConstraint(['AC_code'], ['AC.code'], ), - sa.ForeignKeyConstraint(['SAE_code'], ['SAE.code'], ) - ) - op.drop_column('AC', 'saes') - op.drop_column('SAE', 'ressources') - op.drop_column('SAE', 'acs') - op.drop_column('ressource', 'saes') - op.drop_column('ressource', 'acs') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('ressource', sa.Column('acs', sa.VARCHAR(length=255), nullable=True)) - op.add_column('ressource', sa.Column('saes', sa.VARCHAR(length=255), nullable=True)) - op.add_column('SAE', sa.Column('acs', sa.VARCHAR(length=255), nullable=True)) - op.add_column('SAE', sa.Column('ressources', sa.VARCHAR(length=255), nullable=True)) - op.add_column('AC', sa.Column('saes', sa.VARCHAR(length=255), nullable=True)) - op.drop_table('SAEs_ACs') - op.drop_table('Ressources_SAEs') - op.drop_table('Ressources_ACs') - # ### end Alembic commands ###