Files
monitoring-pf/cmd/bot/main.go
Grendgi d53ecb2add
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 37s
CI / go (push) Successful in 43s
CI / python (push) Successful in 2s
Fix monitoring PF CI lint issues
2026-06-09 11:33:33 +03:00

192 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"log/slog"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
"monitoring-pf/internal/pf"
)
func main() {
cfg := pf.LoadConfig()
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
app, err := pf.OpenApp(ctx, cfg)
if err != nil {
slog.Error("db_open_failed", "error", err)
os.Exit(1)
}
defer func() {
if err := app.Close(); err != nil {
slog.Warn("app_close_failed", "error", err)
}
}()
if !app.TG.Enabled() {
slog.Error("telegram_token_missing")
os.Exit(1)
}
slog.Info("monitoring_pf_go_bot_started")
var offset int64
for ctx.Err() == nil {
updates, err := app.TG.GetUpdates(ctx, offset)
if err != nil {
slog.Warn("telegram_get_updates_failed", "error", err)
time.Sleep(3 * time.Second)
continue
}
for _, update := range updates {
offset = update.UpdateID + 1
if update.Message != nil {
handleMessage(ctx, app, update.Message)
}
}
}
}
func handleMessage(ctx context.Context, app *pf.App, msg *pf.TGMessage) {
text := strings.TrimSpace(msg.Text)
if text == "" || !strings.HasPrefix(text, "/") {
return
}
command, arg := splitCommand(text)
switch command {
case "/start":
handleStart(ctx, app, msg, arg)
case "/whoami":
handleWhoami(ctx, app, msg)
case "/list":
handleList(ctx, app, msg)
case "/check":
handleCheck(ctx, app, msg)
}
}
func splitCommand(text string) (string, string) {
parts := strings.Fields(text)
if len(parts) == 0 {
return "", ""
}
command := strings.Split(parts[0], "@")[0]
arg := ""
if len(parts) > 1 {
arg = parts[1]
}
return command, arg
}
func handleStart(ctx context.Context, app *pf.App, msg *pf.TGMessage, portalUserID string) {
chatID := strconv.FormatInt(msg.Chat.ID, 10)
user := msg.From
username := ""
name := "user_" + chatID
if user != nil {
username = user.Username
name = user.FullName()
}
if portalUserID == "" {
_ = app.TG.SendMessage(ctx, chatID,
"Откройте Portal → Мониторинг PF и нажмите подключение Telegram.\n"+
"Бот должен получить команду вида:\n<code>/start ваш_код_из_Portal</code>")
return
}
emp, err := app.LinkTelegram(ctx, portalUserID, chatID, username, name)
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Не удалось подключить Telegram: "+err.Error())
return
}
_ = app.TG.SendMessage(ctx, chatID,
fmt.Sprintf("✅ Привет, <b>%s</b>! Telegram подключен к вашему аккаунту Portal.\nТеперь можно добавлять объекты мониторинга в Portal.", emp.Name))
}
func handleWhoami(ctx context.Context, app *pf.App, msg *pf.TGMessage) {
chatID := strconv.FormatInt(msg.Chat.ID, 10)
emp, err := app.EmployeeByChatID(ctx, chatID)
if errors.Is(err, sql.ErrNoRows) {
_ = app.TG.SendMessage(ctx, chatID, "Вы пока не подключены. Откройте Portal → Мониторинг PF и запустите подключение.\nchat_id: <code>"+chatID+"</code>")
return
}
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Ошибка: "+err.Error())
return
}
_ = app.TG.SendMessage(ctx, chatID, fmt.Sprintf("Вы: <b>%s</b>\nchat_id: <code>%s</code>", emp.Name, chatID))
}
func handleList(ctx context.Context, app *pf.App, msg *pf.TGMessage) {
chatID := strconv.FormatInt(msg.Chat.ID, 10)
emp, err := app.EmployeeByChatID(ctx, chatID)
if errors.Is(err, sql.ErrNoRows) {
_ = app.TG.SendMessage(ctx, chatID, "Сначала подключитесь через Portal → Мониторинг PF.")
return
}
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Ошибка: "+err.Error())
return
}
projects, err := app.ListProjects(ctx, emp.ID)
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Ошибка: "+err.Error())
return
}
if len(projects) == 0 {
_ = app.TG.SendMessage(ctx, chatID, "У вас пока нет проектов.")
return
}
lines := []string{fmt.Sprintf("<b>Ваши проекты (%d):</b>", len(projects))}
for _, p := range projects {
permit := "—"
if p.DLDPermit != nil {
permit = *p.DLDPermit
}
lines = append(lines, fmt.Sprintf("• #%d %s — <code>%s</code> (%s)", p.ID, p.Title, permit, p.DealType))
}
_ = app.TG.SendMessage(ctx, chatID, strings.Join(lines, "\n"))
}
func handleCheck(ctx context.Context, app *pf.App, msg *pf.TGMessage) {
chatID := strconv.FormatInt(msg.Chat.ID, 10)
emp, err := app.EmployeeByChatID(ctx, chatID)
if errors.Is(err, sql.ErrNoRows) {
_ = app.TG.SendMessage(ctx, chatID, "Сначала подключитесь через Portal → Мониторинг PF.")
return
}
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Ошибка: "+err.Error())
return
}
projects, err := app.ListProjects(ctx, emp.ID)
if err != nil {
_ = app.TG.SendMessage(ctx, chatID, "Ошибка: "+err.Error())
return
}
if len(projects) == 0 {
_ = app.TG.SendMessage(ctx, chatID, "У вас нет проектов.")
return
}
_ = app.TG.SendMessage(ctx, chatID, fmt.Sprintf("⏳ Запускаю проверку %d проектов…", len(projects)))
total := 0
for _, p := range projects {
changes, err := app.Worker.CheckProject(ctx, p.ID)
if err != nil {
slog.Warn("check_project_failed", "project_id", p.ID, "error", err)
continue
}
total += changes
}
_ = app.TG.SendMessage(ctx, chatID, fmt.Sprintf("✅ Готово. Изменений: %d", total))
}