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

328 lines
8.7 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 notify
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"
"git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/tg"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"golang.org/x/exp/slices"
"xorm.io/xorm"
)
type Next struct {
Lesson []database.Lesson
Day []database.Lesson
Week []database.Lesson
}
type NotifyType string
const (
NextLesson NotifyType = "nextnote"
NextDay NotifyType = "nextday"
NextWeek NotifyType = "nextweek"
Changes NotifyType = "changes"
Military NotifyType = "mil"
)
type Notify struct {
NotifyType
IsGroup bool
SheduleId int64
Lesson database.Lesson
}
// Поиск следующей пары, дня, недели
func CheckNext(db *xorm.Engine, now time.Time) ([]Notify, error) {
now = now.Truncate(time.Minute)
var completed []database.Lesson
if err := db.
Find(&completed, &database.Lesson{End: now}); err != nil {
return nil, err
}
var nums []int
for i := range completed {
new_num := completed[i].NumInShedule + 1
if !slices.Contains(nums, new_num) {
nums = append(nums, new_num)
}
}
var next []database.Lesson
if err := db.
Where("date(`begin`) = ?", now.Format("2006-01-02")).
In("numinshedule", nums).
Find(&next); err != nil {
return nil, err
}
var notify []Notify
for _, n := range next {
notify = append(notify, Notify{
NotifyType: NextLesson,
IsGroup: true,
SheduleId: n.GroupId,
Lesson: n,
})
if n.TeacherId != 0 {
notify = append(notify, Notify{
NotifyType: NextLesson,
IsGroup: false,
SheduleId: n.TeacherId,
Lesson: n,
})
}
}
// Отсеиваем последние пары дня
last := ssau_parser.Diff(completed, next)
for _, l := range last {
var next_lesson database.Lesson
if _, err := db.
Where(
"groupid = ? and begin > ?",
l.GroupId, l.Begin.Format("2006-01-02 15:04:05"),
).
Asc("begin").
Get(&next_lesson); err != nil {
return nil, err
}
// Разделяем, какие пары на этой неделе, какие на следующей
_, nl_week := next_lesson.Begin.ISOWeek()
_, now_week := now.ISOWeek()
note := Notify{
IsGroup: true,
SheduleId: next_lesson.GroupId,
Lesson: next_lesson,
}
if nl_week == now_week {
note.NotifyType = NextDay
} else {
note.NotifyType = NextWeek
}
if !slices.Contains(notify, note) {
notify = append(notify, note)
}
}
return notify, nil
}
// Текст уведомления о следующей паре
func StrNext(db *xorm.Engine, note Notify) (string, error) {
// TODO: перескакивать окна
// Подкачиваем группы и подгруппы
var pair []database.Lesson
if !note.IsGroup {
query := database.Lesson{
Begin: note.Lesson.Begin,
TeacherId: note.SheduleId,
}
if err := db.Find(&pair, query); err != nil {
return "", err
}
} else {
pair = append(pair, note.Lesson)
}
str := "Следующая пара:\n\n"
strPair, err := tg.PairToStr(pair, db, note.IsGroup)
if err != nil {
return "", err
}
str += strPair
return str, nil
}
// Текст уведомления о следующем дне
func StrNextDay(bot *tg.Bot, note Notify) (string, error) {
begin := note.Lesson.Begin
day := time.Date(begin.Year(), begin.Month(), begin.Day(), 0, 0, 0, 0, begin.Location())
shedules := []database.ShedulesInUser{
{
IsGroup: true,
SheduleId: note.Lesson.GroupId,
},
}
lessons, err := bot.GetLessons(shedules, day)
if err != nil {
return "", err
}
if len(lessons) != 0 {
pairs := tg.GroupPairs(lessons)
dayStr, err := bot.StrDayShedule(pairs, shedules[0].IsGroup)
if err != nil {
return "", err
}
str := "Сегодня больше ничего нет\n"
str += "Следующие занятия в " + tg.DayStr(day) + ":\n\n" + dayStr
return str, nil
}
return "", nil
}
// Рассылка всех уведомлений
func Mailing(bot *tg.Bot, notes []Notify, now time.Time) {
var ids []int64
for _, note := range notes {
var users []database.TgUser
query := database.ShedulesInUser{
IsGroup: note.IsGroup,
SheduleId: note.SheduleId,
}
var txt string
var err error
var tempTime time.Time
switch note.NotifyType {
case NextLesson:
query.NextNote = true
txt, err = StrNext(bot.DB, note)
tempTime = note.Lesson.Begin.Add(15 * time.Minute)
case NextDay:
query.NextDay = true
txt, err = StrNextDay(bot, note)
// TODO: установить время удаления на момент сообщения о начале пар
tempTime = note.Lesson.Begin.Add(-60 * time.Minute)
case NextWeek:
query.NextWeek = true
}
if err != nil {
log.Println(err)
}
// TODO: проработать разные подгруппы
/*var condition string
if note.Lesson.SubGroup == 0 {
condition = "subgroup in (?, 1, 2)"
} else {
condition = "subgroup in (0, ?)"
}*/
if err := bot.DB.
UseBool(string(note.NotifyType)).
Table("ShedulesInUser").
Cols("tgid").
Join("INNER", "TgUser", "TgUser.l9id = ShedulesInUser.l9id").
// Where(condition, note.Lesson.SubGroup).
Find(&users, &query); err != nil {
log.Println(err)
}
for _, user := range users {
if !slices.Contains(ids, user.TgId) {
if note.NotifyType != NextWeek {
msg := tgbotapi.NewMessage(user.TgId, txt)
msg.ParseMode = tgbotapi.ModeHTML
m, err := bot.TG.Send(msg)
if err != nil {
// Удаление пользователя, заблокировавшего бота
if !strings.Contains(err.Error(), "blocked by user") {
bot.DB.Delete(&user)
bot.DB.Delete(&database.ShedulesInUser{L9Id: user.L9Id})
bot.DB.Delete(&database.User{L9Id: user.L9Id})
continue
} else {
log.Println(err)
}
} else {
AddTemp(m, tempTime, bot)
}
} else {
if err = bot.GetWeekSummary(
note.Lesson.Begin,
&user,
database.ShedulesInUser{},
0,
true,
"На этой неделе больше ничего нет\n\nНа фото расписание на следующую неделю",
); err != nil {
log.Println(err)
continue
}
}
ids = append(ids, user.TgId)
}
}
}
}
// Добавить сообщение в список временных
func AddTemp(m tgbotapi.Message, tempTime time.Time, bot *tg.Bot) {
temp := database.TempMsg{
TgId: m.Chat.ID,
MessageId: m.MessageID,
Destroy: tempTime,
}
if _, err := bot.DB.InsertOne(temp); err != nil {
log.Println(err)
}
}
// Удаление временных сообщений
func ClearTemp(bot *tg.Bot, now time.Time) {
var temp []database.TempMsg
if err := bot.DB.Where("destroy <= ?", now.Format("2006-01-02 15:04:05")).Find(&temp); err != nil {
log.Println(err)
}
for _, msg := range temp {
del := tgbotapi.NewDeleteMessage(msg.TgId, msg.MessageId)
if _, err := bot.TG.Request(del); err != nil {
log.Println(err)
}
if _, err := bot.DB.Delete(&msg); err != nil {
log.Println(err)
}
}
}
var firstMailQuery = `SELECT t.tgId, l.lessonId, u.firsttime
FROM ShedulesInUser u
JOIN (SELECT lessonid, groupid, type, min(begin) as begin FROM Lesson WHERE date(begin) = date('%s') GROUP BY groupid) l
ON '%s' = DATE_SUB(l.Begin, INTERVAL u.firsttime MINUTE) AND u.sheduleid = l.groupid
JOIN TgUser t ON u.L9ID = t.L9ID
WHERE u.first = true AND (l.type != "mil" OR (l.type = "mil" AND u.military = true));`
// Рассылка сообщений о начале занятий
func FirstMailing(bot *tg.Bot, now time.Time) {
now = now.Truncate(time.Minute)
nowStr := now.Format("2006-01-02 15:04:05")
res, err := bot.DB.Query(fmt.Sprintf(firstMailQuery, nowStr, nowStr))
if err != nil {
log.Println(err)
}
for _, r := range res {
lid, _ := strconv.ParseInt(string(r["lessonId"]), 0, 64)
lesson := database.Lesson{LessonId: lid}
if _, err := bot.DB.Get(&lesson); err != nil {
log.Println(err)
}
var str string
if now.Hour() > 16 {
str = "Добрый вечер 🌆\n"
} else if now.Hour() > 11 {
str = "Добрый день 🌞\n"
} else {
str = "Доброе утро 🌅\n"
}
str += fmt.Sprintf("Через %s минут начнутся занятия\n\nПервая пара:\n", r["firsttime"])
pair, err := tg.PairToStr([]database.Lesson{lesson}, bot.DB, true)
if err != nil {
log.Println(err)
}
str += pair
user, _ := strconv.ParseInt(string(r["tgId"]), 0, 64)
mail := tgbotapi.NewMessage(user, str)
msg, err := bot.TG.Send(mail)
if err != nil {
log.Println(err)
continue
}
AddTemp(msg, lesson.Begin.Add(15*time.Minute), bot)
}
}