Add frontend access control enhancements and JWT support
- Hide New Project button for unauthenticated users, show login link - Add lock icon for private projects on home page - Show access level badges on project cards (Owner, Admin, Write, Read) - Add permission expiration date field to AccessManagement component - Add query timeout configuration for database (ORCHARD_DATABASE_QUERY_TIMEOUT) - Add JWT token validation support for external identity providers - Configurable via ORCHARD_JWT_* environment variables - Supports HS256 with secret or RS256 with JWKS - Auto-provisions users from JWT claims
This commit is contained in:
@@ -45,11 +45,13 @@ from .models import (
|
||||
Consumer,
|
||||
AuditLog,
|
||||
User,
|
||||
AccessPermission,
|
||||
)
|
||||
from .schemas import (
|
||||
ProjectCreate,
|
||||
ProjectUpdate,
|
||||
ProjectResponse,
|
||||
ProjectWithAccessResponse,
|
||||
PackageCreate,
|
||||
PackageUpdate,
|
||||
PackageResponse,
|
||||
@@ -947,7 +949,7 @@ def global_search(
|
||||
|
||||
|
||||
# Project routes
|
||||
@router.get("/api/v1/projects", response_model=PaginatedResponse[ProjectResponse])
|
||||
@router.get("/api/v1/projects", response_model=PaginatedResponse[ProjectWithAccessResponse])
|
||||
def list_projects(
|
||||
request: Request,
|
||||
page: int = Query(default=1, ge=1, description="Page number"),
|
||||
@@ -963,8 +965,9 @@ def list_projects(
|
||||
),
|
||||
order: str = Query(default="asc", description="Sort order (asc, desc)"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: Optional[User] = Depends(get_current_user_optional),
|
||||
):
|
||||
user_id = get_user_id(request)
|
||||
user_id = current_user.username if current_user else get_user_id(request)
|
||||
|
||||
# Validate sort field
|
||||
valid_sort_fields = {
|
||||
@@ -1022,8 +1025,51 @@ def list_projects(
|
||||
# Calculate total pages
|
||||
total_pages = math.ceil(total / limit) if total > 0 else 1
|
||||
|
||||
# Build access level info for each project
|
||||
project_ids = [p.id for p in projects]
|
||||
access_map = {}
|
||||
|
||||
if current_user and project_ids:
|
||||
# Get access permissions for this user across these projects
|
||||
permissions = (
|
||||
db.query(AccessPermission)
|
||||
.filter(
|
||||
AccessPermission.project_id.in_(project_ids),
|
||||
AccessPermission.user_id == current_user.username,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
access_map = {p.project_id: p.level for p in permissions}
|
||||
|
||||
# Build response with access levels
|
||||
items = []
|
||||
for p in projects:
|
||||
is_owner = p.created_by == user_id
|
||||
access_level = None
|
||||
|
||||
if is_owner:
|
||||
access_level = "admin"
|
||||
elif p.id in access_map:
|
||||
access_level = access_map[p.id]
|
||||
elif p.is_public:
|
||||
access_level = "read"
|
||||
|
||||
items.append(
|
||||
ProjectWithAccessResponse(
|
||||
id=p.id,
|
||||
name=p.name,
|
||||
description=p.description,
|
||||
is_public=p.is_public,
|
||||
created_at=p.created_at,
|
||||
updated_at=p.updated_at,
|
||||
created_by=p.created_by,
|
||||
access_level=access_level,
|
||||
is_owner=is_owner,
|
||||
)
|
||||
)
|
||||
|
||||
return PaginatedResponse(
|
||||
items=projects,
|
||||
items=items,
|
||||
pagination=PaginationMeta(
|
||||
page=page,
|
||||
limit=limit,
|
||||
|
||||
Reference in New Issue
Block a user