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