From 5251ec3015a172d75a97072c644dbe117cccb1d3 Mon Sep 17 00:00:00 2001 From: Artem Tsyrulnikov Date: Sun, 4 Jan 2026 18:06:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B7=D0=B0=D0=BA=D1=83=D0=BF=20=D0=BC=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=BA=D0=B0=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/backend/backend_client.go | 24 +++++++++++ telegram_bot/bot/bot.go | 42 +++++++++++++++++++ telegram_bot/screens/add_creative.go | 2 +- telegram_bot/screens/creative_details.go | 2 +- telegram_bot/screens/creative_editor.go | 2 +- telegram_bot/screens/my_projects.go | 32 +++++++++++--- .../screens/purchase_optional_details.go | 26 ++++++++---- 7 files changed, 115 insertions(+), 15 deletions(-) diff --git a/telegram_bot/adapter/backend/backend_client.go b/telegram_bot/adapter/backend/backend_client.go index 44c6619..40dffc2 100644 --- a/telegram_bot/adapter/backend/backend_client.go +++ b/telegram_bot/adapter/backend/backend_client.go @@ -206,6 +206,30 @@ func (c *Client) GetWorkspaces( return resp.Items, err } +func (c *Client) CreateWorkspace( + ctx context.Context, + jwt string, + name string, +) (*Workspace, error) { + req := struct { + Name string `json:"name"` + }{ + Name: name, + } + + var workspace Workspace + err := c.do( + ctx, + http.MethodPost, + "api/v1/workspaces", + req, + &workspace, + withBearer(jwt), + ) + + return &workspace, err +} + func (c *Client) GetProjects( ctx context.Context, jwt string, diff --git a/telegram_bot/bot/bot.go b/telegram_bot/bot/bot.go index 1dfc92a..dab2da6 100644 --- a/telegram_bot/bot/bot.go +++ b/telegram_bot/bot/bot.go @@ -3,6 +3,7 @@ package bot import ( "context" "fmt" + "strings" "example.com/m/adapter/backend" "github.com/NicoNex/echotron/v3" @@ -143,6 +144,11 @@ func (b *Bot) SendNew(text string, keyboard echotron.InlineKeyboardMarkup) { func (b *Bot) Edit(text string, keyboard echotron.InlineKeyboardMarkup) { if b.LastMessageID != 0 { + log.Info(). + Int("last_msg_id", b.LastMessageID). + Int("keyboard_rows", len(keyboard.InlineKeyboard)). + Int("text_len", len(text)). + Msg("EditMessageText request") _, err := b.EditMessageText( text, echotron.NewMessageID(b.ChatID, b.LastMessageID), @@ -152,6 +158,13 @@ func (b *Bot) Edit(text string, keyboard echotron.InlineKeyboardMarkup) { }, ) if err != nil { + if strings.Contains(err.Error(), "message is not modified") { + log.Info().Msg("EditMessageText ignored: message is not modified") + if b.exec != nil { + b.exec.handled = true + } + return + } log.Error().Err(err).Msg("EditMessageText") } } else { @@ -195,6 +208,9 @@ func (b *Bot) Update(u *echotron.Update) { log.Info(). Int64("chat_id", b.ChatID). Str("current_state", fmt.Sprintf("%T", b.CurrentState)). + Bool("has_callback", u.CallbackQuery != nil). + Bool("has_message", u.Message != nil). + Bool("has_edited_message", u.EditedMessage != nil). Msg("Update received") // Обрабатываем системные события (добавление в канал, подписки и т.д.) @@ -255,7 +271,21 @@ func (b *Bot) Update(u *echotron.Update) { } if u.CallbackQuery != nil { + log.Info(). + Str("callback_data", u.CallbackQuery.Data). + Int("callback_msg_id", func() int { + if u.CallbackQuery.Message != nil { + return u.CallbackQuery.Message.ID + } + return 0 + }()). + Int("last_msg_id", b.LastMessageID). + Msg("Callback received") b.cleanupCallbackUI(u) + if u.CallbackQuery.Data == "empty" || u.CallbackQuery.Data == "page_info" || u.CallbackQuery.Data == "noop" { + exec.handled = true + return + } if b.GlobalCallbackRouter != nil && u.CallbackQuery.Data != "" { if newState := b.GlobalCallbackRouter(u.CallbackQuery.Data); newState != nil { @@ -272,11 +302,23 @@ func (b *Bot) Update(u *echotron.Update) { } if !exec.handled && !exec.transitioned { + log.Info(). + Bool("has_callback", u.CallbackQuery != nil). + Bool("has_message", u.Message != nil). + Bool("handled", exec.handled). + Bool("transitioned", exec.transitioned). + Msg("No handler handled update, calling common handler") log.Info().Msg("Common handler") b.CurrentState.Handle(b, u) } if !exec.handled && !exec.transitioned { + log.Info(). + Bool("has_callback", u.CallbackQuery != nil). + Bool("has_message", u.Message != nil). + Bool("handled", exec.handled). + Bool("transitioned", exec.transitioned). + Msg("Default feedback triggered") log.Info().Msg("Default feedback") b.SetState(b.DefaultStateFactory(), NewMessage) } diff --git a/telegram_bot/screens/add_creative.go b/telegram_bot/screens/add_creative.go index 61cd6ca..feadc0f 100644 --- a/telegram_bot/screens/add_creative.go +++ b/telegram_bot/screens/add_creative.go @@ -85,7 +85,7 @@ https://t.me/+AbCdEfGhIjKlMn`, [][]echotron.InlineKeyboardButton{ // Начинаем процесс добавления медиа s.WaitingForMedia = true - s.ShowControlPanel(b, `⧉ Добавить медиа + s.ShowControlPanel(b, `+ Добавить медиа Отправьте фото, видео или GIF diff --git a/telegram_bot/screens/creative_details.go b/telegram_bot/screens/creative_details.go index 75c2c49..c111873 100644 --- a/telegram_bot/screens/creative_details.go +++ b/telegram_bot/screens/creative_details.go @@ -116,7 +116,7 @@ https://t.me/+AbCdEfGhIjKlMn`, [][]echotron.InlineKeyboardButton{ case data == "add_media": s.WaitingForMedia = true - s.ShowControlPanel(b, `⧉ Добавить медиа + s.ShowControlPanel(b, `+ Добавить медиа Отправьте фото, видео или GIF diff --git a/telegram_bot/screens/creative_editor.go b/telegram_bot/screens/creative_editor.go index 3a2ff77..dd3e3f8 100644 --- a/telegram_bot/screens/creative_editor.go +++ b/telegram_bot/screens/creative_editor.go @@ -283,7 +283,7 @@ func (e *CreativeEditorFields) ShowManagementPanel(b *bot.Bot, confirmButtonText // Блок редактирования контента buttons = append(buttons, bot.Row( bot.Button("✎ Текст", "edit_text"), - bot.Button("⧉ Медиа", "add_media"), + bot.Button("+ Медиа", "add_media"), )) // Добавление кнопки сразу под основным блоком buttons = append(buttons, bot.Row(bot.Button("+ Добавить кнопку", "add_button"))) diff --git a/telegram_bot/screens/my_projects.go b/telegram_bot/screens/my_projects.go index 5b0a1b1..f27c924 100644 --- a/telegram_bot/screens/my_projects.go +++ b/telegram_bot/screens/my_projects.go @@ -38,12 +38,34 @@ func (s *MyProjects) Enter(b *bot.Bot, mode bot.RenderMode) { } if len(workspaces) == 0 { - b.SendNew("У вас пока нет workspace'ов", bot.Keyboard()) - return - } + // Автоматически создаем workspace с именем пользователя + username := "My Workspace" + chatInfo, err := b.GetChat(b.ChatID) + if err == nil && chatInfo.Result != nil { + if chatInfo.Result.Username != "" { + username = chatInfo.Result.Username + } else if chatInfo.Result.FirstName != "" { + username = chatInfo.Result.FirstName + if chatInfo.Result.LastName != "" { + username += " " + chatInfo.Result.LastName + } + } + } - // Используем первый workspace по умолчанию - s.WorkspaceID = workspaces[0].ID + log.Info().Str("username", username).Msg("Creating default workspace") + workspace, err := b.Backend.CreateWorkspace(context.Background(), jwt, username) + if err != nil { + log.Error().Err(err).Msg("Failed to create workspace") + b.SendNew("❌ Не удалось создать workspace", bot.Keyboard()) + return + } + + s.WorkspaceID = workspace.ID + log.Info().Str("workspace_id", s.WorkspaceID).Str("name", workspace.Name).Msg("Workspace created successfully") + } else { + // Используем первый workspace по умолчанию + s.WorkspaceID = workspaces[0].ID + } } s.renderProjects(b, mode, jwt) diff --git a/telegram_bot/screens/purchase_optional_details.go b/telegram_bot/screens/purchase_optional_details.go index 9b9b28c..51c8438 100644 --- a/telegram_bot/screens/purchase_optional_details.go +++ b/telegram_bot/screens/purchase_optional_details.go @@ -570,9 +570,9 @@ func (s *PurchaseOptionalDetails) renderParamChannels(b *bot.Bot, mode bot.Rende label := fmt.Sprintf("%d", i+1) rows = append(rows, bot.Row( bot.Button(label, fmt.Sprintf("param_edit:%s:%d", param, i)), - bot.Button("⎘", fmt.Sprintf("param_copy:%s:%d", param, i)), - bot.Button("⤵", fmt.Sprintf("param_paste:%s:%d", param, i)), - bot.Button("✎", fmt.Sprintf("param_edit:%s:%d", param, i)), + bot.Button("⧉", fmt.Sprintf("param_copy:%s:%d", param, i)), + bot.Button("⇲", fmt.Sprintf("param_paste:%s:%d", param, i)), + bot.Button("Изменить", fmt.Sprintf("param_edit:%s:%d", param, i)), bot.Button("⌫", fmt.Sprintf("param_clear:%s:%d", param, i)), )) } @@ -630,7 +630,8 @@ func (s *PurchaseOptionalDetails) handleParamCallback(b *bot.Bot, data string) b case strings.HasPrefix(data, "param_edit:"): param, index, ok := s.parseParamIndex(data, "param_edit:") if !ok { - return false + s.Enter(b, bot.EditMessage) + return true } if index >= 0 && index < len(s.Channels) { s.CurrentParam = param @@ -638,10 +639,13 @@ func (s *PurchaseOptionalDetails) handleParamCallback(b *bot.Bot, data string) b s.openChannelEditor(b, param, s.CurrentChannel) return true } + s.Enter(b, bot.EditMessage) + return true case strings.HasPrefix(data, "param_copy:"): param, index, ok := s.parseParamIndex(data, "param_copy:") if !ok { - return false + s.Enter(b, bot.EditMessage) + return true } if index >= 0 && index < len(s.Channels) { username := s.Channels[index].Username @@ -649,10 +653,13 @@ func (s *PurchaseOptionalDetails) handleParamCallback(b *bot.Bot, data string) b s.Enter(b, bot.EditMessage) return true } + s.Enter(b, bot.EditMessage) + return true case strings.HasPrefix(data, "param_paste:"): param, index, ok := s.parseParamIndex(data, "param_paste:") if !ok { - return false + s.Enter(b, bot.EditMessage) + return true } if index >= 0 && index < len(s.Channels) { username := s.Channels[index].Username @@ -660,10 +667,13 @@ func (s *PurchaseOptionalDetails) handleParamCallback(b *bot.Bot, data string) b s.Enter(b, bot.EditMessage) return true } + s.Enter(b, bot.EditMessage) + return true case strings.HasPrefix(data, "param_clear:"): param, index, ok := s.parseParamIndex(data, "param_clear:") if !ok { - return false + s.Enter(b, bot.EditMessage) + return true } if index >= 0 && index < len(s.Channels) { username := s.Channels[index].Username @@ -671,6 +681,8 @@ func (s *PurchaseOptionalDetails) handleParamCallback(b *bot.Bot, data string) b s.Enter(b, bot.EditMessage) return true } + s.Enter(b, bot.EditMessage) + return true case strings.HasPrefix(data, "param_apply_all:"): param := strings.TrimPrefix(data, "param_apply_all:") s.applyParamToAll(param)