diff --git a/app.py b/app.py index 689c71d..9e8541c 100644 --- a/app.py +++ b/app.py @@ -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 con.execute(""" 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 +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 " 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): """Dekodiert Email-Header (z.B. encoded Subject/From).""" if not value: @@ -1600,7 +1672,8 @@ async def telegram_message_handler(update: Update, context: ContextTypes.DEFAULT """Handler für eingehende Nachrichten.""" user_id = update.effective_user.id 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 # 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.") 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 ── try: con = sqlite3.connect(EMAIL_JOURNAL_DB) @@ -1662,9 +1740,22 @@ async def telegram_message_handler(update: Update, context: ContextTypes.DEFAULT return # ── 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( title=f"Telegram: {message_text[:50]}{'...' if len(message_text) > 50 else ''}", - description=message_text, + description=full_description, agent_key='orchestrator', task_type='telegram', created_by=f'telegram_user_{user_id}', @@ -1876,22 +1967,52 @@ def poll_emails(): # Prüfe ob Absender bekannt ist (in Team-Members DB) known_member = is_known_team_member(sender) - - # Wenn unbekannt: Bitte um Vorstellung + + # Wenn unbekannt: Begrüßungs-Email senden (einmalig) + Orchestrator übernimmt extra_context = "" 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""" -## ⚠️ WICHTIG - Neuer Absender: -Diese Email kommt von **{sender}** - diese Person ist noch nicht in der Team-Datenbank! +## ⚠️ WICHTIG - Onboarding neuer Absender: +Diese Email kommt von **{sender}** — diese Person ist noch nicht in der Team-Datenbank! -Bitte in deiner Antwort: -1. Freundlich begrüßen -2. Um Vorstellung bitten: Name, Rolle, Verantwortlichkeiten -3. Fragen was sie im Projekt macht -4. Dann ihre eigentliche Anfrage beantworten +Eine automatische Begrüßungs-Email wurde bereits an {sender_email} gesendet, in der wir um folgende Angaben gebeten haben: +1. Vollständiger Name +2. Rolle / Funktion +3. Verantwortlichkeiten +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: + ``` + + name: [Extrahierter Name] + role: [Extrahierte Rolle] + responsibilities: [Extrahierte Verantwortlichkeiten] + email: {sender_email} + + ``` + Danach Bestätigungs-Email senden: + ``` + + 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 + + ``` """ else: extra_context = f"""