import { appendPlazaEmbedQuery } from './plaza-embed.mjs'; import { resolvePlazaCoverUrl } from './plaza-posts.mjs'; function plazaError(message, code) { return Object.assign(new Error(message), { code }); } export function escapePublicHtml(value) { return String(value ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } export async function loadPlazaPublicPost(pool, postId, { devPreview = false } = {}) { const [rows] = await pool.query( `SELECT pp.id, pp.title, pp.summary, pp.status, pp.cover_url, pr.public_url, pr.status AS publication_status FROM plaza_posts pp JOIN h5_publish_records pr ON pr.id = pp.publication_id WHERE pp.id = ? AND pp.status != 'hidden' LIMIT 1`, [postId], ); const row = rows[0]; if (!row) throw plazaError('帖子不存在或已隐藏', 'POST_NOT_FOUND'); if (row.publication_status !== 'online') { throw plazaError('关联发布未上线', 'PUBLICATION_NOT_ONLINE'); } if (row.status !== 'published') { const allowPreview = devPreview && row.status === 'pending_review'; if (!allowPreview) throw plazaError('帖子不存在或已隐藏', 'POST_NOT_FOUND'); } return row; } export function buildPublicationUrl(publicUrl, portalBase) { const value = String(publicUrl ?? '').trim(); if (!value) return null; if (/^https?:\/\//i.test(value)) return value; const base = String(portalBase ?? '').replace(/\/$/, ''); if (value.startsWith('/')) return `${base}${value}`; return `${base}/${value.replace(/^\/+/, '')}`; } export function renderPlazaPostRedirectHtml(post, targetUrl, { preview = false } = {}) { const title = escapePublicHtml(post.title); const summary = escapePublicHtml(post.summary); const iframeUrl = appendPlazaEmbedQuery(targetUrl); const safeTarget = escapePublicHtml(targetUrl); const safeIframeUrl = escapePublicHtml(iframeUrl); const previewNote = preview ? '

开发预览:该帖子尚未审核通过,仅本地可见。

' : ''; return ` ${title}
返回广场 单独打开原页面

${title}

${summary ? `

${summary}

` : ''} ${previewNote}

若页面未正常加载,可点击这里直接打开

`; } export function attachPlazaPublicRoutes(app, { pool, portalBase, devPreview = false }) { app.get('/plaza/p/:postId', async (req, res) => { if (!pool) return res.status(503).send('Plaza 未启用'); try { const post = await loadPlazaPublicPost(pool, req.params.postId, { devPreview }); const targetUrl = buildPublicationUrl(post.public_url, portalBase); if (!targetUrl) return res.status(404).send('内容链接不存在'); res.set('Content-Type', 'text/html; charset=utf-8'); res.set('Cache-Control', post.status === 'published' ? 'public, max-age=60' : 'private, no-store'); return res.send( renderPlazaPostRedirectHtml(post, targetUrl, { preview: devPreview && post.status === 'pending_review', }), ); } catch (error) { if (error?.code === 'POST_NOT_FOUND') return res.status(404).send('帖子不存在或已隐藏'); if (error?.code === 'PUBLICATION_NOT_ONLINE') return res.status(404).send('关联发布未上线'); return res.status(500).send('页面加载失败'); } }); app.get(['/plaza', '/plaza/'], async (_req, res) => { if (!pool) return res.status(503).send('Plaza 未启用'); try { const [categoryRows] = await pool.query( `SELECT slug, name, icon FROM plaza_categories WHERE is_active = 1 ORDER BY sort_order ASC`, ); const [postRows] = await pool.query( `SELECT pp.id, pp.title, pp.summary, pp.cover_url, pp.published_at, pr.public_url AS public_url, c.name AS category_name, c.slug AS category_slug, c.icon AS category_icon, u.slug AS user_slug, u.display_name AS user_display_name FROM plaza_posts pp JOIN plaza_categories c ON c.id = pp.category_id JOIN h5_publish_records pr ON pr.id = pp.publication_id JOIN h5_users u ON u.id = pp.user_id WHERE pp.status = 'published' ORDER BY pp.hot_score DESC, pp.id DESC LIMIT 24`, ); const cards = postRows .map((post) => { const title = escapePublicHtml(post.title); const summary = escapePublicHtml(post.summary); const author = escapePublicHtml(post.user_display_name || post.user_slug); const category = escapePublicHtml(`${post.category_icon ?? ''} ${post.category_name ?? ''}`.trim()); const coverUrl = escapePublicHtml(resolvePlazaCoverUrl(post.cover_url, post.public_url)); const href = `/plaza/p/${encodeURIComponent(post.id)}`; return `
${title} 封面预览
${category}${author}

${title}

${summary ? `

${summary}

` : ''}
`; }) .join(''); const categoryLinks = categoryRows .map( (category) => `${escapePublicHtml(`${category.icon ?? ''} ${category.name}`.trim())}`, ) .join(''); res.set('Content-Type', 'text/html; charset=utf-8'); res.set('Cache-Control', 'public, max-age=30'); return res.send(` TKMind 发现广场

TKMind Plaza

发现广场

浏览公开发布的 MindSpace 作品。点击卡片进入帖子详情页。

${categoryLinks ? `
${categoryLinks}
` : ''}
${ cards ? `
${cards}
` : '
广场还没有已发布的帖子。发布到 Plaza 并通过审核后会出现在这里。
' }
`); } catch { return res.status(500).send('广场首页加载失败'); } }); }