refactor
This commit is contained in:
@@ -6,42 +6,35 @@ import (
|
||||
|
||||
"example.com/m/bot"
|
||||
"github.com/NicoNex/echotron/v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Login struct{}
|
||||
|
||||
func (s *Login) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
// JWT уже создан в Bot.Update() с актуальными данными пользователя
|
||||
// Теперь создаем login token (это разовый токен для авторизации на сайте)
|
||||
var username *string
|
||||
// Получаем username из сессии если он там сохранен
|
||||
if b.Session.UserName != "" {
|
||||
username = &b.Session.UserName
|
||||
}
|
||||
const msgHelloLogin = `
|
||||
Привет, %s!
|
||||
👇Нажми кнопку для входа на сайт.
|
||||
`
|
||||
|
||||
token, err := b.Backend.CreateLoginToken(context.Background(), b.ChatID, username)
|
||||
func (s *Login) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
token, err := b.Backend.CreateLoginToken(context.Background(), b.ChatID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create login token")
|
||||
b.SendMessage("❌ Произошла ошибка при создании токена входа. Попробуйте позже.", b.ChatID, nil)
|
||||
b.SendNew("❌ Произошла ошибка при создании токена входа. Попробуйте позже.", emptyKeyboard)
|
||||
return
|
||||
}
|
||||
|
||||
loginURL := b.Backend.GetLoginURL(token)
|
||||
loginURL := b.Backend.LoginURL(token)
|
||||
|
||||
usernameDisplay := "аноним"
|
||||
if username != nil && *username != "" {
|
||||
usernameDisplay = *username
|
||||
if b.Session.FirstName != "" {
|
||||
usernameDisplay = b.Session.FirstName
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("Привет, %s!\n\nНажми кнопку ниже для входа на сайт.", usernameDisplay)
|
||||
b.SendMessageWithURLButton(message, "Войти на сайт", loginURL)
|
||||
}
|
||||
func (s *Login) HandleCallback(b *bot.Bot, u *echotron.Update) { return }
|
||||
kb := Keyboard(Row(URLButton("Войти на сайт", loginURL)))
|
||||
|
||||
func (s *Login) HandleMessage(b *bot.Bot, u *echotron.Update) { return }
|
||||
|
||||
func (s *Login) Handle(b *bot.Bot, u *echotron.Update) {
|
||||
b.SetState(&MainMenu{}, bot.NewMessage)
|
||||
return
|
||||
b.SendNew(fmt.Sprintf(msgHelloLogin, usernameDisplay), kb)
|
||||
}
|
||||
func (s *Login) HandleCallback(b *bot.Bot, u *echotron.Update) {}
|
||||
|
||||
func (s *Login) HandleMessage(b *bot.Bot, u *echotron.Update) {}
|
||||
|
||||
func (s *Login) Handle(b *bot.Bot, u *echotron.Update) { b.SetState(&MainMenu{}, bot.NewMessage) }
|
||||
|
||||
@@ -158,6 +158,28 @@ func (s *SelectChannelsForPurchase) HandleCallback(b *bot.Bot, u *echotron.Updat
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем существование каналов через API
|
||||
jwt := b.Session.JWT
|
||||
if jwt == "" {
|
||||
log.Error().Msg("JWT is empty in session")
|
||||
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", Keyboard())
|
||||
return
|
||||
}
|
||||
|
||||
notFoundChannels := s.validateChannels(b, jwt)
|
||||
if len(notFoundChannels) > 0 {
|
||||
text := "❌ Следующие каналы не найдены:\n\n"
|
||||
for _, username := range notFoundChannels {
|
||||
text += fmt.Sprintf("• @%s\n", username)
|
||||
}
|
||||
text += "\nУдалите их из списка и попробуйте снова"
|
||||
|
||||
b.Edit(text, Keyboard(
|
||||
Row(Button("← Назад", "back_to_select")),
|
||||
))
|
||||
return
|
||||
}
|
||||
|
||||
b.SetState(&PurchaseOptionalDetails{
|
||||
WorkspaceID: s.WorkspaceID,
|
||||
ProjectID: s.ProjectID,
|
||||
@@ -313,6 +335,39 @@ func (s *SelectChannelsForPurchase) HandleMessage(b *bot.Bot, u *echotron.Update
|
||||
s.Enter(b, bot.NewMessage)
|
||||
}
|
||||
|
||||
func (s *SelectChannelsForPurchase) validateChannels(b *bot.Bot, jwt string) []string {
|
||||
var notFound []string
|
||||
|
||||
for _, ch := range s.Channels {
|
||||
channels, err := b.Backend.SearchChannels(
|
||||
context.Background(),
|
||||
jwt,
|
||||
ch.Username,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("username", ch.Username).Msg("Failed to search channel")
|
||||
notFound = append(notFound, ch.Username)
|
||||
continue
|
||||
}
|
||||
|
||||
// Проверяем что нашли хотя бы один канал с точным совпадением username
|
||||
found := false
|
||||
for _, channel := range channels {
|
||||
if channel.Username != nil && *channel.Username == ch.Username {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
notFound = append(notFound, ch.Username)
|
||||
}
|
||||
}
|
||||
|
||||
return notFound
|
||||
}
|
||||
|
||||
func (s *SelectChannelsForPurchase) Handle(b *bot.Bot, u *echotron.Update) {
|
||||
// Обрабатываем callback после успешного создания
|
||||
if u.CallbackQuery != nil && u.CallbackQuery.Data == "done" {
|
||||
|
||||
@@ -6,55 +6,74 @@ import (
|
||||
"strings"
|
||||
|
||||
"example.com/m/bot"
|
||||
"example.com/m/ui"
|
||||
"github.com/NicoNex/echotron/v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type SelectWorkspace struct {
|
||||
ChannelID string
|
||||
BackState bot.State
|
||||
ChannelID string
|
||||
BackState bot.State
|
||||
CurrentPage int
|
||||
}
|
||||
|
||||
func (s *SelectWorkspace) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
// JWT уже создан в Bot.Update(), просто берем из сессии
|
||||
jwt := b.Session.JWT
|
||||
if jwt == "" {
|
||||
log.Error().Msg("JWT is empty in session")
|
||||
b.SendNew("❌ Ошибка авторизации. Попробуйте /start", Keyboard())
|
||||
return
|
||||
}
|
||||
const msgChooseWorkspace = `
|
||||
📁 Выбор workspace для канала
|
||||
В какой workspace добавить канал?
|
||||
`
|
||||
|
||||
workspaces, err := b.Backend.GetWorkspaces(context.Background(), jwt)
|
||||
const msgSuccessChooseWorkspace = `
|
||||
✅ Канал успешно добавлен!
|
||||
📊 Проект ID: %s
|
||||
📝 Название: %s
|
||||
🏷 Статус: %s
|
||||
`
|
||||
|
||||
func (s *SelectWorkspace) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
workspaces, err := b.Backend.GetWorkspaces(context.Background(), b.Session.JWT)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get workspaces")
|
||||
b.SendNew("❌ Не удалось загрузить список workspace'ов", Keyboard())
|
||||
return
|
||||
}
|
||||
|
||||
if len(workspaces) == 0 {
|
||||
b.SendNew("У вас пока нет workspace'ов", Keyboard(
|
||||
Row(Button("🏠 Главное меню", "back")),
|
||||
))
|
||||
kb := Keyboard(Row(Button("Главное меню", "back")))
|
||||
b.SendNew("У вас пока нет workspace'ов", kb)
|
||||
return
|
||||
}
|
||||
|
||||
text := "📁 Выбор workspace для канала\n\n"
|
||||
text += "В какой workspace добавить канал?"
|
||||
// Создаем кнопки для всех workspace'ов
|
||||
var allButtons []echotron.InlineKeyboardButton
|
||||
for _, ws := range workspaces {
|
||||
allButtons = append(allButtons, Button(ws.Name, fmt.Sprintf("select_workspace:%s", ws.ID)))
|
||||
}
|
||||
|
||||
// Используем компонент пагинации для автоматической раскладки
|
||||
const workspacesPerPage = 6
|
||||
var buttons [][]echotron.InlineKeyboardButton
|
||||
|
||||
// Создаем кнопки для каждого workspace
|
||||
for _, ws := range workspaces {
|
||||
buttons = append(buttons, Row(
|
||||
Button(ws.Name, fmt.Sprintf("select_workspace:%s", ws.ID)),
|
||||
))
|
||||
// Раскладываем workspace'ы в grid (2 в ряд) с пагинацией
|
||||
elementRows := ui.BuildElementRows(ui.ElementLayoutConfig{
|
||||
CurrentPage: s.CurrentPage,
|
||||
ItemsPerPage: workspacesPerPage,
|
||||
ItemsPerRow: 2,
|
||||
}, allButtons)
|
||||
buttons = append(buttons, elementRows...)
|
||||
|
||||
// Добавляем навигацию (стрелки появятся только если страниц > 1)
|
||||
if navRow := ui.BuildNavigationRow(ui.PaginationConfig{
|
||||
CurrentPage: s.CurrentPage,
|
||||
TotalItems: len(allButtons),
|
||||
ItemsPerPage: workspacesPerPage,
|
||||
}); navRow != nil {
|
||||
buttons = append(buttons, navRow)
|
||||
}
|
||||
|
||||
// Кнопка отмены
|
||||
buttons = append(buttons, Row(Button("❌ Отмена", "cancel")))
|
||||
buttons = append(buttons, Row(Button("Отмена", "cancel")))
|
||||
|
||||
keyboard := Keyboard(buttons...)
|
||||
b.Render(text, keyboard, mode)
|
||||
kb := Keyboard(buttons...)
|
||||
b.Render(msgChooseWorkspace, kb, mode)
|
||||
}
|
||||
|
||||
func (s *SelectWorkspace) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||||
@@ -65,13 +84,22 @@ func (s *SelectWorkspace) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||||
data := u.CallbackQuery.Data
|
||||
|
||||
switch {
|
||||
case data == "prev":
|
||||
if s.CurrentPage > 0 {
|
||||
s.CurrentPage--
|
||||
}
|
||||
s.Enter(b, bot.EditMessage)
|
||||
|
||||
case data == "next":
|
||||
s.CurrentPage++
|
||||
s.Enter(b, bot.EditMessage)
|
||||
|
||||
case data == "cancel", data == "back":
|
||||
if s.BackState != nil {
|
||||
b.SetState(s.BackState, bot.NewMessage)
|
||||
}
|
||||
|
||||
case strings.HasPrefix(data, "select_workspace:"):
|
||||
// Извлекаем workspace_id
|
||||
parts := strings.Split(data, ":")
|
||||
if len(parts) != 2 {
|
||||
log.Error().Str("callback_data", data).Msg("Invalid callback data format")
|
||||
@@ -80,10 +108,6 @@ func (s *SelectWorkspace) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||||
|
||||
workspaceID := parts[1]
|
||||
|
||||
// Показываем индикатор загрузки
|
||||
b.Edit("⏳ Добавляем канал в workspace...", Keyboard())
|
||||
|
||||
// Вызываем API для привязки канала к workspace
|
||||
project, err := b.Backend.AttachChannelToWorkspace(
|
||||
context.Background(),
|
||||
s.ChannelID,
|
||||
@@ -91,27 +115,19 @@ func (s *SelectWorkspace) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||||
b.ChatID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("channel_id", s.ChannelID).Str("workspace_id", workspaceID).Msg("Failed to attach channel to workspace")
|
||||
b.Edit("❌ Не удалось добавить канал в workspace", Keyboard(
|
||||
Row(Button("← Назад", "back_to_select")),
|
||||
))
|
||||
return
|
||||
}
|
||||
|
||||
// Показываем успешное сообщение
|
||||
successText := fmt.Sprintf("✅ Канал успешно добавлен!\n\n"+
|
||||
"📊 Проект ID: %s\n"+
|
||||
"📝 Название: %s\n"+
|
||||
"🏷 Статус: %s",
|
||||
project.ID,
|
||||
project.Title,
|
||||
project.Status,
|
||||
successText := fmt.Sprintf(msgSuccessChooseWorkspace, project.ID, project.Title, project.Status)
|
||||
kb := Keyboard(
|
||||
Row(Button("Мои проекты", "my_projects")),
|
||||
Row(Button("Главное меню", "main_menu")),
|
||||
)
|
||||
|
||||
b.Edit(successText, Keyboard(
|
||||
Row(Button("📋 Мои проекты", "my_projects")),
|
||||
Row(Button("🏠 Главное меню", "main_menu")),
|
||||
))
|
||||
b.Edit(successText, kb)
|
||||
|
||||
case data == "back_to_select":
|
||||
s.Enter(b, bot.EditMessage)
|
||||
|
||||
Reference in New Issue
Block a user