Coverage for src / idx_api / routers / admin.py: 91%
53 statements
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-28 11:09 -0700
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-28 11:09 -0700
1"""Core admin endpoints for authentication and user info."""
3from datetime import datetime
5from fastapi import APIRouter, Depends, Query
6from pydantic import BaseModel
7from sqlalchemy import func, select
8from sqlalchemy.orm import Session
10from idx_api.auth import AdminUser, BrokerUser, RequiredUser
11from idx_api.database import get_db
12from idx_api.models.tour_request import TourRequest
14router = APIRouter()
17# ===== Response Models =====
20class UserResponse(BaseModel):
21 """Current user response."""
23 id: int | None
24 email: str
25 role: str
26 brokerage_id: int | None
27 broker_id: int | None # Broker contact ID
28 agent_id: int | None
30 class Config:
31 from_attributes = True
34class StatusResponse(BaseModel):
35 """Admin status response."""
37 authenticated: bool
38 user: UserResponse
41class TourRequestResponse(BaseModel):
42 """Tour request response model."""
44 id: int
45 property_id: str
46 first_name: str
47 last_name: str
48 email: str
49 phone: str | None
50 message: str | None
51 preferred_date: datetime | None
52 assigned_brokerage_id: int | None
53 assigned_agent_id: int | None
54 status: str
55 created_at: datetime
56 updated_at: datetime
58 class Config:
59 from_attributes = True
62# ===== User Info Endpoints =====
65@router.get("/me", response_model=StatusResponse)
66async def get_current_user_info(user: RequiredUser):
67 """
68 Get current authenticated user information.
70 Requires authentication (either API key or JWT token).
71 """
72 return StatusResponse(
73 authenticated=True,
74 user=UserResponse.model_validate(user),
75 )
78@router.get("/admin-test", response_model=dict)
79async def admin_only_endpoint(user: AdminUser):
80 """
81 Test endpoint that requires admin role.
83 Only users with admin role can access this.
84 """
85 return {
86 "message": "You have admin access!",
87 "user_email": user.email,
88 "user_role": user.role,
89 }
92@router.get("/broker-test", response_model=dict)
93async def broker_endpoint(user: BrokerUser):
94 """
95 Test endpoint that requires broker role (or higher).
97 Broker and admin users can access this.
98 """
99 return {
100 "message": "You have broker access!",
101 "user_email": user.email,
102 "user_role": user.role,
103 "brokerage_id": user.brokerage_id,
104 "broker_id": user.broker_id,
105 }
108# ===== Tour Listing Endpoint =====
111@router.get("/tours")
112async def list_tours(
113 user: AdminUser,
114 db: Session = Depends(get_db),
115 page: int = Query(1, ge=1),
116 page_size: int = Query(20, ge=1, le=100),
117):
118 """
119 List all tour requests with pagination.
121 Requires admin role.
122 """
123 # Count total
124 total = db.scalar(select(func.count()).select_from(TourRequest))
126 # Get paginated results
127 offset = (page - 1) * page_size
128 tours = db.scalars(
129 select(TourRequest)
130 .order_by(TourRequest.created_at.desc())
131 .offset(offset)
132 .limit(page_size)
133 ).all()
135 total_pages = (total + page_size - 1) // page_size
137 return {
138 "items": [TourRequestResponse.model_validate(t) for t in tours],
139 "total": total,
140 "page": page,
141 "page_size": page_size,
142 "total_pages": total_pages,
143 }