Files
iistwin/server/routes/task-crud-extra.routes.ts

163 lines
7.0 KiB
TypeScript
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.

import { Router } from "express";
import { storage } from "../storage";
import { authenticateToken, type AuthenticatedRequest } from "../middleware/auth.middleware";
import { tenantIsolation } from "../middleware/tenant.middleware";
export function registerTaskCrudExtraRoutes(router: ReturnType<typeof import("express").Router>): void {
router.put('/api/tasks/:id/notifications/read', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
const userId = req.user!.id;
const organizationId = req.organizationId!;
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
console.log(`[tasks/:id/notifications/read] Marking read for taskId=${taskId}, userId=${userId}, orgId=${organizationId}`);
await storage.markTaskNotificationsAsRead(taskId, userId, organizationId);
res.json({ success: true });
} catch (err) {
console.error('[tasks/:id/notifications/read]', err);
res.status(500).json({ success: false, error: 'Ошибка сервера' });
}
});
router.post('/api/tasks/:id/view', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
const userId = req.user!.id;
const organizationId = req.organizationId!;
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
// Make sure the task exists in this organization before recording a view.
const task = await storage.getTask(taskId, organizationId);
if (!task) {
return res.status(404).json({ success: false, error: 'Задача не найдена' });
}
await storage.recordTaskView(taskId, userId, organizationId);
res.json({ success: true });
} catch (err) {
console.error('[tasks/:id/view]', err);
res.status(500).json({ success: false, error: 'Ошибка сервера' });
}
});
router.get('/api/tasks/:id/audit-log', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
const task = await storage.getTask(taskId, req.organizationId!);
if (!task) {
return res.status(404).json({ success: false, error: 'Задача не найдена' });
}
const log = await storage.getTaskAuditLog(taskId, req.organizationId!);
res.json({ success: true, log });
} catch (error) {
console.error('Get task audit log error:', error);
res.status(500).json({ success: false, error: 'Ошибка при получении истории задачи' });
}
});
router.get('/api/tasks/:id/subtasks', async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
const subtasks = await storage.getSubtasks(taskId, req.organizationId!);
res.json({ success: true, subtasks });
} catch (error) {
console.error('Get subtasks error:', error);
res.status(500).json({ success: false, error: 'Ошибка при получении подзадач' });
}
});
router.get('/api/tasks/:id/tree', async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
const taskTree = await storage.getTaskTree(taskId, req.organizationId!);
if (!taskTree) {
return res.status(404).json({ success: false, error: 'Задача не найдена' });
}
res.json({ success: true, task: taskTree });
} catch (error) {
console.error('Get task tree error:', error);
res.status(500).json({ success: false, error: 'Ошибка при получении дерева задач' });
}
});
/**
* @swagger
* /api/tasks/{id}/related:
* get:
* tags: [Tasks]
* summary: Получить дерево связанных задач
* description: >
* Возвращает дерево задач, связанных с указанной через таблицу task_relations.
* Связи создаются либо через поля типа «задача» в форме, либо вручную через чат
* (кнопка «Привязать»). Каждый узел рекурсивно содержит своих родителей/детей
* в поле `nodes` (глубина до 10 уровней). Поле `fieldName` указывает имя поля
* связи или «Связь из чата» если привязка выполнена вручную.
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* description: ID задачи
* responses:
* 200:
* description: Дерево связанных задач
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* example: true
* parents:
* type: array
* description: Задачи-родители (данная задача является дочерней)
* items:
* $ref: '#/components/schemas/RelatedTreeNode'
* children:
* type: array
* description: Задачи-дети (данная задача является родительской)
* items:
* $ref: '#/components/schemas/RelatedTreeNode'
* 400:
* description: Неверный ID задачи
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Error'
*/
router.get('/api/tasks/:id/related', async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
if (isNaN(taskId)) {
return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
}
const relatedTasks = await storage.getRelatedTasks(taskId, req.organizationId!);
res.json({ success: true, ...relatedTasks });
} catch (error) {
console.error('Get related tasks error:', error);
res.status(500).json({ success: false, error: 'Ошибка при получении связанных задач' });
}
});
}