journal: multi-select emotions and per-category writing templates
- Mood switches from a single enum column to a many-to-many JournalEntryMood table so an entry can carry several feelings at once; the vocabulary is trimmed to 9 named emotions (dropped the overlapping satisfaction scale) with unified noun-style labels. - Categories can define a content_template that pre-fills the "new entry" textarea when selected (only if the user hasn't started typing), seeded with a Story/Feelings/Decisions/Insights/Actions reflection template on the default "일상" category. - Fixes a real attribute-injection bug found while building the template feature: Jinja's built-in |tojson filter doesn't escape double quotes, which breaks a double-quoted x-data="..." attribute when the JSON payload contains one; added |forceescape and a regression test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@ JOURNAL_MOOD_OPTIONS = [
|
||||
]
|
||||
templates.env.globals["journal_mood_options"] = JOURNAL_MOOD_OPTIONS
|
||||
templates.env.globals["journal_mood_emoji"] = {m.value: emoji for m, emoji, _ in JOURNAL_MOOD_OPTIONS}
|
||||
# Jinja2 내장 |tojson 필터가 이 policy를 읽어서 json.dumps에 넘긴다 — 기본값(ensure_ascii=True)이면
|
||||
# 한글이 \uXXXX로 이스케이프돼 응답 본문에서 읽기 힘들어진다.
|
||||
templates.env.policies["json.dumps_kwargs"] = {"ensure_ascii": False}
|
||||
|
||||
|
||||
def _parse_moods(raw: str) -> list[JournalMood]:
|
||||
@@ -111,6 +114,7 @@ def journal_page(
|
||||
"tab": tab,
|
||||
"categories": categories,
|
||||
"category_id": category_id,
|
||||
"category_templates": {str(c.id): c.content_template or "" for c in categories},
|
||||
"entry_counts": journal_service.count_entries_by_category(db, current.id) if tab == "manage" else {},
|
||||
"on_this_day": journal_service.get_on_this_day(db, current.id, today),
|
||||
"prompt": journal_service.get_random_prompt(db),
|
||||
@@ -274,14 +278,18 @@ def delete_attachment_page(
|
||||
|
||||
@router.post("/journal/categories/new")
|
||||
def create_category_page(
|
||||
request: Request, name: str = Form(""), color: str | None = Form(None), db: Session = Depends(get_db)
|
||||
request: Request,
|
||||
name: str = Form(""),
|
||||
color: str | None = Form(None),
|
||||
content_template: str | None = Form(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
current = _current_user_or_redirect(request, db)
|
||||
if isinstance(current, RedirectResponse):
|
||||
return current
|
||||
|
||||
try:
|
||||
data = JournalCategoryCreate(name=name, color=color)
|
||||
data = JournalCategoryCreate(name=name, color=color, content_template=content_template)
|
||||
except ValidationError as exc:
|
||||
message = exc.errors()[0]["msg"].removeprefix("Value error, ")
|
||||
return HTMLResponse(message)
|
||||
@@ -303,6 +311,7 @@ def edit_category_page(
|
||||
category_id: int,
|
||||
name: str = Form(""),
|
||||
color: str | None = Form(None),
|
||||
content_template: str | None = Form(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
current = _current_user_or_redirect(request, db)
|
||||
@@ -314,7 +323,7 @@ def edit_category_page(
|
||||
return Response(status_code=404)
|
||||
|
||||
try:
|
||||
data = JournalCategoryCreate(name=name, color=color)
|
||||
data = JournalCategoryCreate(name=name, color=color, content_template=content_template)
|
||||
except ValidationError as exc:
|
||||
message = exc.errors()[0]["msg"].removeprefix("Value error, ")
|
||||
return HTMLResponse(message)
|
||||
|
||||
Reference in New Issue
Block a user