парсер

This commit is contained in:
Artem Tsyrulnikov
2026-01-06 21:04:42 +03:00
parent b77e4fd0b6
commit 2c0ae2dfc3
45 changed files with 2202 additions and 51 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"os"
"time"
"example.com/m/adapter/backend"
@@ -12,10 +13,6 @@ import (
"github.com/rs/zerolog/log"
)
const (
botToken = "7718883894:AAHUqtjqHtSs2Rp6Tb4PokqU6syfKmcFvOo"
)
func main() {
logger.Init(logger.Config{
AppName: "tgex-bot",
@@ -23,10 +20,13 @@ func main() {
PrettyConsole: true,
})
// Инициализация backend client
botToken := mustEnv("TELEGRAM__TOKEN")
loginURL := mustEnv("LOGIN_URL")
baseURL := os.Getenv("BACKEND__BASE_URL")
backendClient := backend.New(backend.Config{
BaseURL: "http://backend:8000",
LoginURL: "https://unstabilising-lora-unframable.ngrok-free.dev/api/v1/auth/complete?token=",
BaseURL: baseURL,
LoginURL: loginURL,
})
var mainMenu = func() bot.State { return &screens.MainMenu{} }
@@ -47,3 +47,12 @@ func main() {
break
}
}
func mustEnv(key string) string {
value := os.Getenv(key)
if value == "" {
log.Fatal().Str("env", key).Msg("missing required environment variable")
}
return value
}

View File

@@ -74,6 +74,7 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
case data == "add_button":
// Начинаем процесс добавления кнопки
s.WaitingForButtonText = true
s.PendingButtonType = "invite"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
@@ -81,7 +82,13 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
<i>Например:</i>
• Перейти на сайт
• Написать нам`, [][]echotron.InlineKeyboardButton{
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("✓ Ссылка на канал", "button_type_invite"),
bot.Button("Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
@@ -115,13 +122,14 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
// Если мы уже создали кнопку с placeholder - удаляем её
if s.WaitingForButtonURL && len(s.Buttons) > 0 {
lastButton := s.Buttons[len(s.Buttons)-1]
if lastButton.URL == "https://example.com" {
if lastButton.URL == "https://example.com" || lastButton.URL == inviteLinkPlaceholder {
s.Buttons = s.Buttons[:len(s.Buttons)-1]
s.UpdateCreativePreview(b)
}
}
s.WaitingForButtonText = false
s.WaitingForButtonURL = false
s.PendingButtonType = ""
s.CurrentButtonText = nil
if s.CreativeMessageSent {
@@ -130,6 +138,42 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
s.ShowManagementPanel(b, "✓ Сохранить", "confirm_create", "cancel")
}
case data == "button_type_invite":
s.PendingButtonType = "invite"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
Введите <b>текст кнопки:</b>
<i>Например:</i>
• Перейти на сайт
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("✓ Ссылка на канал", "button_type_invite"),
bot.Button("Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
case data == "button_type_custom":
s.PendingButtonType = "custom"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
Введите <b>текст кнопки:</b>
<i>Например:</i>
• Перейти на сайт
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("Ссылка на канал", "button_type_invite"),
bot.Button("✓ Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
case data == "cancel_edit":
// Отменяем редактирование текста
s.WaitingForTextEdit = false
@@ -255,7 +299,6 @@ func (s *AddCreative) HandleMessage(b *bot.Bot, u *echotron.Update) {
buttonText := u.Message.Text
s.CurrentButtonText = &buttonText
s.WaitingForButtonText = false
s.WaitingForButtonURL = true
// Удаляем сообщение пользователя
_, err := b.DeleteMessage(b.ChatID, u.Message.ID)
@@ -263,22 +306,35 @@ func (s *AddCreative) HandleMessage(b *bot.Bot, u *echotron.Update) {
log.Error().Err(err).Msg("Failed to delete user message")
}
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: "https://example.com",
})
s.UpdateCreativePreview(b)
s.ShowControlPanel(b, `<b>✧ Введите URL для кнопки:</b>
if s.PendingButtonType == "custom" {
s.WaitingForButtonURL = true
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: "https://example.com",
})
s.UpdateCreativePreview(b)
s.ShowControlPanel(b, `<b>✧ Введите URL для кнопки:</b>
URL должен начинаться с <code>https://</code>
<i>Например:</i>
<code>https://example.com</code>
<code>https://t.me/yourchannel</code>`, [][]echotron.InlineKeyboardButton{
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
} else {
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: inviteLinkPlaceholder,
})
s.UpdateCreativePreview(b)
s.PendingButtonType = ""
if s.CreativeMessageSent {
s.showCreativeConfirmation(b)
} else {
s.ShowManagementPanel(b, "✓ Сохранить", "confirm_create", "cancel")
}
}
return
}
@@ -312,6 +368,7 @@ URL должен начинаться с <code>https://</code>
}
s.WaitingForButtonURL = false
s.CurrentButtonText = nil
s.PendingButtonType = ""
s.UpdateCreativePreview(b)

View File

@@ -101,13 +101,20 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
case data == "add_button":
s.WaitingForButtonText = true
s.PendingButtonType = "invite"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
Введите <b>текст кнопки:</b>
<i>Например:</i>
• Перейти на сайт
• Написать нам`, [][]echotron.InlineKeyboardButton{
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("✓ Ссылка на канал", "button_type_invite"),
bot.Button("Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
@@ -132,16 +139,53 @@ https://t.me/+AbCdEfGhIjKlMn</i>`, [][]echotron.InlineKeyboardButton{
// Отменяем добавление кнопки
if s.WaitingForButtonURL && len(s.Buttons) > 0 {
lastButton := s.Buttons[len(s.Buttons)-1]
if lastButton.URL == "https://example.com" {
if lastButton.URL == "https://example.com" || lastButton.URL == inviteLinkPlaceholder {
s.Buttons = s.Buttons[:len(s.Buttons)-1]
s.UpdateCreativePreview(b)
}
}
s.WaitingForButtonText = false
s.WaitingForButtonURL = false
s.PendingButtonType = ""
s.CurrentButtonText = nil
s.showManagementPanelWithDelete(b)
case data == "button_type_invite":
s.PendingButtonType = "invite"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
Введите <b>текст кнопки:</b>
<i>Например:</i>
• Перейти на сайт
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("✓ Ссылка на канал", "button_type_invite"),
bot.Button("Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
case data == "button_type_custom":
s.PendingButtonType = "custom"
s.ShowControlPanel(b, `<b> Добавить кнопку</b>
Введите <b>текст кнопки:</b>
<i>Например:</i>
• Перейти на сайт
• Написать нам
<i>Ссылка на канал подставится автоматически при создании закупа.</i>`, [][]echotron.InlineKeyboardButton{
bot.Row(
bot.Button("Ссылка на канал", "button_type_invite"),
bot.Button("✓ Своя ссылка", "button_type_custom"),
),
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
case data == "cancel_edit", data == "cancel_media":
s.WaitingForMedia = false
s.showManagementPanelWithDelete(b)
@@ -235,7 +279,6 @@ func (s *CreativeDetails) HandleMessage(b *bot.Bot, u *echotron.Update) {
buttonText := u.Message.Text
s.CurrentButtonText = &buttonText
s.WaitingForButtonText = false
s.WaitingForButtonURL = true
// Удаляем сообщение пользователя
_, err := b.DeleteMessage(b.ChatID, u.Message.ID)
@@ -244,19 +287,28 @@ func (s *CreativeDetails) HandleMessage(b *bot.Bot, u *echotron.Update) {
}
// Создаём кнопку с placeholder URL
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: "https://example.com",
})
s.UpdateCreativePreview(b)
s.ShowControlPanel(b, `<b>✧ Введите URL для кнопки:</b>
if s.PendingButtonType == "custom" {
s.WaitingForButtonURL = true
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: "https://example.com",
})
s.UpdateCreativePreview(b)
s.ShowControlPanel(b, `<b>✧ Введите URL для кнопки:</b>
<i>Например:</i>
<code>https://example.com</code>`, [][]echotron.InlineKeyboardButton{
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
bot.Row(bot.Button("« Отмена", "cancel_add_button")),
})
} else {
s.Buttons = append(s.Buttons, InlineButton{
Text: buttonText,
URL: inviteLinkPlaceholder,
})
s.UpdateCreativePreview(b)
s.PendingButtonType = ""
s.showManagementPanelWithDelete(b)
}
return
}
@@ -289,6 +341,7 @@ URL должен начинаться с <code>http://</code> или <code>https
s.WaitingForButtonURL = false
s.CurrentButtonText = nil
s.PendingButtonType = ""
s.UpdateCreativePreview(b)
s.showManagementPanelWithDelete(b)

View File

@@ -33,6 +33,7 @@ type CreativeEditorFields struct {
WaitingForButtonURL bool
CurrentButtonText *string
WaitingForMedia bool
PendingButtonType string
// ID сообщения с креативом (которое постоянно обновляется)
CreativeMessageID *int
@@ -43,6 +44,9 @@ type CreativeEditorFields struct {
previousHasMedia bool
}
const inviteLinkPlaceholder = "{{invite_link}}"
const inviteLinkPreviewURL = "https://t.me/placeholder"
// GetCreativeText возвращает текст для превью креатива
func (e *CreativeEditorFields) GetCreativeText() string {
var result string
@@ -78,10 +82,14 @@ func (e *CreativeEditorFields) GetCreativeButtons() [][]echotron.InlineKeyboardB
var buttons [][]echotron.InlineKeyboardButton
for _, btn := range e.Buttons {
url := btn.URL
if url == inviteLinkPlaceholder {
url = inviteLinkPreviewURL
}
buttons = append(buttons, []echotron.InlineKeyboardButton{
{
Text: btn.Text,
URL: btn.URL,
URL: url,
},
})
}

View File

@@ -1443,9 +1443,13 @@ func (s *PurchaseOptionalDetails) sendCreativeWithInviteLink(
if len(creative.Buttons) > 0 {
editor.Buttons = make([]InlineButton, 0, len(creative.Buttons))
for _, btn := range creative.Buttons {
url := btn.URL
if url == inviteLinkPlaceholder {
url = inviteLink
}
editor.Buttons = append(editor.Buttons, InlineButton{
Text: btn.Text,
URL: btn.URL,
URL: url,
})
}
}