From d75aa35ac3fd9aac159447b3c95d0df9791e0071 Mon Sep 17 00:00:00 2001 From: far-galaxy Date: Thu, 3 Aug 2023 11:27:36 +0400 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE:=20=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=A2=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5:=20=D1=82?= =?UTF-8?q?=D0=BE=20=D0=B6=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + modules/database/database_struct.go | 9 +- modules/tg/bot.go | 15 +- modules/tg/handlers.go | 377 ++++++++++++++-------------- modules/tg/shedule.go | 339 ------------------------- modules/tg/tg_test.go | 26 +- modules/tg/utils.go | 172 ------------- modules/tg/week_shedule.go | 301 ---------------------- 8 files changed, 220 insertions(+), 1021 deletions(-) delete mode 100644 modules/tg/shedule.go delete mode 100644 modules/tg/utils.go delete mode 100644 modules/tg/week_shedule.go diff --git a/.gitignore b/.gitignore index e715b7e..6875226 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ __pycache__ config.json logs +stuff +shedules *.wpr *test.py *.exe diff --git a/modules/database/database_struct.go b/modules/database/database_struct.go index 7573818..a5550c6 100644 --- a/modules/database/database_struct.go +++ b/modules/database/database_struct.go @@ -6,11 +6,18 @@ type User struct { L9Id int64 `xorm:"pk"` } +type Position string + +const ( + NotStarted Position = "not_started" + Ready Position = "ready" +) + type TgUser struct { L9Id int64 `xorm:"pk"` TgId int64 Name string - PosTag string + PosTag Position } type ShedulesInUser struct { diff --git a/modules/tg/bot.go b/modules/tg/bot.go index 9414b31..c5b771b 100644 --- a/modules/tg/bot.go +++ b/modules/tg/bot.go @@ -13,9 +13,9 @@ import ( ) type Bot struct { - TG *tgbotapi.BotAPI - DB *xorm.Engine - TG_user database.TgUser + TG *tgbotapi.BotAPI + DB *xorm.Engine + // TG_user database.TgUser Week int WkPath string Debug *log.Logger @@ -24,6 +24,7 @@ type Bot struct { var env_keys = []string{ "TELEGRAM_APITOKEN", + "TELEGRAM_TEST_USER", } func CheckEnv() error { @@ -99,7 +100,7 @@ func InitUser(db *xorm.Engine, user *tgbotapi.User) (*database.TgUser, error) { L9Id: l9id, Name: name, TgId: id, - PosTag: "ready", + PosTag: database.NotStarted, } _, err = db.Insert(user, tg_user) if err != nil { @@ -119,6 +120,12 @@ func (bot *Bot) HandleUpdate(update tgbotapi.Update) error { return err } bot.Debug.Printf("Message [%d] <%s> %s", user.L9Id, user.Name, msg.Text) + if user.PosTag == database.NotStarted { + err = bot.Start(user) + if err != nil { + return err + } + } } return nil } diff --git a/modules/tg/handlers.go b/modules/tg/handlers.go index 31c41c1..d856059 100644 --- a/modules/tg/handlers.go +++ b/modules/tg/handlers.go @@ -1,235 +1,230 @@ package tg import ( - "strconv" - "strings" - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database" - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/ssau_parser" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "xorm.io/builder" ) -func (bot *Bot) Start() error { - bot.TG_user.PosTag = "ready" - _, err := bot.DB.Update(bot.TG_user) +func (bot *Bot) Start(user *database.TgUser) error { + user.PosTag = "ready" + _, err := bot.DB.Update(user) if err != nil { return err } msg := tgbotapi.NewMessage( - bot.TG_user.TgId, - `Привет! Я новая версия этого бота и пока тут за главного (: -У меня можно посмотреть в удобном формате ближайшие пары, расписание по дням и даже по неделям! + user.TgId, + `Привет! У меня можно посмотреть в удобном формате ближайшие пары, расписание по дням и даже по неделям! Просто напиши мне номер группы или фамилию преподавателя`) msg.ParseMode = tgbotapi.ModeHTML _, err = bot.TG.Send(msg) return err } -func (bot *Bot) Find(query string) error { - var groups []database.Group - bot.DB.Where(builder.Like{"GroupName", query}).Find(&groups) +/* + func (bot *Bot) Find(query string) error { + var groups []database.Group + bot.DB.Where(builder.Like{"GroupName", query}).Find(&groups) - var teachers []database.Teacher - bot.DB.Where(builder.Like{"LastName", query}).Find(&teachers) + var teachers []database.Teacher + bot.DB.Where(builder.Like{"LastName", query}).Find(&teachers) - list, _ := ssau_parser.SearchInRasp(query) + list, _ := ssau_parser.SearchInRasp(query) - allGroups := groups - allTeachers := teachers + allGroups := groups + allTeachers := teachers - for _, elem := range list { - if strings.Contains(elem.Url, "group") { - exists := false - for _, group := range groups { - if elem.Id == group.GroupId { - exists = true - break + for _, elem := range list { + if strings.Contains(elem.Url, "group") { + exists := false + for _, group := range groups { + if elem.Id == group.GroupId { + exists = true + break + } + } + if !exists { + allGroups = append(allGroups, database.Group{GroupId: elem.Id, GroupName: elem.Text}) } } - if !exists { - allGroups = append(allGroups, database.Group{GroupId: elem.Id, GroupName: elem.Text}) - } - } - if strings.Contains(elem.Url, "staff") { - exists := false - for _, teacher := range teachers { - if elem.Id == teacher.TeacherId { - exists = true - break + if strings.Contains(elem.Url, "staff") { + exists := false + for _, teacher := range teachers { + if elem.Id == teacher.TeacherId { + exists = true + break + } + } + if !exists { + name := strings.Split(elem.Text, " ") + allTeachers = append(allTeachers, database.Teacher{ + TeacherId: elem.Id, + LastName: name[0], + FirstName: name[1], + }) } } - if !exists { - name := strings.Split(elem.Text, " ") - allTeachers = append(allTeachers, database.Teacher{ - TeacherId: elem.Id, - LastName: name[0], - FirstName: name[1], - }) - } } + + if len(allGroups) == 1 || len(allTeachers) == 1 { + if bot.TG_user.PosTag == "add" { + msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Подключено!") + keyboard := tgbotapi.NewReplyKeyboard([]tgbotapi.KeyboardButton{tgbotapi.NewKeyboardButton("Главное меню")}) + msg.ReplyMarkup = keyboard + bot.TG.Send(msg) + } else { + var sheduleId int64 + var isGroup bool + if len(allGroups) == 1 { + sheduleId = allGroups[0].GroupId + isGroup = true + } else { + sheduleId = allTeachers[0].TeacherId + isGroup = false + } + shedule := database.ShedulesInUser{ + IsTeacher: !isGroup, + SheduleId: sheduleId, + } + err := bot.GetSummary([]database.ShedulesInUser{shedule}, false) + if err != nil { + return err + } + } + bot.TG_user.PosTag = "ready" + err := bot.UpdateUserDB() + return err + } else if len(allGroups) != 0 { + if bot.TG_user.PosTag == "add" { + bot.TG_user.PosTag = "confirm_add_group" + } else { + bot.TG_user.PosTag = "confirm_see_group" + } + msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Вот что я нашёл.\nВыбери свою группу") + msg.ReplyMarkup = GenerateKeyboard(GenerateGroupsArray(allGroups), query) + bot.TG.Send(msg) + } else if len(allTeachers) != 0 { + if bot.TG_user.PosTag == "add" { + bot.TG_user.PosTag = "confirm_add_teacher" + } else { + bot.TG_user.PosTag = "confirm_see_teacher" + } + msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Вот что я нашёл.\nВыбери нужного преподавателя") + msg.ReplyMarkup = GenerateKeyboard(GenerateTeachersArray(allTeachers), query) + bot.TG.Send(msg) + } else { + msg := tgbotapi.NewMessage(bot.TG_user.TgId, "К сожалению, я ничего не нашёл ):\nПроверь свой запрос") + bot.TG.Send(msg) + } + + _, err := bot.DB.Update(bot.TG_user) + return err } - if len(allGroups) == 1 || len(allTeachers) == 1 { - if bot.TG_user.PosTag == "add" { + func (bot *Bot) SeeShedule(query *tgbotapi.CallbackQuery) error { + isGroup := bot.TG_user.PosTag == "confirm_see_group" + groupId, err := strconv.ParseInt(query.Data, 0, 64) + if err != nil { + return err + } + shedule := database.ShedulesInUser{ + IsTeacher: !isGroup, + SheduleId: groupId, + } + err = bot.GetSummary([]database.ShedulesInUser{shedule}, false) + if err != nil { + return err + } + bot.TG_user.PosTag = "ready" + err = bot.UpdateUserDB() + return err + } + + func (bot *Bot) HandleSummary(query *tgbotapi.CallbackQuery) error { + data := strings.Split(query.Data, "_") + shedule, dt, err := ParseQuery(data) + if err != nil { + return err + } + if data[1] == "personal" { + switch data[0] { + case "day": + bot.GetPersonalDaySummary(int(dt), *query.Message) + case "week": + bot.GetPersonalWeekSummary(int(dt), *query.Message) + default: + bot.GetPersonalSummary(*query.Message) + } + } else { + switch data[0] { + case "day": + bot.GetDaySummary(shedule, dt, false, *query.Message) + case "week": + bot.GetWeekSummary(shedule, dt, false, *query.Message) + default: + bot.GetSummary(shedule, false, *query.Message) + } + } + return nil + } + + func (bot *Bot) Confirm(query *tgbotapi.CallbackQuery) error { + isGroup := bot.TG_user.PosTag == "confirm_add_group" + groupId, err := strconv.ParseInt(query.Data, 0, 64) + if err != nil { + return err + } + var groups []database.ShedulesInUser + err = bot.DB.Find(&groups, &database.ShedulesInUser{ + L9Id: bot.TG_user.L9Id, + SheduleId: groupId, + IsTeacher: !isGroup, + }) + if err != nil { + return err + } + if len(groups) == 0 { + shInUser := database.ShedulesInUser{ + L9Id: bot.TG_user.L9Id, + IsTeacher: !isGroup, + SheduleId: groupId, + } + bot.DB.InsertOne(shInUser) + bot.DeleteMsg(query) msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Подключено!") keyboard := tgbotapi.NewReplyKeyboard([]tgbotapi.KeyboardButton{tgbotapi.NewKeyboardButton("Главное меню")}) msg.ReplyMarkup = keyboard bot.TG.Send(msg) - } else { - var sheduleId int64 - var isGroup bool - if len(allGroups) == 1 { - sheduleId = allGroups[0].GroupId - isGroup = true - } else { - sheduleId = allTeachers[0].TeacherId - isGroup = false - } - shedule := database.ShedulesInUser{ - IsTeacher: !isGroup, - SheduleId: sheduleId, - } - err := bot.GetSummary([]database.ShedulesInUser{shedule}, false) + + bot.TG_user.PosTag = "ready" + err = bot.UpdateUserDB() if err != nil { return err } + } else { + var msg string + if isGroup { + msg = "Эта группа уже подключена!" + } else { + msg = "Этот преподаватель уже подключен!" + } + callback := tgbotapi.NewCallback(query.ID, msg) + bot.TG.Request(callback) } + return nil + } + + func (bot *Bot) Cancel(query *tgbotapi.CallbackQuery) error { bot.TG_user.PosTag = "ready" err := bot.UpdateUserDB() - return err - } else if len(allGroups) != 0 { - if bot.TG_user.PosTag == "add" { - bot.TG_user.PosTag = "confirm_add_group" - } else { - bot.TG_user.PosTag = "confirm_see_group" - } - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Вот что я нашёл.\nВыбери свою группу") - msg.ReplyMarkup = GenerateKeyboard(GenerateGroupsArray(allGroups), query) - bot.TG.Send(msg) - } else if len(allTeachers) != 0 { - if bot.TG_user.PosTag == "add" { - bot.TG_user.PosTag = "confirm_add_teacher" - } else { - bot.TG_user.PosTag = "confirm_see_teacher" - } - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Вот что я нашёл.\nВыбери нужного преподавателя") - msg.ReplyMarkup = GenerateKeyboard(GenerateTeachersArray(allTeachers), query) - bot.TG.Send(msg) - } else { - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "К сожалению, я ничего не нашёл ):\nПроверь свой запрос") - bot.TG.Send(msg) - } - - _, err := bot.DB.Update(bot.TG_user) - return err -} - -func (bot *Bot) SeeShedule(query *tgbotapi.CallbackQuery) error { - isGroup := bot.TG_user.PosTag == "confirm_see_group" - groupId, err := strconv.ParseInt(query.Data, 0, 64) - if err != nil { - return err - } - shedule := database.ShedulesInUser{ - IsTeacher: !isGroup, - SheduleId: groupId, - } - err = bot.GetSummary([]database.ShedulesInUser{shedule}, false) - if err != nil { - return err - } - bot.TG_user.PosTag = "ready" - err = bot.UpdateUserDB() - return err -} - -func (bot *Bot) HandleSummary(query *tgbotapi.CallbackQuery) error { - data := strings.Split(query.Data, "_") - shedule, dt, err := ParseQuery(data) - if err != nil { - return err - } - if data[1] == "personal" { - switch data[0] { - case "day": - bot.GetPersonalDaySummary(int(dt), *query.Message) - case "week": - bot.GetPersonalWeekSummary(int(dt), *query.Message) - default: - bot.GetPersonalSummary(*query.Message) - } - } else { - switch data[0] { - case "day": - bot.GetDaySummary(shedule, dt, false, *query.Message) - case "week": - bot.GetWeekSummary(shedule, dt, false, *query.Message) - default: - bot.GetSummary(shedule, false, *query.Message) - } - } - return nil -} - -func (bot *Bot) Confirm(query *tgbotapi.CallbackQuery) error { - isGroup := bot.TG_user.PosTag == "confirm_add_group" - groupId, err := strconv.ParseInt(query.Data, 0, 64) - if err != nil { - return err - } - var groups []database.ShedulesInUser - err = bot.DB.Find(&groups, &database.ShedulesInUser{ - L9Id: bot.TG_user.L9Id, - SheduleId: groupId, - IsTeacher: !isGroup, - }) - if err != nil { - return err - } - if len(groups) == 0 { - shInUser := database.ShedulesInUser{ - L9Id: bot.TG_user.L9Id, - IsTeacher: !isGroup, - SheduleId: groupId, - } - bot.DB.InsertOne(shInUser) - bot.DeleteMsg(query) - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Подключено!") - keyboard := tgbotapi.NewReplyKeyboard([]tgbotapi.KeyboardButton{tgbotapi.NewKeyboardButton("Главное меню")}) - msg.ReplyMarkup = keyboard - bot.TG.Send(msg) - - bot.TG_user.PosTag = "ready" - err = bot.UpdateUserDB() if err != nil { return err } - } else { - var msg string - if isGroup { - msg = "Эта группа уже подключена!" - } else { - msg = "Этот преподаватель уже подключен!" - } - callback := tgbotapi.NewCallback(query.ID, msg) - bot.TG.Request(callback) + bot.DeleteMsg(query) + + return nil } - return nil -} - -func (bot *Bot) Cancel(query *tgbotapi.CallbackQuery) error { - bot.TG_user.PosTag = "ready" - err := bot.UpdateUserDB() - if err != nil { - return err - } - bot.DeleteMsg(query) - - return nil -} - -func (bot *Bot) Etc() { - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Oй!") +*/ +func (bot *Bot) Etc(user *database.TgUser) { + msg := tgbotapi.NewMessage(user.TgId, "Oй!") bot.TG.Send(msg) } diff --git a/modules/tg/shedule.go b/modules/tg/shedule.go deleted file mode 100644 index 2c15b68..0000000 --- a/modules/tg/shedule.go +++ /dev/null @@ -1,339 +0,0 @@ -package tg - -import ( - "fmt" - "log" - "strconv" - "strings" - "time" - - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database" - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/ssau_parser" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "xorm.io/xorm" -) - -func (bot *Bot) GetPersonalSummary(msg ...tgbotapi.Message) { - var shedules []database.ShedulesInUser - bot.DB.ID(bot.TG_user.L9Id).Find(&shedules) - - if len(shedules) == 0 { - bot.Etc() - return - } else { - err := bot.GetSummary(shedules, true, msg...) - if err != nil { - log.Fatal(err) - } - } -} - -func (bot *Bot) GetSummary(shedules []database.ShedulesInUser, isPersonal bool, editMsg ...tgbotapi.Message) error { - now := time.Now() //.Add(time.Hour * time.Duration(5) * (-1)) - - lessons, err := bot.GetLessons(shedules, now) - if err != nil { - return err - } - if len(lessons) != 0 { - var firstPair, secondPair []database.Lesson - pairs := GroupPairs(lessons) - firstPair = pairs[0] - log.Println(firstPair, secondPair) - - str := "📝Краткая сводка:\n\n" - if pairs[0][0].Begin.Day() != time.Now().Day() { - str += "❗️Сегодня пар нет\nБлижайшие занятия " - if time.Until(firstPair[0].Begin).Hours() < 48 { - str += "завтра\n" - } else { - str += fmt.Sprintf("%s\n\n", firstPair[0].Begin.Format("02.01")) - } - day, err := bot.GetDayShedule(pairs) - if err != nil { - return err - } - str += day - } else { - if firstPair[0].Begin.Before(now) { - str += "Сейчас:\n\n" - } else { - str += "Ближайшая пара сегодня:\n\n" - } - firstStr, err := PairToStr(firstPair, bot.DB) - if err != nil { - return err - } - str += firstStr - if len(pairs) > 1 { - secondPair = pairs[1] - if firstPair[0].Begin.Day() == secondPair[0].Begin.Day() { - str += "\nПосле неё:\n\n" - secondStr, err := PairToStr(secondPair, bot.DB) - if err != nil { - return err - } - str += secondStr - } else { - str += "\nБольше ничего сегодня нет" - } - } else { - str += "\nБольше ничего сегодня нет" - } - - } - - var shId int64 - if isPersonal { - shId = 0 - } else { - shId = shedules[0].SheduleId - } - - markup := SummaryKeyboard( - "near", - shId, - shedules[0].IsTeacher, - 0, - ) - bot.EditOrSend(str, markup, editMsg...) - - } else { - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Ой! Пар не обнаружено ):") - bot.TG.Send(msg) - } - return nil -} - -func (bot *Bot) GetPersonalDaySummary(dt int, msg ...tgbotapi.Message) { - var shedules []database.ShedulesInUser - bot.DB.ID(bot.TG_user.L9Id).Find(&shedules) - - if len(shedules) == 0 { - bot.Etc() - return - } else { - err := bot.GetDaySummary(shedules, dt, true, msg...) - if err != nil { - log.Fatal(err) - } - } -} - -var ruWeekdays = []string{ - "понедельник", - "вторник", - "среду", - "четверг", - "пятницу", - "субботу", -} - -func (bot *Bot) GetDaySummary(shedules []database.ShedulesInUser, dt int, isPersonal bool, editMsg ...tgbotapi.Message) error { - now := time.Now() - day := time.Date(now.Year(), now.Month(), now.Day()+dt, 0, 0, 0, 0, now.Location()) - lessons, err := bot.GetLessons(shedules, day) - if err != nil { - return err - } - if len(lessons) != 0 { - pairs := GroupPairs(lessons) - var str string - - str = fmt.Sprintf( - "Расписание на %s, %s\n\n", - ruWeekdays[int(pairs[0][0].Begin.Weekday())-1], - pairs[0][0].Begin.Format("02.01"), - ) - day, err := bot.GetDayShedule(pairs) - if err != nil { - return err - } - str += day - - var shId int64 - if isPersonal { - shId = 0 - } else { - shId = shedules[0].SheduleId - } - markup := SummaryKeyboard( - "day", - shId, - shedules[0].IsTeacher, - dt, - ) - bot.EditOrSend(str, markup, editMsg...) - } else { - msg := tgbotapi.NewMessage(bot.TG_user.TgId, "Ой! Пар не обнаружено ):") - bot.TG.Send(msg) - } - - return nil -} - -func (bot *Bot) GetLessons(shedules []database.ShedulesInUser, now time.Time, isRetry ...int) ([]database.Lesson, error) { - - condition := CreateCondition(shedules) - - var lessons []database.Lesson - err := bot.DB. - Where("end > ?", now.Format("2006-01-02 15:04:05")). - And(condition). - OrderBy("begin"). - Limit(16). - Find(&lessons) - - if err != nil { - return nil, err - } - - if len(isRetry) == 0 || isRetry[0] < 2 { - _, week := now.ISOWeek() - isRetry, err = bot.LoadShedule(shedules, week, isRetry...) - if err != nil { - return nil, err - } - dw := isRetry[0] - return bot.GetLessons(shedules, now, dw+1) - } else if len(isRetry) != 0 && len(lessons) != 0 { - return lessons, nil - } else { - return nil, nil - } -} - -func (bot *Bot) LoadShedule(shedules []database.ShedulesInUser, week int, isRetry ...int) ([]int, error) { - if len(isRetry) == 0 { - isRetry = []int{0} - } - dw := isRetry[0] - week -= bot.Week - for _, sh := range shedules { - _, err := ssau_parser.DownloadSheduleById(sh.SheduleId, sh.IsTeacher, week+dw) - if err != nil { - return nil, err - } - /* - shedule, err := ssau_parser.Parse(p) - if err != nil { - return nil, err - } - err = ssau_parser.UploadShedule(bot.DB, *shedule) - if err != nil { - return nil, err - } - */ - } - return isRetry, nil -} - -func CreateCondition(shedules []database.ShedulesInUser) string { - var groups []string - var teachers []string - - for _, sh := range shedules { - if sh.IsTeacher { - teachers = append(teachers, strconv.FormatInt(sh.SheduleId, 10)) - } else { - groups = append(groups, strconv.FormatInt(sh.SheduleId, 10)) - } - } - - var condition, teachers_str, groups_str string - if len(groups) > 0 { - groups_str = strings.Join(groups, ",") - condition = "groupId in (" + groups_str + ") " - } - if len(teachers) > 0 { - if len(condition) > 0 { - condition += " or " - } - teachers_str += strings.Join(teachers, ",") - condition += "teacherId in (" + teachers_str + ") " - } - return condition -} - -func (bot *Bot) GetDayShedule(lessons [][]database.Lesson) (string, error) { - var str string - day := lessons[0][0].Begin.Day() - for _, pair := range lessons { - if pair[0].Begin.Day() == day { - line, err := PairToStr(pair, bot.DB) - if err != nil { - return "", err - } - str += line - } else { - break - } - } - return str, nil -} - -func GroupPairs(lessons []database.Lesson) [][]database.Lesson { - var shedule [][]database.Lesson - var pair []database.Lesson - - l_idx := 0 - - for l_idx < len(lessons) { - day := lessons[l_idx].Begin - for l_idx < len(lessons) && lessons[l_idx].Begin == day { - pair = append(pair, lessons[l_idx]) - l_idx++ - } - shedule = append(shedule, pair) - pair = []database.Lesson{} - } - return shedule -} - -func PairToStr(pair []database.Lesson, db *xorm.Engine) (string, error) { - var str string - beginStr := pair[0].Begin.Format("15:04") - endStr := pair[0].End.Format("15:04") - str = fmt.Sprintf("📆 %s - %s\n", beginStr, endStr) - - for i, sublesson := range pair { - var type_emoji string - switch sublesson.Type { - case "lect": - type_emoji = "📗" - case "pract": - type_emoji = "📕" - case "lab": - type_emoji = "📘" - case "other": - type_emoji = "📙" - default: - type_emoji = "📙" - } - str += fmt.Sprintf("%s%s\n", type_emoji, sublesson.Name) - if sublesson.Place != "" { - str += fmt.Sprintf("🧭 %s\n", sublesson.Place) - } - if sublesson.TeacherId != 0 { - var t database.Teacher - _, err := db.ID(sublesson.TeacherId).Get(&t) - if err != nil { - return "", err - } - name := GenerateName(t) - str += fmt.Sprintf("👤 %s\n", name) - } - if sublesson.SubGroup != 0 { - str += fmt.Sprintf("👥 %d\n", sublesson.SubGroup) - } - if sublesson.Comment != "" { - str += fmt.Sprintf("💬 %s\n", sublesson.Comment) - } - if i != len(pair)-1 { - str += "+\n" - } - } - - str += "------------------------------------------\n" - return str, nil -} diff --git a/modules/tg/tg_test.go b/modules/tg/tg_test.go index 7765501..df4e7ec 100644 --- a/modules/tg/tg_test.go +++ b/modules/tg/tg_test.go @@ -3,6 +3,7 @@ package tg import ( "log" "os" + "strconv" "testing" "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database" @@ -15,6 +16,12 @@ var TestDB = database.DB{ Schema: "testdb", } +var TestUser = tgbotapi.User{ + ID: 12345, + FirstName: "Grzegorz", + LastName: "Brzbrz", +} + func TestCheckEnv(t *testing.T) { if err := CheckEnv(); err != nil { log.Fatal(err) @@ -56,17 +63,12 @@ func TestInitUser(t *testing.T) { bot := initTestBot() // Я новенький - user := tgbotapi.User{ - ID: 12345, - FirstName: "Grzegorz", - LastName: "Brzbrz", - } - _, err := InitUser(bot.DB, &user) + _, err := InitUser(bot.DB, &TestUser) if err != nil { log.Fatal(err) } // Я уже Смешарик - _, err = InitUser(bot.DB, &user) + _, err = InitUser(bot.DB, &TestUser) if err != nil { log.Fatal(err) } @@ -75,14 +77,12 @@ func TestInitUser(t *testing.T) { func TestHandleUpdate(t *testing.T) { bot := initTestBot() + user := TestUser + user.ID, _ = strconv.ParseInt(os.Getenv("TELEGRAM_TEST_USER"), 0, 64) update := tgbotapi.Update{ Message: &tgbotapi.Message{ - From: &tgbotapi.User{ - ID: 12345, - FirstName: "Grzegorz", - LastName: "Brzbrz", - }, - Text: "start", + From: &user, + Text: "/start", }, } err := bot.HandleUpdate(update) diff --git a/modules/tg/utils.go b/modules/tg/utils.go deleted file mode 100644 index 1ac6ead..0000000 --- a/modules/tg/utils.go +++ /dev/null @@ -1,172 +0,0 @@ -package tg - -import ( - "fmt" - "strconv" - "strings" - - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" -) - -func GenerateGroupsArray(groups []database.Group) []tgbotapi.InlineKeyboardButton { - var grKeys []tgbotapi.InlineKeyboardButton - for _, gr := range groups { - grKeys = append(grKeys, tgbotapi.NewInlineKeyboardButtonData(gr.GroupName, strconv.FormatInt(gr.GroupId, 10))) - } - return grKeys -} - -func GenerateName(t database.Teacher) string { - var initials string - for _, n := range strings.Split(t.FirstName, " ") { - initials += fmt.Sprintf("%s.", n[:2]) - } - name := fmt.Sprintf("%s %s", t.LastName, initials) - return name -} - -func GenerateTeachersArray(teachers []database.Teacher) []tgbotapi.InlineKeyboardButton { - var teacherKeys []tgbotapi.InlineKeyboardButton - for _, t := range teachers { - name := GenerateName(t) - teacherKeys = append(teacherKeys, tgbotapi.NewInlineKeyboardButtonData(name, strconv.FormatInt(t.TeacherId, 10))) - } - return teacherKeys -} - -func GenerateKeyboard(array []tgbotapi.InlineKeyboardButton, query string) tgbotapi.InlineKeyboardMarkup { - var keys []tgbotapi.InlineKeyboardButton - var markup [][]tgbotapi.InlineKeyboardButton - - for _, key := range array { - keys = append(keys, key) - if len(keys) >= 3 { - markup = append(markup, keys) - keys = []tgbotapi.InlineKeyboardButton{} - } - } - markup = append(markup, keys) - no_one := tgbotapi.NewInlineKeyboardButtonData("Отмена", "cancel") - markup = append(markup, []tgbotapi.InlineKeyboardButton{no_one}) - return tgbotapi.InlineKeyboardMarkup{InlineKeyboard: markup} -} - -func SummaryKeyboard(clickedButton string, sheduleId int64, isTeacher bool, dt int) tgbotapi.InlineKeyboardMarkup { - tail := GenerateButtonTail(sheduleId, 0, isTeacher) - - near := []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("Краткая сводка", "near"+tail), - } - day := []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("День", "day"+tail), - } - week := []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("Неделя", "week"+tail), - } - - update := GenerateButtonTail(sheduleId, dt, isTeacher) - var arrows []tgbotapi.InlineKeyboardButton - if clickedButton == "day" || clickedButton == "week" { - prev_arrow := GenerateButtonTail(sheduleId, dt-1, isTeacher) - next_arrow := GenerateButtonTail(sheduleId, dt+1, isTeacher) - arrows = []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("⏮", clickedButton+prev_arrow), - tgbotapi.NewInlineKeyboardButtonData("🔄", clickedButton+update), - tgbotapi.NewInlineKeyboardButtonData("⏭", clickedButton+next_arrow), - } - } else { - arrows = []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("🔄", clickedButton+update), - } - } - /*options := []tgbotapi.InlineKeyboardButton{ - tgbotapi.NewInlineKeyboardButtonData("Настройки", "options"), - }*/ - - var markup [][]tgbotapi.InlineKeyboardButton - switch clickedButton { - case "day": - markup = [][]tgbotapi.InlineKeyboardButton{ - arrows, near, week, - } - case "week": - markup = [][]tgbotapi.InlineKeyboardButton{ - arrows, near, day, - } - default: - markup = [][]tgbotapi.InlineKeyboardButton{ - arrows, day, week, - } - } - /*if sheduleId == 0 { - markup = append(markup, options) - }*/ - return tgbotapi.InlineKeyboardMarkup{InlineKeyboard: markup} -} - -func GenerateButtonTail(sheduleId int64, dt int, isTeacher bool) string { - var tail string - if sheduleId == 0 { - tail = fmt.Sprintf("_personal_%d_0", dt) - } else if isTeacher { - tail = fmt.Sprintf("_teacher_%d_%d", dt, sheduleId) - } else { - tail = fmt.Sprintf("_group_%d_%d", dt, sheduleId) - } - return tail -} - -func (bot *Bot) EditOrSend(str string, markup tgbotapi.InlineKeyboardMarkup, editMsg ...tgbotapi.Message) { - if len(editMsg) > 0 { - msg := tgbotapi.NewEditMessageText( - editMsg[0].Chat.ID, - editMsg[0].MessageID, - str, - ) - msg.ReplyMarkup = &markup - bot.TG.Request(msg) - } else { - msg := tgbotapi.NewMessage(bot.TG_user.TgId, str) - msg.ReplyMarkup = markup - bot.TG.Send(msg) - } -} - -func ParseQuery(data []string) ([]database.ShedulesInUser, int, error) { - isGroup := data[1] == "group" - sheduleId, err := strconv.ParseInt(data[3], 0, 64) - if err != nil { - return nil, 0, err - } - shedule := database.ShedulesInUser{ - IsTeacher: !isGroup, - SheduleId: sheduleId, - } - dt, err := strconv.ParseInt(data[2], 0, 0) - if err != nil { - return nil, 0, err - } - return []database.ShedulesInUser{shedule}, int(dt), nil -} - -var SumKey = []string{"near", "day", "week"} - -func KeywordContains(str string, keywords []string) bool { - for _, key := range keywords { - if strings.Contains(str, key) { - return true - } - } - return false -} - -func (bot *Bot) DeleteMsg(query *tgbotapi.CallbackQuery) { - delete := tgbotapi.NewDeleteMessage(query.From.ID, query.Message.MessageID) - bot.TG.Request(delete) -} - -func (bot *Bot) UpdateUserDB() error { - _, err := bot.DB.ID(bot.TG_user.L9Id).Update(bot.TG_user) - return err -} diff --git a/modules/tg/week_shedule.go b/modules/tg/week_shedule.go deleted file mode 100644 index f2a252c..0000000 --- a/modules/tg/week_shedule.go +++ /dev/null @@ -1,301 +0,0 @@ -package tg - -import ( - "fmt" - "log" - "math" - "os" - "sort" - "strings" - "time" - - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database" - "git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/ssau_parser" - wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "github.com/icza/gox/timex" -) - -func (bot *Bot) GetWeekLessons(shedules []database.ShedulesInUser, week int, isRetry ...int) ([]database.Lesson, error) { - condition := CreateCondition(shedules) - - var lessons []database.Lesson - err := bot.DB. - Where("WEEK(`begin`, 1) = ?", week+bot.Week). - And(condition). - OrderBy("begin"). - Find(&lessons) - - if err != nil { - return nil, err - } - if len(isRetry) == 0 || isRetry[0] < 2 { - isRetry, err = bot.LoadShedule(shedules, week+bot.Week, isRetry...) - if err != nil { - return nil, err - } - dw := isRetry[0] - return bot.GetWeekLessons(shedules, week, dw+1) - } else if len(isRetry) != 0 && len(lessons) != 0 { - return lessons, nil - } else { - return nil, nil - } -} - -var days = [6]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} - -func (bot *Bot) GetPersonalWeekSummary(dt int, msg ...tgbotapi.Message) { - var shedules []database.ShedulesInUser - bot.DB.ID(bot.TG_user.L9Id).Find(&shedules) - - if len(shedules) == 0 { - bot.Etc() - return - } else { - err := bot.GetWeekSummary(shedules, dt, true, msg...) - if err != nil { - log.Fatal(err) - } - } -} - -func (bot *Bot) GetWeekSummary(shedules []database.ShedulesInUser, dw int, isPersonal bool, editMsg ...tgbotapi.Message) error { - _, week := time.Now().ISOWeek() - week += dw - lessons, err := bot.GetWeekLessons(shedules, week-bot.Week) - if err != nil { - log.Fatal(err) - } - - var dates []time.Time - begins := make(map[time.Time]bool) - ends := make(map[time.Time]bool) - height := 0 - minDay := lessons[0].NumInShedule - for _, lesson := range lessons { - t := lesson.Begin - begin := time.Date(2000, 1, 1, t.Hour(), t.Minute(), 0, 0, t.Location()) - begins[begin] = true - - e := lesson.End - end := time.Date(2000, 1, 1, e.Hour(), e.Minute(), 0, 0, e.Location()) - ends[end] = true - - if lesson.NumInShedule > height { - height = lesson.NumInShedule - } else if lesson.NumInShedule < minDay { - minDay = lesson.NumInShedule - } - } - var times []ssau_parser.Pair - var beginsSlice []time.Time - var endsSlice []time.Time - for b := range begins { - beginsSlice = append(beginsSlice, b) - } - for e := range ends { - endsSlice = append(endsSlice, e) - } - sort.Slice(beginsSlice, func(i, j int) bool { - return beginsSlice[i].Before(beginsSlice[j]) - }) - sort.Slice(endsSlice, func(i, j int) bool { - return endsSlice[i].Before(endsSlice[j]) - }) - for i, b := range beginsSlice { - sh := ssau_parser.Pair{ - Begin: b, - End: endsSlice[i], - } - times = append(times, sh) - } - - weekBegin := timex.WeekStart(lessons[0].Begin.Year(), week) - for i := range days { - dates = append(dates, weekBegin.Add(time.Hour*time.Duration(24*i))) - } - - shedule := make([][6][]database.Lesson, height-minDay+1) - pairs := GroupPairs(lessons) - - for _, p := range pairs { - day := int(math.Floor(p[0].Begin.Sub(weekBegin).Hours() / 24)) - shedule[p[0].NumInShedule-minDay][day] = p - } - - html := bot.CreateHTMLShedule(week, shedule, dates, times) - - if _, err := os.Stat("shedules"); os.IsNotExist(err) { - err = os.Mkdir("shedules", os.ModePerm) - if err != nil { - return err - } - } - - fname := fmt.Sprintf("./shedules/%d_%d.html", bot.TG_user.L9Id, week-bot.Week) - f, _ := os.Create(fname) - defer f.Close() - f.WriteString(html) - - wkhtml.SetPath(bot.WkPath) - pdfg, err := wkhtml.NewPDFGenerator() - if err != nil { - return err - } - pdfg.Dpi.Set(300) - pdfg.MarginBottom.Set(0) - pdfg.MarginTop.Set(0) - pdfg.MarginLeft.Set(0) - pdfg.MarginRight.Set(0) - pdfg.Orientation.Set(wkhtml.OrientationLandscape) - pdfg.PageSize.Set(wkhtml.PageSizeA4) - pdfg.AddPage(wkhtml.NewPageReader(strings.NewReader(html))) - - err = pdfg.Create() - if err != nil { - return err - } - - fname = fmt.Sprintf("./shedules/%d_%d.pdf", bot.TG_user.L9Id, week-bot.Week) - err = pdfg.WriteFile(fname) - if err != nil { - return err - } - - photoBytes, err := os.ReadFile(fname) - if err != nil { - return err - } - fname = fmt.Sprintf("Расписание %d неделя.pdf", week-bot.Week) - photoFileBytes := tgbotapi.FileBytes{ - Name: fname, - Bytes: photoBytes, - } - - msg := tgbotapi.NewDocument(bot.TG_user.TgId, photoFileBytes) - _, err = bot.TG.Send(msg) - if err != nil { - return err - } - var shId int64 - if isPersonal { - shId = 0 - } else { - shId = shedules[0].SheduleId - } - markup := SummaryKeyboard( - "week", - shId, - shedules[0].IsTeacher, - dw, - ) - _, nowWeek := time.Now().ISOWeek() - var str string - if week == nowWeek { - str = fmt.Sprintf("Расписание на текущую (%d) неделю сообщением ниже 👇", week-bot.Week) - } else if week-nowWeek == 1 { - str = fmt.Sprintf("Расписание на следующую (%d) неделю сообщением ниже 👇", week-bot.Week) - } else { - str = fmt.Sprintf("Расписание на %d неделю сообщением ниже 👇", week-bot.Week) - } - bot.EditOrSend(str, markup, editMsg...) - return nil -} - -const head = ` - - -Тестовая страница с расписанием - - - - - - - -` -const lessonHead = ` -

-

%s


` - -var weekdays = [6]string{ - "пн", - "вт", - "ср", - "чт", - "пт", - "сб", -} - -func (bot *Bot) CreateHTMLShedule(week int, shedule [][6][]database.Lesson, dates []time.Time, times []ssau_parser.Pair) string { - html := head - html += fmt.Sprintf("
%d неделя
\n", week-bot.Week) - html += "\n\n" - - for i, d := range dates { - day := d.Format("02") - html += fmt.Sprintf("", weekdays[i], day) - } - html += "\n" - for t, tline := range shedule { - begin := times[t].Begin.Format("15:04") - end := times[t].End.Format("15:04") - html += fmt.Sprintf("\n", begin, end) - for i, l := range tline { - - if len(l) > 0 { - html += fmt.Sprintf(lessonHead, l[0].Type, l[0].Name) - if l[0].TeacherId != 0 { - var t database.Teacher - bot.DB.ID(l[0].TeacherId).Get(&t) - name := GenerateName(t) - html += fmt.Sprintf("
%s
\n", name) - } - if l[0].Place != "" { - html += fmt.Sprintf("

%s

\n", l[0].Place) - } - if l[0].SubGroup != 0 { - html += fmt.Sprintf("

%d

\n", l[0].SubGroup) - } - if l[0].Comment != "" { - html += fmt.Sprintf("

%s

\n", l[0].Comment) - } - - if len(l) == 2 { - html += "
\n" - if l[0].Name != l[1].Name { - html += fmt.Sprintf("

\n

%s


", l[1].Name) - } - if l[1].TeacherId != 0 { - var t database.Teacher - bot.DB.ID(l[1].TeacherId).Get(&t) - name := GenerateName(t) - html += fmt.Sprintf("
%s
\n", name) - } - if l[1].Place != "" { - html += fmt.Sprintf("

%s

\n", l[1].Place) - } - if l[1].SubGroup != 0 { - html += fmt.Sprintf("

%d

\n", l[1].SubGroup) - } - if l[1].Comment != "" { - html += fmt.Sprintf("

%s

\n", l[1].Comment) - } - } - - html += "\n" - - } else { - html += "\n" - } - if i%7 == 6 { - html += "\n" - } - } - } - html += "
Время%s

%s

%s
%s
" - return html -}