const express = require('express'); const db = require('../db'); const requireModerator = require('../middleware/requireModerator'); const router = express.Router(); const multer = require('multer'); const path = require('path'); const fs = require('fs'); const uploadDir = path.join(__dirname, '../../uploads'); if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true }); const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, uploadDir), filename: (req, file, cb) => { const ext = path.extname(file.originalname); const name = Date.now() + '-' + Math.round(Math.random() * 1e6) + ext; cb(null, name); } }); const ALLOWED_MIME_TYPES = [ 'image/jpeg', 'image/png', 'video/mp4', 'video/quicktime' ]; const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20 МБ const upload = multer({ storage, limits: { fileSize: MAX_FILE_SIZE }, fileFilter: (req, file, cb) => { if (ALLOWED_MIME_TYPES.includes(file.mimetype)) { cb(null, true); } else { cb(new Error('Недопустимый тип файла')); } } }); // ============================================ // 📸 СЛАЙДЫ ДЛЯ КАРУСЕЛИ (В САМОМ НАЧАЛЕ) // ============================================ // Получить все активные слайды router.get('/slides', async (req, res) => { console.log('📸 GET /slides'); try { const [rows] = await db.query( 'SELECT * FROM slides WHERE is_active = 1 ORDER BY `order` ASC' ); res.json(rows); } catch (err) { console.error('❌ Ошибка получения слайдов:', err); res.status(500).json({ message: 'Ошибка сервера', error: err.message }); } }); // Получить все слайды (для админки) router.get('/slides/all', async (req, res) => { console.log('📸 GET /slides/all'); try { const [rows] = await db.query( 'SELECT * FROM slides ORDER BY `order` ASC' ); res.json(rows); } catch (err) { console.error('❌ Ошибка получения всех слайдов:', err); res.status(500).json({ message: 'Ошибка сервера', error: err.message }); } }); // Загрузка изображения для слайда router.post('/slides/upload', upload.single('image'), (req, res) => { console.log('📸 POST /slides/upload'); console.log('📁 req.file:', req.file); if (!req.file) { return res.status(400).json({ message: 'Файл не загружен' }); } const relPath = '/uploads/' + req.file.filename; console.log('✅ Изображение загружено:', relPath); res.json({ path: relPath }); }); // Создать слайд router.post('/slides', async (req, res) => { console.log('📸 POST /slides'); const { image_url, title, description, link, order, is_active } = req.body; if (!image_url) { return res.status(400).json({ message: 'image_url обязателен' }); } try { const [result] = await db.query( `INSERT INTO slides (image_url, title, description, link, \`order\`, is_active, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())`, [image_url, title || null, description || null, link || null, order || 0, is_active !== undefined ? is_active : 1] ); console.log('✅ Слайд создан, ID:', result.insertId); res.json({ id: result.insertId, message: 'Слайд создан' }); } catch (err) { console.error('❌ Ошибка создания слайда:', err); res.status(500).json({ message: 'Ошибка сервера', error: err.message }); } }); // Обновить слайд router.put('/slides/:id', async (req, res) => { console.log('📸 PUT /slides/' + req.params.id); const { id } = req.params; const { image_url, title, description, link, order, is_active } = req.body; if (!image_url) { return res.status(400).json({ message: 'image_url обязателен' }); } try { await db.query( `UPDATE slides SET image_url = ?, title = ?, description = ?, link = ?, \`order\` = ?, is_active = ?, updated_at = NOW() WHERE id = ?`, [image_url, title || null, description || null, link || null, order || 0, is_active !== undefined ? is_active : 1, id] ); console.log('✅ Слайд обновлён, ID:', id); res.json({ message: 'Слайд обновлён' }); } catch (err) { console.error('❌ Ошибка обновления слайда:', err); res.status(500).json({ message: 'Ошибка сервера', error: err.message }); } }); // Удалить слайд router.delete('/slides/:id', async (req, res) => { console.log('📸 DELETE /slides/' + req.params.id); const { id } = req.params; try { await db.query('DELETE FROM slides WHERE id = ?', [id]); console.log('✅ Слайд удалён, ID:', id); res.json({ message: 'Слайд удалён' }); } catch (err) { console.error('❌ Ошибка удаления слайда:', err); res.status(500).json({ message: 'Ошибка сервера', error: err.message }); } }); // ============================================ // 📚 ОСТАЛЬНЫЕ МАРШРУТЫ (НИЖЕ) // ============================================ // Получить все блоки для вкладки router.get('/:tab', async (req, res) => { const { tab } = req.params; if (!['info', 'union', 'events', 'help', 'housing'].includes(tab)) return res.status(400).json({ message: 'Некорректная вкладка' }); try { const [rows] = await db.query('SELECT * FROM content_blocks WHERE tab = ? ORDER BY created_at ASC', [tab]); res.json(rows); } catch (err) { res.status(500).json({ message: 'Ошибка сервера' }); } }); // Загрузка файла (image/video) router.post('/:tab/upload', requireModerator, upload.single('file'), (req, res) => { if (!req.file) return res.status(400).json({ message: 'Файл не загружен' }); const relPath = '/uploads/' + req.file.filename; res.json({ path: relPath }); }); // Добавить новый блок router.post('/:tab', requireModerator, async (req, res) => { const { tab } = req.params; const { content } = req.body; if (!['info', 'union', 'events', 'help', 'housing'].includes(tab)) return res.status(400).json({ message: 'Некорректная вкладка' }); try { const [result] = await db.query( 'INSERT INTO content_blocks (tab, type, content, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())', [tab, 'text', content, req.session.userId] ); res.json({ id: result.insertId }); } catch (err) { res.status(500).json({ message: 'Ошибка сервера' }); } }); // Обновить блок router.put('/:tab/:id', requireModerator, async (req, res) => { const { tab, id } = req.params; const { content } = req.body; if (!['info', 'union', 'events', 'help', 'housing'].includes(tab)) return res.status(400).json({ message: 'Некорректная вкладка' }); try { await db.query( 'UPDATE content_blocks SET content = ?, updated_at = NOW() WHERE id = ? AND tab = ?', [content, id, tab] ); res.json({ message: 'Обновлено' }); } catch (err) { res.status(500).json({ message: 'Ошибка сервера' }); } }); // Удалить блок router.delete('/:tab/:id', requireModerator, async (req, res) => { const { tab, id } = req.params; if (!['info', 'union', 'events', 'help', 'housing'].includes(tab)) return res.status(400).json({ message: 'Некорректная вкладка' }); try { await db.query('DELETE FROM content_blocks WHERE id = ? AND tab = ?', [id, tab]); res.json({ message: 'Удалено' }); } catch (err) { res.status(500).json({ message: 'Ошибка сервера' }); } }); router.get('/section/:section', async (req, res) => { const { section } = req.params; if (!['events', 'help', 'housing'].includes(section)) { return res.status(400).json({ message: 'Некорректный раздел' }); } try { const [rows] = await db.query( 'SELECT * FROM content_blocks WHERE tab = ? ORDER BY created_at ASC', [section] ); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ message: 'Ошибка сервера' }); } }); // Сохранить контент раздела router.post('/section/:section', requireModerator, async (req, res) => { const { section } = req.params; const { content } = req.body; if (!['events', 'help', 'housing'].includes(section)) { return res.status(400).json({ message: 'Некорректный раздел' }); } try { await db.query('DELETE FROM content_blocks WHERE tab = ?', [section]); const [result] = await db.query( 'INSERT INTO content_blocks (tab, type, content, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())', [section, 'text', content, req.session.userId] ); res.json({ success: true, id: result.insertId, message: 'Раздел сохранён' }); } catch (err) { console.error(err); res.status(500).json({ message: 'Ошибка сервера' }); } }); module.exports = router;