up
This commit is contained in:
@@ -1,28 +1,206 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
type TelegramController struct {
|
||||
Service *services.TelegramService
|
||||
// TelegramIndex renderiza la vista de configuración de Telegram.
|
||||
func TelegramIndex(c *fiber.Ctx) error {
|
||||
return c.Render("telegram", fiber.Map{
|
||||
"user": c.Locals("user"),
|
||||
"modules": c.Locals("userModules"),
|
||||
}, "layouts/main")
|
||||
}
|
||||
|
||||
func NewTelegramController(service *services.TelegramService) *TelegramController {
|
||||
return &TelegramController{Service: service}
|
||||
}
|
||||
|
||||
func (tc *TelegramController) SendMessage(chatID interface{}, message string) error {
|
||||
if chatID == "" || message == "" {
|
||||
return fmt.Errorf("chat_id and message are required")
|
||||
}
|
||||
|
||||
err := tc.Service.SendMessage(chatID, message)
|
||||
// GetTelegramConfigs devuelve todas las configs en JSON.
|
||||
func GetTelegramConfigs(c *fiber.Ctx) error {
|
||||
items, err := models.GetAllTelegramConfigs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending message: %v", err)
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(items)
|
||||
}
|
||||
|
||||
// CreateTelegramConfig crea una nueva configuración.
|
||||
func CreateTelegramConfig(c *fiber.Ctx) error {
|
||||
var m models.TelegramConfig
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
if strings.TrimSpace(m.Nombre) == "" || strings.TrimSpace(m.BotToken) == "" || strings.TrimSpace(m.ChatID) == "" {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "nombre, bot_token y chat_id son obligatorios"})
|
||||
}
|
||||
m.Activo = true
|
||||
if err := models.CreateTelegramConfig(&m); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.Status(201).JSON(m)
|
||||
}
|
||||
|
||||
// UpdateTelegramConfig actualiza una configuración.
|
||||
func UpdateTelegramConfig(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
var m models.TelegramConfig
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
m.ID = uint(id)
|
||||
// Si no se envía bot_token, mantener el existente
|
||||
if strings.TrimSpace(m.BotToken) == "" {
|
||||
cfg, err := models.GetTelegramConfigByID(uint(id))
|
||||
if err != nil {
|
||||
return c.Status(404).JSON(fiber.Map{"error": "no encontrado"})
|
||||
}
|
||||
m.BotToken = cfg.BotToken
|
||||
}
|
||||
if err := models.UpdateTelegramConfig(&m); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
// DeleteTelegramConfig elimina una configuración.
|
||||
func DeleteTelegramConfig(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
if err := models.DeleteTelegramConfig(uint(id)); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
// TestTelegramConfig envía un mensaje de prueba al bot configurado.
|
||||
func TestTelegramConfig(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
cfg, err := models.GetTelegramConfigByID(uint(id))
|
||||
if err != nil {
|
||||
return c.Status(404).JSON(fiber.Map{"error": "Configuración no encontrada"})
|
||||
}
|
||||
msg := "✅ <b>Prueba de conexión</b>\nEsta es una notificación de prueba desde <b>u-site admin</b>."
|
||||
sendErr := sendTelegramMessage(cfg.BotToken, cfg.ChatID, msg)
|
||||
logEntry := &models.TelegramLog{
|
||||
TelegramConfigID: cfg.ID,
|
||||
Titulo: "Prueba manual",
|
||||
Mensaje: msg,
|
||||
Estado: "ok",
|
||||
}
|
||||
if sendErr != nil {
|
||||
logEntry.Estado = "failed"
|
||||
logEntry.ErrorMsg = sendErr.Error()
|
||||
_ = models.CreateTelegramLog(logEntry)
|
||||
return c.Status(422).JSON(fiber.Map{"ok": false, "error": sendErr.Error()})
|
||||
}
|
||||
_ = models.CreateTelegramLog(logEntry)
|
||||
return c.JSON(fiber.Map{"ok": true, "message": "Mensaje enviado"})
|
||||
}
|
||||
|
||||
// SendTelegramNotification envía un mensaje personalizado a una o varias configs.
|
||||
// Body: { "config_ids": [1,2], "titulo": "...", "mensaje": "..." }
|
||||
func SendTelegramNotification(c *fiber.Ctx) error {
|
||||
type Req struct {
|
||||
ConfigIDs []uint `json:"config_ids"`
|
||||
Titulo string `json:"titulo"`
|
||||
Mensaje string `json:"mensaje"`
|
||||
}
|
||||
var req Req
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
if strings.TrimSpace(req.Mensaje) == "" {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "El mensaje no puede estar vacío"})
|
||||
}
|
||||
if len(req.ConfigIDs) == 0 {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Selecciona al menos un destino"})
|
||||
}
|
||||
|
||||
text := req.Mensaje
|
||||
if req.Titulo != "" {
|
||||
text = fmt.Sprintf("<b>%s</b>\n\n%s", req.Titulo, req.Mensaje)
|
||||
}
|
||||
|
||||
var enviados, fallidos int
|
||||
for _, cid := range req.ConfigIDs {
|
||||
cfg, err := models.GetTelegramConfigByID(cid)
|
||||
if err != nil || !cfg.Activo {
|
||||
fallidos++
|
||||
continue
|
||||
}
|
||||
sendErr := sendTelegramMessage(cfg.BotToken, cfg.ChatID, text)
|
||||
logEntry := &models.TelegramLog{
|
||||
TelegramConfigID: cfg.ID,
|
||||
Titulo: req.Titulo,
|
||||
Mensaje: req.Mensaje,
|
||||
Estado: "ok",
|
||||
}
|
||||
if sendErr != nil {
|
||||
logEntry.Estado = "failed"
|
||||
logEntry.ErrorMsg = sendErr.Error()
|
||||
fallidos++
|
||||
} else {
|
||||
enviados++
|
||||
}
|
||||
_ = models.CreateTelegramLog(logEntry)
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": fallidos == 0, "enviados": enviados, "fallidos": fallidos})
|
||||
}
|
||||
|
||||
// GetTelegramLogs devuelve el historial paginado de mensajes enviados.
|
||||
func GetTelegramLogs(c *fiber.Ctx) error {
|
||||
page, _ := strconv.Atoi(c.Query("page", "1"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
limit := 30
|
||||
offset := (page - 1) * limit
|
||||
items, total, err := models.GetTelegramLogs(limit, offset)
|
||||
if err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"items": items,
|
||||
"total": total,
|
||||
"totalPages": int(math.Ceil(float64(total) / float64(limit))),
|
||||
"page": page,
|
||||
})
|
||||
}
|
||||
|
||||
// ─── helper interno ───────────────────────────────────────────────────────────
|
||||
|
||||
func sendTelegramMessage(botToken, chatID, text string) error {
|
||||
if botToken == "" {
|
||||
return fmt.Errorf("bot_token vacío")
|
||||
}
|
||||
apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", botToken)
|
||||
payload := map[string]interface{}{
|
||||
"chat_id": chatID,
|
||||
"text": text,
|
||||
"parse_mode": "HTML",
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
resp, err := http.Post(apiURL, "application/json", bytes.NewReader(body)) //nolint:noctx
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("Telegram respondió %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user