- Backend: DELETE /api/telegram/webhook Endpoint + TelegramService.DeleteWebhook() - api.js: apiTelegramWebhookInfo(), apiTelegramRegisterWebhook(), apiTelegramDeleteWebhook() - Settings-Page: Neue 'Telegram Bot' Section (nur für Admins, nur wenn konfiguriert) - Status abrufen: Webhook-URL, ausstehende Updates, letzter Fehler, Aktiv-Badge - Webhook registrieren: prompt() für Base-URL, POST an Telegram API - Webhook entfernen: Bestätigungsdialog + DELETE - CSS: .telegram-status-box, .tg-status-row, .tg-label, .tg-value, .tg-badge
157 lines
5.0 KiB
C#
157 lines
5.0 KiB
C#
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 (von Telegram aufgerufen – keine Cookie-Auth!)
|
||
app.MapPost("/api/telegram/webhook", HandleWebhook);
|
||
|
||
// Link-Code generieren (aus Web-UI, braucht Auth)
|
||
app.MapPost("/api/telegram/link", HandleCreateLink);
|
||
|
||
// Webhook registrieren (Admin)
|
||
app.MapPost("/api/telegram/register-webhook", HandleRegisterWebhook);
|
||
|
||
// Telegram-Status (ob konfiguriert – für Frontend)
|
||
app.MapGet("/api/telegram/status", HandleStatus);
|
||
|
||
// Webhook-Info (Admin)
|
||
app.MapGet("/api/telegram/webhook-info", HandleWebhookInfo);
|
||
|
||
// Webhook löschen (Admin)
|
||
app.MapDelete("/api/telegram/webhook", HandleDeleteWebhook);
|
||
}
|
||
|
||
private static async Task HandleWebhook(HttpRequest req, HttpResponse res, TelegramService telegram)
|
||
{
|
||
if (!telegram.IsConfigured)
|
||
{
|
||
res.StatusCode = 404;
|
||
return;
|
||
}
|
||
|
||
// Secret-Token prüfen
|
||
var secret = req.Headers["X-Telegram-Bot-Api-Secret-Token"].ToString();
|
||
if (secret != telegram.WebhookSecret)
|
||
{
|
||
res.StatusCode = 403;
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
|
||
// Fire-and-forget – Telegram erwartet schnelle 200 OK Antwort
|
||
_ = Task.Run(async () =>
|
||
{
|
||
try { await telegram.HandleUpdate(body); }
|
||
catch (Exception ex) { Console.Error.WriteLine($"[Telegram] Fehler: {ex.Message}"); }
|
||
});
|
||
}
|
||
catch
|
||
{
|
||
// Malformed JSON – ignorieren
|
||
}
|
||
|
||
res.StatusCode = 200;
|
||
}
|
||
|
||
private static async Task HandleCreateLink(HttpRequest req, HttpResponse res, DatabaseService db, TelegramService telegram)
|
||
{
|
||
if (!telegram.IsConfigured)
|
||
{
|
||
res.StatusCode = 400;
|
||
await res.WriteAsJsonAsync(new { error = "Telegram Bot nicht konfiguriert" });
|
||
return;
|
||
}
|
||
|
||
var userId = req.HttpContext.GetUserId();
|
||
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
|
||
|
||
if (!body.TryGetProperty("sessionId", out var sidEl))
|
||
{
|
||
res.StatusCode = 400;
|
||
await res.WriteAsJsonAsync(new { error = "sessionId required" });
|
||
return;
|
||
}
|
||
|
||
var sessionId = sidEl.GetString();
|
||
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 agentId = session.AgentId;
|
||
var code = await db.CreateTelegramLinkCode(userId, sessionId, agentId);
|
||
|
||
await res.WriteAsJsonAsync(new { code, expiresInSeconds = 300 });
|
||
}
|
||
|
||
private static async Task HandleRegisterWebhook(HttpRequest req, HttpResponse res, TelegramService telegram)
|
||
{
|
||
if (!req.HttpContext.IsAdmin())
|
||
{
|
||
res.StatusCode = 403;
|
||
await res.WriteAsJsonAsync(new { error = "Admin required" });
|
||
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());
|
||
await res.WriteAsJsonAsync(new { result });
|
||
}
|
||
|
||
private static async Task HandleStatus(HttpResponse res, TelegramService telegram)
|
||
{
|
||
await res.WriteAsJsonAsync(new { configured = telegram.IsConfigured });
|
||
}
|
||
|
||
private static async Task HandleWebhookInfo(HttpRequest req, HttpResponse res, TelegramService telegram)
|
||
{
|
||
if (!req.HttpContext.IsAdmin())
|
||
{
|
||
res.StatusCode = 403;
|
||
await res.WriteAsJsonAsync(new { error = "Admin required" });
|
||
return;
|
||
}
|
||
|
||
var result = await telegram.GetWebhookInfo();
|
||
res.ContentType = "application/json";
|
||
await res.WriteAsync(result);
|
||
}
|
||
|
||
private static async Task HandleDeleteWebhook(HttpRequest req, HttpResponse res, TelegramService telegram)
|
||
{
|
||
if (!req.HttpContext.IsAdmin())
|
||
{
|
||
res.StatusCode = 403;
|
||
await res.WriteAsJsonAsync(new { error = "Admin required" });
|
||
return;
|
||
}
|
||
|
||
var result = await telegram.DeleteWebhook();
|
||
res.ContentType = "application/json";
|
||
await res.WriteAsync(result);
|
||
}
|
||
}
|