DRY across the "organize/recall" backend surface:
- serialize.py (new): serialize_label(label) — the base {id,name,color}
shape. labels.py builds on it (adds count); sync deltas will (S4).
- labeling.py (new): resolve_owned_label_ids() + reconcile_manual_labels()
— the "set a note's MANUAL (picker) labels, leave the via_tag rows alone"
logic was duplicated line-for-line between notes.set_note_labels and
sync._apply_note_manual_labels. Now one home; both adopt it (removes the
redundant `chosen`==owned recompute in notes). Behavior-preserving.
- labels.py: json_error/not_found/parse_uuid, colors.normalize_color, and
serialize_label; dropped local LABEL_COLORS + _normalize_label_color
(NOTE_COLORS is the single palette) and `import uuid` (rule 22).
- saved_filters.py: json_error/not_found/parse_uuid for its 2 uuid parses
+ error shapes.
- graph.py: no change — no error/uuid/palette-normalize duplication to fold.
Test: DB-free test_serialize_label_shape guards the base shape.
sync.py's reconciliation swap is behavior-identical; operator-verified on
deploy (no Postgres CI lane).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
47 lines
1.2 KiB
Python
47 lines
1.2 KiB
Python
import uuid
|
|
|
|
import pytest
|
|
|
|
from thoughtsync.app import create_app
|
|
from thoughtsync.models.label import Label
|
|
from thoughtsync.serialize import serialize_label
|
|
|
|
|
|
@pytest.fixture
|
|
def app():
|
|
return create_app()
|
|
|
|
|
|
def test_serialize_label_shape():
|
|
# The base {id, name, color} shape the labels API and (S4) sync deltas both build on.
|
|
lid = uuid.uuid4()
|
|
assert serialize_label(Label(id=lid, name="ideas", color="teal")) == {
|
|
"id": str(lid),
|
|
"name": "ideas",
|
|
"color": "teal",
|
|
}
|
|
|
|
|
|
async def test_labels_requires_auth(app):
|
|
client = app.test_client()
|
|
resp = await client.get("/api/labels")
|
|
assert resp.status_code == 401
|
|
|
|
|
|
async def test_set_note_labels_requires_auth(app):
|
|
client = app.test_client()
|
|
resp = await client.put(
|
|
"/api/notes/00000000-0000-0000-0000-000000000000/labels",
|
|
json={"label_ids": []},
|
|
)
|
|
assert resp.status_code == 401
|
|
|
|
|
|
async def test_merge_label_requires_auth(app):
|
|
client = app.test_client()
|
|
resp = await client.post(
|
|
"/api/labels/00000000-0000-0000-0000-000000000000/merge",
|
|
json={"into": "00000000-0000-0000-0000-000000000001"},
|
|
)
|
|
assert resp.status_code == 401
|