ваше сообщение коммита

This commit is contained in:
2026-01-13 20:14:20 +03:00
parent 77f1cea967
commit e93b9f3a8f
6 changed files with 484 additions and 17 deletions

View File

@@ -1590,6 +1590,107 @@ router.get('/blog/:slug', async (req, res) => {
}
});
// Получить публичную страницу по slug (для /content/published)
router.get('/published/:slug', async (req, res) => {
try {
const tableName = `admin_pages_simple`;
let slug = req.params.slug;
// Декодируем slug (на случай если он был закодирован)
try {
slug = decodeURIComponent(slug);
} catch (e) {
console.warn('[pages] Ошибка декодирования slug:', e.message);
}
// Валидация slug
if (!slug || typeof slug !== 'string' || slug.trim() === '') {
return res.status(400).json({ error: 'Невалидный slug' });
}
slug = slug.trim();
// Проверяем, есть ли таблица
const existsRes = await db.getQuery()(
`SELECT to_regclass($1) as exists`, [tableName]
);
if (!existsRes.rows[0].exists) {
return res.status(404).json({ error: 'Страница не найдена' });
}
// Получаем страницу по slug (без условия show_in_blog)
const { rows } = await db.getQuery()(
`SELECT * FROM ${tableName}
WHERE slug = $1
AND visibility = 'public'
AND status = 'published'
LIMIT 1`,
[slug]
);
console.log(`[pages] GET /published/:slug: поиск по slug "${slug}", найдено строк: ${rows.length}`);
if (rows.length === 0) {
// Пробуем найти страницу без учета регистра
const { rows: rowsCaseInsensitive } = await db.getQuery()(
`SELECT * FROM ${tableName}
WHERE LOWER(TRIM(slug)) = LOWER(TRIM($1))
AND visibility = 'public'
AND status = 'published'
LIMIT 1`,
[slug]
);
if (rowsCaseInsensitive.length > 0) {
console.log(`[pages] GET /published/:slug: найдено с учетом регистра, slug в БД: "${rowsCaseInsensitive[0].slug}"`);
return res.json(rowsCaseInsensitive[0]);
}
return res.status(404).json({ error: 'Страница не найдена' });
}
console.log(`[pages] GET /published/:slug: страница найдена, id: ${rows[0].id}, slug: ${rows[0].slug}`);
// Расшифровываем зашифрованные поля
const page = rows[0];
const encryptionUtils = require('../utils/encryptionUtils');
const encryptionKey = encryptionUtils.getEncryptionKey();
// Создаем объект с расшифрованными данными
const decryptedPage = { ...page };
// Расшифровываем поля, если они зашифрованы
const fieldsToDecrypt = ['title', 'summary', 'content', 'seo', 'settings'];
for (const field of fieldsToDecrypt) {
const encryptedField = `${field}_encrypted`;
if (page[encryptedField]) {
try {
const decryptResult = await db.getQuery()(
`SELECT decrypt_text($1, $2) as ${field}`,
[page[encryptedField], encryptionKey]
);
if (decryptResult.rows[0] && decryptResult.rows[0][field] !== null) {
decryptedPage[field] = decryptResult.rows[0][field];
}
} catch (decryptError) {
console.warn(`[pages] GET /published/:slug: ошибка расшифровки поля ${field}:`, decryptError.message);
if (page[field]) {
decryptedPage[field] = page[field];
}
}
} else if (page[field]) {
decryptedPage[field] = page[field];
}
}
res.json(decryptedPage);
} catch (error) {
console.error('Ошибка получения публичной страницы по slug:', error);
res.status(500).json({ error: 'Ошибка получения страницы' });
}
});
// Получить иерархическую структуру всех публичных страниц
router.get('/public/structure', async (req, res) => {
try {
@@ -1903,7 +2004,12 @@ router.get('/internal/all', async (req, res) => {
});
// Получить одну опубликованную страницу по id
router.get('/public/:id', async (req, res) => {
router.get('/public/:id', async (req, res, next) => {
// Пропускаем специальные endpoints
if (req.params.id === 'robots.txt' || req.params.id === 'sitemap.xml') {
return next();
}
try {
const tableName = `admin_pages_simple`;
@@ -1950,7 +2056,7 @@ Disallow: /admin/
Disallow: /content/create
Disallow: /content/edit
Sitemap: ${baseUrl}/pages/public/sitemap.xml
Sitemap: ${baseUrl}/api/pages/public/sitemap.xml
`;
res.setHeader('Content-Type', 'text/plain');
@@ -2005,7 +2111,8 @@ router.get('/public/sitemap.xml', async (req, res) => {
// Добавляем страницы блога с использованием slug
for (const page of blogPages) {
const lastmod = page.updated_at || page.created_at || new Date().toISOString();
const dateObj = page.updated_at || page.created_at || new Date();
const lastmod = dateObj instanceof Date ? dateObj.toISOString() : String(dateObj);
const pageUrl = page.slug
? `${baseUrl}/blog/${page.slug}`
: `${baseUrl}/blog?page=${page.id}`;
@@ -2021,22 +2128,25 @@ router.get('/public/sitemap.xml', async (req, res) => {
// Получаем остальные публичные страницы (без show_in_blog)
const { rows: otherPages } = await db.getQuery()(`
SELECT id, updated_at, created_at
SELECT id, slug, updated_at, created_at
FROM ${tableName}
WHERE status = 'published' AND visibility = 'public' AND (show_in_blog IS NULL OR show_in_blog = FALSE)
ORDER BY created_at DESC
`);
// Добавляем остальные публичные страницы
// Добавляем остальные публичные страницы с использованием slug
for (const page of otherPages) {
const lastmod = page.updated_at || page.created_at || new Date().toISOString();
const pageUrl = `${baseUrl}/content/published?page=${page.id}`;
sitemap += ` <url>
const dateObj = page.updated_at || page.created_at || new Date();
const lastmod = dateObj instanceof Date ? dateObj.toISOString() : String(dateObj);
const pageUrl = page.slug
? `${baseUrl}/content/published/${page.slug}`
: `${baseUrl}/content/published?page=${page.id}`;
sitemap += ` <url>
<loc>${escapeXml(pageUrl)}</loc>
<lastmod>${lastmod.split('T')[0]}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
<priority>0.7</priority>
</url>
`;
}