admin_to_react
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
const logger = require('../logger');
|
||||
const bcrypt = require('bcrypt');
|
||||
const moderDb = require('../moders/db');
|
||||
require('dotenv').config({ path: __dirname + './config.env' });
|
||||
exports.login = (req, res) => {
|
||||
const { password } = req.body;
|
||||
if (password === process.env.ADMIN_PASSWORD) {
|
||||
req.session.isAuthenticated = true;
|
||||
logger.info('Login successful');
|
||||
res.status(200).send('Login successful');
|
||||
} else {
|
||||
res.status(401).send('Invalid password');
|
||||
logger.warn('Неверный пароль');
|
||||
}
|
||||
};
|
||||
|
||||
exports.getCsrfToken = (req, res) => {
|
||||
res.json({ csrfToken: req.csrfToken() });
|
||||
};
|
||||
|
||||
exports.moderLogin = async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
try {
|
||||
const [users] = await moderDb.query('SELECT * FROM users WHERE username = ?', [username]);
|
||||
if (users.length === 0) {
|
||||
return res.status(401).json({ message: 'Неверные учетные данные' });
|
||||
}
|
||||
const user = users[0];
|
||||
const match = await bcrypt.compare(password, user.password_hash);
|
||||
if (!match) {
|
||||
return res.status(401).json({ message: 'Неверные учетные данные' });
|
||||
}
|
||||
req.session.moderId = user.id;
|
||||
req.session.moderName = user.username;
|
||||
res.json({ message: 'Успешный вход', username: user.username });
|
||||
} catch (error) {
|
||||
logger.error('Ошибка входа модератора:', error);
|
||||
res.status(500).json({ message: 'Ошибка сервера' });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const logger = require('../logger');
|
||||
|
||||
const CARD_LOG_PATH = path.resolve(__dirname, '..', process.env.CARD_LOG_PATH);
|
||||
const initCardLogs = async () => {
|
||||
try {
|
||||
await fs.ensureDir(path.dirname(CARD_LOG_PATH));
|
||||
if (!(await fs.pathExists(CARD_LOG_PATH))) {
|
||||
await fs.writeFile(CARD_LOG_PATH, '');
|
||||
logger.info(`Card log file created at: ${CARD_LOG_PATH}`);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Failed to initialize card logs:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
initCardLogs().catch(err => {
|
||||
logger.error('Card logs initialization error:', err);
|
||||
});
|
||||
|
||||
const cardEvent = (req, res) => {
|
||||
logger.info('[CARD EVENT] Received:', req.body);
|
||||
|
||||
if (!req.body || !req.body.event) {
|
||||
logger.error('Invalid request body:', req.body);
|
||||
return res.status(400).json({ message: 'Missing required field: event' });
|
||||
}
|
||||
|
||||
const { event, uid = 'N/A', timestamp = Date.now() } = req.body;
|
||||
const logLine = `[${new Date(timestamp).toISOString()}] [${event}] UID: ${uid}\n`;
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(CARD_LOG_PATH)) {
|
||||
initCardLogs();
|
||||
}
|
||||
fs.appendFileSync(CARD_LOG_PATH, logLine);
|
||||
logger.info('[CARD EVENT] Log written to:', CARD_LOG_PATH);
|
||||
return res.status(200).json({ message: 'OK', path: CARD_LOG_PATH });
|
||||
|
||||
} catch (err) {
|
||||
logger.error('[CARD EVENT] Failed to write log:', err);
|
||||
return res.status(500).json({
|
||||
message: 'Failed to write log',
|
||||
error: err.message,
|
||||
path: CARD_LOG_PATH
|
||||
});
|
||||
}
|
||||
};
|
||||
const getCardLogs = async (req, res) => {
|
||||
try {
|
||||
if (!(await fs.pathExists(CARD_LOG_PATH))) {
|
||||
await initCardLogs();
|
||||
return res.status(200).type('text/plain').send('Card logs initialized');
|
||||
}
|
||||
const logs = await fs.readFile(CARD_LOG_PATH, 'utf-8');
|
||||
res.type('text/plain').send(logs);
|
||||
} catch (err) {
|
||||
logger.error('Error reading card logs:', err);
|
||||
res.status(500).json({
|
||||
error: err.message,
|
||||
path: CARD_LOG_PATH
|
||||
});
|
||||
}
|
||||
};
|
||||
module.exports = {
|
||||
cardEvent,
|
||||
getCardLogs,
|
||||
initCardLogs
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
const axios = require('axios');
|
||||
const WebSocket = require('ws');
|
||||
const iconv = require('iconv-lite');
|
||||
const logger = require('../logger')
|
||||
exports.checkDb = async (req, res) => {
|
||||
let adminToDbStatus = { status: 'offline', message: 'Test not performed' };
|
||||
try {
|
||||
const dbConfig = {
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
server: process.env.DB_SERVER,
|
||||
database: process.env.DB_NAME,
|
||||
options: { encrypt: false, trustServerCertificate: true },
|
||||
pool: { max: 1, min: 0, idleTimeoutMillis: 5000 },
|
||||
requestTimeout: 5000
|
||||
};
|
||||
const pool = new sql.ConnectionPool(dbConfig);
|
||||
await pool.connect();
|
||||
await pool.query`SELECT 1`;
|
||||
adminToDbStatus = { status: 'online', message: 'Прямое подключение успешно' };
|
||||
await pool.close();
|
||||
} catch (error) {
|
||||
adminToDbStatus = { status: 'offline', message: `Ошибка прямого подключения: ${error.message}` };
|
||||
}
|
||||
|
||||
let backendToDbStatus = { status: 'offline', message: 'Test not performed' };
|
||||
try {
|
||||
const response = await axios.get(`${process.env.BACKEND_URL}/api/db-status`, { timeout: 3000 });
|
||||
if (response.data.status === 'ok') {
|
||||
backendToDbStatus = { status: 'online', message: 'Бэкенд успешно подключен' };
|
||||
} else {
|
||||
backendToDbStatus = { status: 'offline', message: 'Бэкенд сообщил об ошибке' };
|
||||
}
|
||||
} catch (error) {
|
||||
backendToDbStatus = { status: 'offline', message: 'Не удалось связаться с бэкендом' };
|
||||
}
|
||||
|
||||
res.json({
|
||||
adminToDb: adminToDbStatus,
|
||||
backendToDb: backendToDbStatus
|
||||
});
|
||||
};
|
||||
|
||||
exports.checkStatus = async (req, res) => {
|
||||
try {
|
||||
await axios.get(`${process.env.BACKEND_URL}/api/test`, { timeout: 2000 });
|
||||
res.json({ status: 'online' });
|
||||
} catch (error) {
|
||||
res.json({ status: 'offline' });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const logger = require('../logger');
|
||||
|
||||
const ADMIN_LOG = path.resolve(__dirname, '..', process.env.ADMIN_LOG);
|
||||
const BACKEND_APP_LOG = path.resolve(__dirname, '..', process.env.BACKEND_APP_LOG);
|
||||
const CARD_LOG = path.resolve(__dirname, '..', process.env.CARD_LOG);
|
||||
|
||||
const getLogs = async (req, res) => {
|
||||
try {
|
||||
const logPath = path.join(__dirname, '..', '../backend/logs/app.log');
|
||||
const logs = await fs.readFile(logPath, 'utf-8');
|
||||
res.type('text/plain');
|
||||
res.send(logs);
|
||||
} catch (error) {
|
||||
logger.error('Error reading log file:', error);
|
||||
res.status(500).send('Could not read log file.');
|
||||
}
|
||||
};
|
||||
|
||||
const clearLogs = async (req, res) => {
|
||||
try {
|
||||
const logPath = path.join(__dirname, '..', '../backend/logs/app.log');
|
||||
await fs.truncate(logPath, 0);
|
||||
res.status(200).json({ message: 'Logs cleared successfully' });
|
||||
} catch (error) {
|
||||
logger.error('Error clearing log file:', error);
|
||||
res.status(500).send('Could not clear log file.');
|
||||
}
|
||||
};
|
||||
|
||||
const getMonitoringLogs = async (req, res) => {
|
||||
const logSources = [
|
||||
{ name: 'Admin', path: ADMIN_LOG },
|
||||
{ name: 'Backend', path: BACKEND_APP_LOG },
|
||||
{ name: 'CardReader', path: CARD_LOG }
|
||||
];
|
||||
|
||||
let allEvents = [];
|
||||
|
||||
for (const source of logSources) {
|
||||
try {
|
||||
if (!(await fs.pathExists(source.path))) {
|
||||
logger.warn(`Log file not found: ${source.path}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const content = await fs.readFile(source.path, 'utf-8');
|
||||
const lines = content.split(/\r?\n/);
|
||||
|
||||
lines.forEach(line => {
|
||||
if (!line) return;
|
||||
try {
|
||||
const jsonLog = JSON.parse(line);
|
||||
if (['warn', 'error'].includes(jsonLog.level?.toLowerCase())) {
|
||||
allEvents.push({
|
||||
timestamp: jsonLog.timestamp || new Date().toISOString(),
|
||||
level: jsonLog.level.toUpperCase(),
|
||||
source: source.name,
|
||||
message: jsonLog.message
|
||||
});
|
||||
}
|
||||
return;
|
||||
} catch (e) {
|
||||
}
|
||||
const match = line.match(/\[([^\]]+)\] \[([^\]]+)\] (.*)/);
|
||||
if (match) {
|
||||
const level = match[2].toLowerCase();
|
||||
if (['warn', 'error'].includes(level)) {
|
||||
allEvents.push({
|
||||
timestamp: new Date(match[1]).toISOString(),
|
||||
level: level.toUpperCase(),
|
||||
source: source.name,
|
||||
message: match[3]
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`Error reading or parsing log file ${source.path}:`, err);
|
||||
allEvents.push({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: 'ERROR',
|
||||
source: 'Monitoring',
|
||||
message: `Could not read log file: ${source.name}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
allEvents.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
||||
|
||||
res.json(allEvents);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getLogs,
|
||||
clearLogs,
|
||||
getMonitoringLogs
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
const moderDb = require('../moders/db');
|
||||
const bcrypt = require('bcrypt');
|
||||
const logger = require('../logger');
|
||||
|
||||
const getModers = async (req, res) => {
|
||||
try {
|
||||
const [rows] = await moderDb.query('SELECT id, username FROM users ORDER BY id ASC');
|
||||
res.json(rows);
|
||||
} catch (e) {
|
||||
logger.error('Ошибка получения списка модераторов:', e);
|
||||
res.status(500).json({ message: 'Ошибка получения списка модераторов' });
|
||||
}
|
||||
};
|
||||
|
||||
const addModer = async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ message: 'username и password обязательны' });
|
||||
}
|
||||
try {
|
||||
const [exists] = await moderDb.query('SELECT id FROM users WHERE username = ?', [username]);
|
||||
if (exists.length) {
|
||||
return res.status(409).json({ message: 'Пользователь с таким username уже существует' });
|
||||
}
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
const [result] = await moderDb.query('INSERT INTO users (username, password_hash) VALUES (?, ?)', [username, hash]);
|
||||
res.json({ id: result.insertId, username });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка добавления модератора:', e);
|
||||
res.status(500).json({ message: 'Ошибка добавления модератора' });
|
||||
}
|
||||
};
|
||||
|
||||
const changePassword = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { password } = req.body;
|
||||
if (!password) {
|
||||
return res.status(400).json({ message: 'password обязателен' });
|
||||
}
|
||||
try {
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
const [result] = await moderDb.query('UPDATE users SET password_hash = ? WHERE id = ?', [hash, id]);
|
||||
if (result.affectedRows === 0) {
|
||||
return res.status(404).json({ message: 'Модератор не найден' });
|
||||
}
|
||||
res.json({ message: 'Пароль обновлён' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка смены пароля модератора:', e);
|
||||
res.status(500).json({ message: 'Ошибка смены пароля модератора' });
|
||||
}
|
||||
};
|
||||
|
||||
const deleteModer = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
try {
|
||||
const [result] = await moderDb.query('DELETE FROM users WHERE id = ?', [id]);
|
||||
if (result.affectedRows === 0) {
|
||||
return res.status(404).json({ message: 'Модератор не найден' });
|
||||
}
|
||||
res.json({ message: 'Модератор удалён' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка удаления модератора:', e);
|
||||
res.status(500).json({ message: 'Ошибка удаления модератора' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getModers,
|
||||
addModer,
|
||||
changePassword,
|
||||
deleteModer
|
||||
};
|
||||
@@ -0,0 +1,174 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const logger = require('../logger');
|
||||
|
||||
const configEnvPath = path.join(__dirname, '..', 'config.env');
|
||||
const modersEnvPath = path.join(__dirname, '..', 'moders', 'config.env');
|
||||
const backendConfigPath = path.join(__dirname, '..', '../backend/config.json');
|
||||
|
||||
const parseEnv = async (filePath) => {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
const lines = content.split(/\r?\n/);
|
||||
const result = {};
|
||||
for (const line of lines) {
|
||||
if (!line.trim() || line.trim().startsWith('#')) continue;
|
||||
const idx = line.indexOf('=');
|
||||
if (idx === -1) continue;
|
||||
const key = line.slice(0, idx).trim();
|
||||
const value = line.slice(idx + 1).trim();
|
||||
result[key] = value;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const updateEnv = async (filePath, updates) => {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
const lines = content.split(/\r?\n/);
|
||||
const keys = Object.keys(updates);
|
||||
const updated = new Set();
|
||||
const newLines = lines.map(line => {
|
||||
if (!line.trim() || line.trim().startsWith('#') || !line.includes('=')) return line;
|
||||
const idx = line.indexOf('=');
|
||||
const key = line.slice(0, idx).trim();
|
||||
if (keys.includes(key)) {
|
||||
updated.add(key);
|
||||
return `${key}=${updates[key]}`;
|
||||
}
|
||||
return line;
|
||||
});
|
||||
for (const key of keys) {
|
||||
if (!updated.has(key)) {
|
||||
newLines.push(`${key}=${updates[key]}`);
|
||||
}
|
||||
}
|
||||
await fs.writeFile(filePath, newLines.join('\n'), 'utf-8');
|
||||
};
|
||||
|
||||
const getMysqlSettings = async (req, res) => {
|
||||
try {
|
||||
const env = await parseEnv(modersEnvPath);
|
||||
res.json({
|
||||
MYSQL_HOST: env.MYSQL_HOST || '',
|
||||
MYSQL_PORT: env.MYSQL_PORT || '',
|
||||
MYSQL_USER: env.MYSQL_USER || '',
|
||||
MYSQL_PASSWORD: env.MYSQL_PASSWORD || '',
|
||||
MYSQL_DATABASE: env.MYSQL_DATABASE || ''
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Ошибка чтения moders/config.env:', e);
|
||||
res.status(500).json({ message: 'Ошибка чтения moders/config.env' });
|
||||
}
|
||||
};
|
||||
|
||||
const updateMysqlSettings = async (req, res) => {
|
||||
const updates = req.body;
|
||||
if (updates.MYSQL_PASSWORD === '') {
|
||||
delete updates.MYSQL_PASSWORD;
|
||||
}
|
||||
if (Object.keys(updates).length === 0) {
|
||||
return res.status(400).json({ message: 'Нет данных для обновления' });
|
||||
}
|
||||
try {
|
||||
await updateEnv(modersEnvPath, updates);
|
||||
res.json({ message: 'Параметры MySQL обновлены' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка записи moders/config.env:', e);
|
||||
res.status(500).json({ message: 'Ошибка записи moders/config.env' });
|
||||
}
|
||||
};
|
||||
|
||||
const getCorsSettings = async (req, res) => {
|
||||
try {
|
||||
const env = await parseEnv(configEnvPath);
|
||||
const origins = (env.ALLOWED_ORIGINS || '').split(',').map(o => o.trim()).filter(Boolean);
|
||||
res.json({ ALLOWED_ORIGINS: origins });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка чтения ALLOWED_ORIGINS:', e);
|
||||
res.status(500).json({ message: 'Ошибка чтения ALLOWED_ORIGINS' });
|
||||
}
|
||||
};
|
||||
|
||||
const updateCorsSettings = async (req, res) => {
|
||||
const { ALLOWED_ORIGINS } = req.body;
|
||||
if (!Array.isArray(ALLOWED_ORIGINS) || !ALLOWED_ORIGINS.length) {
|
||||
return res.status(400).json({ message: 'Список ALLOWED_ORIGINS обязателен' });
|
||||
}
|
||||
try {
|
||||
await updateEnv(configEnvPath, { ALLOWED_ORIGINS: ALLOWED_ORIGINS.join(', ') });
|
||||
res.json({ message: 'ALLOWED_ORIGINS обновлён' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка записи ALLOWED_ORIGINS:', e);
|
||||
res.status(500).json({ message: 'Ошибка записи ALLOWED_ORIGINS' });
|
||||
}
|
||||
};
|
||||
|
||||
const getAdminServerSettings = async (req, res) => {
|
||||
try {
|
||||
const env = await parseEnv(configEnvPath);
|
||||
res.json({
|
||||
PORT: env.PORT || '',
|
||||
ADMIN_URL: env.ADMIN_URL || ''
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Ошибка чтения config.env (admin-server):', e);
|
||||
res.status(500).json({ message: 'Ошибка чтения config.env' });
|
||||
}
|
||||
};
|
||||
|
||||
const updateAdminServerSettings = async (req, res) => {
|
||||
const { PORT, ADMIN_URL } = req.body;
|
||||
if (!PORT || !ADMIN_URL) {
|
||||
return res.status(400).json({ message: 'PORT и ADMIN_URL обязательны' });
|
||||
}
|
||||
try {
|
||||
await updateEnv(configEnvPath, { PORT, ADMIN_URL });
|
||||
res.json({ message: 'Параметры admin-server обновлены' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка записи config.env (admin-server):', e);
|
||||
res.status(500).json({ message: 'Ошибка записи config.env' });
|
||||
}
|
||||
};
|
||||
|
||||
const getBackendServerSettings = async (req, res) => {
|
||||
try {
|
||||
const config = await fs.readJson(backendConfigPath);
|
||||
res.json({
|
||||
host: config.server?.host || '',
|
||||
port: config.server?.port || ''
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Ошибка чтения backend/config.json:', e);
|
||||
res.status(500).json({ message: 'Ошибка чтения backend/config.json' });
|
||||
}
|
||||
};
|
||||
|
||||
const updateBackendServerSettings = async (req, res) => {
|
||||
const { host, port } = req.body;
|
||||
if (!host || !port) {
|
||||
return res.status(400).json({ message: 'host и port обязательны' });
|
||||
}
|
||||
try {
|
||||
const config = await fs.readJson(backendConfigPath);
|
||||
config.server = config.server || {};
|
||||
config.server.host = host;
|
||||
config.server.port = port;
|
||||
await fs.writeJson(backendConfigPath, config, { spaces: 4 });
|
||||
res.json({ message: 'Параметры backend-server обновлены' });
|
||||
} catch (e) {
|
||||
logger.error('Ошибка записи backend/config.json:', e);
|
||||
res.status(500).json({ message: 'Ошибка записи backend/config.json' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getMssqlSettings,
|
||||
updateMssqlSettings,
|
||||
getMysqlSettings,
|
||||
updateMysqlSettings,
|
||||
getCorsSettings,
|
||||
updateCorsSettings,
|
||||
getAdminServerSettings,
|
||||
updateAdminServerSettings,
|
||||
getBackendServerSettings,
|
||||
updateBackendServerSettings
|
||||
};
|
||||
Reference in New Issue
Block a user