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/shedule.go

422 lines
10 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"
"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
}