Files
pulse-api/internal/scheduler/scheduler.go

196 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package scheduler
import (
"fmt"
"log"
"time"
"github.com/robfig/cron/v3"
"github.com/daniil/homelab-api/internal/bot"
"github.com/daniil/homelab-api/internal/model"
"github.com/daniil/homelab-api/internal/repository"
)
type Scheduler struct {
cron *cron.Cron
bot *bot.Bot
userRepo *repository.UserRepository
taskRepo *repository.TaskRepository
habitRepo *repository.HabitRepository
}
func New(b *bot.Bot, userRepo *repository.UserRepository, taskRepo *repository.TaskRepository, habitRepo *repository.HabitRepository) *Scheduler {
return &Scheduler{
cron: cron.New(),
bot: b,
userRepo: userRepo,
taskRepo: taskRepo,
habitRepo: habitRepo,
}
}
func (s *Scheduler) Start() {
if s.bot == nil || s.bot.GetAPI() == nil {
log.Println("Scheduler: bot not configured, skipping")
return
}
// Run every minute
s.cron.AddFunc("* * * * *", s.checkNotifications)
s.cron.Start()
log.Println("Scheduler started")
}
func (s *Scheduler) Stop() {
s.cron.Stop()
}
func (s *Scheduler) checkNotifications() {
users, err := s.userRepo.GetUsersWithNotifications()
if err != nil {
log.Printf("Scheduler: error getting users: %v", err)
return
}
for _, user := range users {
go s.checkUserNotifications(user)
}
}
func (s *Scheduler) checkUserNotifications(user model.User) {
if !user.TelegramChatID.Valid {
return
}
chatID := user.TelegramChatID.Int64
// Get user timezone
loc, err := time.LoadLocation(user.Timezone)
if err != nil {
loc = time.FixedZone("Europe/Moscow", 3*60*60)
}
now := time.Now().In(loc)
currentTime := now.Format("15:04")
today := now.Format("2006-01-02")
weekday := int(now.Weekday())
// 1. Morning briefing at 09:00
if currentTime == "09:00" {
s.sendMorningBriefing(user.ID, chatID, loc)
}
// 2. Task reminders
s.checkTaskReminders(user.ID, chatID, currentTime, today)
// 3. Habit reminders
s.checkHabitReminders(user.ID, chatID, currentTime, weekday)
}
func (s *Scheduler) sendMorningBriefing(userID, chatID int64, loc *time.Location) {
tasks, err := s.taskRepo.GetTodayTasks(userID)
if err != nil {
log.Printf("Scheduler: error getting tasks for user %d: %v", userID, err)
return
}
habits, err := s.habitRepo.ListByUser(userID, false)
if err != nil {
log.Printf("Scheduler: error getting habits for user %d: %v", userID, err)
return
}
// Filter habits for today
weekday := int(time.Now().In(loc).Weekday())
var todayHabits int
for _, habit := range habits {
if habit.Frequency == "daily" {
todayHabits++
} else {
for _, day := range habit.TargetDays {
if day == weekday {
todayHabits++
break
}
}
}
}
if len(tasks) == 0 && todayHabits == 0 {
return // Nothing to report
}
text := "☀️ <b>Доброе утро!</b>\n\n"
if len(tasks) > 0 {
text += fmt.Sprintf("📋 Задач на сегодня: <b>%d</b>\n", len(tasks))
for i, task := range tasks {
if i >= 3 {
text += fmt.Sprintf(" ... и ещё %d\n", len(tasks)-3)
break
}
text += fmt.Sprintf(" • %s %s\n", task.Icon, task.Title)
}
text += "\n"
}
if todayHabits > 0 {
text += fmt.Sprintf("🎯 Привычек: <b>%d</b>\n", todayHabits)
}
text += "\n/tasks — посмотреть задачи\n/habits — посмотреть привычки"
s.bot.SendMessage(chatID, text)
}
func (s *Scheduler) checkTaskReminders(userID, chatID int64, currentTime, today string) {
tasks, err := s.taskRepo.GetTasksWithReminder(currentTime, today)
if err != nil {
log.Printf("Scheduler: error getting task reminders: %v", err)
return
}
for _, task := range tasks {
if task.UserID != userID {
continue
}
text := fmt.Sprintf("⏰ <b>Напоминание о задаче:</b>\n\n%s <b>%s</b>", task.Icon, task.Title)
if task.Description != "" {
text += fmt.Sprintf("\n<i>%s</i>", task.Description)
}
text += fmt.Sprintf("\n\n/done_%d — отметить выполненной", task.ID)
s.bot.SendMessage(chatID, text)
}
}
func (s *Scheduler) checkHabitReminders(userID, chatID int64, currentTime string, weekday int) {
habits, err := s.habitRepo.GetHabitsWithReminder(currentTime, weekday)
if err != nil {
log.Printf("Scheduler: error getting habit reminders: %v", err)
return
}
for _, habit := range habits {
if habit.UserID != userID {
continue
}
// Check if already completed today
completed, _ := s.habitRepo.IsHabitCompletedToday(habit.ID, userID)
if completed {
continue
}
text := fmt.Sprintf("⏰ <b>Напоминание о привычке:</b>\n\n%s <b>%s</b>", habit.Icon, habit.Name)
if habit.Description != "" {
text += fmt.Sprintf("\n<i>%s</i>", habit.Description)
}
text += fmt.Sprintf("\n\n/check_%d — отметить выполненной", habit.ID)
s.bot.SendMessage(chatID, text)
}
}