agent_tracker/models.py
michael 48db28b8fb Add local user login alongside Microsoft SSO
- Show both Microsoft SSO and local login options on login page
- Add admin user management: create local users with password
- Add admin password reset for local users only
- Add self-service password change on profile page for local users
- Display auth provider (Local/SSO) in admin user table
- New API endpoints: POST /api/admin/users, POST /api/admin/users/{email}/reset-password, POST /api/users/change-password
- SSO and local auth remain separate (no dual-auth)
- Minimum 8 character password requirement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 06:58:45 -06:00

192 lines
7.8 KiB
Python

from pydantic import BaseModel, EmailStr, Field
from typing import Optional, List
class UsageTimelineEntry(BaseModel):
date: str = Field(..., description="Date in YYYY-MM-DD format")
message_count: int = Field(..., ge=0, description="Number of messages on this date")
class AiAgent(BaseModel):
agent_id: int
agent_name: str
agent_tool: str | None = Field(default=None, title="The tool or platform where the agent operates", max_length=100)
agent_description: str | None = Field(default=None, title="The description of the agent", max_length=300)
agent_purpose: str | None = Field(default=None, title="The purpose of the agent", max_length=200)
agent_version: str | None = Field(default=None, title="The version of the agent", max_length=100)
agent_status: str | None = Field(default=None, title="The status of the agent", max_length=100, enum=['Active', 'Inactive', 'Deprecated', 'Development'])
agent_location: str | None = Field(default=None, title="The location of the agent", max_length=100)
agent_department: str | None = Field(default=None, title="The department of the agent", max_length=100)
agent_contact_person: str | None = Field(default=None, title="The contact person for the agent", max_length=100)
agent_created_at: str | None = Field(default=None, title="The creation date of the agent", max_length=100)
agent_updated_at: str | None = Field(default=None, title="The last update date of the agent", max_length=100)
agent_tags: list[str] | None = Field(default=None, title="Tags associated with the agent", max_length=100)
agent_metadata: dict[str, str] | None = Field(default=None, title="Metadata associated with the agent")
agent_userbase: list[str] | None = Field(default=None, title="Userbase associated with the agent")
agent_capabilities: list[str] | None = Field(default=None, title="Capabilities of the agent")
url: str | None = Field(default=None, title="Direct link to create a conversation with this agent")
quality_audit_status: bool | None = Field(default=False, title="Quality audit status")
quality_audit_updated_by: str | None = Field(default=None, title="Admin user ID who updated quality audit")
quality_audit_updated_at: str | None = Field(default=None, title="Quality audit last update timestamp")
quality_audit_updated_by_name: str | None = Field(default=None, title="Admin user name who updated quality audit")
risk_factor: int | None = Field(default=None, title="Risk factor rating (1-5)", ge=1, le=5)
last_edited_by: str | None = Field(default=None, title="Email of user who last edited this agent")
# User Base Model
class UserCreate(BaseModel):
email: EmailStr
password: str
full_name: Optional[str] = None
class UserLogin(BaseModel):
email: EmailStr
password: str
class UserResponse(BaseModel):
email: EmailStr
full_name: Optional[str] = None
is_active: bool
is_admin: bool
auth_provider: Optional[str] = "local"
class UserUpdate(BaseModel):
full_name: Optional[str] = None
is_active: Optional[bool] = None
is_admin: Optional[bool] = None
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
# Admin user management models
class AdminUserCreate(BaseModel):
email: EmailStr
full_name: Optional[str] = None
password: str = Field(..., min_length=8)
is_admin: bool = False
class AdminPasswordReset(BaseModel):
new_password: str = Field(..., min_length=8)
class PasswordChange(BaseModel):
current_password: str
new_password: str = Field(..., min_length=8)
# Agent models for creation and response
class AiAgentCreate(BaseModel):
agent_name: str
agent_tool: str
agent_description: Optional[str] = None
agent_purpose: Optional[str] = None
agent_version: Optional[str] = None
agent_status: Optional[str] = "Development"
agent_location: Optional[str] = None
agent_department: Optional[str] = None
agent_contact_person: Optional[str] = None
agent_tags: Optional[list[str]] = None
agent_metadata: Optional[dict[str, str]] = None
agent_userbase: Optional[list[str]] = None
agent_capabilities: Optional[list[str]] = None
url: Optional[str] = None
quality_audit_status: Optional[bool] = False
quality_audit_updated_by: Optional[str] = None
quality_audit_updated_at: Optional[str] = None
quality_audit_updated_by_name: Optional[str] = None
risk_factor: Optional[int] = Field(default=None, ge=1, le=5)
last_edited_by: Optional[str] = None
class AiAgentResponse(BaseModel):
agent_id: str
agent_name: str
agent_tool: Optional[str] = None
agent_description: Optional[str] = None
agent_purpose: Optional[str] = None
agent_version: Optional[str] = None
agent_status: Optional[str] = None
agent_location: Optional[str] = None
agent_department: Optional[str] = None
agent_contact_person: Optional[str] = None
agent_created_at: Optional[str] = None
agent_updated_at: Optional[str] = None
agent_tags: Optional[list[str]] = None
agent_metadata: Optional[dict[str, str]] = None
agent_userbase: Optional[list[str]] = None
agent_capabilities: Optional[list[str]] = None
url: Optional[str] = None
quality_audit_status: Optional[bool] = None
quality_audit_updated_by: Optional[str] = None
quality_audit_updated_at: Optional[str] = None
quality_audit_updated_by_name: Optional[str] = None
risk_factor: Optional[int] = None
last_edited_by: Optional[str] = None
created_by: str
# Usage tracking fields (new)
usage_timeline: Optional[List[dict]] = None
conversation_count: Optional[int] = None
unique_users: Optional[int] = None
total_messages: Optional[int] = None
first_used: Optional[str] = None
last_used: Optional[str] = None
# Agent Collector API Models (for compatibility with agent_collector app)
class AgentCollectorCreate(BaseModel):
name: str = Field(min_length=1)
description: str = Field(min_length=1)
purpose: str = Field(min_length=1)
tool: str = Field(min_length=1)
location: Optional[str] = None
userbase: Optional[list[str]] = None
version: Optional[str] = None
creation_date: Optional[str] = None # ISO 8601 datetime string
last_updated: Optional[str] = None # ISO 8601 datetime string
capabilities: Optional[list[str]] = None
status: Optional[str] = Field(default="development", pattern="^(?i)(active|inactive|deprecated|development)$")
department: Optional[str] = None
contact_person: Optional[str] = None
tags: Optional[list[str]] = None
metadata: Optional[dict] = None
url: Optional[str] = None
# Usage tracking fields (new)
usage_timeline: Optional[List[UsageTimelineEntry]] = None
conversation_count: Optional[int] = Field(default=None, ge=0)
unique_users: Optional[int] = Field(default=None, ge=0)
total_messages: Optional[int] = Field(default=None, ge=0)
first_used: Optional[str] = None # ISO 8601 datetime string
last_used: Optional[str] = None # ISO 8601 datetime string
class AgentCollectorResponse(BaseModel):
status: str = "success"
message: str = "Agent data collected successfully"
agent_id: str
class HealthCheckResponse(BaseModel):
status: str
message: str
timestamp: str
database: dict
class AgentUsageTrackingResponse(BaseModel):
status: str = "usage_logged"
message: str = "Agent already exists, usage tracked"
agent_name: str
class AgentUsageRecord(BaseModel):
agent_name: str
agent_data: dict
timestamp: str
usage_count: Optional[int] = None
class AgentUsageStatsResponse(BaseModel):
agent_name: str
total_usage_count: int
first_usage: Optional[str] = None
last_usage: Optional[str] = None
usage_by_period: dict
conversation_count: Optional[int] = None
unique_users: Optional[int] = None