package main import ( "context" "errors" "strconv" "strings" "fergalla.com/dockerbot/internal/apperrors" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" ) func (appCtx *App) handleDockerInfo(ctx context.Context, b *bot.Bot, chatID int64, params []string) { if len(params) == 0 { appCtx.sendMessage(ctx, b, chatID, appCtx.T("e.container.missing_name", map[string]string{"example": "info"}), true, nil) return } text, keyboard, err := appCtx.renderContainerDetail(ctx, params[0], 0) if err != nil { appCtx.logger.Error( "Failed to render container info", "module", "Bot", "container", params[0], "error", err, ) if errors.Is(err, apperrors.ErrContainerNotFound) { appCtx.sendMessage(ctx, b, chatID, appCtx.T("e.container.not_found"), true, nil) } else { appCtx.sendMessage(ctx, b, chatID, appCtx.T("e.container.info"), true, nil) } return } appCtx.sendMessage(ctx, b, chatID, text, true, keyboard) } func (appCtx *App) callbackHandlerContainer(ctx context.Context, b *bot.Bot, update *models.Update) { if update.CallbackQuery == nil { return } cb := update.CallbackQuery data := cb.Data parts := strings.Split(data, ":") if len(parts) < 3 { return } scope := parts[0] action := parts[1] container := parts[2] if scope != "docker_action" { return } // 🧠 estado (page opcional) pageIndex := 0 if len(parts) >= 4 { if p, err := strconv.Atoi(parts[3]); err == nil { pageIndex = p } } var successMsg string // 🔧 acción (excepto refresh) if action != "refresh" { err := appCtx.dockerInfo.ContainerAction(container, action) if err != nil { appCtx.logger.Error( "Docker action failed (callback)", "module", "Docker", "action", action, "container", container, "error", err, ) var msg string if errors.Is(err, apperrors.ErrContainerNotFound) { msg = appCtx.T("e.docker.connection") } else { msg = appCtx.T("e.container.action") } b.AnswerCallbackQuery(ctx, &bot.AnswerCallbackQueryParams{ CallbackQueryID: cb.ID, Text: msg, ShowAlert: true, }) return } successMsg = appCtx.T("a.container."+action, map[string]string{ "name": container, }) } // 🔄 invalidar cache SIEMPRE (acción o refresh) appCtx.containerCache.Invalidate() // 🎨 render centralizado text, keyboard, err := appCtx.renderContainerDetail(ctx, container, pageIndex) if err != nil { msg := appCtx.T("e.container.info") if err.Error() == "container_not_found" { msg = appCtx.T("e.container.not_found") } b.AnswerCallbackQuery(ctx, &bot.AnswerCallbackQueryParams{ CallbackQueryID: cb.ID, Text: msg, ShowAlert: true, }) return } // ✅ respuesta UX b.AnswerCallbackQuery(ctx, &bot.AnswerCallbackQueryParams{ CallbackQueryID: cb.ID, Text: successMsg, ShowAlert: false, }) // 🔄 actualizar mensaje _, err = b.EditMessageText(ctx, &bot.EditMessageTextParams{ ChatID: cb.Message.Message.Chat.ID, MessageID: cb.Message.Message.ID, Text: text, ParseMode: "html", ReplyMarkup: keyboard, }) if err != nil { appCtx.logger.Warn( "Failed to edit message after action", "module", "Bot", "error", err, ) return } } func (appCtx *App) callbackDockerInfo(ctx context.Context, b *bot.Bot, update *models.Update) { if update.CallbackQuery == nil { return } cb := update.CallbackQuery parts := strings.Split(cb.Data, ":") if len(parts) < 2 { return } container := parts[1] pageIndex := 0 if len(parts) >= 3 { if p, err := strconv.Atoi(parts[2]); err == nil { pageIndex = p } } text, keyboard, err := appCtx.renderContainerDetail(ctx, container, pageIndex) if err != nil { var msg string if errors.Is(err, apperrors.ErrContainerNotFound) { msg = appCtx.T("e.container.not_found") } else { msg = appCtx.T("e.container.info") } b.AnswerCallbackQuery(ctx, &bot.AnswerCallbackQueryParams{ CallbackQueryID: cb.ID, Text: msg, ShowAlert: true, }) return } b.AnswerCallbackQuery(ctx, &bot.AnswerCallbackQueryParams{ CallbackQueryID: cb.ID, }) _, err = b.EditMessageText(ctx, &bot.EditMessageTextParams{ ChatID: cb.Message.Message.Chat.ID, MessageID: cb.Message.Message.ID, Text: text, ParseMode: "html", ReplyMarkup: keyboard, }) if err != nil { appCtx.logger.Warn("Failed to edit message (container info)", "error", err) return } }