fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
157
server/routes/form-access.routes.ts
Normal file
157
server/routes/form-access.routes.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { Router } from "express";
|
||||
import { storage } from "../storage";
|
||||
import { authenticateToken, requireFormAdminOrPermission } from "../middleware/auth.middleware";
|
||||
import { z } from "zod";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// GET /api/forms/:id/access-rules
|
||||
router.get('/api/forms/:id/access-rules',
|
||||
authenticateToken,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const formId = parseInt(req.params.id);
|
||||
if (isNaN(formId)) return res.status(400).json({ error: 'Неверный ID формы' });
|
||||
const rules = await storage.getFormAccessRules(formId, (req as any).organizationId!);
|
||||
res.json({ success: true, rules });
|
||||
} catch (err) {
|
||||
console.error('Get form access rules error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при получении правил доступа' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// POST /api/forms/:id/access-rules
|
||||
router.post('/api/forms/:id/access-rules',
|
||||
authenticateToken,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const formId = parseInt(req.params.id);
|
||||
if (isNaN(formId)) return res.status(400).json({ error: 'Неверный ID формы' });
|
||||
|
||||
const schema = z.object({
|
||||
targetType: z.enum(['user', 'role']),
|
||||
targetId: z.number().positive(),
|
||||
accessLevel: z.enum(['participate', 'view_all', 'admin']).default('participate'),
|
||||
});
|
||||
const body = schema.parse(req.body);
|
||||
|
||||
const rule = await storage.createFormAccessRule({
|
||||
formId,
|
||||
organizationId: (req as any).organizationId!,
|
||||
targetType: body.targetType,
|
||||
targetId: body.targetId,
|
||||
accessLevel: body.accessLevel,
|
||||
});
|
||||
res.json({ success: true, rule });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return res.status(400).json({ error: 'Неверные данные', details: err.errors });
|
||||
}
|
||||
console.error('Create form access rule error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при создании правила доступа' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// PUT /api/forms/:id/access-rules/:ruleId
|
||||
router.put('/api/forms/:id/access-rules/:ruleId',
|
||||
authenticateToken,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const ruleId = parseInt(req.params.ruleId);
|
||||
if (isNaN(ruleId)) return res.status(400).json({ error: 'Неверный ID правила' });
|
||||
|
||||
const schema = z.object({
|
||||
accessLevel: z.enum(['participate', 'view_all', 'admin']),
|
||||
});
|
||||
const body = schema.parse(req.body);
|
||||
|
||||
const rule = await storage.updateFormAccessRule(ruleId, (req as any).organizationId!, {
|
||||
accessLevel: body.accessLevel,
|
||||
});
|
||||
res.json({ success: true, rule });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return res.status(400).json({ error: 'Неверные данные', details: err.errors });
|
||||
}
|
||||
console.error('Update form access rule error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при обновлении правила доступа' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// DELETE /api/forms/:id/access-rules/:ruleId
|
||||
router.delete('/api/forms/:id/access-rules/:ruleId',
|
||||
authenticateToken,
|
||||
requireFormAdminOrPermission('forms.manage'),
|
||||
async (req, res) => {
|
||||
try {
|
||||
const ruleId = parseInt(req.params.ruleId);
|
||||
if (isNaN(ruleId)) return res.status(400).json({ error: 'Неверный ID правила' });
|
||||
await storage.deleteFormAccessRule(ruleId, (req as any).organizationId!);
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
console.error('Delete form access rule error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при удалении правила доступа' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// PUT /api/forms/:id/visibility
|
||||
router.put('/api/forms/:id/visibility',
|
||||
authenticateToken,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const formId = parseInt(req.params.id);
|
||||
if (isNaN(formId)) return res.status(400).json({ error: 'Неверный ID формы' });
|
||||
|
||||
const schema = z.object({
|
||||
visibility: z.enum(['organization', 'restricted']),
|
||||
});
|
||||
const body = schema.parse(req.body);
|
||||
|
||||
const { db } = await import("../db");
|
||||
const { forms } = await import("@shared/schema");
|
||||
const { eq, and } = await import("drizzle-orm");
|
||||
const [form] = await db.update(forms)
|
||||
.set({ visibility: body.visibility })
|
||||
.where(and(eq(forms.id, formId), eq(forms.organizationId, (req as any).organizationId!)))
|
||||
.returning();
|
||||
res.json({ success: true, form });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return res.status(400).json({ error: 'Неверные данные', details: err.errors });
|
||||
}
|
||||
console.error('Update form visibility error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при обновлении видимости формы' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// POST /api/forms/:id/transfer-ownership
|
||||
router.post('/api/forms/:id/transfer-ownership',
|
||||
authenticateToken,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const formId = parseInt(req.params.id);
|
||||
if (isNaN(formId)) return res.status(400).json({ error: 'Неверный ID формы' });
|
||||
|
||||
const schema = z.object({
|
||||
newAuthorId: z.number().positive(),
|
||||
});
|
||||
const body = schema.parse(req.body);
|
||||
|
||||
await storage.transferFormOwnership(formId, (req as any).organizationId!, body.newAuthorId);
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
return res.status(400).json({ error: 'Неверные данные', details: err.errors });
|
||||
}
|
||||
console.error('Transfer form ownership error:', err);
|
||||
res.status(500).json({ error: 'Ошибка при передаче прав на форму' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user