From 54cc9372afb9fee8ea22c4e09449c676490d71ad Mon Sep 17 00:00:00 2001 From: Grendgi Date: Fri, 5 Jun 2026 10:40:42 +0300 Subject: [PATCH] Resolve monitoring PF bot deep links --- internal/pf/http.go | 12 +++++++--- internal/pf/telegram.go | 52 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/internal/pf/http.go b/internal/pf/http.go index 052d117..9a16131 100644 --- a/internal/pf/http.go +++ b/internal/pf/http.go @@ -66,9 +66,15 @@ func (s Server) accessMe(w http.ResponseWriter, r *http.Request) { writeError(w, http.StatusInternalServerError, err.Error()) return } + botUsername := s.App.Cfg.TGBotUsername + if botUsername == "" { + if resolved, err := s.App.TG.BotUsername(r.Context()); err == nil { + botUsername = resolved + } + } var link *string - if s.App.Cfg.TGBotUsername != "" && portalID != "" { - v := "https://t.me/" + s.App.Cfg.TGBotUsername + "?start=" + portalID + if botUsername != "" && portalID != "" { + v := "https://t.me/" + botUsername + "?start=" + portalID link = &v } var command *string @@ -81,7 +87,7 @@ func (s Server) accessMe(w http.ResponseWriter, r *http.Request) { "portal_user_id": nullablePlain(portalID), "telegram_linked": emp != nil && emp.TGChatID != nil && *emp.TGChatID != "", "employee": emp, - "telegram_bot_username": nullablePlain(s.App.Cfg.TGBotUsername), + "telegram_bot_username": nullablePlain(botUsername), "telegram_start_command": command, "telegram_start_link": link, }) diff --git a/internal/pf/telegram.go b/internal/pf/telegram.go index 4e3f2b6..104123e 100644 --- a/internal/pf/telegram.go +++ b/internal/pf/telegram.go @@ -9,12 +9,15 @@ import ( "net/http" "net/url" "strings" + "sync" "time" ) type Telegram struct { - token string - client *http.Client + token string + client *http.Client + mu sync.Mutex + username string } type tgResponse[T any] struct { @@ -46,6 +49,11 @@ type TGUser struct { LastName string `json:"last_name"` } +type TGBotUser struct { + ID int64 `json:"id"` + Username string `json:"username"` +} + func NewTelegram(token string) *Telegram { return &Telegram{token: token, client: &http.Client{Timeout: 35 * time.Second}} } @@ -54,6 +62,46 @@ func (t *Telegram) Enabled() bool { return strings.TrimSpace(t.token) != "" } +func (t *Telegram) BotUsername(ctx context.Context) (string, error) { + if !t.Enabled() { + return "", nil + } + t.mu.Lock() + if t.username != "" { + username := t.username + t.mu.Unlock() + return username, nil + } + t.mu.Unlock() + + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, t.apiURL("getMe"), nil) + if err != nil { + return "", err + } + resp, err := t.client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + var out tgResponse[TGBotUser] + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + return "", err + } + if !out.OK { + return "", errors.New(out.Description) + } + username := strings.TrimPrefix(strings.TrimSpace(out.Result.Username), "@") + if username == "" { + return "", nil + } + t.mu.Lock() + t.username = username + t.mu.Unlock() + return username, nil +} + func (t *Telegram) SendMessage(ctx context.Context, chatID string, text string) error { if !t.Enabled() { return nil