- AdminJS at /admin with auth (admin role only) - Manage: users, categories, tools, content blocks, settings - DB tables: settings, categories, tools, content_blocks - Users table: added role (user/admin) and is_blocked fields - API: /api/settings, /api/tools, /api/content/:section - Sidebar: admin link visible only for admin users - Removed /logs from public routes (now in AdminJS) - Video converter: fixed ffmpeg codecs for RPi5 (h264_v4l2m2m) - Dependencies: sequelize, @adminjs/sequelize, mariadb
113 lines
3.5 KiB
JavaScript
113 lines
3.5 KiB
JavaScript
const express = require('express');
|
|
const bcrypt = require('bcrypt');
|
|
const path = require('path');
|
|
const db = require('../lib/db');
|
|
const log = require('../lib/logger');
|
|
|
|
const router = express.Router();
|
|
const SALT_ROUNDS = 10;
|
|
|
|
// Pages
|
|
router.get('/login', (req, res) => {
|
|
if (req.session.user) return res.redirect('/dashboard');
|
|
res.sendFile(path.join(__dirname, '..', 'public', 'login.html'));
|
|
});
|
|
|
|
router.get('/register', (req, res) => {
|
|
if (req.session.user) return res.redirect('/dashboard');
|
|
res.sendFile(path.join(__dirname, '..', 'public', 'register.html'));
|
|
});
|
|
|
|
// Login API
|
|
router.post('/login', express.json(), express.urlencoded({ extended: true }), async (req, res) => {
|
|
const { email, password } = req.body;
|
|
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: 'Email и пароль обязательны' });
|
|
}
|
|
|
|
try {
|
|
const user = await db.findUserByEmail(email.toLowerCase().trim());
|
|
if (!user) {
|
|
return res.status(401).json({ error: 'Неверный email или пароль' });
|
|
}
|
|
|
|
const valid = await bcrypt.compare(password, user.password_hash);
|
|
if (!valid) {
|
|
return res.status(401).json({ error: 'Неверный email или пароль' });
|
|
}
|
|
|
|
await db.updateLastLogin(user.id);
|
|
|
|
req.session.user = {
|
|
id: user.id,
|
|
email: user.email,
|
|
name: user.display_name || user.email.split('@')[0],
|
|
role: user.role || 'user',
|
|
};
|
|
|
|
log.info(`Login: ${user.email}`);
|
|
res.json({ ok: true, redirect: req.session.returnTo || '/dashboard' });
|
|
delete req.session.returnTo;
|
|
} catch (err) {
|
|
log.error('Login error', { error: err.message });
|
|
res.status(500).json({ error: 'Ошибка сервера' });
|
|
}
|
|
});
|
|
|
|
// Register API
|
|
router.post('/register', express.json(), express.urlencoded({ extended: true }), async (req, res) => {
|
|
const { email, password, password2, name } = req.body;
|
|
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: 'Email и пароль обязательны' });
|
|
}
|
|
|
|
const emailClean = email.toLowerCase().trim();
|
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailClean)) {
|
|
return res.status(400).json({ error: 'Некорректный email' });
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
return res.status(400).json({ error: 'Пароль минимум 6 символов' });
|
|
}
|
|
|
|
if (password2 && password !== password2) {
|
|
return res.status(400).json({ error: 'Пароли не совпадают' });
|
|
}
|
|
|
|
try {
|
|
const existing = await db.findUserByEmail(emailClean);
|
|
if (existing) {
|
|
return res.status(409).json({ error: 'Этот email уже зарегистрирован' });
|
|
}
|
|
|
|
const hash = await bcrypt.hash(password, SALT_ROUNDS);
|
|
const displayName = (name || '').trim() || emailClean.split('@')[0];
|
|
const userId = await db.createUser(emailClean, hash, displayName);
|
|
|
|
req.session.user = { id: userId, email: emailClean, name: displayName };
|
|
|
|
log.info(`Register: ${emailClean}`);
|
|
res.json({ ok: true, redirect: '/dashboard' });
|
|
} catch (err) {
|
|
log.error('Register error', { error: err.message });
|
|
res.status(500).json({ error: 'Ошибка сервера' });
|
|
}
|
|
});
|
|
|
|
// Logout
|
|
router.get('/logout', (req, res) => {
|
|
req.session.destroy(() => {
|
|
res.redirect('/');
|
|
});
|
|
});
|
|
|
|
// Current user info
|
|
router.get('/me', (req, res) => {
|
|
if (!req.session.user) return res.status(401).json({ error: 'Not authenticated' });
|
|
res.json(req.session.user);
|
|
});
|
|
|
|
module.exports = router;
|