feat: add super admin bypass in tree list filter
Super admins now see all trees regardless of ownership, team, or public/default status. Previously the build_tree_access_filter function had no super_admin check, so admins could only see their own trees plus public/default/team trees. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ from typing import Annotated, Optional
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select, func, or_
|
from sqlalchemy import select, func, or_, true as sa_true
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from app.core.database import get_db
|
from app.core.database import get_db
|
||||||
@@ -22,17 +22,22 @@ def build_tree_access_filter(current_user: User):
|
|||||||
"""Build the access filter for trees based on user permissions.
|
"""Build the access filter for trees based on user permissions.
|
||||||
|
|
||||||
Returns trees that are:
|
Returns trees that are:
|
||||||
|
- All trees (for super admins)
|
||||||
- Default/system trees (visible to all)
|
- Default/system trees (visible to all)
|
||||||
- Public trees
|
- Public trees
|
||||||
- User's own trees
|
- User's own trees
|
||||||
- Trees from user's team
|
- Trees from user's team
|
||||||
"""
|
"""
|
||||||
return or_(
|
if current_user.is_super_admin:
|
||||||
|
return sa_true()
|
||||||
|
conditions = [
|
||||||
Tree.is_default == True,
|
Tree.is_default == True,
|
||||||
Tree.is_public == True,
|
Tree.is_public == True,
|
||||||
Tree.author_id == current_user.id,
|
Tree.author_id == current_user.id,
|
||||||
Tree.team_id == current_user.team_id if current_user.team_id else False
|
]
|
||||||
)
|
if current_user.team_id:
|
||||||
|
conditions.append(Tree.team_id == current_user.team_id)
|
||||||
|
return or_(*conditions)
|
||||||
|
|
||||||
|
|
||||||
def build_tree_response(tree: Tree) -> TreeListResponse:
|
def build_tree_response(tree: Tree) -> TreeListResponse:
|
||||||
|
|||||||
@@ -172,6 +172,37 @@ class TestTrees:
|
|||||||
active_ids = [tree["id"] for tree in active_trees]
|
active_ids = [tree["id"] for tree in active_trees]
|
||||||
assert test_tree["id"] not in active_ids
|
assert test_tree["id"] not in active_ids
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_super_admin_sees_all_trees(
|
||||||
|
self, client: AsyncClient, auth_headers: dict, admin_auth_headers: dict
|
||||||
|
):
|
||||||
|
"""Test that super admin can see all trees including private ones from other users."""
|
||||||
|
# Create a private (non-public, non-default) tree as a regular user
|
||||||
|
tree_data = {
|
||||||
|
"name": "Private User Tree",
|
||||||
|
"description": "Only visible to author and super admin",
|
||||||
|
"tree_structure": {
|
||||||
|
"id": "root",
|
||||||
|
"type": "solution",
|
||||||
|
"title": "Private",
|
||||||
|
"description": "Private tree"
|
||||||
|
},
|
||||||
|
"is_public": False,
|
||||||
|
"is_default": False
|
||||||
|
}
|
||||||
|
|
||||||
|
create_response = await client.post(
|
||||||
|
"/api/v1/trees", json=tree_data, headers=auth_headers
|
||||||
|
)
|
||||||
|
assert create_response.status_code == 201
|
||||||
|
private_tree_id = create_response.json()["id"]
|
||||||
|
|
||||||
|
# Super admin should see it in list
|
||||||
|
list_response = await client.get("/api/v1/trees", headers=admin_auth_headers)
|
||||||
|
assert list_response.status_code == 200
|
||||||
|
tree_ids = [t["id"] for t in list_response.json()]
|
||||||
|
assert private_tree_id in tree_ids
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_create_tree_unauthorized(self, client: AsyncClient):
|
async def test_create_tree_unauthorized(self, client: AsyncClient):
|
||||||
"""Test that creating a tree without auth fails."""
|
"""Test that creating a tree without auth fails."""
|
||||||
|
|||||||
Reference in New Issue
Block a user