Files
gott/Endpoints/TelegramEndpoint.cs
T
Meleki b0d8bef5ea feat: Public-Flag für Agents + verfügbare Agents/Bots Endpoints erweitert
- AgentRecord: neues IsPublic-Feld mit DB-Migration
- GET /api/agents/available: eigene + public Agents (alle Properties + isOwner)
- GET /api/telegram/bots/available: alle Properties außer Token/Secret + sessionCount
- Agent-Page: Public-Checkbox (andere User können Agent in Sessions verwenden)
- Dashboard: agentMap aus availableAgents gebaut (public Agents fremder User auflösbar)
- Session-Page + Cronjob-Page: Agent-Picker nutzt /available statt /agents
- Agent-Cards: Public- und Fremd-Badges
- Fix: Chat-Button bei Sessions mit public Agent eines anderen Users nicht mehr disabled
2026-03-08 20:25:52 +01:00

316 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Text.Json;
using System.Threading.Tasks;
using Gott.Extensions;
using Gott.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
namespace Gott.Endpoints;
public static class TelegramEndpoint
{
public static void MapTelegramEndpoints(this IEndpointRouteBuilder app)
{
// Webhook pro Bot (von Telegram aufgerufen – keine Cookie-Auth!)
app.MapPost("/api/telegram/webhook/{botId}", HandleWebhook);
// ── Telegram Bot CRUD ──
app.MapGet("/api/telegram/bots", HandleGetBots);
app.MapGet("/api/telegram/bots/available", HandleGetAvailableBots);
app.MapPost("/api/telegram/bots", HandleCreateBot);
app.MapGet("/api/telegram/bots/{botId}", HandleGetBot);
app.MapPut("/api/telegram/bots/{botId}", HandleUpdateBot);
app.MapDelete("/api/telegram/bots/{botId}", HandleDeleteBot);
// ── Webhook-Verwaltung (pro Bot) ──
app.MapPost("/api/telegram/bots/{botId}/register-webhook", HandleRegisterWebhook);
app.MapGet("/api/telegram/bots/{botId}/webhook-info", HandleWebhookInfo);
app.MapDelete("/api/telegram/bots/{botId}/webhook", HandleDeleteWebhook);
// ── Session Telegram-Config ──
app.MapGet("/api/sessions/{sessionId}/telegram", HandleGetSessionTelegram);
app.MapPut("/api/sessions/{sessionId}/telegram", HandleSaveSessionTelegram);
}
// ── Webhook Handler ──
private static async Task HandleWebhook(string botId, HttpRequest req, HttpResponse res, TelegramService telegram, DatabaseService db)
{
var bot = await db.GetTelegramBot(botId);
if (bot == null)
{
res.StatusCode = 404;
return;
}
// Secret-Token prüfen
var secret = req.Headers["X-Telegram-Bot-Api-Secret-Token"].ToString();
if (!string.IsNullOrEmpty(bot.WebhookSecret) && secret != bot.WebhookSecret)
{
res.StatusCode = 403;
return;
}
try
{
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
_ = Task.Run(async () =>
{
try { await telegram.HandleUpdate(body, bot); }
catch (Exception ex) { Console.Error.WriteLine($"[Telegram] Fehler für Bot {bot.Name}: {ex.Message}"); }
});
}
catch
{
// Malformed JSON – ignorieren
}
res.StatusCode = 200;
}
// ── Bot CRUD ──
private static async Task HandleGetBots(HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var bots = await db.GetTelegramBots(userId);
var result = new System.Collections.Generic.List<object>();
foreach (var bot in bots)
{
var sessionCount = await db.GetTelegramBotSessionCount(bot.BotId);
result.Add(new
{
botId = bot.BotId,
name = bot.Name,
botToken = bot.BotToken,
webhookSecret = bot.WebhookSecret,
isPublic = bot.IsPublic,
sessionCount,
createdAt = bot.CreatedAt,
updatedAt = bot.UpdatedAt
});
}
await res.WriteAsJsonAsync(result);
}
private static async Task HandleGetBot(string botId, HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Bot nicht gefunden" });
return;
}
var sessionCount = await db.GetTelegramBotSessionCount(bot.BotId);
await res.WriteAsJsonAsync(new
{
botId = bot.BotId,
name = bot.Name,
botToken = bot.BotToken,
webhookSecret = bot.WebhookSecret,
isPublic = bot.IsPublic,
sessionCount,
createdAt = bot.CreatedAt,
updatedAt = bot.UpdatedAt
});
}
private static async Task HandleCreateBot(HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
var name = body.TryGetProperty("name", out var n) ? n.GetString()?.Trim() : null;
var botToken = body.TryGetProperty("botToken", out var t) ? t.GetString()?.Trim() : null;
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(botToken))
{
res.StatusCode = 400;
await res.WriteAsJsonAsync(new { error = "Name und Bot-Token sind erforderlich" });
return;
}
var bot = await db.CreateTelegramBot(userId, name, botToken);
await res.WriteAsJsonAsync(new
{
botId = bot.BotId,
name = bot.Name,
botToken = bot.BotToken,
webhookSecret = bot.WebhookSecret,
createdAt = bot.CreatedAt
});
}
private static async Task HandleUpdateBot(string botId, HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Bot nicht gefunden" });
return;
}
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
var name = body.TryGetProperty("name", out var n) ? n.GetString()?.Trim() : bot.Name;
var botToken = body.TryGetProperty("botToken", out var t) ? t.GetString()?.Trim() : bot.BotToken;
var isPublic = body.TryGetProperty("isPublic", out var p) ? p.GetBoolean() : bot.IsPublic;
await db.UpdateTelegramBot(botId, name, botToken, isPublic);
await res.WriteAsJsonAsync(new { ok = true });
}
private static async Task HandleDeleteBot(string botId, HttpRequest req, HttpResponse res, DatabaseService db, TelegramService telegram)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Bot nicht gefunden" });
return;
}
// Webhook bei Telegram löschen
try { await telegram.DeleteWebhook(bot); } catch { /* ignore */ }
await db.DeleteTelegramBot(botId);
await res.WriteAsJsonAsync(new { ok = true });
}
// ── Webhook-Verwaltung ──
private static async Task HandleRegisterWebhook(string botId, HttpRequest req, HttpResponse res, DatabaseService db, TelegramService telegram)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Bot nicht gefunden" });
return;
}
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
if (!body.TryGetProperty("baseUrl", out var urlEl))
{
res.StatusCode = 400;
await res.WriteAsJsonAsync(new { error = "baseUrl required" });
return;
}
var result = await telegram.RegisterWebhook(urlEl.GetString(), bot);
res.ContentType = "application/json";
await res.WriteAsync(result);
}
private static async Task HandleWebhookInfo(string botId, HttpRequest req, HttpResponse res, DatabaseService db, TelegramService telegram)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
return;
}
var result = await telegram.GetWebhookInfo(bot);
res.ContentType = "application/json";
await res.WriteAsync(result);
}
private static async Task HandleDeleteWebhook(string botId, HttpRequest req, HttpResponse res, DatabaseService db, TelegramService telegram)
{
var userId = req.HttpContext.GetUserId();
var bot = await db.GetTelegramBot(botId);
if (bot == null || bot.UserId != userId)
{
res.StatusCode = 404;
return;
}
var result = await telegram.DeleteWebhook(bot);
res.ContentType = "application/json";
await res.WriteAsync(result);
}
// ── Verfügbare Bots (eigene + public) ──
private static async Task HandleGetAvailableBots(HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var bots = await db.GetAvailableTelegramBots(userId);
var result = new System.Collections.Generic.List<object>();
foreach (var bot in bots)
{
var isOwner = bot.UserId == userId;
var sessionCount = await db.GetTelegramBotSessionCount(bot.BotId);
result.Add(new
{
botId = bot.BotId,
name = bot.Name,
isOwner,
isPublic = bot.IsPublic,
sessionCount,
createdAt = bot.CreatedAt,
updatedAt = bot.UpdatedAt
});
}
await res.WriteAsJsonAsync(result);
}
// ── Session Telegram-Config ──
private static async Task HandleGetSessionTelegram(string sessionId, HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var session = await db.GetSession(sessionId);
if (session == null || session.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Session nicht gefunden" });
return;
}
await res.WriteAsJsonAsync(new
{
telegramBotId = session.TelegramBotId ?? "",
chatId = session.TelegramChatId ?? "",
configured = !string.IsNullOrEmpty(session.TelegramBotId)
});
}
private static async Task HandleSaveSessionTelegram(string sessionId, HttpRequest req, HttpResponse res, DatabaseService db)
{
var userId = req.HttpContext.GetUserId();
var session = await db.GetSession(sessionId);
if (session == null || session.UserId != userId)
{
res.StatusCode = 404;
await res.WriteAsJsonAsync(new { error = "Session nicht gefunden" });
return;
}
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
var botId = body.TryGetProperty("telegramBotId", out var b) ? b.GetString() : null;
var chatId = body.TryGetProperty("chatId", out var c) ? c.GetString() : session.TelegramChatId;
// Bot-Zuordnung setzen
if (botId != null)
{
await db.SetSessionTelegramBot(sessionId, string.IsNullOrEmpty(botId) ? null : botId);
}
// Chat-ID aktualisieren (leerer String → NULL)
await db.UpdateSessionTelegramChat(sessionId, string.IsNullOrEmpty(chatId) ? null : chatId);
await res.WriteAsJsonAsync(new { ok = true });
}
}