feat: add Telegram notifications for user signup and Stripe events
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m34s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m34s
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
37
utils/telegram.py
Normal file
37
utils/telegram.py
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user