"""Action read-models for workspace — tenant-scoped, actor-assignment based.""" from __future__ import annotations from typing import Any from psycopg2.extras import RealDictCursor from db import get_connection from services.actions import OPEN_ACTION_STATUSES, _attach_assignments, _serialize_row from tenant_context import TenantContext def _require_actor(ctx: TenantContext) -> str: if not ctx.actor_id: raise ValueError("Kein Actor im TenantContext") return ctx.actor_id def _list_assigned_actions( *, tenant_id: str, actor_id: str, statuses: list[str], ) -> list[dict[str, Any]]: conn = get_connection() try: with conn.cursor(cursor_factory=RealDictCursor) as cur: cur.execute( """ SELECT a.id, a.tenant_id, a.initiative_id, a.title, a.description, a.status, a.priority, a.created_at, a.updated_at, i.title AS initiative_title FROM actions a JOIN action_assignments aa ON aa.action_id = a.id AND aa.tenant_id = a.tenant_id JOIN initiatives i ON i.id = a.initiative_id AND i.tenant_id = a.tenant_id WHERE a.tenant_id = %s AND aa.actor_id = %s AND a.status = ANY(%s) ORDER BY CASE a.priority WHEN 'high' THEN 0 WHEN 'normal' THEN 1 WHEN 'low' THEN 2 END, a.updated_at DESC """, (tenant_id, actor_id, statuses), ) actions = [_serialize_row(dict(row)) for row in cur.fetchall()] finally: conn.close() return _attach_assignments(actions, tenant_id=tenant_id) def get_my_open_actions(ctx: TenantContext) -> list[dict[str, Any]]: """Open + in_progress actions assigned to current actor (excludes blocked).""" actor_id = _require_actor(ctx) return _list_assigned_actions( tenant_id=ctx.tenant_id, actor_id=actor_id, statuses=["open", "in_progress"], ) def get_my_blocked_actions(ctx: TenantContext) -> list[dict[str, Any]]: """Blocked actions assigned to current actor.""" actor_id = _require_actor(ctx) return _list_assigned_actions( tenant_id=ctx.tenant_id, actor_id=actor_id, statuses=["blocked"], ) def get_all_my_open_actions(ctx: TenantContext) -> list[dict[str, Any]]: """All non-terminal open actions (open, in_progress, blocked) — legacy compat.""" actor_id = _require_actor(ctx) return _list_assigned_actions( tenant_id=ctx.tenant_id, actor_id=actor_id, statuses=list(OPEN_ACTION_STATUSES), )