FlotillasGPS - Sistema completo de monitoreo de flotillas GPS

Sistema completo para monitoreo y gestion de flotas de vehiculos con:
- Backend FastAPI con PostgreSQL/TimescaleDB
- Frontend React con TypeScript y TailwindCSS
- App movil React Native con Expo
- Soporte para dispositivos GPS, Meshtastic y celulares
- Video streaming en vivo con MediaMTX
- Geocercas, alertas, viajes y reportes
- Autenticacion JWT y WebSockets en tiempo real

Documentacion completa y guias de usuario incluidas.
This commit is contained in:
FlotillasGPS Developer
2026-01-21 08:18:00 +00:00
commit 51d78bacf4
248 changed files with 50171 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
"""
Schemas Pydantic para Usuario.
"""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, EmailStr, Field, field_validator
from app.schemas.base import BaseSchema, TimestampSchema
class UsuarioBase(BaseSchema):
"""Schema base de usuario."""
email: EmailStr
nombre: str = Field(..., min_length=2, max_length=100)
apellido: Optional[str] = Field(None, max_length=100)
telefono: Optional[str] = Field(None, max_length=20)
class UsuarioCreate(UsuarioBase):
"""Schema para crear usuario."""
password: str = Field(..., min_length=8, max_length=100)
es_admin: bool = False
@field_validator("password")
@classmethod
def validate_password(cls, v: str) -> str:
if len(v) < 8:
raise ValueError("La contraseña debe tener al menos 8 caracteres")
if not any(c.isupper() for c in v):
raise ValueError("La contraseña debe tener al menos una mayúscula")
if not any(c.islower() for c in v):
raise ValueError("La contraseña debe tener al menos una minúscula")
if not any(c.isdigit() for c in v):
raise ValueError("La contraseña debe tener al menos un número")
return v
class UsuarioUpdate(BaseSchema):
"""Schema para actualizar usuario."""
nombre: Optional[str] = Field(None, min_length=2, max_length=100)
apellido: Optional[str] = Field(None, max_length=100)
telefono: Optional[str] = Field(None, max_length=20)
avatar_url: Optional[str] = None
preferencias: Optional[str] = None
class UsuarioUpdatePassword(BaseModel):
"""Schema para cambiar contraseña."""
password_actual: str
password_nuevo: str = Field(..., min_length=8, max_length=100)
@field_validator("password_nuevo")
@classmethod
def validate_password(cls, v: str) -> str:
if len(v) < 8:
raise ValueError("La contraseña debe tener al menos 8 caracteres")
return v
class UsuarioResponse(UsuarioBase, TimestampSchema):
"""Schema de respuesta de usuario."""
id: int
es_admin: bool
activo: bool
ultimo_acceso: Optional[datetime] = None
avatar_url: Optional[str] = None
class UsuarioInDB(UsuarioResponse):
"""Schema interno con hash de password."""
password_hash: str
# ============================================================================
# Schemas de Autenticación
# ============================================================================
class LoginRequest(BaseModel):
"""Schema para solicitud de login."""
email: EmailStr
password: str
class LoginResponse(BaseModel):
"""Schema de respuesta de login."""
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int
user: UsuarioResponse
class RefreshTokenRequest(BaseModel):
"""Schema para refresh token."""
refresh_token: str
class TokenResponse(BaseModel):
"""Schema de respuesta de tokens."""
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int