From f7622e13d5da79020848b86cc13d4e21f931ad65 Mon Sep 17 00:00:00 2001 From: markov Date: Mon, 2 Mar 2026 09:02:53 +0100 Subject: [PATCH] UUID refactoring: remove slug from JWT, mentions stored as IDs, WS filtering by member_id only --- src/tracker/api/auth.py | 5 ++--- src/tracker/api/tasks.py | 8 ++++---- src/tracker/ws/handler.py | 3 ++- src/tracker/ws/manager.py | 19 ++++--------------- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/tracker/api/auth.py b/src/tracker/api/auth.py index 036fa60..914fbbc 100644 --- a/src/tracker/api/auth.py +++ b/src/tracker/api/auth.py @@ -34,10 +34,9 @@ def verify_password(password: str, hashed: str) -> bool: return hashlib.sha256(password.encode()).hexdigest() == hashed -def create_jwt(member_id: str, slug: str, role: str) -> str: +def create_jwt(member_id: str, role: str) -> str: payload = { "sub": str(member_id), - "slug": slug, "role": role, "exp": datetime.now(timezone.utc) + timedelta(hours=JWT_EXPIRE_HOURS), } @@ -111,7 +110,7 @@ async def login(req: LoginRequest, db: AsyncSession = Depends(get_db)): member.password_hash = hash_password(req.password) await db.commit() - token = create_jwt(str(member.id), member.slug, member.role) + token = create_jwt(str(member.id), member.role) return LoginResponse( token=token, member_id=str(member.id), diff --git a/src/tracker/api/tasks.py b/src/tracker/api/tasks.py index 53ecfd3..f842c03 100644 --- a/src/tracker/api/tasks.py +++ b/src/tracker/api/tasks.py @@ -109,8 +109,8 @@ async def _system_message( actor_slug = actor.slug if actor else "system" actor_brief = MemberBrief(id=str(actor.id), slug=actor.slug, name=actor.name) if actor else None - # Mentioned members as slugs (DB storage) and briefs (broadcast) - mention_slugs = [m.slug for m in (mentioned_members or [])] + # Mentioned members as IDs (DB storage) and briefs (broadcast) + mention_ids = [str(m.id) for m in (mentioned_members or [])] mention_briefs = [MemberBrief(id=str(m.id), slug=m.slug, name=m.name) for m in (mentioned_members or [])] chat_id = await _get_project_chat_id(db, task.project_id) @@ -122,7 +122,7 @@ async def _system_message( author_id=None, actor_id=actor.id if actor else None, content=task_text, - mentions=mention_slugs, # still stored as slugs in DB for compat + mentions=mention_ids, # still stored as slugs in DB for compat ) db.add(task_msg) @@ -135,7 +135,7 @@ async def _system_message( author_id=None, actor_id=actor.id if actor else None, content=chat_text, - mentions=mention_slugs, + mentions=mention_ids, ) db.add(chat_msg) diff --git a/src/tracker/ws/handler.py b/src/tracker/ws/handler.py index ca0eaff..6dd4369 100644 --- a/src/tracker/ws/handler.py +++ b/src/tracker/ws/handler.py @@ -31,7 +31,8 @@ def _to_member_brief(member: Member) -> MemberBrief: def _to_message_out(msg: Message, author: Member | None = None) -> MessageOut: - mention_briefs = [MemberBrief(id="", slug=s, name=s) for s in (msg.mentions or [])] + # mentions stored as member IDs in DB + mention_briefs = [MemberBrief(id=mid, slug="", name="") for mid in (msg.mentions or [])] return MessageOut( id=str(msg.id), chat_id=str(msg.chat_id) if msg.chat_id else None, diff --git a/src/tracker/ws/manager.py b/src/tracker/ws/manager.py index 13e2057..a53f342 100644 --- a/src/tracker/ws/manager.py +++ b/src/tracker/ws/manager.py @@ -97,19 +97,13 @@ class ConnectionManager: message["project_id"] = project_id raw_mentions = message.get("mentions", []) - # Extract member IDs from mentions (objects or strings) + # Extract member IDs from mentions mention_ids: set[str] = set() - mention_slugs: set[str] = set() for m in raw_mentions: if isinstance(m, dict): if m.get("id"): mention_ids.add(m["id"]) - if m.get("slug"): - mention_slugs.add(m["slug"]) - elif isinstance(m, str): - mention_slugs.add(m) - content = message.get("content", "") author_type = message.get("author_type", "") payload = {"type": event_type or WSEventType.MESSAGE_NEW, "data": message} @@ -132,21 +126,16 @@ class ConnectionManager: if client.chat_listen == ListenMode.NONE: continue - # System messages: only if agent is mentioned (by ID or slug for compat) + # System messages: only if agent is mentioned (by ID) if author_type == AuthorType.SYSTEM: - mentioned = ( - client.member_id in mention_ids or - client.member_slug in mention_slugs or - f"@{client.member_slug}" in content # text fallback for compat - ) - if not mentioned: + if client.member_id not in mention_ids: continue await self.send_to_session(session_id, payload) continue # Regular messages: chat_listen filter if client.chat_listen in (ListenMode.MENTIONS, ListenMode.ASSIGNED): - if client.member_id not in mention_ids and client.member_slug not in mention_slugs: + if client.member_id not in mention_ids: continue await self.send_to_session(session_id, payload)