422 lines
10 KiB
Go
422 lines
10 KiB
Go
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"
|
||
td "github.com/mergestat/timediff"
|
||
"xorm.io/xorm"
|
||
)
|
||
|
||
func (bot *Bot) GetPersonal(now time.Time, user *database.TgUser, editMsg ...tgbotapi.Message) (tgbotapi.Message, error) {
|
||
var shedules []database.ShedulesInUser
|
||
bot.DB.Where("l9id = ?", user.L9Id).Find(&shedules)
|
||
|
||
if len(shedules) == 0 {
|
||
user.PosTag = database.Add
|
||
if _, err := bot.DB.ID(user.L9Id).Update(user); err != nil {
|
||
return tgbotapi.Message{}, err
|
||
}
|
||
|
||
msg := tgbotapi.NewMessage(
|
||
user.TgId,
|
||
"У тебя пока никакого расписания не подключено\n"+
|
||
"Введи <b>номер группы</b>",
|
||
)
|
||
msg.ReplyMarkup = tgbotapi.ReplyKeyboardRemove{RemoveKeyboard: true}
|
||
msg.ParseMode = tgbotapi.ModeHTML
|
||
return bot.TG.Send(msg)
|
||
} else {
|
||
return bot.GetSummary(now, user, shedules, true, editMsg...)
|
||
}
|
||
}
|
||
|
||
// Получить краткую сводку
|
||
func (bot *Bot) GetSummary(
|
||
now time.Time,
|
||
user *database.TgUser,
|
||
shedules []database.ShedulesInUser,
|
||
isPersonal bool,
|
||
editMsg ...tgbotapi.Message,
|
||
) (
|
||
tgbotapi.Message,
|
||
error,
|
||
) {
|
||
|
||
nilMsg := tgbotapi.Message{}
|
||
lessons, err := bot.GetLessons(shedules, now)
|
||
if err != nil {
|
||
return nilMsg, 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() != now.Day() {
|
||
str += "❗️Сегодня пар нет\nБлижайшие занятия "
|
||
str += td.TimeDiff(
|
||
firstPair[0].Begin,
|
||
td.WithLocale("ru_RU"),
|
||
td.WithStartTime(now),
|
||
)
|
||
if firstPair[0].Begin.Sub(now).Hours() > 36 {
|
||
str += fmt.Sprintf(
|
||
", <b>%d %s</b>",
|
||
firstPair[0].Begin.Day(),
|
||
Month[firstPair[0].Begin.Month()-1],
|
||
)
|
||
}
|
||
str += "\n\n"
|
||
day, err := bot.StrDayShedule(pairs, shedules[0].IsGroup)
|
||
if err != nil {
|
||
return nilMsg, err
|
||
}
|
||
str += day
|
||
} else {
|
||
if firstPair[0].Begin.Before(now) {
|
||
str += "Сейчас:\n\n"
|
||
} else {
|
||
dt := td.TimeDiff(
|
||
firstPair[0].Begin,
|
||
td.WithLocale("ru_RU"),
|
||
td.WithStartTime(now),
|
||
)
|
||
str += fmt.Sprintf("Ближайшая пара %s:\n\n", dt)
|
||
}
|
||
firstStr, err := PairToStr(firstPair, bot.DB, shedules[0].IsGroup)
|
||
if err != nil {
|
||
return nilMsg, 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, shedules[0].IsGroup)
|
||
if err != nil {
|
||
return nilMsg, err
|
||
}
|
||
str += secondStr
|
||
} else {
|
||
str += "\nБольше ничего сегодня нет"
|
||
}
|
||
} else {
|
||
str += "\nБольше ничего сегодня нет"
|
||
}
|
||
|
||
}
|
||
|
||
var shId int64
|
||
if isPersonal {
|
||
shId = 0
|
||
} else {
|
||
shId = shedules[0].SheduleId
|
||
}
|
||
|
||
markup := SummaryKeyboard(
|
||
// TODO: создать тип таких префиксов
|
||
"sh_near",
|
||
shId,
|
||
shedules[0].IsGroup,
|
||
0,
|
||
)
|
||
return bot.EditOrSend(user.TgId, str, "", markup, editMsg...)
|
||
|
||
} else {
|
||
return bot.EditOrSend(
|
||
user.TgId,
|
||
"Ой! Занятий не обнаружено ):",
|
||
"",
|
||
tgbotapi.InlineKeyboardMarkup{},
|
||
editMsg...)
|
||
}
|
||
}
|
||
|
||
// ПОлучить расписание на день
|
||
func (bot *Bot) GetDaySummary(
|
||
now time.Time,
|
||
user *database.TgUser,
|
||
shedules []database.ShedulesInUser,
|
||
dt int,
|
||
isPersonal bool,
|
||
editMsg ...tgbotapi.Message,
|
||
) (
|
||
tgbotapi.Message,
|
||
error,
|
||
) {
|
||
nilMsg := tgbotapi.Message{}
|
||
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 nilMsg, err
|
||
}
|
||
if len(lessons) != 0 {
|
||
pairs := GroupPairs(lessons)
|
||
var str string
|
||
firstPair := pairs[0][0].Begin
|
||
dayStr := DayStr(day)
|
||
|
||
var shId int64
|
||
if isPersonal {
|
||
shId = 0
|
||
} else {
|
||
shId = shedules[0].SheduleId
|
||
}
|
||
markup := SummaryKeyboard(
|
||
"sh_day",
|
||
shId,
|
||
shedules[0].IsGroup,
|
||
dt,
|
||
)
|
||
|
||
if firstPair.Day() != day.Day() {
|
||
str = fmt.Sprintf("В %s, занятий нет", dayStr)
|
||
return bot.EditOrSend(user.TgId, str, "", markup, editMsg...)
|
||
}
|
||
str = fmt.Sprintf("Расписание на %s\n\n", dayStr)
|
||
|
||
// TODO: придумать скачки для пустых дней
|
||
//dt += int(firstPair.Sub(day).Hours()) / 24
|
||
day, err := bot.StrDayShedule(pairs, shedules[0].IsGroup)
|
||
if err != nil {
|
||
return nilMsg, err
|
||
}
|
||
str += day
|
||
return bot.EditOrSend(user.TgId, str, "", markup, editMsg...)
|
||
} else {
|
||
msg := tgbotapi.NewMessage(user.TgId, "Ой! Пар не обнаружено ):")
|
||
return bot.TG.Send(msg)
|
||
}
|
||
|
||
}
|
||
|
||
// Строка даты формата "среду, 1 января"
|
||
func DayStr(day time.Time) string {
|
||
dayStr := fmt.Sprintf(
|
||
"%s, <b>%d %s</b>",
|
||
weekdays[int(day.Weekday())],
|
||
day.Day(),
|
||
Month[day.Month()-1],
|
||
)
|
||
return dayStr
|
||
}
|
||
|
||
// Получить список ближайших занятий (для краткой сводки или расписания на день)
|
||
func (bot *Bot) GetLessons(shedules []database.ShedulesInUser, now time.Time) ([]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(32).
|
||
Find(&lessons)
|
||
|
||
return lessons, err
|
||
}
|
||
|
||
// Загрузка расписания из ssau.ru/rasp
|
||
func (bot *Bot) LoadShedule(shedule ssau_parser.WeekShedule, now time.Time) (
|
||
[]database.Lesson,
|
||
[]database.Lesson,
|
||
error,
|
||
) {
|
||
sh := ssau_parser.WeekShedule{
|
||
SheduleId: shedule.SheduleId,
|
||
IsGroup: shedule.IsGroup,
|
||
}
|
||
var add, del []database.Lesson
|
||
for week := 1; week < 21; week++ {
|
||
sh.Week = week
|
||
if err := sh.DownloadById(true); err != nil {
|
||
if strings.Contains(err.Error(), "404") {
|
||
break
|
||
}
|
||
return nil, nil, err
|
||
}
|
||
a, d, err := ssau_parser.UpdateSchedule(bot.DB, sh)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
add = append(add, a...)
|
||
del = append(del, d...)
|
||
}
|
||
// Обновляем время обновления
|
||
if len(add) > 0 || len(del) > 0 {
|
||
if sh.IsGroup {
|
||
gr := database.Group{GroupId: sh.SheduleId}
|
||
if _, err := bot.DB.Get(&gr); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
gr.LastUpd = now
|
||
if _, err := bot.DB.ID(gr.GroupId).Update(gr); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
} else {
|
||
t := database.Teacher{TeacherId: sh.SheduleId}
|
||
if _, err := bot.DB.Get(&t); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
t.LastUpd = now
|
||
if _, err := bot.DB.ID(t.TeacherId).Update(t); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
}
|
||
}
|
||
return add, del, nil
|
||
}
|
||
|
||
// Создать условие поиска группы/преподавателя
|
||
func CreateCondition(shedules []database.ShedulesInUser) string {
|
||
var groups []string
|
||
var teachers []string
|
||
|
||
for _, sh := range shedules {
|
||
if !sh.IsGroup {
|
||
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 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
|
||
}
|
||
|
||
var Icons = map[string]string{
|
||
"lect": "📗 Лекция ",
|
||
"pract": "📕 Практика ",
|
||
"lab": "📘 Лаба ",
|
||
"other": "📙 Прочее ",
|
||
"mil": "🫡",
|
||
"window": "🏝",
|
||
"exam": "💀 Экзамен",
|
||
"cons": "🗨 Консультация",
|
||
"kurs": "🤯 Курсовая",
|
||
}
|
||
|
||
// Конвертация занятий с текст
|
||
func PairToStr(pair []database.Lesson, db *xorm.Engine, isGroup bool) (string, error) {
|
||
var str string
|
||
beginStr := pair[0].Begin.Format("15:04")
|
||
var endStr string
|
||
if pair[0].Type == "mil" {
|
||
endStr = "∞"
|
||
} else {
|
||
endStr = pair[0].End.Format("15:04")
|
||
}
|
||
str = fmt.Sprintf("📆 %s - %s\n", beginStr, endStr)
|
||
|
||
var groups []database.Lesson
|
||
if !isGroup {
|
||
groups = pair[:]
|
||
pair = pair[:1]
|
||
}
|
||
|
||
for i, sublesson := range pair {
|
||
type_emoji := Icons[sublesson.Type]
|
||
str += fmt.Sprintf("%s%s\n", type_emoji, sublesson.Name)
|
||
if sublesson.Place != "" {
|
||
str += fmt.Sprintf("🧭 %s\n", sublesson.Place)
|
||
}
|
||
if !isGroup {
|
||
break
|
||
}
|
||
if sublesson.TeacherId != 0 {
|
||
var t database.Teacher
|
||
_, err := db.ID(sublesson.TeacherId).Get(&t)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
str += fmt.Sprintf("👤 %s %s\n", t.FirstName, t.ShortName)
|
||
}
|
||
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"
|
||
}
|
||
}
|
||
|
||
if !isGroup {
|
||
for _, gr := range groups {
|
||
var t database.Group
|
||
_, err := db.ID(gr.GroupId).Get(&t)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
str += fmt.Sprintf("👥 %s\n", t.GroupName)
|
||
if gr.SubGroup != 0 {
|
||
str += fmt.Sprintf("👥 Подгруппа: %d\n", gr.SubGroup)
|
||
}
|
||
}
|
||
if pair[0].Comment != "" {
|
||
str += fmt.Sprintf("💬 %s\n", pair[0].Comment)
|
||
}
|
||
}
|
||
|
||
str += "------------------------------------------\n"
|
||
return str, nil
|
||
}
|
||
|
||
// Текст расписания на день
|
||
func (bot *Bot) StrDayShedule(lessons [][]database.Lesson, isGroup bool) (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, isGroup)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
str += line
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
return str, nil
|
||
}
|