journal: real markdown editor (EasyMDE) with live preview toggle, fix default template
- Replace the plain textarea with EasyMDE (vendored locally, no CDN) for markdown authoring: syntax highlighting, smart list continuation, and a custom text-based toolbar (built-in EasyMDE toolbar icons require Font Awesome from a CDN, which this app doesn't use). unorderedListStyle is set to "-" to match the app's own template convention. - Add a preview/edit toggle button that swaps the editor for the exact same server-rendered markdown (via /journal/preview) shown after saving, instead of always showing both. - Fix create/edit entry routes to verify the submitted category_id actually belongs to the current user before inserting -- every other write path in this app already checked ownership; this one didn't (found while manually testing the new editor with a typo'd category id that happened to belong to someone else's category, which surfaced as an IntegrityError 500 instead of a clean 404-equivalent). - Fix the default "일상" category template: bare "-" bullet lines don't parse as list items in the markdown renderer (they need a trailing space), and the content_template validator was silently stripping that trailing space off on every save. Backfill migration updates any category still holding the old, broken template text. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
from app.markdown_utils import render_markdown
|
||||
|
||||
|
||||
def test_bold_and_heading_render_as_html():
|
||||
html = render_markdown("# 제목\n\n**굵게** 쓴 문장입니다")
|
||||
assert "<h1>제목</h1>" in html
|
||||
assert "<strong>굵게</strong>" in html
|
||||
|
||||
|
||||
def test_single_newline_becomes_line_break():
|
||||
html = render_markdown("첫째 줄\n둘째 줄")
|
||||
assert "<br" in html
|
||||
|
||||
|
||||
def test_list_renders_as_html_list():
|
||||
html = render_markdown("- 하나\n- 둘")
|
||||
assert "<ul>" in html
|
||||
assert "<li>하나</li>" in html
|
||||
|
||||
|
||||
def test_dash_and_star_bullets_render_identically():
|
||||
# 마크다운 글머리 기호는 -/*/+ 전부 동일하게 처리돼야 한다 — 에디터 쪽 기본 기호(unorderedListStyle)만
|
||||
# "-"로 바뀌었을 뿐, 렌더링 결과는 어떤 기호를 써도 같아야 한다.
|
||||
assert render_markdown("- 하나\n- 둘") == render_markdown("* 하나\n* 둘") == render_markdown("+ 하나\n+ 둘")
|
||||
|
||||
|
||||
def test_script_tag_is_stripped_not_executed():
|
||||
html = render_markdown('<script>alert("xss")</script>본문')
|
||||
assert "<script" not in html
|
||||
assert "alert" not in html or "<script" not in html # 태그는 지워지고 텍스트만 남아야 함
|
||||
|
||||
|
||||
def test_javascript_href_is_neutralized():
|
||||
html = render_markdown('[click me](javascript:alert(1))')
|
||||
assert "javascript:" not in html
|
||||
|
||||
|
||||
def test_onerror_attribute_is_stripped():
|
||||
html = render_markdown('<img src=x onerror="alert(1)">본문')
|
||||
assert "onerror" not in html
|
||||
assert "<img" not in html # img는 허용 태그 목록에 없음
|
||||
|
||||
|
||||
def test_allowed_link_href_is_preserved():
|
||||
html = render_markdown("[내 블로그](https://example.com)")
|
||||
assert 'href="https://example.com"' in html
|
||||
Reference in New Issue
Block a user