ernestmindres commited on
Commit
ae9e3d1
·
verified ·
1 Parent(s): 2c8253e

Update web_routes.py

Browse files
Files changed (1) hide show
  1. web_routes.py +127 -51
web_routes.py CHANGED
@@ -1,5 +1,5 @@
1
  # web_routes.py
2
-
3
  from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, send_from_directory, current_app # <-- NOUVEAUX IMPORTS
4
  from werkzeug.utils import secure_filename # <-- NOUVEL IMPORT (pourrait ne pas être nécessaire avec uuid, mais sécurisant)
5
  import os
@@ -7,11 +7,13 @@ import uuid # <-- NOUVEL IMPORT
7
  from auth_backend import get_plan_details
8
  from baserow_storage import get_health_status
9
 
10
- def allowed_file(filename):
11
- """Vérifie si le fichier a une extension autorisée (HTML)."""
12
- # Utilise la liste des extensions de app.py
 
 
13
  return '.' in filename and \
14
- filename.rsplit('.', 1)[1].lower() in current_app.config['ALLOWED_EXTENSIONS']
15
 
16
  # Création du Blueprint 'web_bp'
17
  web_bp = Blueprint('web_bp', __name__)
@@ -101,59 +103,133 @@ def html_launcher():
101
  # Le template 'html_launcher.html' doit être créé.
102
  return render_template("html_launcher.html")
103
 
104
- @web_bp.route("/upload-html", methods=['POST'])
105
- def upload_html():
 
 
 
106
  """
107
- Gère le téléversement du fichier HTML, le stocke temporairement et retourne son URL.
108
  """
109
- # 1. Vérification de la présence du fichier dans la requête
110
- if 'html_file' not in request.files:
111
- return jsonify({"status": "error", "message": "Aucun fichier n'a été envoyé."}), 400
112
 
113
- file = request.files['html_file']
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- # 2. Vérification si le nom de fichier est vide
116
- if file.filename == '':
117
- return jsonify({"status": "error", "message": "Aucun fichier sélectionné."}), 400
118
-
119
- # 3. Vérification de l'extension et sauvegarde
120
- if file and allowed_file(file.filename):
121
- # Sécurité: Générer un nom de fichier unique pour éviter les conflits et les attaques de chemin
122
- original_extension = file.filename.rsplit('.', 1)[1].lower()
123
- unique_filename = str(uuid.uuid4()) + '.' + original_extension
124
- save_path = os.path.join(current_app.config['UPLOAD_FOLDER'], unique_filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
- try:
127
- file.save(save_path)
128
-
129
- # Retourner l'URL temporaire (route serve_temp_html)
130
- file_url = url_for('web_bp.serve_temp_html', filename=unique_filename)
 
 
 
 
 
 
 
 
131
 
132
- return jsonify({
133
- "status": "success",
134
- "message": "Fichier téléversé avec succès.",
135
- "file_url": file_url
136
- }), 200
137
 
138
- except Exception as e:
139
- current_app.logger.error(f"Erreur lors de la sauvegarde du fichier: {e}")
140
- return jsonify({"status": "error", "message": "Erreur serveur lors du téléversement."}), 500
141
- else:
142
- return jsonify({"status": "error", "message": "Type de fichier non autorisé. Seuls les fichiers HTML sont permis."}), 400
143
-
144
- @web_bp.route("/temp-html/<filename>")
145
- def serve_temp_html(filename):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  """
147
- Sert le fichier HTML temporaire à partir du dossier d'upload.
 
148
  """
149
- # Sécurité: Rejeter toute tentative de traversée de répertoire (..)
150
- if '..' in filename or not allowed_file(filename):
151
- return "Accès refusé", 403
 
 
 
 
 
 
 
152
 
153
- # Utiliser send_from_directory pour servir le fichier
154
- return send_from_directory(
155
- current_app.config['UPLOAD_FOLDER'],
156
- filename,
157
- # S'assurer que le navigateur le considère comme une page web
158
- mimetype='text/html'
159
- )
 
 
 
 
 
1
  # web_routes.py
2
+ import shutil
3
  from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, send_from_directory, current_app # <-- NOUVEAUX IMPORTS
4
  from werkzeug.utils import secure_filename # <-- NOUVEL IMPORT (pourrait ne pas être nécessaire avec uuid, mais sécurisant)
5
  import os
 
7
  from auth_backend import get_plan_details
8
  from baserow_storage import get_health_status
9
 
10
+ # NOUVEAU : Fonction pour vérifier les extensions autorisées pour le déploiement statique
11
+ def allowed_static_file(filename):
12
+ """Vérifie si le fichier a une extension autorisée (HTML, CSS, JS)."""
13
+ # Ajout de .css et .js aux extensions autorisées
14
+ STATIC_ALLOWED_EXTENSIONS = {'html', 'htm', 'css', 'js', 'jpg', 'jpeg', 'png', 'gif', 'svg'}
15
  return '.' in filename and \
16
+ filename.rsplit('.', 1)[1].lower() in STATIC_ALLOWED_EXTENSIONS
17
 
18
  # Création du Blueprint 'web_bp'
19
  web_bp = Blueprint('web_bp', __name__)
 
103
  # Le template 'html_launcher.html' doit être créé.
104
  return render_template("html_launcher.html")
105
 
106
+
107
+
108
+ # --- NOUVELLE ROUTE : Page de Déploiement Statique ---
109
+ @web_bp.route("/static-deploy")
110
+ def static_deploy_page():
111
  """
112
+ Route pour afficher l'interface de déploiement statique.
113
  """
114
+ # Récupérer l'ID de déploiement temporaire de la session s'il existe
115
+ deploy_id = session.get('current_deploy_id')
 
116
 
117
+ # Si un ID existe, on peut récupérer la liste des fichiers pour l'afficher
118
+ files = []
119
+ base_dir = None
120
+ if deploy_id:
121
+ base_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], deploy_id)
122
+ if os.path.exists(base_dir):
123
+ # Parcourir le dossier pour lister les fichiers
124
+ for root, _, filenames in os.walk(base_dir):
125
+ for filename in filenames:
126
+ # Rendre le chemin relatif à la base_dir
127
+ relative_path = os.path.relpath(os.path.join(root, filename), base_dir)
128
+ files.append(relative_path)
129
 
130
+ # L'état du bouton "Lancer"
131
+ index_file_present = 'index.html' in files
132
+
133
+ return render_template("static_deploy.html",
134
+ files=files,
135
+ index_file_present=index_file_present,
136
+ deploy_id=deploy_id)
137
+
138
+ # --- NOUVELLE ROUTE : Upload de Fichiers Statiques Multiples ---
139
+ @web_bp.route("/upload-static", methods=['POST'])
140
+ def upload_static_files():
141
+ """
142
+ Gère le téléversement de multiples fichiers statiques (HTML, CSS, JS, images).
143
+ Crée un dossier temporaire unique par session/déploiement.
144
+ """
145
+ # 1. Obtenir un ID de déploiement unique pour cette session (ou en créer un)
146
+ deploy_id = session.get('current_deploy_id')
147
+ if not deploy_id:
148
+ deploy_id = str(uuid.uuid4())
149
+ session['current_deploy_id'] = deploy_id
150
+
151
+ # 2. Définir le chemin de base du dossier d'upload
152
+ base_deploy_path = os.path.join(current_app.config['UPLOAD_FOLDER'], deploy_id)
153
+
154
+ # 3. Supprimer l'ancien dossier s'il existe (pour un nouveau déploiement)
155
+ # L'utilisateur doit effacer le contenu existant ou le remplacer
156
+ if os.path.exists(base_deploy_path):
157
+ # Pour simplifier, on supprime tout avant le nouvel upload
158
+ shutil.rmtree(base_deploy_path)
159
 
160
+ os.makedirs(base_deploy_path) # Créer le nouveau dossier
161
+
162
+ # 4. Vérification de la présence de fichiers
163
+ if not request.files:
164
+ return jsonify({"status": "error", "message": "Aucun fichier n'a été envoyé."}), 400
165
+
166
+ uploaded_files_list = []
167
+ index_html_present = False
168
+
169
+ # 5. Parcourir tous les fichiers envoyés
170
+ for key, file in request.files.items():
171
+ if file.filename == '':
172
+ continue
173
 
174
+ if file and allowed_static_file(file.filename):
175
+ # Sécurité: Utiliser secure_filename et s'assurer que le chemin est plat
176
+ filename = secure_filename(file.filename)
177
+ save_path = os.path.join(base_deploy_path, filename)
 
178
 
179
+ try:
180
+ file.save(save_path)
181
+ uploaded_files_list.append(filename)
182
+ if filename.lower() == 'index.html':
183
+ index_html_present = True
184
+
185
+ except Exception as e:
186
+ current_app.logger.error(f"Erreur lors de la sauvegarde du fichier {filename}: {e}")
187
+ # En cas d'erreur critique, on pourrait vouloir rollback (supprimer le dossier)
188
+ return jsonify({"status": "error", "message": f"Erreur serveur lors du téléversement de {filename}."}), 500
189
+ else:
190
+ return jsonify({"status": "error", "message": f"Type de fichier non autorisé: {file.filename}."}), 400
191
+
192
+ if not uploaded_files_list:
193
+ return jsonify({"status": "error", "message": "Aucun fichier valide n'a été téléversé."}), 400
194
+
195
+ # 6. Générer l'URL de base pour le lancement (doit pointer vers serve_static)
196
+ launch_url = url_for('web_bp.serve_static', deploy_id=deploy_id, filename='index.html')
197
+
198
+ return jsonify({
199
+ "status": "success",
200
+ "message": "Fichiers téléversés avec succès.",
201
+ "file_count": len(uploaded_files_list),
202
+ "index_present": index_html_present,
203
+ "launch_url": launch_url,
204
+ "deploy_id": deploy_id
205
+ }), 200
206
+
207
+ # --- NOUVELLE ROUTE : Servir les Fichiers Statiques ---
208
+ @web_bp.route("/serve-static/<deploy_id>/<path:filename>")
209
+ def serve_static(deploy_id, filename):
210
  """
211
+ Sert les fichiers statiques (HTML, CSS, JS, images) à partir du dossier
212
+ temporaire identifié par deploy_id.
213
  """
214
+ # 1. Sécurité: Rejeter toute tentative de traversée de répertoire (..)
215
+ if '..' in filename:
216
+ return "Accès refusé: Tentative de traversée de répertoire", 403
217
+
218
+ # 2. Définir le répertoire de base de l'ID de déploiement
219
+ root_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], deploy_id)
220
+
221
+ # 3. Vérifier que le fichier est bien autorisé (pour la sécurité, même si on utilise send_from_directory)
222
+ if not allowed_static_file(filename):
223
+ return "Type de fichier non autorisé", 403
224
 
225
+ # 4. Utiliser send_from_directory pour servir le fichier
226
+ try:
227
+ # send_from_directory va gérer les mimetypes
228
+ return send_from_directory(
229
+ root_dir,
230
+ filename,
231
+ conditional=True # Support des requêtes conditionnelles (mise en cache)
232
+ )
233
+ except Exception:
234
+ # Fichier non trouvé ou autre erreur
235
+ return "Fichier non trouvé", 404