- Introduced common.js for shared functions including API calls, error reporting, and UI helpers. - Implemented feedback.js for the feedback reporting page, including form handling and displaying feedback status. - Added layout.js for managing galaxy and section layouts in the visualization. - Created login.js for user authentication with session management. - Developed search.js for term searching based on user input and synonyms. - Implemented signup.js for user registration with validation and immediate login.
101 lines
4.5 KiB
Python
101 lines
4.5 KiB
Python
"""피드백·오류를 터미널에서 확인하고 처리하는 도구.
|
||
|
||
.venv/bin/python -m server.cli feedback # 처리 대기(new, in_progress) 목록
|
||
.venv/bin/python -m server.cli feedback --all # 전체
|
||
.venv/bin/python -m server.cli show 12 # 한 건 자세히 (대상 용어 현재 값 포함)
|
||
.venv/bin/python -m server.cli resolve 12 "정의 문장을 교재 p.188 기준으로 수정"
|
||
.venv/bin/python -m server.cli status 12 in_progress
|
||
.venv/bin/python -m server.cli term 지역사회 간호사정 # 용어 현재 값 확인
|
||
"""
|
||
import argparse
|
||
import json
|
||
|
||
from . import db
|
||
|
||
|
||
def _print_fb(r, full=False):
|
||
tgt = f" [{r['target_type']}:{r['target_label'] or r['target_id']}]" if r["target_type"] else ""
|
||
occ = f" ×{r['occurrences']}" if (r["occurrences"] or 1) > 1 else ""
|
||
print(f"#{r['id']:<4} {r['status']:<11} {r['kind']:<12} {r['category'] or ''}{tgt}{occ} {r['created_at']}")
|
||
msg = r["message"] or ""
|
||
print(" " + (msg if full else msg[:160].replace("\n", " ")))
|
||
if r["suggestion"]:
|
||
print(" → 제안: " + (r["suggestion"] if full else r["suggestion"][:160]))
|
||
if full:
|
||
for k in ("page_url", "reporter", "contact", "admin_note", "resolution", "handled_by", "user_agent"):
|
||
if r[k]:
|
||
print(f" {k}: {r[k]}")
|
||
if r["context"]:
|
||
print(" context:", r["context"][:3000])
|
||
|
||
|
||
def main():
|
||
ap = argparse.ArgumentParser()
|
||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||
f = sub.add_parser("feedback")
|
||
f.add_argument("--all", action="store_true")
|
||
f.add_argument("--kind")
|
||
s = sub.add_parser("show")
|
||
s.add_argument("id", type=int)
|
||
r = sub.add_parser("resolve")
|
||
r.add_argument("id", type=int)
|
||
r.add_argument("resolution")
|
||
st = sub.add_parser("status")
|
||
st.add_argument("id", type=int)
|
||
st.add_argument("status", choices=["new", "in_progress", "resolved", "rejected", "duplicate"])
|
||
t = sub.add_parser("term")
|
||
t.add_argument("name", nargs="+")
|
||
a = ap.parse_args()
|
||
con = db.connect()
|
||
|
||
if a.cmd == "feedback":
|
||
where = "1=1" if a.all else "status IN ('new','in_progress')"
|
||
args = []
|
||
if a.kind:
|
||
where += " AND kind=?"
|
||
args.append(a.kind)
|
||
rows = con.execute(f"SELECT * FROM feedback WHERE {where} ORDER BY id", args).fetchall()
|
||
print(f"{len(rows)}건")
|
||
for r in rows:
|
||
_print_fb(r)
|
||
elif a.cmd == "show":
|
||
r = con.execute("SELECT * FROM feedback WHERE id=?", (a.id,)).fetchone()
|
||
if not r:
|
||
return print("없음")
|
||
_print_fb(r, full=True)
|
||
if r["target_type"] == "term" and r["target_id"]:
|
||
_show_term(con, r["target_id"])
|
||
elif a.cmd in ("resolve", "status"):
|
||
status = "resolved" if a.cmd == "resolve" else a.status
|
||
with con:
|
||
if a.cmd == "resolve":
|
||
con.execute("UPDATE feedback SET status=?, resolution=?, handled_by='developer', updated_at=? WHERE id=?",
|
||
(status, a.resolution, db.now(), a.id))
|
||
else:
|
||
con.execute("UPDATE feedback SET status=?, handled_by='developer', updated_at=? WHERE id=?", (status, db.now(), a.id))
|
||
db.audit(con, "developer(cli)", "update", "feedback", str(a.id), None, {"status": status})
|
||
print("완료")
|
||
elif a.cmd == "term":
|
||
name = " ".join(a.name)
|
||
r = con.execute("SELECT term_id FROM terms WHERE name=? OR term_id=?", (name, name)).fetchone()
|
||
if not r:
|
||
rows = con.execute("SELECT term_id,name FROM terms WHERE name LIKE ? LIMIT 20", (f"%{name}%",)).fetchall()
|
||
for x in rows:
|
||
print(x["term_id"], x["name"])
|
||
return
|
||
_show_term(con, r["term_id"])
|
||
|
||
|
||
def _show_term(con, term_id):
|
||
t = db.row(con.execute("SELECT * FROM terms WHERE term_id=?", (term_id,)).fetchone())
|
||
print("\n--- 대상 용어 현재 값")
|
||
print(json.dumps({k: t[k] for k in ("term_id", "name", "aliases", "galaxy_id", "section_id", "definition_text",
|
||
"definition_book", "definition_page", "easy", "example", "review_status")},
|
||
ensure_ascii=False, indent=1))
|
||
for s in con.execute("SELECT book_id,page,path,snippet FROM term_sources WHERE term_id=?", (term_id,)):
|
||
print(f" 출처 {s['book_id']} p.{s['page']} {s['path']}\n {(s['snippet'] or '')[:150]}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|