feat(评论): 添加Markdown支持和XSS过滤功能
添加marked和xss依赖包用于评论内容的Markdown渲染和XSS过滤 修改邮件模板以支持HTML格式的评论内容显示 更新数据库存储逻辑,同时保存原始文本和渲染后的HTML内容
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "^4.11.3",
|
||||
"marked": "^17.0.1",
|
||||
"nodemailer": "^7.0.12",
|
||||
"ua-parser-js": "^2.0.7"
|
||||
"ua-parser-js": "^2.0.7",
|
||||
"xss": "^1.0.15"
|
||||
}
|
||||
}
|
||||
|
||||
1484
cwd-comments-api/pnpm-lock.yaml
generated
1484
cwd-comments-api/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -67,9 +67,22 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
`).run();
|
||||
|
||||
// 3. 准备数据
|
||||
const content = checkContent(rawContent);
|
||||
const contentText = checkContent(rawContent);
|
||||
const author = checkContent(rawAuthor);
|
||||
|
||||
// Markdown 渲染与 XSS 过滤
|
||||
const html = await marked.parse(rawContent, { async: true });
|
||||
const contentHtml = xss(html, {
|
||||
whiteList: {
|
||||
...xss.whiteList,
|
||||
code: ['class'],
|
||||
span: ['class', 'style'],
|
||||
pre: ['class'],
|
||||
div: ['class', 'style'],
|
||||
img: ['src', 'alt', 'title', 'width', 'height', 'style']
|
||||
}
|
||||
});
|
||||
|
||||
console.log('PostComment:request', {
|
||||
postSlug: post_slug,
|
||||
hasParent: parentId !== null && parentId !== undefined,
|
||||
@@ -99,8 +112,8 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
`${uaResult.browser.name || ""} ${uaResult.browser.version || ""}`.trim(),
|
||||
uaResult.device.model || uaResult.device.type || "Desktop",
|
||||
userAgent,
|
||||
content,
|
||||
content,
|
||||
contentText,
|
||||
contentHtml,
|
||||
parentId || null,
|
||||
"approved" // 或者从环境变量读取默认状态
|
||||
).run();
|
||||
@@ -140,8 +153,8 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
const isAdminReply = !!adminEmail && email === adminEmail;
|
||||
|
||||
const parentComment = await c.env.CWD_DB.prepare(
|
||||
"SELECT author, email, content_text FROM Comment WHERE id = ?"
|
||||
).bind(parentId).first<{ author: string, email: string, content_text: string }>();
|
||||
"SELECT author, email, content_html FROM Comment WHERE id = ?"
|
||||
).bind(parentId).first<{ author: string, email: string, content_html: string }>();
|
||||
|
||||
if (parentComment && parentComment.email && parentComment.email !== email) {
|
||||
let canSendUserMail = true;
|
||||
@@ -163,9 +176,9 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
toEmail: parentComment.email,
|
||||
toName: parentComment.author,
|
||||
postTitle: data.post_title,
|
||||
parentComment: parentComment.content_text,
|
||||
parentComment: parentComment.content_html,
|
||||
replyAuthor: author,
|
||||
replyContent: content,
|
||||
replyContent: contentHtml,
|
||||
postUrl: data.post_url,
|
||||
}, notifySettings.smtp);
|
||||
await c.env.CWD_DB.prepare(
|
||||
@@ -187,7 +200,7 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
||||
postTitle: data.post_title,
|
||||
postUrl: data.post_url,
|
||||
commentAuthor: author,
|
||||
commentContent: content
|
||||
commentContent: contentHtml
|
||||
}, notifySettings.smtp);
|
||||
await c.env.CWD_DB.prepare(
|
||||
"INSERT INTO EmailLog (recipient, type, ip_address, created_at) VALUES (?, ?, ?, ?)"
|
||||
|
||||
@@ -255,11 +255,11 @@ export async function sendCommentReplyNotification(
|
||||
</p>
|
||||
<div style="margin:0 0 18px 0;padding:14px 16px;border-radius:10px;background:#f3f4f6;border:1px solid #e5e7eb;">
|
||||
<div style="font-size:12px;color:#6b7280;margin-bottom:6px;">你之前的评论</div>
|
||||
<div style="font-size:14px;color:#374151;white-space:pre-wrap;">${parentComment}</div>
|
||||
<div style="font-size:14px;color:#374151;">${parentComment}</div>
|
||||
</div>
|
||||
<div style="margin:0 0 24px 0;padding:14px 16px;border-radius:10px;background:#eff6ff;border:1px solid #bfdbfe;">
|
||||
<div style="font-size:12px;color:#1d4ed8;margin-bottom:6px;">最新回复</div>
|
||||
<div style="font-size:14px;color:#1f2937;white-space:pre-wrap;">${replyContent}</div>
|
||||
<div style="font-size:14px;color:#1f2937;">${replyContent}</div>
|
||||
</div>
|
||||
<div style="text-align:center;margin-bottom:8px;">
|
||||
<a href="${postUrl}" style="display:inline-block;padding:10px 22px;border-radius:999px;background:#2563eb;color:#ffffff;font-size:14px;font-weight:500;text-decoration:none;">
|
||||
@@ -327,7 +327,7 @@ export async function sendCommentNotification(
|
||||
</p>
|
||||
<div style="margin:0 0 18px 0;padding:14px 16px;border-radius:10px;background:#f9fafb;border:1px solid #e5e7eb;">
|
||||
<div style="font-size:12px;color:#6b7280;margin-bottom:6px;">评论内容</div>
|
||||
<div style="font-size:14px;color:#374151;white-space:pre-wrap;">${commentContent}</div>
|
||||
<div style="font-size:14px;color:#374151;">${commentContent}</div>
|
||||
</div>
|
||||
<div style="margin:0 0 8px 0;">
|
||||
<a href="${postUrl}" style="display:inline-block;padding:10px 22px;border-radius:999px;background:#047857;color:#ffffff;font-size:14px;font-weight:500;text-decoration:none;">
|
||||
|
||||
Reference in New Issue
Block a user