Feedback reply: light Markdown formatting (bold / bullets / heading)
Per Codex: a constrained Markdown-ish composer rather than contenteditable. * goodnews/markup.render_reply_html — escapes everything first, then introduces only a tiny whitelist (**bold**, - bullets, #/##/### headings, paragraphs, line breaks). No links, attributes, inline styles, or raw HTML passthrough. * feedback_replies.message_html column (+ live migration); replies store both the Markdown text and the rendered HTML. * email_send.send_feedback_reply now sends multipart text/plain + text/html (the sanitized render, wrapped in a trusted email template). * Frontend: textarea + a small toolbar (Bold / • List / H) that inserts Markdown; the reply thread renders the server-sanitized HTML. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -246,6 +246,7 @@ CREATE TABLE IF NOT EXISTS feedback_replies (
|
||||
feedback_id INTEGER NOT NULL REFERENCES feedback(id) ON DELETE CASCADE,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
message TEXT NOT NULL,
|
||||
message_html TEXT,
|
||||
sent_to TEXT NOT NULL,
|
||||
sent_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@@ -320,3 +321,8 @@ def _migrate(conn: sqlite3.Connection) -> None:
|
||||
fb_cols = {row["name"] for row in conn.execute("PRAGMA table_info(feedback)")}
|
||||
if fb_cols and "read_at" not in fb_cols:
|
||||
conn.execute("ALTER TABLE feedback ADD COLUMN read_at TEXT")
|
||||
|
||||
# feedback_replies.message_html (rendered Markdown subset) added later.
|
||||
rep_cols = {row["name"] for row in conn.execute("PRAGMA table_info(feedback_replies)")}
|
||||
if rep_cols and "message_html" not in rep_cols:
|
||||
conn.execute("ALTER TABLE feedback_replies ADD COLUMN message_html TEXT")
|
||||
|
||||
Reference in New Issue
Block a user