feat(tags): add tag management interfaces and update related schemas

This commit is contained in:
Abhimanyu Saharan
2026-02-12 18:35:48 +05:30
parent 2ebdead95b
commit 8d7d9da4e9
146 changed files with 6956 additions and 8645 deletions

View File

@@ -10,20 +10,20 @@ from app.api import agent as agent_api
from app.core.agent_auth import AgentAuthContext
from app.models.agents import Agent
from app.models.boards import Board
from app.models.task_tags import TaskTag
from app.models.tags import Tag
@dataclass
class _FakeExecResult:
tags: list[TaskTag]
tags: list[Tag]
def all(self) -> list[TaskTag]:
def all(self) -> list[Tag]:
return self.tags
@dataclass
class _FakeSession:
tags: list[TaskTag]
tags: list[Tag]
async def exec(self, _query: object) -> _FakeExecResult:
return _FakeExecResult(self.tags)
@@ -52,18 +52,18 @@ def _agent_ctx(*, board_id: UUID | None) -> AgentAuthContext:
@pytest.mark.asyncio
async def test_list_task_tags_returns_task_tag_refs() -> None:
async def test_list_tags_returns_tag_refs() -> None:
board = _board()
session = _FakeSession(
tags=[
TaskTag(
Tag(
id=uuid4(),
organization_id=board.organization_id,
name="Backend",
slug="backend",
color="0f172a",
),
TaskTag(
Tag(
id=uuid4(),
organization_id=board.organization_id,
name="Urgent",
@@ -73,7 +73,7 @@ async def test_list_task_tags_returns_task_tag_refs() -> None:
],
)
response = await agent_api.list_task_tags(
response = await agent_api.list_tags(
board=board,
session=session, # type: ignore[arg-type]
agent_ctx=_agent_ctx(board_id=board.id),
@@ -85,12 +85,12 @@ async def test_list_task_tags_returns_task_tag_refs() -> None:
@pytest.mark.asyncio
async def test_list_task_tags_rejects_cross_board_agent() -> None:
async def test_list_tags_rejects_cross_board_agent() -> None:
board = _board()
session = _FakeSession(tags=[])
with pytest.raises(HTTPException) as exc:
await agent_api.list_task_tags(
await agent_api.list_tags(
board=board,
session=session, # type: ignore[arg-type]
agent_ctx=_agent_ctx(board_id=uuid4()),

View File

@@ -7,8 +7,8 @@ from uuid import uuid4
import pytest
from app.models.task_tags import TaskTag
from app.services import task_tags
from app.models.tags import Tag
from app.services import tags
@dataclass
@@ -27,18 +27,18 @@ class _FakeSession:
self.added.append(value)
def test_slugify_task_tag_normalizes_text():
assert task_tags.slugify_task_tag("Release / QA") == "release-qa"
assert task_tags.slugify_task_tag(" ### ") == "tag"
def test_slugify_tag_normalizes_text():
assert tags.slugify_tag("Release / QA") == "release-qa"
assert tags.slugify_tag(" ### ") == "tag"
@pytest.mark.asyncio
async def test_validate_task_tag_ids_dedupes_and_preserves_order():
async def test_validate_tag_ids_dedupes_and_preserves_order():
org_id = uuid4()
tag_a = uuid4()
tag_b = uuid4()
session = _FakeSession(exec_results=[{tag_a, tag_b}])
result = await task_tags.validate_task_tag_ids(
result = await tags.validate_tag_ids(
session,
organization_id=org_id,
tag_ids=[tag_a, tag_b, tag_a],
@@ -47,13 +47,13 @@ async def test_validate_task_tag_ids_dedupes_and_preserves_order():
@pytest.mark.asyncio
async def test_validate_task_tag_ids_rejects_missing_tags():
async def test_validate_tag_ids_rejects_missing_tags():
org_id = uuid4()
tag_a = uuid4()
missing = uuid4()
session = _FakeSession(exec_results=[{tag_a}])
with pytest.raises(task_tags.HTTPException) as exc:
await task_tags.validate_task_tag_ids(
with pytest.raises(tags.HTTPException) as exc:
await tags.validate_tag_ids(
session,
organization_id=org_id,
tag_ids=[tag_a, missing],
@@ -63,7 +63,7 @@ async def test_validate_task_tag_ids_rejects_missing_tags():
@pytest.mark.asyncio
async def test_load_task_tag_state_groups_rows_by_task_id():
async def test_load_tag_state_groups_rows_by_task_id():
task_a = uuid4()
task_b = uuid4()
tag_a = uuid4()
@@ -73,7 +73,7 @@ async def test_load_task_tag_state_groups_rows_by_task_id():
[
(
task_a,
TaskTag(
Tag(
id=tag_a,
organization_id=uuid4(),
name="Backend",
@@ -83,7 +83,7 @@ async def test_load_task_tag_state_groups_rows_by_task_id():
),
(
task_a,
TaskTag(
Tag(
id=tag_b,
organization_id=uuid4(),
name="Urgent",
@@ -93,7 +93,7 @@ async def test_load_task_tag_state_groups_rows_by_task_id():
),
(
task_b,
TaskTag(
Tag(
id=tag_b,
organization_id=uuid4(),
name="Urgent",
@@ -104,7 +104,7 @@ async def test_load_task_tag_state_groups_rows_by_task_id():
],
],
)
state = await task_tags.load_task_tag_state(
state = await tags.load_tag_state(
session,
task_ids=[task_a, task_b],
)
@@ -114,12 +114,12 @@ async def test_load_task_tag_state_groups_rows_by_task_id():
@pytest.mark.asyncio
async def test_replace_task_tags_replaces_existing_links():
async def test_replace_tags_replaces_existing_links():
task_id = uuid4()
tag_a = uuid4()
tag_b = uuid4()
session = _FakeSession(exec_results=[None])
await task_tags.replace_task_tags(
await tags.replace_tags(
session,
task_id=task_id,
tag_ids=[tag_a, tag_b, tag_a],