diff --git a/routes/auth_routes.py b/routes/auth_routes.py index 5452186..5b9c6d5 100644 --- a/routes/auth_routes.py +++ b/routes/auth_routes.py @@ -272,6 +272,21 @@ async def register_v1(request: Request): try: user = create_user(user_create) + # Alert admin via Telegram on signup + try: + from utils.telegram import send_telegram_notification + import asyncio + msg = ( + f"👤 *Nouvelle inscription !*\n\n" + f"• *Email* : `{user.email}`\n" + f"• *Nom* : `{user.name or 'Non renseigné'}`\n" + f"• *ID* : `{user.id}`\n" + f"• *Forfait* : `{user.plan.value}`\n" + f"• *Date* : {datetime.now(timezone.utc).strftime('%d/%m/%Y %H:%M:%S')} UTC" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification: {tel_err}") except ValueError as exc: msg = str(exc).strip().lower() if "email already registered" in msg or "email already" in msg: diff --git a/services/payment_service.py b/services/payment_service.py index 25196fd..234cdb7 100644 --- a/services/payment_service.py +++ b/services/payment_service.py @@ -336,6 +336,21 @@ async def handle_checkout_completed(session: Dict): ) except Exception as e: logger.error("Failed to send credit purchase email: %s", e) + + # Send Telegram notification + try: + from utils.telegram import send_telegram_notification + import asyncio + msg = ( + f"💰 *Achat de crédits !*\n\n" + f"• *Utilisateur* : `{user.name or 'Non renseigné'}` (`{user.email}`)\n" + f"• *Crédits achetés* : `{credits}`\n" + f"• *Montant* : `{session.get('amount_total', 0) / 100:.2f} {session.get('currency', 'eur').upper()}`\n" + f"• *ID Transaction* : `{session_id}`" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification for credits checkout: {tel_err}") return # It's a subscription @@ -420,6 +435,22 @@ async def handle_checkout_completed(session: Dict): except Exception as e: logger.error("Failed to send activation email: %s", e) + # Send Telegram notification + try: + from utils.telegram import send_telegram_notification + import asyncio + ends_str = subscription_ends_at.strftime("%d/%m/%Y") if subscription_ends_at else "Non spécifiée" + msg = ( + f"⭐ *Nouvel Abonnement Activé !*\n\n" + f"• *Utilisateur* : `{user.name or 'Non renseigné'}` (`{user.email}`)\n" + f"• *Forfait* : `{plan.upper()}`\n" + f"• *Montant* : `{session.get('amount_total', 0) / 100:.2f} {session.get('currency', 'eur').upper()}`\n" + f"• *Date de fin* : {ends_str}" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification for subscription activation: {tel_err}") + async def handle_subscription_updated(subscription: Dict): """Handle subscription updates""" @@ -474,6 +505,19 @@ async def handle_subscription_updated(subscription: Dict): except Exception as e: logger.error("Failed to send cancellation email in handle_subscription_updated: %s", e) + # Send Telegram notification for cancellation request + try: + from utils.telegram import send_telegram_notification + import asyncio + msg = ( + f"🔕 *Désinscription programmée (Stripe)*\n\n" + f"• *Utilisateur* : `{user.name or 'Non renseigné'}` (`{user.email}`)\n" + f"• *Date de fin d'accès* : {ends_str}" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification for subscription cancellation request: {tel_err}") + async def handle_subscription_deleted(subscription: Dict): """Handle subscription cancellation (actually ended)""" @@ -509,6 +553,19 @@ async def handle_subscription_deleted(subscription: Dict): except Exception as e: logger.error("Failed to send subscription ended email: %s", e) + # Send Telegram notification for ended subscription + try: + from utils.telegram import send_telegram_notification + import asyncio + msg = ( + f"❌ *Abonnement Terminé / Expiré (Stripe)*\n\n" + f"• *Utilisateur* : `{user.name or 'Non renseigné'}` (`{user.email}`)\n" + f"• *Statut* : Retour au forfait `FREE`" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification for subscription ended: {tel_err}") + async def handle_payment_failed(invoice: Dict): """Handle failed payment — set subscription status to PAST_DUE and send email""" @@ -547,6 +604,19 @@ async def handle_payment_failed(invoice: Dict): ) except Exception as e: logger.error("Failed to send payment failed email: %s", e) + + # Send Telegram notification + try: + from utils.telegram import send_telegram_notification + import asyncio + msg = ( + f"⚠️ *Échec de paiement (Stripe)*\n\n" + f"• *Utilisateur* : `{db_user.name or 'Non renseigné'}` (`{db_user.email}`)\n" + f"• *Statut* : Facture impayée, forfait passé en `PAST_DUE`" + ) + asyncio.create_task(send_telegram_notification(msg)) + except Exception as tel_err: + logger.error(f"Failed to send telegram notification for payment failed: {tel_err}") except Exception as exc: logger.error("handle_payment_failed DB error: %s", exc) diff --git a/utils/telegram.py b/utils/telegram.py new file mode 100644 index 0000000..b86add6 --- /dev/null +++ b/utils/telegram.py @@ -0,0 +1,37 @@ +import os +import logging +import httpx + +logger = logging.getLogger(__name__) + +async def send_telegram_notification(message: str) -> bool: + """ + Envoie un message formaté en Markdown à l'administrateur via Telegram. + Utilise les variables d'environnement TELEGRAM_BOT_TOKEN et TELEGRAM_CHAT_ID. + """ + bot_token = os.getenv("TELEGRAM_BOT_TOKEN") + chat_id = os.getenv("TELEGRAM_CHAT_ID") + + if not bot_token or not chat_id: + logger.warning("Notification Telegram ignorée : TELEGRAM_BOT_TOKEN ou TELEGRAM_CHAT_ID non configuré.") + return False + + url = f"https://api.telegram.org/bot{bot_token}/sendMessage" + payload = { + "chat_id": chat_id, + "text": message, + "parse_mode": "Markdown" + } + + try: + async with httpx.AsyncClient(timeout=10.0) as client: + resp = await client.post(url, json=payload) + if resp.status_code == 200: + logger.info("Notification Telegram envoyée avec succès.") + return True + else: + logger.error(f"Échec de l'envoi Telegram (HTTP {resp.status_code}): {resp.text}") + return False + except Exception as e: + logger.error(f"Erreur lors de l'envoi de la notification Telegram : {e}") + return False