Files
iistwin/server/routes/chat.notifications.routes.ts
Ильяс Султанов 1f5ecb6da4 fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric,
  чтобы браузер не округлял значения через input type=number
- пробелы при вставке в number-поля удаляются
- бэкенд нормализует значения number-полей в строку перед сохранением
- добавлен хелпер normalizeFieldValueForStorage

Closes: искажение расчётного счёта и других длинных числовых полей
2026-07-07 21:03:40 +03:00

183 lines
7.2 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";
import { validateRequest } from "../middleware/validation.middleware";
import { createSubscriptionSchema, updateSubscriptionSchema } from "@shared/schema";
import { notificationService } from "../services/notification.service";
export function registerChatNotificationRoutes(router: Router): void {
// Get user notifications
router.get('/api/notifications',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const { unread } = req.query;
const isReadFilter = unread === 'true' ? false : undefined;
const notifications = await storage.getUserNotifications(
req.user!.id, req.organizationId!, isReadFilter
);
res.json({ success: true, notifications });
} catch (error) {
console.error('Get notifications error:', error);
res.status(500).json({ success: false, error: 'Ошибка при загрузке уведомлений' });
}
}
);
// Mark notification as read
router.put('/api/notifications/:id/read',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const notificationId = parseInt(req.params.id);
if (isNaN(notificationId)) {
return res.status(400).json({ success: false, error: 'Некорректный ID уведомления' });
}
const updatedNotification = await storage.markNotificationAsRead(
notificationId, req.user!.id, req.organizationId!
);
res.json({ success: true, message: 'Уведомление отмечено как прочитанное', notification: updatedNotification });
} catch (error) {
console.error('Mark notification as read error:', error);
res.status(500).json({ success: false, error: 'Ошибка при обновлении уведомления' });
}
}
);
// Mark all notifications as read
router.put('/api/notifications/read-all',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
await storage.markAllNotificationsAsRead(req.user!.id, req.organizationId!);
res.json({ success: true, message: 'Все уведомления отмечены как прочитанные' });
} catch (error) {
console.error('Mark all notifications as read error:', error);
res.status(500).json({ success: false, error: 'Ошибка при обновлении уведомлений' });
}
}
);
// Delete notification
router.delete('/api/notifications/:id',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const notificationId = parseInt(req.params.id);
if (isNaN(notificationId)) {
return res.status(400).json({ success: false, error: 'Некорректный ID уведомления' });
}
await storage.deleteNotification(notificationId, req.user!.id, req.organizationId!);
res.json({ success: true, message: 'Уведомление удалено' });
} catch (error) {
console.error('Delete notification error:', error);
res.status(500).json({ success: false, error: 'Ошибка при удалении уведомления' });
}
}
);
// Get all event types for subscription
router.get('/api/subscriptions/event-types',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const eventTypes = await notificationService.getEventTypes();
res.json({ success: true, eventTypes });
} catch (error) {
console.error('Get event types error:', error);
res.status(500).json({ success: false, error: 'Ошибка при загрузке типов событий' });
}
}
);
// Get user subscriptions
router.get('/api/subscriptions',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const subscriptions = await notificationService.getUserSubscriptions(
req.user!.id, req.organizationId!
);
res.json({ success: true, subscriptions });
} catch (error) {
console.error('Get subscriptions error:', error);
res.status(500).json({ success: false, error: 'Ошибка при загрузке подписок' });
}
}
);
// Create subscription
router.post('/api/subscriptions',
authenticateToken,
tenantIsolation,
validateRequest(createSubscriptionSchema),
async (req: AuthenticatedRequest, res) => {
try {
const subscription = await notificationService.createSubscription({
userId: req.user!.id,
organizationId: req.organizationId!,
eventTypeCode: req.body.eventTypeCode,
targetType: req.body.targetType,
targetId: req.body.targetId,
channels: req.body.channels,
});
res.status(201).json({ success: true, message: 'Подписка создана', subscription });
} catch (error) {
console.error('Create subscription error:', error);
res.status(500).json({ success: false, error: 'Ошибка при создании подписки' });
}
}
);
// Update subscription
router.patch('/api/subscriptions/:id',
authenticateToken,
tenantIsolation,
validateRequest(updateSubscriptionSchema),
async (req: AuthenticatedRequest, res) => {
try {
const subscriptionId = parseInt(req.params.id);
if (isNaN(subscriptionId)) {
return res.status(400).json({ success: false, error: 'Некорректный ID подписки' });
}
const subscription = await notificationService.updateSubscription(
subscriptionId, req.user!.id, req.organizationId!, req.body
);
if (!subscription) {
return res.status(404).json({ success: false, error: 'Подписка не найдена' });
}
res.json({ success: true, message: 'Подписка обновлена', subscription });
} catch (error) {
console.error('Update subscription error:', error);
res.status(500).json({ success: false, error: 'Ошибка при обновлении подписки' });
}
}
);
// Delete subscription
router.delete('/api/subscriptions/:id',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const subscriptionId = parseInt(req.params.id);
if (isNaN(subscriptionId)) {
return res.status(400).json({ success: false, error: 'Некорректный ID подписки' });
}
await notificationService.deleteSubscription(subscriptionId, req.user!.id, req.organizationId!);
res.json({ success: true, message: 'Подписка удалена' });
} catch (error) {
console.error('Delete subscription error:', error);
res.status(500).json({ success: false, error: 'Ошибка при удалении подписки' });
}
}
);
}