feat: 스니펫 공용화 — 서버 PostgreSQL 테이블 + API, 프론트는 브릿지 대신 HTTP
결정(9/21): 공용 하나, 개인 로컬 없음.
- backend apps/snippets: Snippet(name PK·desc·body·category) + SnippetUsage(사람별 count/last_used).
GET/POST /api/v1/snippets, PUT/DELETE /snippets/{name}, POST /snippets/{name}/use — 옛 브릿지 5개와 1:1,
이름 정규화·중복 409·빈 내용 400 규칙 동일. import_snippets 커맨드로 옛 snippets.db 적재. 테스트 3개
- frontend snippets.api.ts 만 HTTP 로 교체(훅·페이지·타입 무변경). 테스트 axios-mock-adapter 로
- ponytail: Tauri 로컬 SQLite 커맨드는 미사용 상태로 남김. 지울 때 Rust+브릿지 테스트 함께
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
df5feaad3a
commit
2e7bae4c06
@@ -0,0 +1,48 @@
|
||||
"""/api/v1/snippets — 공용 스니펫 CRUD + 내 usage."""
|
||||
|
||||
import sqlite3
|
||||
|
||||
from django.core.management import call_command
|
||||
|
||||
from apps.snippets.models import Snippet
|
||||
|
||||
|
||||
def test_crud_and_usage(auth_api, user):
|
||||
r = auth_api.post("/api/v1/snippets", {"name": " alv filter ", "body": "x", "category": ""}, format="json")
|
||||
assert r.status_code == 201 and r.json()["data"]["name"] == "ALV_FILTER" and r.json()["data"]["category"] == "코드"
|
||||
assert auth_api.post("/api/v1/snippets", {"name": "ALV_FILTER", "body": "y"}, format="json").status_code == 409
|
||||
assert auth_api.post("/api/v1/snippets", {"name": "", "body": "y"}, format="json").status_code == 400
|
||||
assert auth_api.post("/api/v1/snippets", {"name": "B", "body": " "}, format="json").status_code == 400
|
||||
|
||||
r = auth_api.put("/api/v1/snippets/alv_filter", {"desc": "d", "body": "z", "category": "ALV"}, format="json")
|
||||
assert r.status_code == 200 and r.json()["data"]["body"] == "z" and r.json()["data"]["category"] == "ALV"
|
||||
|
||||
for _ in range(2):
|
||||
r = auth_api.post("/api/v1/snippets/ALV_FILTER/use")
|
||||
assert r.json()["data"]["usageCount"] == 2 and r.json()["data"]["lastUsed"] > 0
|
||||
lst = auth_api.get("/api/v1/snippets").json()["data"]
|
||||
assert lst[0]["name"] == "ALV_FILTER" and lst[0]["usageCount"] == 2
|
||||
|
||||
assert auth_api.delete("/api/v1/snippets/ALV_FILTER").json()["data"] == {"name": "ALV_FILTER"}
|
||||
assert auth_api.get("/api/v1/snippets").json()["data"] == []
|
||||
|
||||
|
||||
def test_usage_is_per_user(auth_api, user, django_user_model, api):
|
||||
Snippet.objects.create(name="S", body="b")
|
||||
auth_api.post("/api/v1/snippets/S/use")
|
||||
other = django_user_model.objects.create_user(username="o@x.com", email="o@x.com", password="x")
|
||||
api.force_authenticate(other)
|
||||
assert api.get("/api/v1/snippets").json()["data"][0]["usageCount"] == 0
|
||||
|
||||
|
||||
def test_import_from_sqlite(db, tmp_path):
|
||||
p = tmp_path / "old.db"
|
||||
con = sqlite3.connect(p)
|
||||
con.execute("CREATE TABLE snippets(name TEXT PRIMARY KEY, desc TEXT, body TEXT, category TEXT)")
|
||||
con.executemany("INSERT INTO snippets VALUES (?,?,?,?)", [("a b", "d", "x", "코드"), ("EMPTY", "", " ", "코드"), ("C", "", "y", "")])
|
||||
con.commit()
|
||||
call_command("import_snippets", str(p))
|
||||
names = {s.name: s for s in Snippet.objects.all()}
|
||||
assert set(names) == {"A_B", "C"} and names["C"].category == "코드"
|
||||
call_command("import_snippets", str(p)) # 재실행해도 중복 없음
|
||||
assert Snippet.objects.count() == 2
|
||||
Reference in New Issue
Block a user