""" Protected Routes Example Shows how to structure routes under /api/protected with session-based auth. Route structure: /api/auth/ - Public (login, register, logout) /api/public/ - Public (health, docs) /api/protected/ - Authenticated (all users) /api/protected/employee/ - Employees only /api/protected/customer/ - Customers only /api/admin/ - Admins only """ from fastapi import APIRouter, Depends, HTTPException from typing import List, Optional from .session_store import Session, UserType from .session_middleware import get_current_session, get_optional_session from .rbac_middleware import ( require_employee, require_customer, require_permission, require_role, require_any_role, ) # ============================================= # Router Setup # ============================================= # Protected routes - require authentication protected_router = APIRouter(prefix="/api/protected", tags=["Protected"]) # Employee-only routes employee_router = APIRouter(prefix="/api/protected/employee", tags=["Employee"]) # Customer-only routes customer_router = APIRouter(prefix="/api/protected/customer", tags=["Customer"]) # Admin routes admin_router = APIRouter(prefix="/api/admin", tags=["Admin"]) # ============================================= # Protected Routes (All Authenticated Users) # ============================================= @protected_router.get("/profile") async def get_profile(session: Session = Depends(get_current_session)): """Get current user's profile.""" return { "user_id": session.user_id, "email": session.email, "user_type": session.user_type.value, "roles": session.roles, "permissions": session.permissions, "tenant_id": session.tenant_id, } @protected_router.get("/notifications") async def get_notifications(session: Session = Depends(get_current_session)): """Get user's notifications.""" # TODO: Implement actual notification fetching return { "notifications": [], "unread_count": 0, } @protected_router.post("/logout") async def logout(session: Session = Depends(get_current_session)): """Logout current session.""" from .session_store import get_session_store store = await get_session_store() await store.revoke_session(session.session_id) return {"message": "Logged out successfully"} @protected_router.post("/logout-all") async def logout_all(session: Session = Depends(get_current_session)): """Logout from all devices.""" from .session_store import get_session_store store = await get_session_store() count = await store.revoke_all_user_sessions(session.user_id) return {"message": f"Logged out from {count} sessions"} @protected_router.get("/sessions") async def get_active_sessions(session: Session = Depends(get_current_session)): """Get all active sessions for current user.""" from .session_store import get_session_store store = await get_session_store() sessions = await store.get_active_sessions(session.user_id) return { "sessions": [ { "session_id": s.session_id, "ip_address": s.ip_address, "user_agent": s.user_agent, "created_at": s.created_at.isoformat() if s.created_at else None, "last_activity_at": s.last_activity_at.isoformat() if s.last_activity_at else None, "is_current": s.session_id == session.session_id, } for s in sessions ] } # ============================================= # Employee Routes # ============================================= @employee_router.get("/dashboard") async def employee_dashboard(session: Session = Depends(require_employee)): """Employee dashboard with overview data.""" return { "user_type": "employee", "email": session.email, "roles": session.roles, "widgets": [ {"type": "today_classes", "title": "Heutige Stunden"}, {"type": "pending_corrections", "title": "Ausstehende Korrekturen"}, {"type": "absent_students", "title": "Abwesende Schueler"}, ], } @employee_router.get("/grades") async def get_grades( class_id: Optional[str] = None, session: Session = Depends(require_permission("grades:read")) ): """Get grades (employee only, requires grades:read permission).""" # TODO: Implement actual grade fetching return { "grades": [], "class_id": class_id, } @employee_router.post("/grades") async def create_grade( grade_data: dict, session: Session = Depends(require_permission("grades:write")) ): """Create a new grade (requires grades:write permission).""" # TODO: Implement grade creation return {"message": "Grade created"} @employee_router.get("/attendance") async def get_attendance( date: Optional[str] = None, class_id: Optional[str] = None, session: Session = Depends(require_permission("attendance:read")) ): """Get attendance records.""" return { "attendance": [], "date": date, "class_id": class_id, } @employee_router.post("/attendance") async def mark_attendance( attendance_data: dict, session: Session = Depends(require_permission("attendance:write")) ): """Mark student attendance.""" return {"message": "Attendance recorded"} @employee_router.get("/students") async def get_students( class_id: Optional[str] = None, session: Session = Depends(require_permission("students:read")) ): """Get student list.""" return { "students": [], "class_id": class_id, } @employee_router.get("/corrections") async def get_corrections( session: Session = Depends(require_permission("corrections:read")) ): """Get pending corrections.""" return { "corrections": [], "pending_count": 0, } # ============================================= # Customer Routes # ============================================= @customer_router.get("/dashboard") async def customer_dashboard(session: Session = Depends(require_customer)): """Customer dashboard.""" return { "user_type": "customer", "email": session.email, "widgets": [ {"type": "my_children", "title": "Meine Kinder"}, {"type": "upcoming_meetings", "title": "Anstehende Termine"}, {"type": "recent_grades", "title": "Aktuelle Noten"}, ], } @customer_router.get("/my-children") async def get_my_children( session: Session = Depends(require_permission("children:read")) ): """Get parent's children.""" # TODO: Implement actual children fetching return { "children": [], } @customer_router.get("/my-grades") async def get_my_grades( session: Session = Depends(require_permission("own_grades:read")) ): """Get student's own grades.""" return { "grades": [], "average": None, } @customer_router.get("/my-attendance") async def get_my_attendance( session: Session = Depends(require_permission("own_attendance:read")) ): """Get student's own attendance.""" return { "attendance_records": [], "absence_count": 0, } @customer_router.get("/children/{child_id}/grades") async def get_child_grades( child_id: str, session: Session = Depends(require_permission("children:grades:read")) ): """Get child's grades (for parents).""" # TODO: Verify parent-child relationship return { "child_id": child_id, "grades": [], } @customer_router.get("/appointments") async def get_appointments(session: Session = Depends(require_customer)): """Get upcoming appointments/meetings.""" return { "appointments": [], } @customer_router.post("/appointments/{slot_id}/book") async def book_appointment( slot_id: str, session: Session = Depends(require_permission("meetings:join")) ): """Book a parent meeting slot.""" return { "message": "Appointment booked", "slot_id": slot_id, } # ============================================= # Admin Routes # ============================================= @admin_router.get("/users") async def list_users( page: int = 1, limit: int = 50, session: Session = Depends(require_permission("users:read")) ): """List all users (admin only).""" return { "users": [], "total": 0, "page": page, "limit": limit, } @admin_router.get("/users/{user_id}") async def get_user( user_id: str, session: Session = Depends(require_permission("users:read")) ): """Get user details.""" return { "user_id": user_id, "email": None, "roles": [], } @admin_router.put("/users/{user_id}/roles") async def update_user_roles( user_id: str, roles: List[str], session: Session = Depends(require_permission("users:manage")) ): """Update user roles (admin only).""" return { "message": "Roles updated", "user_id": user_id, "roles": roles, } @admin_router.get("/audit-log") async def get_audit_log( page: int = 1, limit: int = 100, session: Session = Depends(require_permission("audit:read")) ): """Get audit log entries.""" return { "entries": [], "total": 0, "page": page, "limit": limit, } @admin_router.get("/rbac/roles") async def list_roles( session: Session = Depends(require_permission("rbac:read")) ): """List all RBAC roles.""" return { "roles": [], } @admin_router.get("/rbac/permissions") async def list_permissions( session: Session = Depends(require_permission("rbac:read")) ): """List all permissions.""" from .rbac_middleware import EMPLOYEE_PERMISSIONS, CUSTOMER_PERMISSIONS, ADMIN_PERMISSIONS return { "employee_permissions": EMPLOYEE_PERMISSIONS, "customer_permissions": CUSTOMER_PERMISSIONS, "admin_permissions": ADMIN_PERMISSIONS, } # ============================================= # Router Registration Helper # ============================================= def register_protected_routes(app): """ Register all protected route routers with FastAPI app. Usage: from session.protected_routes import register_protected_routes register_protected_routes(app) """ app.include_router(protected_router) app.include_router(employee_router) app.include_router(customer_router) app.include_router(admin_router)