Telegram: Bot=Session statt User-Level, Chat-Code-Refactoring
- Telegram-Config (Bot-Token, Webhook-Secret, ChatId) von User-Settings
in sessions-Tabelle verschoben → jede Session hat ihren eigenen Bot
- Link-Code-System komplett entfernt (TelegramLinkRecord gelöscht)
- /start verknüpft automatisch, kein /link mehr nötig
- Alle Endpoints session-basiert: /api/sessions/{id}/telegram/*
- Webhook-URL pro Session: /api/telegram/webhook/{sessionId}
Refactoring: Doppelten Chat-Code eliminiert
- Neuer ChatService: PrepareContext, BuildHistoryFromDb, ResolveModelId
- Neues ChatContext-Model als gemeinsame Datenstruktur
- AnthropicService.ChatNonStreaming() für Telegram (statt eigenem Loop)
- TelegramService um ~180 Zeilen reduziert, kein eigener Claude-Loop mehr
- ChatEndpoint nutzt ChatService.PrepareContext() statt eigener Setup-Logik
- Model-Mapping nur noch an einer Stelle (3x → 1x)
Frontend
- Telegram-Section von Settings-Page in Session-Bearbeitungsseite verschoben
- Webhook-Secret readonly, wird einmalig generiert und persistent gespeichert
- Status wird automatisch geladen, Register/Delete je nach Webhook-Status
- Toast-Notification-System (showToast) in ui.js
- Link-Code-Modal und Telegram-Menüpunkt im Dashboard entfernt
- Telegram-Badge auf Session-Cards (konfiguriert/verbunden)
Bugfix: Bearer statt x-api-key für OAuth-Tokens im TelegramService
This commit is contained in:
1 parent
a0752ea492
commit
0120bb8f73
21 files changed
+994
-1272
No files matched your search
+30
-59
@@ -159,6 +159,9 @@ public class DatabaseService
|
||||
|
||||
// User-Zuordnung
|
||||
TryAddColumn(conn, "sessions", "user_id", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_bot_token", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_webhook_secret", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_chat_id", "TEXT");
|
||||
TryAddColumn(conn, "agents", "user_id", "TEXT");
|
||||
TryAddColumn(conn, "users", "is_admin", "INTEGER NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "users", "persona", "TEXT");
|
||||
@@ -331,7 +334,9 @@ public class DatabaseService
|
||||
s.CreatedAt,
|
||||
s.UpdatedAt,
|
||||
MessageCount = activeCount,
|
||||
TotalMessageCount = totalCount
|
||||
TotalMessageCount = totalCount,
|
||||
TelegramConfigured = !string.IsNullOrEmpty(s.TelegramBotToken),
|
||||
TelegramLinked = !string.IsNullOrEmpty(s.TelegramChatId)
|
||||
});
|
||||
}
|
||||
return results;
|
||||
@@ -809,79 +814,45 @@ public class DatabaseService
|
||||
new { userId, settings, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
// ── Telegram ──
|
||||
// ── Telegram (Session-basiert) ──
|
||||
|
||||
public async Task<string> CreateTelegramLinkCode(string userId, string sessionId, string agentId)
|
||||
public async Task<SessionRecord> GetSessionByTelegramChatId(long chatId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var code = Guid.NewGuid().ToString("N")[..6].ToUpperInvariant();
|
||||
var now = DateTime.UtcNow.ToString("o");
|
||||
var expires = DateTime.UtcNow.AddMinutes(5).ToString("o");
|
||||
return await conn.QuerySingleOrDefaultAsync<SessionRecord>(
|
||||
"SELECT * FROM sessions WHERE telegram_chat_id = @chatId AND is_deleted = 0",
|
||||
new { chatId = chatId.ToString() });
|
||||
}
|
||||
|
||||
// Alten Code für diese Session löschen
|
||||
await conn.ExecuteAsync(
|
||||
"DELETE FROM telegram_links WHERE link_code IS NOT NULL AND user_id = @userId AND session_id = @sessionId",
|
||||
new { userId, sessionId });
|
||||
|
||||
// Neuen Pending-Link-Code erstellen (noch ohne telegram_chat_id)
|
||||
public async Task UpdateSessionTelegram(string sessionId, string botToken, string webhookSecret, string chatId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO telegram_links (telegram_chat_id, user_id, session_id, agent_id, link_code, expires_at, created_at, updated_at)
|
||||
VALUES (0, @userId, @sessionId, @agentId, @code, @expires, @now, @now)",
|
||||
new { userId, sessionId, agentId, code, expires, now });
|
||||
|
||||
return code;
|
||||
UPDATE sessions SET telegram_bot_token = @botToken, telegram_webhook_secret = @webhookSecret,
|
||||
telegram_chat_id = @chatId, updated_at = @now
|
||||
WHERE session_id = @sessionId",
|
||||
new { sessionId, botToken, webhookSecret, chatId, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
public async Task<TelegramLinkRecord> RedeemTelegramLinkCode(string code, long chatId)
|
||||
public async Task SetSessionTelegramChatId(string sessionId, string chatId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var now = DateTime.UtcNow.ToString("o");
|
||||
|
||||
var link = await conn.QuerySingleOrDefaultAsync<TelegramLinkRecord>(
|
||||
"SELECT * FROM telegram_links WHERE link_code = @code AND telegram_chat_id = 0",
|
||||
new { code });
|
||||
|
||||
if (link == null) return null;
|
||||
if (string.Compare(link.ExpiresAt, now, StringComparison.Ordinal) < 0) return null;
|
||||
|
||||
// Bestehende Verknüpfung für diese chatId entfernen
|
||||
// Erst alte Verknüpfung mit dieser chatId entfernen (ein Telegram-Chat = eine Session)
|
||||
await conn.ExecuteAsync(
|
||||
"DELETE FROM telegram_links WHERE telegram_chat_id = @chatId",
|
||||
new { chatId });
|
||||
|
||||
// Pending-Eintrag aktivieren
|
||||
await conn.ExecuteAsync(@"
|
||||
UPDATE telegram_links SET telegram_chat_id = @chatId, link_code = NULL, expires_at = NULL, updated_at = @now
|
||||
WHERE id = @id",
|
||||
new { chatId, now, id = link.Id });
|
||||
|
||||
link.TelegramChatId = chatId;
|
||||
link.LinkCode = null;
|
||||
return link;
|
||||
"UPDATE sessions SET telegram_chat_id = NULL, updated_at = @now WHERE telegram_chat_id = @chatId",
|
||||
new { chatId, now = DateTime.UtcNow.ToString("o") });
|
||||
// Dann diese Session verknüpfen
|
||||
await conn.ExecuteAsync(
|
||||
"UPDATE sessions SET telegram_chat_id = @chatId, updated_at = @now WHERE session_id = @sessionId",
|
||||
new { sessionId, chatId, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
public async Task<TelegramLinkRecord> GetTelegramLink(long chatId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
return await conn.QuerySingleOrDefaultAsync<TelegramLinkRecord>(
|
||||
"SELECT * FROM telegram_links WHERE telegram_chat_id = @chatId",
|
||||
new { chatId });
|
||||
}
|
||||
|
||||
public async Task UpdateTelegramSession(long chatId, string sessionId, string agentId)
|
||||
public async Task ClearSessionTelegramChatId(string sessionId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
await conn.ExecuteAsync(
|
||||
"UPDATE telegram_links SET session_id = @sessionId, agent_id = @agentId, updated_at = @now WHERE telegram_chat_id = @chatId",
|
||||
new { chatId, sessionId, agentId, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
public async Task DeleteTelegramLink(long chatId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
await conn.ExecuteAsync(
|
||||
"DELETE FROM telegram_links WHERE telegram_chat_id = @chatId",
|
||||
new { chatId });
|
||||
"UPDATE sessions SET telegram_chat_id = NULL, updated_at = @now WHERE session_id = @sessionId",
|
||||
new { sessionId, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SessionRecord>> GetUserSessions(string userId)
|
||||
|
||||
Reference in new issue
Block a user