Files
fast-next-template/backend/app/schemas/sessions.py
Felipe Cardoso c589b565f0 Add pyproject.toml for consolidated project configuration and replace Black, isort, and Flake8 with Ruff
- Introduced `pyproject.toml` to centralize backend tool configurations (e.g., Ruff, mypy, coverage, pytest).
- Replaced Black, isort, and Flake8 with Ruff for linting, formatting, and import sorting.
- Updated `requirements.txt` to include Ruff and remove replaced tools.
- Added `Makefile` to streamline development workflows with commands for linting, formatting, type-checking, testing, and cleanup.
2025-11-10 11:55:15 +01:00

184 lines
5.5 KiB
Python

"""
Pydantic schemas for user session management.
"""
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class SessionBase(BaseModel):
"""Base schema for user sessions."""
device_name: str | None = Field(
None, max_length=255, description="Friendly device name"
)
device_id: str | None = Field(
None, max_length=255, description="Persistent device identifier"
)
class SessionCreate(SessionBase):
"""Schema for creating a new session (internal use)."""
user_id: UUID
refresh_token_jti: str = Field(..., max_length=255)
ip_address: str | None = Field(None, max_length=45)
user_agent: str | None = Field(None, max_length=500)
last_used_at: datetime
expires_at: datetime
location_city: str | None = Field(None, max_length=100)
location_country: str | None = Field(None, max_length=100)
class SessionUpdate(BaseModel):
"""Schema for updating a session (internal use)."""
last_used_at: datetime | None = None
is_active: bool | None = None
refresh_token_jti: str | None = None
expires_at: datetime | None = None
class SessionResponse(SessionBase):
"""
Schema for session responses to clients.
This is what users see when they list their active sessions.
"""
id: UUID
ip_address: str | None = None
location_city: str | None = None
location_country: str | None = None
last_used_at: datetime
created_at: datetime
expires_at: datetime
is_current: bool = Field(
default=False, description="Whether this is the current session"
)
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={
"example": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"device_name": "iPhone 14",
"device_id": "device-abc-123",
"ip_address": "192.168.1.100",
"location_city": "San Francisco",
"location_country": "United States",
"last_used_at": "2025-10-31T12:00:00Z",
"created_at": "2025-10-30T09:00:00Z",
"expires_at": "2025-11-06T09:00:00Z",
"is_current": True,
}
},
)
class SessionListResponse(BaseModel):
"""Response containing list of sessions."""
sessions: list[SessionResponse]
total: int = Field(..., description="Total number of active sessions")
model_config = ConfigDict(
json_schema_extra={
"example": {
"sessions": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"device_name": "iPhone 14",
"ip_address": "192.168.1.100",
"last_used_at": "2025-10-31T12:00:00Z",
"created_at": "2025-10-30T09:00:00Z",
"expires_at": "2025-11-06T09:00:00Z",
"is_current": True,
}
],
"total": 1,
}
}
)
class LogoutRequest(BaseModel):
"""Request schema for logout endpoint."""
refresh_token: str = Field(
..., description="Refresh token for the session to logout from", min_length=10
)
model_config = ConfigDict(
json_schema_extra={
"example": {"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
}
)
class AdminSessionResponse(SessionBase):
"""
Schema for session responses in admin panel.
Includes user information for admin to see who owns each session.
"""
id: UUID
user_id: UUID
user_email: str = Field(..., description="Email of the user who owns this session")
user_full_name: str | None = Field(None, description="Full name of the user")
ip_address: str | None = None
location_city: str | None = None
location_country: str | None = None
last_used_at: datetime
created_at: datetime
expires_at: datetime
is_active: bool
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={
"example": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"user_id": "456e7890-e89b-12d3-a456-426614174001",
"user_email": "user@example.com",
"user_full_name": "John Doe",
"device_name": "iPhone 14",
"device_id": "device-abc-123",
"ip_address": "192.168.1.100",
"location_city": "San Francisco",
"location_country": "United States",
"last_used_at": "2025-10-31T12:00:00Z",
"created_at": "2025-10-30T09:00:00Z",
"expires_at": "2025-11-06T09:00:00Z",
"is_active": True,
}
},
)
class DeviceInfo(BaseModel):
"""Device information extracted from request."""
device_name: str | None = None
device_id: str | None = None
ip_address: str | None = None
user_agent: str | None = None
location_city: str | None = None
location_country: str | None = None
model_config = ConfigDict(
json_schema_extra={
"example": {
"device_name": "Chrome on MacBook",
"device_id": "device-xyz-789",
"ip_address": "192.168.1.50",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
"location_city": "San Francisco",
"location_country": "United States",
}
}
)