
✨ Features: - 🤖 Telegram bot for task management between programmer and girlfriend - 📝 Task creation with types (personal/shared) and priorities - ⏰ Time-based reminders and notifications - 📊 Statistics and progress tracking - 🤝 Shared tasks for couples 🛠 Tech Stack: - Backend: NestJS + TypeScript - Database: PostgreSQL + TypeORM - Bot: Telegraf - Deployment: Docker + Docker Compose 🐳 Docker Deployment: - Multi-stage Dockerfile for optimized builds - Docker Compose with environment variables - Health checks and automatic restarts - Production-ready configuration 📦 Files included: - Complete NestJS application - Docker deployment configuration - Environment variables setup - Deployment scripts and documentation - Health monitoring and logging
130 lines
4.7 KiB
TypeScript
130 lines
4.7 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
||
import { Cron, CronExpression } from '@nestjs/schedule';
|
||
import { TaskService } from './task.service';
|
||
import { TelegramBotService } from './telegram-bot.service';
|
||
|
||
@Injectable()
|
||
export class ReminderService {
|
||
private readonly logger = new Logger(ReminderService.name);
|
||
|
||
constructor(
|
||
private taskService: TaskService,
|
||
private telegramBotService: TelegramBotService,
|
||
) {}
|
||
|
||
// Проверяем напоминания каждую минуту
|
||
@Cron(CronExpression.EVERY_MINUTE)
|
||
async checkReminders() {
|
||
try {
|
||
const tasks = await this.taskService.findTasksWithReminders();
|
||
|
||
for (const task of tasks) {
|
||
if (task.shouldSendReminder()) {
|
||
this.logger.log(`Отправляю напоминание для задачи: ${task.title} (ID: ${task.id})`);
|
||
await this.telegramBotService.sendReminder(task);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
this.logger.error('Ошибка при проверке напоминаний:', error);
|
||
}
|
||
}
|
||
|
||
// Ежедневное уведомление о задачах на сегодня (в 9:00)
|
||
@Cron('0 9 * * *')
|
||
async sendDailyTasksSummary() {
|
||
try {
|
||
this.logger.log('Отправляю ежедневную сводку задач');
|
||
|
||
const todayTasks = await this.taskService.findTasksDueToday();
|
||
const overdueTasks = await this.taskService.findOverdueTasks();
|
||
|
||
if (todayTasks.length === 0 && overdueTasks.length === 0) {
|
||
return;
|
||
}
|
||
|
||
// Группируем задачи по пользователям
|
||
const userTasks = new Map<string, { today: any[], overdue: any[] }>();
|
||
|
||
for (const task of todayTasks) {
|
||
if (task.assignedTo) {
|
||
const userId = task.assignedTo.telegramId;
|
||
if (!userTasks.has(userId)) {
|
||
userTasks.set(userId, { today: [], overdue: [] });
|
||
}
|
||
userTasks.get(userId)!.today.push(task);
|
||
}
|
||
}
|
||
|
||
for (const task of overdueTasks) {
|
||
if (task.assignedTo) {
|
||
const userId = task.assignedTo.telegramId;
|
||
if (!userTasks.has(userId)) {
|
||
userTasks.set(userId, { today: [], overdue: [] });
|
||
}
|
||
userTasks.get(userId)!.overdue.push(task);
|
||
}
|
||
}
|
||
|
||
// Отправляем сводку каждому пользователю
|
||
for (const [telegramId, tasks] of userTasks) {
|
||
let message = '🌅 *Доброе утро! Сводка задач на сегодня:*\n\n';
|
||
|
||
if (tasks.today.length > 0) {
|
||
message += `📅 *Задачи на сегодня (${tasks.today.length}):*\n`;
|
||
for (const task of tasks.today) {
|
||
message += `${task.getStatusEmoji()} ${task.title} (ID: ${task.id})\n`;
|
||
}
|
||
message += '\n';
|
||
}
|
||
|
||
if (tasks.overdue.length > 0) {
|
||
message += `⚠️ *Просроченные задачи (${tasks.overdue.length}):*\n`;
|
||
for (const task of tasks.overdue) {
|
||
message += `${task.getStatusEmoji()} ${task.title} (ID: ${task.id})\n`;
|
||
}
|
||
message += '\n';
|
||
}
|
||
|
||
message += 'Хорошего дня! 💪';
|
||
|
||
await this.telegramBotService['sendNotification'](telegramId, message);
|
||
}
|
||
} catch (error) {
|
||
this.logger.error('Ошибка при отправке ежедневной сводки:', error);
|
||
}
|
||
}
|
||
|
||
// Еженедельная сводка (по воскресеньям в 20:00)
|
||
@Cron('0 20 * * 0')
|
||
async sendWeeklySummary() {
|
||
try {
|
||
this.logger.log('Отправляю еженедельную сводку');
|
||
|
||
// Получаем всех активных пользователей
|
||
const users = await this.taskService['userService'].getAllUsers();
|
||
|
||
for (const user of users) {
|
||
const stats = await this.taskService.getTaskStats(user.id);
|
||
|
||
const message = `
|
||
📊 *Еженедельная сводка для ${user.getFullName()} ${user.getRoleEmoji()}*
|
||
|
||
📈 *Статистика за неделю:*
|
||
📝 Всего задач: ${stats.total}
|
||
✅ Завершено: ${stats.completed}
|
||
⏳ В работе: ${stats.pending + stats.inProgress}
|
||
❌ Отменено: ${stats.cancelled}
|
||
|
||
👤 Личных: ${stats.personal}
|
||
🤝 Общих: ${stats.shared}
|
||
|
||
${stats.completed > 0 ? '🎉 Отличная работа!' : '💪 Давай активнее на следующей неделе!'}
|
||
`;
|
||
|
||
await this.telegramBotService['sendNotification'](user.telegramId, message);
|
||
}
|
||
} catch (error) {
|
||
this.logger.error('Ошибка при отправке еженедельной сводки:', error);
|
||
}
|
||
}
|
||
}
|