Spaces:
Build error
Build error
| # embed_routes.py | |
| from flask import Blueprint, request, jsonify, redirect, url_for | |
| from auth_backend import register_end_user, login_end_user, reset_end_user_password | |
| from typing import Tuple | |
| # Création du Blueprint 'embed_bp' | |
| embed_bp = Blueprint('embed_bp', __name__) | |
| # --- Style et Structure de Base des Formulaires --- | |
| # Le style CSS est inclus directement pour que le client n'ait qu'un seul bloc à copier/coller. | |
| HTML_FORM_STYLE = """ | |
| <style> | |
| .embed-form-container { | |
| max-width: 400px; | |
| margin: 20px auto; | |
| padding: 20px; | |
| border: 1px solid #ccc; | |
| border-radius: 8px; | |
| font-family: Arial, sans-serif; | |
| box-shadow: 2px 2px 5px rgba(0,0,0,0.1); | |
| } | |
| .embed-form-container h3 { | |
| text-align: center; | |
| color: #333; | |
| margin-bottom: 20px; | |
| } | |
| .embed-form-container label { | |
| display: block; | |
| margin-bottom: 5px; | |
| font-weight: bold; | |
| } | |
| .embed-form-container input[type="text"], | |
| .embed-form-container input[type="email"], | |
| .embed-form-container input[type="password"] { | |
| width: 100%; | |
| padding: 10px; | |
| margin-bottom: 15px; | |
| border: 1px solid #ddd; | |
| border-radius: 4px; | |
| box-sizing: border-box; | |
| } | |
| .embed-form-container button { | |
| width: 100%; | |
| padding: 10px; | |
| background-color: #007bff; | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| } | |
| .embed-form-container button:hover { | |
| background-color: #0056b3; | |
| } | |
| .embed-form-message { | |
| padding: 10px; | |
| margin-top: 15px; | |
| border-radius: 4px; | |
| text-align: center; | |
| } | |
| .embed-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } | |
| .embed-error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } | |
| </style> | |
| """ | |
| # Le placeholder CLIENT_ID_PLACEHOLDER sera remplacé par l'ID de votre client. | |
| BASE_FORM_STRUCTURE = """ | |
| {style} | |
| <div class="embed-form-container"> | |
| <h3>{title}</h3> | |
| <form id="{id_prefix}-form" method="POST" action="/embed/{route}" onsubmit="return handleFormSubmit(this);"> | |
| <input type="hidden" name="client_id" value="CLIENT_ID_PLACEHOLDER"> | |
| {fields} | |
| <button type="submit">{button_text}</button> | |
| {footer} | |
| </form> | |
| <div id="{id_prefix}-message" class="embed-form-message" style="display:none;"></div> | |
| </div> | |
| """ | |
| # --- 1. Formulaire d'Inscription (Sign Up) --- | |
| REGISTRATION_FIELDS = """ | |
| <label for="reg_username">Nom d'utilisateur</label> | |
| <input type="text" id="reg_username" name="username" required> | |
| <label for="reg_email">Email</label> | |
| <input type="email" id="reg_email" name="email" required> | |
| <label for="reg_password">Mot de passe</label> | |
| <input type="password" id="reg_password" name="password" required> | |
| <label for="reg_confirm_password">Confirmer Mot de passe</label> | |
| <input type="password" id="reg_confirm_password" name="confirm_password" required> | |
| """ | |
| REGISTRATION_FOOTER = '<p style="text-align:center; margin-top:10px;">Déjà un compte? <a href="#" onclick="showLoginForm(); return false;">Connectez-vous</a></p>' | |
| REGISTRATION_FORM_HTML_TEMPLATE = BASE_FORM_STRUCTURE.format( | |
| style=HTML_FORM_STYLE, | |
| title="Inscription", | |
| id_prefix="reg", | |
| route="register", | |
| fields=REGISTRATION_FIELDS, | |
| button_text="S'inscrire", | |
| footer=REGISTRATION_FOOTER | |
| ) | |
| # --- 2. Formulaire de Connexion (Login) --- | |
| LOGIN_FIELDS = """ | |
| <label for="log_email">Email</label> | |
| <input type="email" id="log_email" name="email" required> | |
| <label for="log_password">Mot de passe</label> | |
| <input type="password" id="log_password" name="password" required> | |
| """ | |
| LOGIN_FOOTER = '<p style="text-align:center; margin-top:10px;">Pas encore de compte? <a href="#" onclick="showRegistrationForm(); return false;">Inscrivez-vous</a></p><p style="text-align:center;"><a href="#" onclick="showResetForm(); return false;">Mot de passe oublié?</a></p>' | |
| LOGIN_FORM_HTML_TEMPLATE = BASE_FORM_STRUCTURE.format( | |
| style=HTML_FORM_STYLE, | |
| title="Connexion", | |
| id_prefix="log", | |
| route="login", | |
| fields=LOGIN_FIELDS, | |
| button_text="Se connecter", | |
| footer=LOGIN_FOOTER | |
| ) | |
| # --- 3. Formulaire de Récupération de Compte (Password Reset) --- | |
| RESET_FIELDS = """ | |
| <label for="reset_email">Email</label> | |
| <input type="email" id="reset_email" name="email" required> | |
| <label for="reset_password">Nouveau Mot de Passe</label> | |
| <input type="password" id="reset_password" name="new_password" required> | |
| <label for="reset_confirm_password">Confirmer Nouveau Mot de Passe</label> | |
| <input type="password" id="reset_confirm_password" name="confirm_password" required> | |
| """ | |
| RESET_FOOTER = '<p style="text-align:center; margin-top:10px;"><a href="#" onclick="showLoginForm(); return false;">Retour à la Connexion</a></p>' | |
| RESET_FORM_HTML_TEMPLATE = BASE_FORM_STRUCTURE.format( | |
| style=HTML_FORM_STYLE, | |
| title="Réinitialisation du Mot de Passe", | |
| id_prefix="reset", | |
| route="reset-password", | |
| fields=RESET_FIELDS, | |
| button_text="Réinitialiser le Mot de Passe", | |
| footer=RESET_FOOTER | |
| ) | |
| # --- Fonction Utilitaires pour Récupérer les Formulaires --- | |
| def get_forms_html(client_id: str) -> Tuple[str, str, str, str]: | |
| """ | |
| Génère les codes HTML des trois formulaires en injectant le client_id. | |
| Retourne (registration_html, login_html, reset_html, javascript_snippet) | |
| """ | |
| reg_html = REGISTRATION_FORM_HTML_TEMPLATE.replace('CLIENT_ID_PLACEHOLDER', client_id) | |
| log_html = LOGIN_FORM_HTML_TEMPLATE.replace('CLIENT_ID_PLACEHOLDER', client_id) | |
| res_html = RESET_FORM_HTML_TEMPLATE.replace('CLIENT_ID_PLACEHOLDER', client_id) | |
| # Script JavaScript pour gérer les soumissions AJAX et l'affichage des messages | |
| JAVASCRIPT_SNIPPET = """ | |
| <script> | |
| function handleFormSubmit(form) { | |
| const url = form.action; | |
| const method = form.method; | |
| const formData = new FormData(form); | |
| // Déterminer la boite de message | |
| const formIdPrefix = form.id.replace('-form', ''); | |
| const messageBox = document.getElementById(formIdPrefix + '-message'); | |
| messageBox.style.display = 'none'; | |
| messageBox.className = 'embed-form-message'; | |
| fetch(url, { | |
| method: method, | |
| body: new URLSearchParams(formData) | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| messageBox.textContent = data.message; | |
| if (data.status === 'Success') { | |
| messageBox.classList.add('embed-success'); | |
| form.reset(); // Vider le formulaire après succès | |
| } else { | |
| messageBox.classList.add('embed-error'); | |
| } | |
| messageBox.style.display = 'block'; | |
| }) | |
| .catch(error => { | |
| messageBox.textContent = 'Une erreur de communication est survenue.'; | |
| messageBox.classList.add('embed-error'); | |
| messageBox.style.display = 'block'; | |
| console.error('Error:', error); | |
| }); | |
| return false; // Empêche la soumission de formulaire par défaut | |
| } | |
| // Fonctions de basculement (si les trois formulaires sont sur la même page) | |
| const formContainers = document.querySelectorAll('.embed-form-container'); | |
| function showForm(id_prefix) { | |
| formContainers.forEach(el => { | |
| const isTarget = el.querySelector('form').id.startsWith(id_prefix); | |
| el.style.display = isTarget ? 'block' : 'none'; | |
| }); | |
| } | |
| // Fonctions d'aide pour le basculement | |
| function showRegistrationForm() { showForm('reg-'); } | |
| function showLoginForm() { showForm('log-'); } | |
| function showResetForm() { showForm('reset-'); } | |
| // Afficher le formulaire de connexion par défaut si tous les liens de basculement sont inclus | |
| // window.onload = () => { if (document.getElementById('log-form')) showLoginForm(); }; | |
| </script> | |
| """ | |
| return reg_html, log_html, res_html, JAVASCRIPT_SNIPPET | |
| # ---------------------------------------------------------------------- | |
| # --- Routes API pour la Soumission des Formulaires Embarqués (Unauthenticated) --- | |
| # ---------------------------------------------------------------------- | |
| def embed_register(): | |
| """ Point de terminaison pour l'inscription d'un utilisateur final. """ | |
| client_id = request.form.get("client_id") | |
| username = request.form.get("username") | |
| email = request.form.get("email") | |
| password = request.form.get("password") | |
| confirm_password = request.form.get("confirm_password") | |
| if not all([client_id, username, email, password, confirm_password]): | |
| return jsonify({"status": "Error", "message": "Tous les champs sont requis."}), 400 | |
| user_id, message, _ = register_end_user(client_id, username, email, password, confirm_password) | |
| if user_id: | |
| return jsonify({"status": "Success", "message": message, "user_id": user_id}), 200 | |
| else: | |
| return jsonify({"status": "Error", "message": message}), 400 | |
| def embed_login(): | |
| """ Point de terminaison pour la connexion d'un utilisateur final. """ | |
| client_id = request.form.get("client_id") | |
| email = request.form.get("email") | |
| password = request.form.get("password") | |
| if not all([client_id, email, password]): | |
| return jsonify({"status": "Error", "message": "Email et mot de passe sont requis."}), 400 | |
| user_id, message, user_data = login_end_user(client_id, email, password) | |
| if user_id: | |
| # Note : Vous devriez créer un token JWT ici ou gérer la session d'une autre manière sécurisée | |
| return jsonify({"status": "Success", "message": message, "user_id": user_id, "user_data": user_data}), 200 | |
| else: | |
| return jsonify({"status": "Error", "message": message}), 401 | |
| def embed_reset_password(): | |
| """ Point de terminaison pour la réinitialisation de mot de passe d'un utilisateur final. """ | |
| client_id = request.form.get("client_id") | |
| email = request.form.get("email") | |
| new_password = request.form.get("new_password") | |
| confirm_password = request.form.get("confirm_password") | |
| if not all([client_id, email, new_password, confirm_password]): | |
| return jsonify({"status": "Error", "message": "Tous les champs sont requis."}), 400 | |
| success, message = reset_end_user_password(client_id, email, new_password, confirm_password) | |
| if success: | |
| return jsonify({"status": "Success", "message": message}), 200 | |
| else: | |
| return jsonify({"status": "Error", "message": message}), 400 |