notifications
This commit is contained in:
@@ -3,6 +3,12 @@ const postgresLogger = require('./postgres');
|
||||
const { getDb } = require('./database');
|
||||
const emailNotifications = require('./email-notifications');
|
||||
|
||||
/**
|
||||
* Отправляет уведомления о событиях в задаче согласно новой логике:
|
||||
* - Если инициатор = автор → уведомления всем исполнителям
|
||||
* - Если инициатор = исполнитель → уведомление только автору
|
||||
* - Иначе (например, администратор вне задачи) → уведомления всем, кроме инициатора (старое поведение)
|
||||
*/
|
||||
async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, authorId, comment = '', status = '', userName = '') {
|
||||
try {
|
||||
const db = getDb();
|
||||
@@ -14,7 +20,7 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
console.log(`📢 Начинаем отправку уведомлений для задачи ${taskId}:`);
|
||||
console.log(` Тип: ${type}, Автор действия: ${authorId}, Название: ${taskTitle}`);
|
||||
|
||||
// Получаем заказчика
|
||||
// 1. Получаем автора задачи (создателя)
|
||||
const creator = await new Promise((resolve, reject) => {
|
||||
db.get(`
|
||||
SELECT t.created_by as user_id, u.name as user_name, u.login as user_login, u.email
|
||||
@@ -27,7 +33,12 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
});
|
||||
});
|
||||
|
||||
// Получаем исполнителей
|
||||
if (!creator) {
|
||||
console.error(`❌ Задача ${taskId} не найдена или у неё нет автора`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Получаем всех исполнителей задачи
|
||||
const assignees = await new Promise((resolve, reject) => {
|
||||
db.all(`
|
||||
SELECT ta.user_id, u.name as user_name, u.login as user_login, u.email
|
||||
@@ -40,7 +51,7 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
});
|
||||
});
|
||||
|
||||
// Получаем информацию об авторе действия
|
||||
// 3. Получаем информацию об авторе действия (инициаторе)
|
||||
const author = await new Promise((resolve, reject) => {
|
||||
db.get("SELECT name, login, email FROM users WHERE id = ?", [authorId], (err, row) => {
|
||||
if (err) reject(err);
|
||||
@@ -50,7 +61,31 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
|
||||
const authorName = author ? author.name : 'Система';
|
||||
const authorLogin = author ? author.login : 'system';
|
||||
|
||||
|
||||
// 4. Определяем получателей уведомления согласно новой логике
|
||||
let recipients = [];
|
||||
|
||||
// Проверяем, является ли инициатор автором задачи
|
||||
if (parseInt(authorId) === parseInt(creator.user_id)) {
|
||||
// Инициатор = автор → уведомления всем исполнителям
|
||||
recipients = assignees;
|
||||
console.log(` Инициатор является автором. Получатели: ${assignees.length} исполнителей`);
|
||||
}
|
||||
// Проверяем, является ли инициатор одним из исполнителей
|
||||
else {
|
||||
const isInitiatorAssignee = assignees.some(a => parseInt(a.user_id) === parseInt(authorId));
|
||||
if (isInitiatorAssignee) {
|
||||
// Инициатор = исполнитель → уведомление только автору
|
||||
recipients = [creator];
|
||||
console.log(` Инициатор является исполнителем. Получатель: автор`);
|
||||
} else {
|
||||
// Инициатор не является ни автором, ни исполнителем (например, администратор)
|
||||
// Отправляем уведомления всем участникам, кроме инициатора (старое поведение)
|
||||
recipients = [creator, ...assignees].filter(p => parseInt(p.user_id) !== parseInt(authorId));
|
||||
console.log(` Инициатор вне задачи. Получатели: ${recipients.length} участников (старое поведение)`);
|
||||
}
|
||||
}
|
||||
|
||||
// Логируем в PostgreSQL (если настроено)
|
||||
let postgresLogIds = [];
|
||||
if (postgresLogger.initialized) {
|
||||
@@ -62,31 +97,29 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
authorId,
|
||||
authorName,
|
||||
authorLogin,
|
||||
participants: [...(creator ? [{...creator, role: 'creator'}] : []), ...assignees.map(a => ({...a, role: 'assignee'}))],
|
||||
recipients,
|
||||
comment,
|
||||
status,
|
||||
userName
|
||||
});
|
||||
}
|
||||
|
||||
// Отправляем email уведомления
|
||||
const participants = [...(creator ? [creator] : []), ...assignees].filter(p => p.user_id !== authorId);
|
||||
|
||||
for (const participant of participants) {
|
||||
// 5. Отправляем email уведомления выбранным получателям
|
||||
for (const recipient of recipients) {
|
||||
const taskData = {
|
||||
taskId,
|
||||
title: taskTitle,
|
||||
description: taskDescription,
|
||||
due_date: null, // Можно добавить получение срока из БД
|
||||
due_date: null, // при необходимости можно добавить получение срока из БД
|
||||
author_name: authorName,
|
||||
comment: comment,
|
||||
status: status,
|
||||
user_name: userName || participant.user_name,
|
||||
hours_left: type === 'deadline' ? 24 : null // Для уведомлений о дедлайне
|
||||
user_name: userName || recipient.user_name,
|
||||
hours_left: type === 'deadline' ? 24 : null
|
||||
};
|
||||
|
||||
await emailNotifications.sendTaskNotification(
|
||||
participant.user_id,
|
||||
recipient.user_id,
|
||||
taskData,
|
||||
type
|
||||
);
|
||||
@@ -99,7 +132,9 @@ async function sendTaskNotifications(type, taskId, taskTitle, taskDescription, a
|
||||
}
|
||||
}
|
||||
|
||||
// Обновим функцию для уведомлений о дедлайнах
|
||||
/**
|
||||
* Отправляет уведомление о приближающемся дедлайне
|
||||
*/
|
||||
async function sendDeadlineNotification(assignment, hoursLeft) {
|
||||
try {
|
||||
const taskData = {
|
||||
@@ -118,7 +153,7 @@ async function sendDeadlineNotification(assignment, hoursLeft) {
|
||||
'deadline'
|
||||
);
|
||||
|
||||
// Отправляем уведомление заказчику
|
||||
// Отправляем уведомление заказчику (автору)
|
||||
await emailNotifications.sendTaskNotification(
|
||||
assignment.created_by,
|
||||
taskData,
|
||||
@@ -132,6 +167,9 @@ async function sendDeadlineNotification(assignment, hoursLeft) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет приближающиеся дедлайны и отправляет уведомления
|
||||
*/
|
||||
async function checkUpcomingDeadlines() {
|
||||
const now = new Date();
|
||||
const in48Hours = new Date(now.getTime() + 48 * 60 * 60 * 1000).toISOString();
|
||||
@@ -179,7 +217,9 @@ async function checkUpcomingDeadlines() {
|
||||
});
|
||||
}
|
||||
|
||||
// Вспомогательные функции для работы с PostgreSQL
|
||||
/**
|
||||
* Логирует уведомление в PostgreSQL
|
||||
*/
|
||||
async function logNotificationToPostgres(data) {
|
||||
try {
|
||||
const {
|
||||
@@ -190,7 +230,7 @@ async function logNotificationToPostgres(data) {
|
||||
authorId,
|
||||
authorName,
|
||||
authorLogin,
|
||||
participants = [],
|
||||
recipients = [],
|
||||
comment = '',
|
||||
status = '',
|
||||
userName = '',
|
||||
@@ -217,11 +257,9 @@ async function logNotificationToPostgres(data) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Логируем для каждого получателя отдельно
|
||||
const recipientsToNotify = participants.filter(p => p.user_id !== authorId);
|
||||
const logIds = [];
|
||||
|
||||
for (const recipient of recipientsToNotify) {
|
||||
for (const recipient of recipients) {
|
||||
const logId = await postgresLogger.logNotification({
|
||||
taskId,
|
||||
taskTitle,
|
||||
@@ -252,6 +290,9 @@ async function logNotificationToPostgres(data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет статус доставки уведомления в PostgreSQL
|
||||
*/
|
||||
async function updatePostgresLogStatus(logIds, status, errorMessage = null, sentAt = null) {
|
||||
if (!logIds || logIds.length === 0) return;
|
||||
|
||||
@@ -260,6 +301,9 @@ async function updatePostgresLogStatus(logIds, status, errorMessage = null, sent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает тему уведомления в зависимости от типа
|
||||
*/
|
||||
function getNotificationSubject(type, taskTitle) {
|
||||
switch (type) {
|
||||
case 'created':
|
||||
@@ -277,11 +321,14 @@ function getNotificationSubject(type, taskTitle) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует внутренний статус в читаемый текст
|
||||
*/
|
||||
function getStatusText(status) {
|
||||
const statusMap = {
|
||||
'assigned': 'Назначена',
|
||||
'in_progress': 'В работе',
|
||||
'completed': 'Завершена',
|
||||
'completed': 'Выполнена',
|
||||
'overdue': 'Просрочена',
|
||||
'rework': 'На доработке'
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user