Fix Telegram: handle None message text and include reply context for bot message replies

This commit is contained in:
eric 2026-02-23 07:57:03 +00:00
parent 86dc556c4e
commit ab21363032

145
app.py
View file

@ -313,6 +313,14 @@ def init_journal():
) )
""") """)
# Tabelle für gesendete Begrüßungs-Emails (Onboarding-Flow)
con.execute("""
CREATE TABLE IF NOT EXISTS greeting_sent (
email TEXT PRIMARY KEY,
sent_at TEXT NOT NULL
)
""")
# Default-Werte setzen falls nicht vorhanden # Default-Werte setzen falls nicht vorhanden
con.execute(""" con.execute("""
INSERT OR IGNORE INTO app_settings (key, value, updated_at) INSERT OR IGNORE INTO app_settings (key, value, updated_at)
@ -1514,6 +1522,70 @@ def is_known_team_member(sender_address):
return result # Returns (name, role) or None return result # Returns (name, role) or None
def has_greeting_been_sent(sender_email):
"""Prüft ob für diese Email-Adresse bereits eine Begrüßungs-Email gesendet wurde."""
addr = sender_email.lower().strip()
con = sqlite3.connect(EMAIL_JOURNAL_DB)
row = con.execute("SELECT sent_at FROM greeting_sent WHERE email = ?", (addr,)).fetchone()
con.close()
return row is not None
def mark_greeting_sent(sender_email):
"""Markiert, dass für diese Email-Adresse eine Begrüßungs-Email gesendet wurde."""
addr = sender_email.lower().strip()
con = sqlite3.connect(EMAIL_JOURNAL_DB)
con.execute(
"INSERT OR IGNORE INTO greeting_sent (email, sent_at) VALUES (?, ?)",
(addr, datetime.now().isoformat())
)
con.commit()
con.close()
def send_greeting_email(sender_email, sender_raw=''):
"""Sendet automatische Begrüßungs-Email an neue @diversityball.at-Mitglieder."""
# Versuche einen Namen aus der Absenderadresse zu erraten
name_guess = sender_email.split('@')[0].replace('.', ' ').replace('_', ' ').title()
# Falls "Vorname Nachname <email>" Format, Name extrahieren
display_name_match = re.match(r'^([^<]+)<', sender_raw)
if display_name_match:
extracted = display_name_match.group(1).strip().strip('"')
if extracted:
name_guess = extracted
subject = "Willkommen beim Diversity Ball Wien 2026 — kurze Vorstellung erbeten"
body = f"""Hallo {name_guess},
herzlich willkommen bei unserem Team für den Diversity Ball Wien 2026!
Damit wir dich schnell in unser System integrieren können, benötigen wir noch kurz folgende Informationen:
1. Vollständiger Name: (z.B. "Max Mustermann")
2. Deine Rolle / Funktion: (z.B. "Musikmanager", "Catering-Koordinator")
3. Deine Verantwortlichkeiten: (Was machst du konkret?)
4. Telegram-Handle oder Telegram-ID: (Optional, z.B. "@mustermann")
5. Telefonnummer: (Optional)
Danach können wir dich direkt bei relevanten Tasks informieren!
Viele Grüße,
Orchestrator Event Management für den Diversity Ball Wien"""
success, msg = send_email(
sender_email,
subject,
body,
triggered_by='system:greeting'
)
if success:
mark_greeting_sent(sender_email)
logger.info("[Greeting] Begrüßungs-Email an %s gesendet.", sender_email)
else:
logger.warning("[Greeting] Fehler beim Senden der Begrüßungs-Email an %s: %s", sender_email, msg)
return success
def decode_email_header_value(value): def decode_email_header_value(value):
"""Dekodiert Email-Header (z.B. encoded Subject/From).""" """Dekodiert Email-Header (z.B. encoded Subject/From)."""
if not value: if not value:
@ -1600,7 +1672,8 @@ async def telegram_message_handler(update: Update, context: ContextTypes.DEFAULT
"""Handler für eingehende Nachrichten.""" """Handler für eingehende Nachrichten."""
user_id = update.effective_user.id user_id = update.effective_user.id
username = update.effective_user.username or update.effective_user.first_name username = update.effective_user.username or update.effective_user.first_name
message_text = update.message.text # text kann None sein (Sticker, Foto, Voice etc.) caption als Fallback
message_text = update.message.text or update.message.caption or ''
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
# Whitelist-Check # Whitelist-Check
@ -1608,6 +1681,11 @@ async def telegram_message_handler(update: Update, context: ContextTypes.DEFAULT
await update.message.reply_text("⛔ Zugriff verweigert. Verwende /start für Details.") await update.message.reply_text("⛔ Zugriff verweigert. Verwende /start für Details.")
return return
# Leere Nachrichten (Sticker, GIF etc. ohne Text) ignorieren
if not message_text.strip():
await update.message.reply_text(" Bitte schick mir eine Textnachricht.")
return
# ── Prüfe ob diese Nachricht eine Antwort auf einen offenen standup_reply-Task ist ── # ── Prüfe ob diese Nachricht eine Antwort auf einen offenen standup_reply-Task ist ──
try: try:
con = sqlite3.connect(EMAIL_JOURNAL_DB) con = sqlite3.connect(EMAIL_JOURNAL_DB)
@ -1662,9 +1740,22 @@ async def telegram_message_handler(update: Update, context: ContextTypes.DEFAULT
return return
# ── Normale Nachricht → neuer Orchestrator-Task ────────────────────────── # ── Normale Nachricht → neuer Orchestrator-Task ──────────────────────────
# Falls der User auf eine Bot-Nachricht geantwortet hat: Reply-Kontext einbetten
reply_context = ''
if update.message.reply_to_message:
original = update.message.reply_to_message
original_text = original.text or original.caption or ''
if original_text:
reply_context = (
f"\n\n[Kontext: Der User antwortet auf folgende Bot-Nachricht]\n"
f"---\n{original_text[:1000]}\n---"
)
full_description = message_text + reply_context
task_id = create_task( task_id = create_task(
title=f"Telegram: {message_text[:50]}{'...' if len(message_text) > 50 else ''}", title=f"Telegram: {message_text[:50]}{'...' if len(message_text) > 50 else ''}",
description=message_text, description=full_description,
agent_key='orchestrator', agent_key='orchestrator',
task_type='telegram', task_type='telegram',
created_by=f'telegram_user_{user_id}', created_by=f'telegram_user_{user_id}',
@ -1876,22 +1967,52 @@ def poll_emails():
# Prüfe ob Absender bekannt ist (in Team-Members DB) # Prüfe ob Absender bekannt ist (in Team-Members DB)
known_member = is_known_team_member(sender) known_member = is_known_team_member(sender)
# Wenn unbekannt: Bitte um Vorstellung # Wenn unbekannt: Begrüßungs-Email senden (einmalig) + Orchestrator übernimmt
extra_context = "" extra_context = ""
if not known_member: if not known_member:
# Einmalige Begrüßungs-Email für neue @diversityball.at-Mitglieder
if not has_greeting_been_sent(sender_email):
send_greeting_email(sender_email, sender_raw=sender)
logger.info("[EmailPoller] Begrüßungs-Email an neuen Absender %s gesendet.", sender_email)
extra_context = f""" extra_context = f"""
## ⚠️ WICHTIG - Neuer Absender: ## ⚠️ WICHTIG - Onboarding neuer Absender:
Diese Email kommt von **{sender}** - diese Person ist noch nicht in der Team-Datenbank! Diese Email kommt von **{sender}** diese Person ist noch nicht in der Team-Datenbank!
Bitte in deiner Antwort: Eine automatische Begrüßungs-Email wurde bereits an {sender_email} gesendet, in der wir um folgende Angaben gebeten haben:
1. Freundlich begrüßen 1. Vollständiger Name
2. Um Vorstellung bitten: Name, Rolle, Verantwortlichkeiten 2. Rolle / Funktion
3. Fragen was sie im Projekt macht 3. Verantwortlichkeiten
4. Dann ihre eigentliche Anfrage beantworten 4. Telegram-Handle oder Telegram-ID (optional)
5. Telefonnummer (optional)
Der Orchestrator wird die Informationen dann mit @ADD_TEAM_MEMBER oder @UPDATE_TEAM_MEMBER in die Datenbank eintragen. **Deine Aufgabe als Orchestrator:**
- Beantworte die eigentliche Anfrage der Person freundlich und direkt
- Wenn diese Email BEREITS die Onboarding-Antwort enthält (Name, Rolle, etc. sind erkennbar):
Extrahiere die Daten und registriere die Person sofort:
```
<add_team_member>
name: [Extrahierter Name]
role: [Extrahierte Rolle]
responsibilities: [Extrahierte Verantwortlichkeiten]
email: {sender_email}
</add_team_member>
```
Danach Bestätigungs-Email senden:
```
<send_email>
to: {sender_email}
subject: Willkommen im Team Registrierung abgeschlossen!
body: Hallo [Name],
du wurdest erfolgreich in unserem System registriert! Ab sofort wirst du bei relevanten Tasks direkt informiert.
Viele Grüße,
Orchestrator Event Management für den Diversity Ball Wien
</send_email>
```
""" """
else: else:
extra_context = f""" extra_context = f"""