156 lines
3.9 KiB
Go
156 lines
3.9 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
|
||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||
)
|
||
|
||
type Task struct {
|
||
ID string `json:"id"`
|
||
Content string `json:"content"`
|
||
Due *struct {
|
||
Date string `json:"date"`
|
||
} `json:"due"`
|
||
}
|
||
|
||
var (
|
||
todoistToken = os.Getenv("TODOIST_TOKEN")
|
||
telegramToken = os.Getenv("TELEGRAM_TOKEN")
|
||
chatID = os.Getenv("CHAT_ID")
|
||
bot *tgbotapi.BotAPI
|
||
overdueTasks = map[string]bool{}
|
||
)
|
||
|
||
func getOverdueTasks() []Task {
|
||
log.Println("[INFO] Запрашиваю задачи из Todoist...")
|
||
req, _ := http.NewRequest("GET", "https://api.todoist.com/rest/v2/tasks", nil)
|
||
req.Header.Set("Authorization", "Bearer "+todoistToken)
|
||
|
||
resp, err := http.DefaultClient.Do(req)
|
||
if err != nil {
|
||
log.Println("Ошибка запроса Todoist:", err)
|
||
return nil
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
var tasks []Task
|
||
if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil {
|
||
log.Println("Ошибка парсинга задач:", err)
|
||
return nil
|
||
}
|
||
|
||
now := time.Now().Format("2006-01-02T15:04")
|
||
var overdue []Task
|
||
for _, task := range tasks {
|
||
if task.Due != nil && strings.Compare(task.Due.Date, now) < 0 {
|
||
overdue = append(overdue, task)
|
||
}
|
||
}
|
||
return overdue
|
||
}
|
||
|
||
func closeTask(taskID string) {
|
||
url := fmt.Sprintf("https://api.todoist.com/rest/v2/tasks/%s/close", taskID)
|
||
req, _ := http.NewRequest("POST", url, nil)
|
||
req.Header.Set("Authorization", "Bearer "+todoistToken)
|
||
http.DefaultClient.Do(req)
|
||
}
|
||
|
||
func getRandomReminderMessage(task Task) string {
|
||
reminderMessages := []string{
|
||
"⏰ Ну что, сделал уже?! Задача: %s",
|
||
"⏰ Эй, не забыл про задачу? %s",
|
||
"⏰ Напоминаю о задаче: %s",
|
||
"⏰ Задача все еще ждет выполнения: %s",
|
||
"⏰ Пора бы уже сделать: %s",
|
||
}
|
||
|
||
randomIndex := time.Now().UnixNano() % int64(len(reminderMessages))
|
||
return fmt.Sprintf(reminderMessages[randomIndex], task.Content)
|
||
}
|
||
|
||
func isQuietHours() bool {
|
||
// Get current time in CET timezone
|
||
cet, err := time.LoadLocation("Europe/Paris") // Paris is in CET
|
||
if err != nil {
|
||
log.Println("Ошибка загрузки таймзоны:", err)
|
||
return false // If we can't determine the time, assume it's not quiet hours
|
||
}
|
||
|
||
now := time.Now().In(cet)
|
||
hour := now.Hour()
|
||
|
||
// Quiet hours are from 23:00 to 08:00
|
||
return hour >= 23 || hour < 8
|
||
}
|
||
|
||
func spamCheck() {
|
||
// Don't send messages during quiet hours
|
||
if isQuietHours() {
|
||
log.Println("[INFO] Тихий час (23:00-08:00 CET). Уведомления отключены.")
|
||
return
|
||
}
|
||
|
||
tasks := getOverdueTasks()
|
||
for _, task := range tasks {
|
||
if !overdueTasks[task.ID] {
|
||
msg := tgbotapi.NewMessage(toInt64(chatID), fmt.Sprintf("🔥 Просрочено: %s", task.Content))
|
||
button := tgbotapi.NewInlineKeyboardMarkup(
|
||
tgbotapi.NewInlineKeyboardRow(
|
||
tgbotapi.NewInlineKeyboardButtonData("✅ Сделал", task.ID),
|
||
),
|
||
)
|
||
msg.ReplyMarkup = button
|
||
bot.Send(msg)
|
||
overdueTasks[task.ID] = true
|
||
} else {
|
||
reminderMessage := getRandomReminderMessage(task)
|
||
bot.Send(tgbotapi.NewMessage(toInt64(chatID), reminderMessage))
|
||
}
|
||
}
|
||
}
|
||
|
||
func toInt64(s string) int64 {
|
||
var n int64
|
||
fmt.Sscan(s, &n)
|
||
return n
|
||
}
|
||
|
||
func main() {
|
||
var err error
|
||
bot, err = tgbotapi.NewBotAPI(telegramToken)
|
||
if err != nil {
|
||
log.Fatal("Ошибка запуска бота:", err)
|
||
}
|
||
|
||
log.Println("[INFO] Бот запущен")
|
||
|
||
u := tgbotapi.NewUpdate(0)
|
||
u.Timeout = 60
|
||
updates := bot.GetUpdatesChan(u)
|
||
|
||
ticker := time.NewTicker(1 * time.Hour)
|
||
go func() {
|
||
spamCheck()
|
||
for range ticker.C {
|
||
spamCheck()
|
||
}
|
||
}()
|
||
|
||
for update := range updates {
|
||
if update.CallbackQuery != nil {
|
||
taskID := update.CallbackQuery.Data
|
||
closeTask(taskID)
|
||
bot.Send(tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, "✅ Задача закрыта!"))
|
||
delete(overdueTasks, taskID)
|
||
}
|
||
}
|
||
}
|