Files
DLE/backend/routes/pages.js

322 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
const express = require('express');
const router = express.Router();
const db = require('../db');
const FIELDS_TO_EXCLUDE = ['image', 'tags'];
// Проверка и создание общей таблицы для всех админов
async function ensureAdminPagesTable(fields) {
fields = fields.filter(f => !FIELDS_TO_EXCLUDE.includes(f));
const tableName = `admin_pages_simple`;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
}
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) {
// Формируем SQL для создания таблицы с зашифрованными полями
let columns = [
'id SERIAL PRIMARY KEY',
'author_address_encrypted TEXT NOT NULL', // Зашифрованный адрес автора
'created_at TIMESTAMP DEFAULT NOW()',
'updated_at TIMESTAMP DEFAULT NOW()'
];
for (const field of fields) {
columns.push(`"${field}_encrypted" TEXT`);
}
const sql = `CREATE TABLE ${tableName} (${columns.join(', ')})`;
await db.getQuery()(sql);
} else {
// Проверяем, есть ли все нужные столбцы, и добавляем недостающие
const colRes = await db.getQuery()(
`SELECT column_name FROM information_schema.columns WHERE table_name = $1`, [tableName]
);
const existingCols = colRes.rows.map(r => r.column_name);
// Добавляем поле author_address_encrypted если его нет
if (!existingCols.includes('author_address_encrypted')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN author_address_encrypted TEXT`
);
}
for (const field of fields) {
const encryptedField = `${field}_encrypted`;
if (!existingCols.includes(encryptedField)) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN "${encryptedField}" TEXT`
);
}
}
}
return { tableName, encryptionKey };
}
// Создать страницу (только для админа)
router.post('/', async (req, res) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.address) {
return res.status(403).json({ error: 'Требуется подключение кошелька' });
}
// Проверяем роль админа через токены в кошельке
const authService = require('../services/auth-service');
const isAdmin = await authService.checkAdminTokens(req.session.address);
if (!isAdmin) {
return res.status(403).json({ error: 'Only admin can create pages' });
}
const authorAddress = req.session.address;
const fields = Object.keys(req.body).filter(f => !FIELDS_TO_EXCLUDE.includes(f));
const tableName = `admin_pages_simple`;
// Формируем SQL для вставки данных
const colNames = ['author_address', ...fields].join(', ');
const values = [authorAddress, ...fields.map(f => {
const value = typeof req.body[f] === 'object' ? JSON.stringify(req.body[f]) : req.body[f];
return value || '';
})];
const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
const sql = `INSERT INTO ${tableName} (${colNames}) VALUES (${placeholders}) RETURNING *`;
const { rows } = await db.getQuery()(sql, values);
res.json(rows[0]);
});
// Получить все страницы админов
router.get('/', async (req, res) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.address) {
return res.status(403).json({ error: 'Требуется подключение кошелька' });
}
// Проверяем роль админа через токены в кошельке
const authService = require('../services/auth-service');
const isAdmin = await authService.checkAdminTokens(req.session.address);
if (!isAdmin) {
return res.status(403).json({ error: 'Only admin can view pages' });
}
const tableName = `admin_pages_simple`;
// Получаем ключ шифрования
const fs = require('fs');
const path = require('path');
let encryptionKey = 'default-key';
try {
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
if (fs.existsSync(keyPath)) {
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
}
} catch (keyError) {
// console.error('Error reading encryption key:', keyError);
}
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) return res.json([]);
// Получаем все страницы всех админов
const { rows } = await db.getQuery()(`
SELECT * FROM ${tableName}
ORDER BY created_at DESC
`);
res.json(rows);
});
// Получить одну страницу по id (только для админа)
router.get('/:id', async (req, res) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.address) {
return res.status(403).json({ error: 'Требуется подключение кошелька' });
}
// Проверяем роль админа через токены в кошельке
const authService = require('../services/auth-service');
const isAdmin = await authService.checkAdminTokens(req.session.address);
if (!isAdmin) {
return res.status(403).json({ error: 'Only admin can view pages' });
}
const tableName = `admin_pages_simple`;
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) return res.status(404).json({ error: 'Page table not found' });
const { rows } = await db.getQuery()(
`SELECT * FROM ${tableName} WHERE id = $1`,
[req.params.id]
);
if (!rows.length) return res.status(404).json({ error: 'Page not found' });
res.json(rows[0]);
});
// Редактировать страницу по id
router.patch('/:id', async (req, res) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.address) {
return res.status(403).json({ error: 'Требуется подключение кошелька' });
}
// Проверяем роль админа через токены в кошельке
const authService = require('../services/auth-service');
const isAdmin = await authService.checkAdminTokens(req.session.address);
if (!isAdmin) {
return res.status(403).json({ error: 'Only admin can edit pages' });
}
const tableName = `admin_pages_simple`;
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) return res.status(404).json({ error: 'Page table not found' });
const fields = Object.keys(req.body).filter(f => !FIELDS_TO_EXCLUDE.includes(f));
if (!fields.length) return res.status(400).json({ error: 'No fields to update' });
const filteredBody = {};
fields.forEach(f => {
// Преобразуем объекты в JSON строки
filteredBody[f] = typeof req.body[f] === 'object' ? JSON.stringify(req.body[f]) : req.body[f];
});
const setClause = fields.map((f, i) => `"${f}" = $${i + 1}`).join(', ');
const values = Object.values(filteredBody);
values.push(req.params.id);
const sql = `UPDATE ${tableName} SET ${setClause}, updated_at = NOW() WHERE id = $${fields.length + 1} RETURNING *`;
const { rows } = await db.getQuery()(sql, values);
if (!rows.length) return res.status(404).json({ error: 'Page not found' });
res.json(rows[0]);
});
// Удалить страницу по id
router.delete('/:id', async (req, res) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.address) {
return res.status(403).json({ error: 'Требуется подключение кошелька' });
}
// Проверяем роль админа через токены в кошельке
const authService = require('../services/auth-service');
const isAdmin = await authService.checkAdminTokens(req.session.address);
if (!isAdmin) {
return res.status(403).json({ error: 'Only admin can delete pages' });
}
const tableName = `admin_pages_simple`;
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) return res.status(404).json({ error: 'Page table not found' });
const { rows } = await db.getQuery()(
`DELETE FROM ${tableName} WHERE id = $1 RETURNING *`,
[req.params.id]
);
if (!rows.length) return res.status(404).json({ error: 'Page not found' });
res.json(rows[0]);
});
// Публичные маршруты для просмотра страниц (доступны всем пользователям)
// Получить все опубликованные страницы
router.get('/public/all', async (req, res) => {
try {
const tableName = `admin_pages_simple`;
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) {
return res.json([]);
}
// Получаем все опубликованные страницы всех админов
const { rows } = await db.getQuery()(`
SELECT * FROM ${tableName}
WHERE status = 'published'
ORDER BY created_at DESC
`);
res.json(rows);
} catch (error) {
console.error('Ошибка получения публичных страниц:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
}
});
// Получить одну опубликованную страницу по id
router.get('/public/:id', async (req, res) => {
try {
const tableName = `admin_pages_simple`;
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) {
return res.status(404).json({ error: 'Страница не найдена или не опубликована' });
}
// Ищем страницу среди всех админов
const { rows } = await db.getQuery()(`
SELECT * FROM ${tableName}
WHERE id = $1 AND status = 'published'
`, [req.params.id]);
if (rows.length > 0) {
return res.json(rows[0]);
}
res.status(404).json({ error: 'Страница не найдена или не опубликована' });
} catch (error) {
console.error('Ошибка получения публичной страницы:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
}
});
module.exports = router;