Mailix / embed_routes.py
ernestmindres's picture
Upload embed_routes.py
70a4985 verified
# 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) ---
# ----------------------------------------------------------------------
@embed_bp.route("/register", methods=['POST'])
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
@embed_bp.route("/login", methods=['POST'])
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
@embed_bp.route("/reset-password", methods=['POST'])
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