106 lines
3.3 KiB
Go
106 lines
3.3 KiB
Go
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"regexp"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// mattermostSend отправляет сообщение в Mattermost через Bot API.
|
||
// HTML-теги из Telegram автоматически конвертируются в Markdown.
|
||
// Если бот не настроен — пишет в лог и не паникует.
|
||
func mattermostSend(message string) error {
|
||
if !isMattermostConfigured() {
|
||
log.Printf("[Mattermost] Не настроен (нужны MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID) — пропускаем")
|
||
return fmt.Errorf("mattermost не настроен")
|
||
}
|
||
|
||
mdMessage := mmHTMLToMarkdown(message)
|
||
|
||
type mmPost struct {
|
||
ChannelID string `json:"channel_id"`
|
||
Message string `json:"message"`
|
||
}
|
||
|
||
payload := mmPost{
|
||
ChannelID: cfgMattermostChannelID,
|
||
Message: mdMessage,
|
||
}
|
||
|
||
jsonData, err := json.Marshal(payload)
|
||
if err != nil {
|
||
return fmt.Errorf("marshal error: %w", err)
|
||
}
|
||
|
||
apiURL := fmt.Sprintf("%s/api/v4/posts", strings.TrimRight(cfgMattermostURL, "/"))
|
||
|
||
log.Printf("[Mattermost] Отправка: %s (channel: %s)", apiURL, cfgMattermostChannelID)
|
||
|
||
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
|
||
if err != nil {
|
||
return fmt.Errorf("ошибка создания запроса: %w", err)
|
||
}
|
||
req.Header.Set("Content-Type", "application/json")
|
||
req.Header.Set("Authorization", "Bearer "+cfgMattermostBotToken)
|
||
|
||
client := &http.Client{Timeout: 15 * time.Second}
|
||
resp, err := client.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("ошибка отправки в Mattermost (%s): %w", apiURL, err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusCreated {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("mattermost api error: status %d, body: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// mmHTMLToMarkdown конвертирует HTML-теги Telegram в Markdown для Mattermost.
|
||
//
|
||
// <b>текст</b> → **текст**
|
||
// <i>текст</i> → _текст_
|
||
// <code>текст</code> → `текст`
|
||
// <pre>текст</pre> → ```текст```
|
||
// ━━━ (разделители) → ---
|
||
// Остальные теги → удаляются
|
||
func mmHTMLToMarkdown(html string) string {
|
||
s := html
|
||
|
||
// <b>...</b> → **...**
|
||
s = regexp.MustCompile(`<b>([\s\S]*?)</b>`).ReplaceAllString(s, "**$1**")
|
||
|
||
// <i>...</i> → _..._
|
||
s = regexp.MustCompile(`<i>([\s\S]*?)</i>`).ReplaceAllString(s, "_$1_")
|
||
|
||
// <code>...</code> → `...`
|
||
s = regexp.MustCompile(`<code>([\s\S]*?)</code>`).ReplaceAllString(s, "`$1`")
|
||
|
||
// <pre>...</pre> → ```...```
|
||
s = regexp.MustCompile(`<pre>([\s\S]*?)</pre>`).ReplaceAllString(s, "```$1```")
|
||
|
||
// HTML-entities
|
||
s = strings.ReplaceAll(s, "<", "<")
|
||
s = strings.ReplaceAll(s, ">", ">")
|
||
s = strings.ReplaceAll(s, "&", "&")
|
||
s = strings.ReplaceAll(s, """, `"`)
|
||
|
||
// Горизонтальные разделители (━━━...) → ---
|
||
s = regexp.MustCompile(`━+`).ReplaceAllString(s, "---")
|
||
|
||
// Убираем оставшиеся HTML-теги
|
||
s = regexp.MustCompile(`<[^>]+>`).ReplaceAllString(s, "")
|
||
|
||
// Убираем лишние пустые строки (более двух подряд)
|
||
s = regexp.MustCompile(`\n{3,}`).ReplaceAllString(s, "\n\n")
|
||
|
||
return strings.TrimSpace(s)
|
||
}
|