This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
l9_stud_bot/modules/tg/bot.go

302 lines
7.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package tg
import (
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
"time"
"git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/joho/godotenv"
"xorm.io/xorm"
)
type Bot struct {
TG *tgbotapi.BotAPI
DB *xorm.Engine
TestUser int64
HelpTxt string
Week int
WkPath string
Debug *log.Logger
Updates *tgbotapi.UpdatesChannel
}
var env_keys = []string{
"TELEGRAM_APITOKEN",
"TELEGRAM_TEST_USER",
"WK_PATH",
"MYSQL_USER",
"MYSQL_PASS",
"MYSQL_DB",
"START_WEEK",
}
func CheckEnv() error {
if err := godotenv.Load(); err != nil {
log.Print("No .env file found")
}
for _, key := range env_keys {
if _, exists := os.LookupEnv(key); !exists {
return fmt.Errorf("lost env key: %s", key)
}
}
return nil
}
// Полная инициализация бота со стороны Telegram и БД
func InitBot(files database.LogFiles, db database.DB, token string) (*Bot, error) {
var bot Bot
engine, err := database.Connect(db, files.DBLogFile)
if err != nil {
return nil, err
}
//defer engine.Close()
bot.DB = engine
bot.TG, err = tgbotapi.NewBotAPI(token)
if err != nil {
return nil, err
}
bot.TG.Debug = true
//logger := log.New(io.MultiWriter(os.Stdout, database.CreateLog("tg")), "", log.LstdFlags)
logger := log.New(files.TgLogFile, "", log.LstdFlags)
err = tgbotapi.SetLogger(logger)
if err != nil {
return nil, err
}
bot.GetUpdates()
log.Printf("Authorized on account %s", bot.TG.Self.UserName)
bot.Debug = log.New(io.MultiWriter(os.Stderr, files.DebugFile), "", log.LstdFlags)
return &bot, nil
}
func (bot *Bot) GetUpdates() {
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates := bot.TG.GetUpdatesChan(u)
bot.Updates = &updates
}
// Получение данных о пользователе из БД и создание нового при необходимости
func InitUser(db *xorm.Engine, user *tgbotapi.User) (*database.TgUser, error) {
id := user.ID
name := user.FirstName + " " + user.LastName
var users []database.TgUser
err := db.Find(&users, &database.TgUser{TgId: id})
if err != nil {
return nil, err
}
var tg_user database.TgUser
if len(users) == 0 {
l9id, err := database.GenerateID(db)
if err != nil {
return nil, err
}
user := database.User{
L9Id: l9id,
}
tg_user = database.TgUser{
L9Id: l9id,
Name: name,
TgId: id,
PosTag: database.NotStarted,
}
_, err = db.Insert(user, tg_user)
if err != nil {
return nil, err
}
} else {
tg_user = users[0]
}
return &tg_user, nil
}
func (bot *Bot) HandleUpdate(update tgbotapi.Update, now ...time.Time) (tgbotapi.Message, error) {
nilMsg := tgbotapi.Message{}
if update.Message != nil {
msg := update.Message
user, err := InitUser(bot.DB, msg.From)
if err != nil {
return nilMsg, err
}
bot.Debug.Printf("Message [%d] <%s> %s", user.L9Id, user.Name, msg.Text)
if strings.Contains(msg.Text, "/help") {
msg := tgbotapi.NewMessage(user.TgId, bot.HelpTxt)
return bot.TG.Send(msg)
}
switch user.PosTag {
case database.NotStarted:
err = bot.Start(user)
case database.Ready:
if len(now) == 0 {
now = append(now, msg.Time())
}
if msg.Text == "Моё расписание" {
return bot.GetPersonal(now[0], user)
} else if msg.Text == "Настройки" {
return bot.GetOptions(user)
} else if strings.Contains(msg.Text, "/keyboard") {
options := database.ShedulesInUser{
L9Id: user.L9Id,
}
if _, err := bot.DB.Get(&options); err != nil {
return nilMsg, err
}
msg := tgbotapi.NewMessage(user.TgId, "Клавиатура выдана")
msg.ReplyMarkup = GeneralKeyboard(options.UID != 0)
return bot.TG.Send(msg)
} else if strings.Contains(msg.Text, "/scream") && user.TgId == bot.TestUser {
var users []database.TgUser
if err := bot.DB.Where("tgid > 0").Find(&users); err != nil {
return nilMsg, err
}
msg := tgbotapi.NewMessage(
0,
strings.TrimPrefix(msg.Text, "/scream"),
)
for _, u := range users {
msg.ChatID = u.TgId
if _, err := bot.TG.Send(msg); err != nil {
if !strings.Contains(err.Error(), "blocked by user") {
bot.Debug.Println(err)
}
}
}
msg.ChatID = bot.TestUser
msg.Text = "Сообщения отправлены"
return bot.TG.Send(msg)
}
return bot.Find(now[0], user, msg.Text)
case database.Add:
return bot.Find(now[0], user, msg.Text)
case database.Set:
return bot.SetFirstTime(msg, user)
case database.Delete:
return bot.DeleteGroup(user, msg.Text)
default:
return bot.Etc(user)
}
if err != nil {
return nilMsg, err
}
}
if update.CallbackQuery != nil {
query := update.CallbackQuery
user, err := InitUser(bot.DB, query.From)
if err != nil {
return nilMsg, err
}
bot.Debug.Printf("Callback [%d] <%s> %s", user.L9Id, user.Name, query.Data)
if query.Data == "cancel" {
return nilMsg, bot.Cancel(user, query)
}
if user.PosTag == database.NotStarted {
err = bot.Start(user)
} else if user.PosTag == database.Ready || user.PosTag == database.Add {
if strings.Contains(query.Data, "sh") {
err = bot.HandleSummary(user, query, now...)
} else if strings.Contains(query.Data, "opt") {
err = bot.HandleOptions(user, query)
} else {
err = bot.GetShedule(user, query, now...)
}
} else {
return bot.Etc(user)
}
if err != nil {
return nilMsg, err
}
/*if query.ID != "" {
callback := tgbotapi.NewCallback(query.ID, query.Data)
_, err = bot.TG.Request(callback)
if err != nil {
return nilMsg, err
}
}*/
}
return nilMsg, nil
}
func (bot *Bot) DeleteGroup(user *database.TgUser, text string) (tgbotapi.Message, error) {
nilMsg := tgbotapi.Message{}
user.PosTag = database.Ready
if _, err := bot.DB.ID(user.L9Id).Update(user); err != nil {
return nilMsg, err
}
var msg tgbotapi.MessageConfig
if strings.ToLower(text) == "да" {
userInfo := database.ShedulesInUser{
L9Id: user.L9Id,
}
if _, err := bot.DB.Delete(&userInfo); err != nil {
return nilMsg, err
}
files := database.File{
TgId: user.L9Id,
IsPersonal: true,
}
if _, err := bot.DB.UseBool("IsPersonal").Delete(&files); err != nil {
return nilMsg, err
}
msg = tgbotapi.NewMessage(user.TgId, "Группа отключена")
msg.ReplyMarkup = GeneralKeyboard(false)
} else {
msg = tgbotapi.NewMessage(user.TgId, "Действие отменено")
}
return bot.TG.Send(msg)
}
func (bot *Bot) SetFirstTime(msg *tgbotapi.Message, user *database.TgUser) (tgbotapi.Message, error) {
nilMsg := tgbotapi.Message{}
t, err := strconv.Atoi(msg.Text)
if err != nil {
msg := tgbotapi.NewMessage(
user.TgId,
"Ой, время соообщения о начале занятий введено как-то неверно ):",
)
return bot.TG.Send(msg)
}
userInfo := database.ShedulesInUser{
L9Id: user.L9Id,
}
if _, err := bot.DB.Get(&userInfo); err != nil {
return nilMsg, err
}
if t <= 10 {
msg := tgbotapi.NewMessage(
user.TgId,
"Ой, установлено слишком малое время. Попробуй ввести большее время",
)
return bot.TG.Send(msg)
} else if t > 240 {
msg := tgbotapi.NewMessage(
user.TgId,
"Ой, установлено слишком большое время. Попробуй ввести меньшее время",
)
return bot.TG.Send(msg)
}
userInfo.FirstTime = t / 5 * 5
if _, err := bot.DB.ID(userInfo.UID).Update(userInfo); err != nil {
return nilMsg, err
}
user.PosTag = database.Ready
if _, err := bot.DB.ID(user.L9Id).Update(user); err != nil {
return nilMsg, err
}
return bot.GetOptions(user)
}