Create src/config/upload.js with createUpload() factory and shared ALLOWED_FILE_TYPES constant. Replace duplicated multer configs in 5 route files with calls to the shared factory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
223 lines
5.8 KiB
JavaScript
223 lines
5.8 KiB
JavaScript
import express from 'express';
|
|
import path from 'path';
|
|
import * as aiKurzyController from '../controllers/ai-kurzy.controller.js';
|
|
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
|
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
|
import { validateBody, validateParams, validateQuery } from '../middlewares/security/validateInput.js';
|
|
import { z } from 'zod';
|
|
import { createUpload, ALLOWED_FILE_TYPES } from '../config/upload.js';
|
|
|
|
const router = express.Router();
|
|
|
|
const upload = createUpload({
|
|
maxSizeMB: 10,
|
|
allowedTypes: ALLOWED_FILE_TYPES,
|
|
errorMessage: 'Nepovolený typ súboru. Povolené: PDF, Word, Excel, obrázky, CSV, TXT.',
|
|
diskPath: path.join(process.cwd(), 'uploads', 'ai-kurzy'),
|
|
});
|
|
|
|
// Validation schemas
|
|
const kurzIdSchema = z.object({
|
|
kurzId: z.string().regex(/^\d+$/),
|
|
});
|
|
|
|
const ucastnikIdSchema = z.object({
|
|
ucastnikId: z.string().regex(/^\d+$/),
|
|
});
|
|
|
|
const registraciaIdSchema = z.object({
|
|
registraciaId: z.string().regex(/^\d+$/),
|
|
});
|
|
|
|
const createKurzSchema = z.object({
|
|
nazov: z.string().min(1).max(255),
|
|
typKurzu: z.string().min(1).max(100),
|
|
popis: z.string().optional().nullable(),
|
|
cena: z.string().or(z.number()),
|
|
maxKapacita: z.number().int().positive().optional().nullable(),
|
|
aktivny: z.boolean().optional(),
|
|
farba: z.string().max(20).optional().nullable(),
|
|
});
|
|
|
|
const updateKurzSchema = createKurzSchema.partial();
|
|
|
|
const createUcastnikSchema = z.object({
|
|
titul: z.string().max(50).optional().nullable(),
|
|
meno: z.string().min(1).max(100),
|
|
priezvisko: z.string().min(1).max(100),
|
|
email: z.string().email().max(255),
|
|
telefon: z.string().max(50).optional().nullable(),
|
|
firma: z.string().max(255).optional().nullable(),
|
|
firmaIco: z.string().max(20).optional().nullable(),
|
|
firmaDic: z.string().max(20).optional().nullable(),
|
|
firmaIcDph: z.string().max(25).optional().nullable(),
|
|
firmaSidlo: z.string().optional().nullable(),
|
|
mesto: z.string().max(100).optional().nullable(),
|
|
ulica: z.string().max(255).optional().nullable(),
|
|
psc: z.string().max(10).optional().nullable(),
|
|
});
|
|
|
|
const updateUcastnikSchema = createUcastnikSchema.partial();
|
|
|
|
const createRegistraciaSchema = z.object({
|
|
kurzId: z.number().int().positive(),
|
|
ucastnikId: z.number().int().positive(),
|
|
datumOd: z.string().optional().nullable(),
|
|
datumDo: z.string().optional().nullable(),
|
|
formaKurzu: z.enum(['prezencne', 'online', 'hybridne']).optional(),
|
|
pocetUcastnikov: z.number().int().positive().optional(),
|
|
fakturaCislo: z.string().max(100).optional().nullable(),
|
|
fakturaVystavena: z.boolean().optional(),
|
|
zaplatene: z.boolean().optional(),
|
|
stav: z.enum(['potencialny', 'registrovany', 'potvrdeny', 'absolvoval', 'zruseny']).optional(),
|
|
poznamka: z.string().optional().nullable(),
|
|
});
|
|
|
|
const updateRegistraciaSchema = createRegistraciaSchema.partial();
|
|
|
|
const registracieQuerySchema = z.object({
|
|
kurzId: z.string().regex(/^\d+$/).optional(),
|
|
});
|
|
|
|
// All routes require authentication and admin role
|
|
router.use(authenticate);
|
|
router.use(requireAdmin);
|
|
|
|
// ==================== STATISTICS ====================
|
|
|
|
router.get('/stats', aiKurzyController.getStats);
|
|
|
|
// ==================== KURZY ====================
|
|
|
|
router.get('/kurzy', aiKurzyController.getAllKurzy);
|
|
|
|
router.post(
|
|
'/kurzy',
|
|
validateBody(createKurzSchema),
|
|
aiKurzyController.createKurz
|
|
);
|
|
|
|
router.get(
|
|
'/kurzy/:kurzId',
|
|
validateParams(kurzIdSchema),
|
|
aiKurzyController.getKurzById
|
|
);
|
|
|
|
router.put(
|
|
'/kurzy/:kurzId',
|
|
validateParams(kurzIdSchema),
|
|
validateBody(updateKurzSchema),
|
|
aiKurzyController.updateKurz
|
|
);
|
|
|
|
router.delete(
|
|
'/kurzy/:kurzId',
|
|
validateParams(kurzIdSchema),
|
|
aiKurzyController.deleteKurz
|
|
);
|
|
|
|
// ==================== UCASTNICI ====================
|
|
|
|
router.get('/ucastnici', aiKurzyController.getAllUcastnici);
|
|
|
|
router.post(
|
|
'/ucastnici',
|
|
validateBody(createUcastnikSchema),
|
|
aiKurzyController.createUcastnik
|
|
);
|
|
|
|
router.get(
|
|
'/ucastnici/:ucastnikId',
|
|
validateParams(ucastnikIdSchema),
|
|
aiKurzyController.getUcastnikById
|
|
);
|
|
|
|
router.put(
|
|
'/ucastnici/:ucastnikId',
|
|
validateParams(ucastnikIdSchema),
|
|
validateBody(updateUcastnikSchema),
|
|
aiKurzyController.updateUcastnik
|
|
);
|
|
|
|
router.delete(
|
|
'/ucastnici/:ucastnikId',
|
|
validateParams(ucastnikIdSchema),
|
|
aiKurzyController.deleteUcastnik
|
|
);
|
|
|
|
// ==================== REGISTRACIE ====================
|
|
|
|
router.get(
|
|
'/registracie',
|
|
validateQuery(registracieQuerySchema),
|
|
aiKurzyController.getAllRegistracie
|
|
);
|
|
|
|
router.post(
|
|
'/registracie',
|
|
validateBody(createRegistraciaSchema),
|
|
aiKurzyController.createRegistracia
|
|
);
|
|
|
|
router.get(
|
|
'/registracie/:registraciaId',
|
|
validateParams(registraciaIdSchema),
|
|
aiKurzyController.getRegistraciaById
|
|
);
|
|
|
|
router.put(
|
|
'/registracie/:registraciaId',
|
|
validateParams(registraciaIdSchema),
|
|
validateBody(updateRegistraciaSchema),
|
|
aiKurzyController.updateRegistracia
|
|
);
|
|
|
|
router.delete(
|
|
'/registracie/:registraciaId',
|
|
validateParams(registraciaIdSchema),
|
|
aiKurzyController.deleteRegistracia
|
|
);
|
|
|
|
// ==================== COMBINED TABLE (Excel-style) ====================
|
|
|
|
router.get('/table', aiKurzyController.getCombinedTable);
|
|
|
|
const updateFieldSchema = z.object({
|
|
field: z.string(),
|
|
value: z.any(),
|
|
});
|
|
|
|
router.patch(
|
|
'/table/:registraciaId/field',
|
|
validateParams(registraciaIdSchema),
|
|
validateBody(updateFieldSchema),
|
|
aiKurzyController.updateField
|
|
);
|
|
|
|
// ==================== PRILOHY (Documents) ====================
|
|
|
|
const prilohaIdSchema = z.object({
|
|
prilohaId: z.string().regex(/^\d+$/),
|
|
});
|
|
|
|
router.get(
|
|
'/registracie/:registraciaId/prilohy',
|
|
validateParams(registraciaIdSchema),
|
|
aiKurzyController.getPrilohy
|
|
);
|
|
|
|
router.post(
|
|
'/registracie/:registraciaId/prilohy',
|
|
validateParams(registraciaIdSchema),
|
|
upload.single('file'),
|
|
aiKurzyController.uploadPriloha
|
|
);
|
|
|
|
router.delete(
|
|
'/prilohy/:prilohaId',
|
|
validateParams(prilohaIdSchema),
|
|
aiKurzyController.deletePriloha
|
|
);
|
|
|
|
export default router;
|