"""FlowDeck — My Tasks router (v1.9.0).""" from __future__ import annotations import json import logging from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse from jinja2 import Environment, FileSystemLoader from app.auth.session import SessionManager from app.db import get_conn logger = logging.getLogger(__name__) router = APIRouter(tags=["my-tasks"], prefix="/my-tasks") def _get_current_user(request: Request) -> dict | None: session = request.cookies.get("flowdeck_session", "") return SessionManager.decode_session(session) @router.get("", response_class=HTMLResponse) async def my_tasks_dashboard(request: Request, view: str = "all", days: int = 7): """My Tasks — aggregates all pages assigned to the current user across all collections.""" user = _get_current_user(request) user_login = user.get("login", "admin") if user else "admin" with get_conn() as conn: collections = conn.execute("SELECT * FROM collections ORDER BY name").fetchall() grouped: dict[str, list[dict]] = {} for col in collections: col_id = col["id"] pages = conn.execute( "SELECT * FROM collection_pages WHERE collection_id=? AND parent_id IS NULL ORDER BY position", (col_id,), ).fetchall() collection_tasks = [] for p in pages: props = {} try: props = json.loads(p["property_values_json"] or "{}") except (json.JSONDecodeError, TypeError): pass due_date = props.get("due_date", "") status = props.get("status", "—") assignee = props.get("assignee", "") if view != "all" and assignee and assignee != user_login: continue collection_tasks.append({ "id": p["id"], "title": p["title"] or "Untitled", "icon": p["icon"] or "📋", "status": status, "due_date": due_date, }) if collection_tasks: grouped[col["name"]] = collection_tasks total = sum(len(t) for t in grouped.values()) # Build content HTML sections = "" for col_name, tasks in grouped.items(): items = "" for t in tasks: due_badge = f"{t['due_date']}" if t.get("due_date") else "" status_cls = t['status'].lower().replace(' ', '-') if t.get('status') else 'none' status_badge = f"{t.get('status', '—')}" items += f"
{t['icon']}{t['title']}{status_badge}{due_badge}
" sections += f"
{col_name} {len(tasks)}
{items}
" content_html = f"""

📋 My Tasks

{total} tasks across {len(grouped)} collections

All Today Overdue Next 7 days
{sections}
""" from app.routers.dashboard import _sidebar_data env = Environment(loader=FileSystemLoader("app/templates")) sidebar = _sidebar_data(request, []) block_tpl = env.from_string( '{% extends "base.html" %}{% block content %}{{ content_html|safe }}{% endblock %}' ) return block_tpl.render( **sidebar, request=request, content_html=content_html, page_title="My Tasks", title_prefix="My Tasks", page_icon="📋", ) @router.get("/api") async def my_tasks_api(request: Request, view: str = "all", days: int = 7): """API: return my tasks as JSON.""" user = _get_current_user(request) user.get("login", "admin") if user else "admin" with get_conn() as conn: collections = conn.execute("SELECT * FROM collections ORDER BY name").fetchall() result = {} for col in collections: pages = conn.execute( "SELECT * FROM collection_pages WHERE collection_id=? AND parent_id IS NULL ORDER BY position", (col["id"],), ).fetchall() tasks = [] for p in pages: props = json.loads(p["property_values_json"]) tasks.append({ "id": p["id"], "title": p["title"], "icon": p["icon"], "properties": props, }) if tasks: result[col["name"]] = tasks return {"tasks": result, "total": sum(len(t) for t in result.values())}