Oliver-ai-bot_2.0/backend/app/models/user.py
Vadym Samoilenko 349f9c243e feat: agent builder — dynamic agents with admin editor, user catalog, and PA creation
- Backend: Agent model + migration 022 (creates agents table, seeds system agents, backfills conversations, adds What's New announcement)
- Backend: agents CRUD API (/agents/), role-based permission matrix, agent_manager role
- Backend: chat endpoint refactored to resolve agent by slug, use agent's LLM config/tools/RAG
- Backend: PA CreateAgentTool + ListAgentsTool for conversational agent creation
- Backend: LLMFactory extended with get_llm_from_config() + stream_completion_with_llm()
- Frontend: AgentListItem/Agent types, useAgentStore, dynamic sidebar with lucide icon resolution
- Frontend: Admin → Agents tab + full LibreChat-style AgentEditorModal (react-hook-form)
- Frontend: AgentPickerModal (Browse Templates + Create Custom), AgentCard
- Frontend: chat page reads ?agent=slug, shows dynamic header/welcome/prompts from DB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 15:54:35 +01:00

50 lines
1.9 KiB
Python

"""
User Model with Role-Based Access Control (RBAC)
"""
from sqlalchemy import Column, String, Boolean, DateTime, Enum, ForeignKey
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from app.database import Base
import uuid
from datetime import datetime
import enum
class UserRole(enum.Enum):
"""User role enum for RBAC"""
SUPER_ADMIN = "super_admin"
CONTENT_MANAGER = "content_manager"
AGENT_MANAGER = "agent_manager"
USER = "user"
class User(Base):
"""
User model with Microsoft Entra ID integration
Auto-provisioned on first login
"""
__tablename__ = "users"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
entra_id = Column(String, unique=True, nullable=False, index=True) # Azure AD object ID
email = Column(String, unique=True, nullable=False, index=True)
display_name = Column(String)
role = Column(String, default="user", nullable=False)
department_id = Column(UUID(as_uuid=True), ForeignKey("departments.id", ondelete="SET NULL"), nullable=True)
is_active = Column(Boolean, default=True, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
last_login_at = Column(DateTime, nullable=True)
# Region — derived from MS Graph usageLocation at login, used for RAG filtering
region_code = Column(String(20), nullable=True, index=True)
# Access Control — features granted via AD Groups or admin override
allowed_features = Column(JSONB, default=list, nullable=False, server_default='[]')
features_override = Column(Boolean, default=False, nullable=False, server_default='false')
# Relationships
department = relationship("Department", back_populates="users")
conversations = relationship("Conversation", back_populates="user", cascade="all, delete-orphan")
def __repr__(self):
return f"<User {self.email} ({self.role})>"