192 lines
5.5 KiB
Go
192 lines
5.5 KiB
Go
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))
|
||
}
|