diff --git a/app/routers/dashboard.py b/app/routers/dashboard.py index 15d4544..b03f4c6 100644 --- a/app/routers/dashboard.py +++ b/app/routers/dashboard.py @@ -387,3 +387,70 @@ async def create_workspace_project(request: Request): conn.commit() pid = cursor.lastrowid return {"id": pid, "name": name, "forge": "builtin"} + + +# ═══════════ Workspace Members API ═══════════ + +@router.get("/api/workspace/{ws_id:int}/members") +async def list_members(request: Request, ws_id: int): + """List all members of a workspace.""" + with get_conn() as conn: + rows = conn.execute( + """SELECT u.id, u.login, u.full_name, u.avatar_url, wm.role, wm.joined_at + FROM workspace_members wm JOIN users u ON u.id = wm.user_id + WHERE wm.workspace_id=? ORDER BY wm.joined_at""", (ws_id,) + ).fetchall() + return {"members": [dict(r) for r in rows]} + + +@router.post("/api/workspace/{ws_id:int}/members") +async def invite_member(request: Request, ws_id: int): + """Invite a user to a workspace by email.""" + import json + body = await request.json() + email = body.get("email", "").strip() + role = body.get("role", "editor") + if role not in ("owner", "admin", "editor", "viewer"): + return {"error": "Invalid role"}, 400 + with get_conn() as conn: + user = conn.execute("SELECT id FROM users WHERE login=? OR email=?", (email, email)).fetchone() + if not user: + return {"error": "User not found"}, 404 + try: + conn.execute( + "INSERT INTO workspace_members (workspace_id, user_id, role) VALUES (?, ?, ?)", + (ws_id, user["id"], role), + ) + conn.commit() + except Exception: + return {"error": "Already a member"}, 409 + return {"status": "ok", "user_id": user["id"], "role": role} + + +@router.put("/api/workspace/{ws_id:int}/members/{user_id:int}") +async def update_member_role(request: Request, ws_id: int, user_id: int): + """Change a member's role.""" + import json + body = await request.json() + role = body.get("role", "editor") + if role not in ("owner", "admin", "editor", "viewer"): + return {"error": "Invalid role"} + with get_conn() as conn: + conn.execute( + "UPDATE workspace_members SET role=? WHERE workspace_id=? AND user_id=?", + (role, ws_id, user_id), + ) + conn.commit() + return {"status": "ok"} + + +@router.delete("/api/workspace/{ws_id:int}/members/{user_id:int}") +async def remove_member(request: Request, ws_id: int, user_id: int): + """Remove a member from a workspace.""" + with get_conn() as conn: + conn.execute( + "DELETE FROM workspace_members WHERE workspace_id=? AND user_id=?", + (ws_id, user_id), + ) + conn.commit() + return {"status": "ok"}