262 lines
9.9 KiB
JavaScript
262 lines
9.9 KiB
JavaScript
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; |