Docfile commited on
Commit
c5ca48a
·
verified ·
1 Parent(s): 5db7925

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +213 -0
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, redirect, url_for, flash
2
+ from flask_sqlalchemy import SQLAlchemy
3
+ from sqlalchemy import func # Import func
4
+ from bleach import clean
5
+ from bs4 import BeautifulSoup
6
+
7
+ cle = os.environ.get("TOKEN")
8
+
9
+
10
+
11
+
12
+ app = Flask(__name__)
13
+ app.config['SQLALCHEMY_DATABASE_URI'] = cle
14
+ app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
15
+ app.config['SECRET_KEY'] = 'une_cle_secrete_tres_longue' # Clé secrète pour les messages flash
16
+
17
+ db = SQLAlchemy(app)
18
+
19
+ # --- Modèles (adaptés de models.py, pour la cohérence) ---
20
+
21
+ class Matiere(db.Model):
22
+ """Modèle représentant une matière."""
23
+ __tablename__ = 'matiere'
24
+ id = db.Column(db.Integer, primary_key=True)
25
+ nom = db.Column(db.String(64), unique=True, nullable=False)
26
+ sous_categories = db.relationship('SousCategorie', backref='matiere', lazy='dynamic', cascade="all, delete-orphan")
27
+
28
+ def __repr__(self):
29
+ return f"<Matiere {self.nom}>"
30
+
31
+ class SousCategorie(db.Model):
32
+ """Modèle représentant une sous-catégorie."""
33
+ __tablename__ = 'sous_categorie'
34
+ id = db.Column(db.Integer, primary_key=True)
35
+ nom = db.Column(db.String(64), nullable=False)
36
+ matiere_id = db.Column(db.Integer, db.ForeignKey('matiere.id'), nullable=False)
37
+ textes = db.relationship('Texte', backref='sous_categorie', lazy='dynamic', cascade="all, delete-orphan")
38
+ __table_args__ = (db.UniqueConstraint('nom', 'matiere_id', name='_nom_matiere_uc'), {})
39
+
40
+ def __repr__(self):
41
+ return f"<SousCategorie {self.nom}>"
42
+
43
+ class Texte(db.Model):
44
+ """Modèle représentant un texte."""
45
+ __tablename__ = 'texte'
46
+ id = db.Column(db.Integer, primary_key=True)
47
+ titre = db.Column(db.String(128), nullable=False)
48
+ contenu = db.Column(db.Text, nullable=False)
49
+ sous_categorie_id = db.Column(db.Integer, db.ForeignKey('sous_categorie.id'), nullable=False)
50
+
51
+ def __repr__(self):
52
+ return f"<Texte {self.titre}>"
53
+
54
+
55
+ # --- Fonctions utilitaires ---
56
+
57
+ def sanitize_html(html_content):
58
+ """Assainit le contenu HTML (comme dans ton admin.py)."""
59
+ allowed_tags = [
60
+ 'a', 'abbr', 'acronym', 'b', 'blockquote', 'br', 'code', 'div', 'em',
61
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'li', 'ol', 'p',
62
+ 'pre', 'span', 'strong', 'table', 'tbody', 'td', 'th', 'thead', 'tr', 'ul'
63
+ ]
64
+ allowed_attributes = {
65
+ '*': ['class', 'id', 'style'],
66
+ 'a': ['href', 'rel', 'target', 'title'],
67
+ 'img': ['alt', 'src', 'width', 'height'],
68
+ 'table': ['border', 'cellpadding', 'cellspacing']
69
+ }
70
+ cleaned_html = clean(html_content, tags=allowed_tags, attributes=allowed_attributes, strip=True)
71
+ soup = BeautifulSoup(cleaned_html, 'html.parser')
72
+ for tag in soup.find_all():
73
+ if not tag.contents and tag.name not in ['br', 'hr', 'img']:
74
+ tag.decompose()
75
+ return str(soup)
76
+
77
+ # --- Routes ---
78
+
79
+ @app.route('/', methods=['GET', 'POST'])
80
+ def gere():
81
+ if request.method == 'POST':
82
+ # Traitement des actions (ajout, modification, suppression)
83
+ action = request.form.get('action')
84
+
85
+ if action == 'add_matiere':
86
+ nom_matiere = request.form.get('nom_matiere')
87
+ if nom_matiere:
88
+ nouvelle_matiere = Matiere(nom=nom_matiere)
89
+ db.session.add(nouvelle_matiere)
90
+ try:
91
+ db.session.commit()
92
+ flash(f"Matière '{nom_matiere}' ajoutée avec succès.", 'success')
93
+ except Exception as e:
94
+ db.session.rollback()
95
+ flash(f"Erreur lors de l'ajout de la matière : {e}", 'danger')
96
+
97
+ elif action == 'add_sous_categorie':
98
+ nom_sous_categorie = request.form.get('nom_sous_categorie')
99
+ matiere_id = request.form.get('matiere_id')
100
+ if nom_sous_categorie and matiere_id:
101
+ nouvelle_sous_categorie = SousCategorie(nom=nom_sous_categorie, matiere_id=matiere_id)
102
+ db.session.add(nouvelle_sous_categorie)
103
+ try:
104
+ db.session.commit()
105
+ flash(f"Sous-catégorie '{nom_sous_categorie}' ajoutée avec succès.", 'success')
106
+ except Exception as e:
107
+ db.session.rollback()
108
+ flash(f"Erreur : {e}", 'danger')
109
+ elif action == 'add_texte':
110
+ titre_texte = request.form.get('titre_texte')
111
+ contenu_texte = request.form.get('contenu_texte')
112
+ sous_categorie_id = request.form.get('sous_categorie_id')
113
+
114
+ if titre_texte and contenu_texte and sous_categorie_id:
115
+ # Assainir le contenu HTML
116
+ contenu_texte_sanitized = sanitize_html(contenu_texte)
117
+ nouveau_texte = Texte(titre=titre_texte, contenu=contenu_texte_sanitized, sous_categorie_id=sous_categorie_id)
118
+ db.session.add(nouveau_texte)
119
+ try:
120
+ db.session.commit()
121
+ flash(f"Texte '{titre_texte}' ajouté avec succès.", 'success')
122
+ except Exception as e:
123
+ db.session.rollback()
124
+ flash(f"Erreur lors de l'ajout : {e}", 'danger')
125
+
126
+
127
+ elif action.startswith('edit_matiere_'):
128
+ matiere_id = int(action.split('_')[-1])
129
+ matiere = Matiere.query.get_or_404(matiere_id)
130
+ matiere.nom = request.form.get(f'edit_nom_matiere_{matiere_id}')
131
+ try:
132
+ db.session.commit()
133
+ flash(f"Matière '{matiere.nom}' modifiée avec succès.", 'success')
134
+ except Exception as e:
135
+ db.session.rollback()
136
+ flash(f"Erreur lors de la modification : {e}", 'danger')
137
+
138
+ elif action.startswith('edit_sous_categorie_'):
139
+ sous_categorie_id = int(action.split('_')[-1])
140
+ sous_categorie = SousCategorie.query.get_or_404(sous_categorie_id)
141
+ sous_categorie.nom = request.form.get(f'edit_nom_sous_categorie_{sous_categorie_id}')
142
+ sous_categorie.matiere_id = request.form.get(f'edit_matiere_id_{sous_categorie_id}')
143
+ try:
144
+ db.session.commit()
145
+ flash(f"Sous-catégorie '{sous_categorie.nom}' modifiée avec succès.", 'success')
146
+ except Exception as e:
147
+ db.session.rollback()
148
+ flash(f"Erreur : {e}", 'danger')
149
+
150
+
151
+ elif action.startswith('edit_texte_'):
152
+ texte_id = int(action.split('_')[-1])
153
+ texte = Texte.query.get_or_404(texte_id)
154
+ texte.titre = request.form.get(f'edit_titre_texte_{texte_id}')
155
+ contenu = request.form.get(f'edit_contenu_texte_{texte_id}')
156
+ if contenu:
157
+ texte.contenu = sanitize_html(contenu)
158
+ texte.sous_categorie_id = request.form.get(f'edit_sous_categorie_id_{texte_id}')
159
+
160
+ try:
161
+ db.session.commit()
162
+ flash(f"Texte '{texte.titre}' modifié avec succès.", 'success')
163
+ except Exception as e:
164
+ db.session.rollback()
165
+ flash(f"Erreur : {e}", 'danger')
166
+
167
+
168
+ elif action.startswith('delete_matiere_'):
169
+ matiere_id = int(action.split('_')[-1])
170
+ matiere = Matiere.query.get_or_404(matiere_id)
171
+ db.session.delete(matiere)
172
+ try:
173
+ db.session.commit()
174
+ flash(f"Matière '{matiere.nom}' supprimée avec succès.", 'success')
175
+ except Exception as e:
176
+ db.session.rollback()
177
+ flash(f"Erreur : {e}", 'danger')
178
+
179
+ elif action.startswith('delete_sous_categorie_'):
180
+ sous_categorie_id = int(action.split('_')[-1])
181
+ sous_categorie = SousCategorie.query.get_or_404(sous_categorie_id)
182
+ db.session.delete(sous_categorie)
183
+ try:
184
+ db.session.commit()
185
+ flash(f"Sous-catégorie '{sous_categorie.nom}' supprimée.", 'success')
186
+ except Exception as e:
187
+ db.session.rollback()
188
+ flash(f"Erreur : {e}", 'danger')
189
+
190
+
191
+ elif action.startswith('delete_texte_'):
192
+ texte_id = int(action.split('_')[-1])
193
+ texte = Texte.query.get_or_404(texte_id)
194
+ db.session.delete(texte)
195
+ try:
196
+ db.session.commit()
197
+ flash(f"Texte '{texte.titre}' supprimé avec succès.", 'success')
198
+ except Exception as e:
199
+ db.session.rollback()
200
+ flash(f"Erreur : {e}",'danger')
201
+
202
+ return redirect(url_for('gere'))
203
+
204
+ # Récupération de toutes les données pour l'affichage
205
+ matieres = Matiere.query.order_by(func.lower(Matiere.nom)).all()
206
+ sous_categories = SousCategorie.query.order_by(func.lower(SousCategorie.nom)).all()
207
+ textes = Texte.query.order_by(Texte.titre).all()
208
+ return render_template('gere.html', matieres=matieres, sous_categories=sous_categories, textes=textes)
209
+
210
+ if __name__ == '__main__':
211
+ with app.app_context():
212
+ db.create_all() # Crée les tables si elles n'existent pas
213
+ app.run(debug=True, port=5001) # Port différent pour éviter les conflits