- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
import type { Response, NextFunction } from 'express';
|
|
import type { AuthenticatedRequest } from './auth.middleware';
|
|
import { _tenantCtx } from '../db';
|
|
|
|
// Validates that the authenticated user belongs to an organization.
|
|
// If authenticateToken already opened a per-request tenant context (the common
|
|
// case), this middleware just sets req.organizationId and calls next().
|
|
// It never opens a second connection — the context from authenticateToken is reused.
|
|
export const tenantIsolation = (
|
|
req: AuthenticatedRequest,
|
|
res: Response,
|
|
next: NextFunction
|
|
): void => {
|
|
if (!req.user?.organizationId) {
|
|
res.status(400).json({ success: false, error: 'Ошибка идентификации организации' });
|
|
return;
|
|
}
|
|
req.organizationId = req.user.organizationId;
|
|
next();
|
|
};
|
|
|
|
export const validateTenantAccess = (
|
|
req: AuthenticatedRequest,
|
|
res: Response,
|
|
next: NextFunction
|
|
) => {
|
|
const requestedOrgId = req.params.organizationId || req.body.organizationId;
|
|
if (requestedOrgId && parseInt(requestedOrgId) !== req.organizationId) {
|
|
return res.status(403).json({
|
|
error: 'Доступ запрещен: нет прав на данные другой организации',
|
|
});
|
|
}
|
|
next();
|
|
};
|