apac-ops-bot/backend/app/models/conversation.py
SamoilenkoVadym b284cadb86 Add test user authentication and RBAC admin panel
Implemented simple authentication for testing and admin panel for user management:

Backend:
- Add simple email/password login for test users (admin@test.local, user@test.local)
- Implement RBAC (Role-Based Access Control) with Permission enum
- Create admin endpoints for user management and system analytics
- Add bcrypt password hashing for test users
- Create script to generate test users in database

Frontend:
- Add SimpleLogin component for test authentication
- Create AdminPanel with user management and system analytics
- Add role-based navigation (Admin tab visible only for admins)
- Update AuthContext to support both MSAL and simple login
- Add API methods for admin operations

Features:
- Admins can view all users, manage roles, activate/deactivate accounts
- Admins can view system-wide analytics (users, conversations, tokens, costs)
- Regular users only see their own chats and usage
- Role badges in UI show user role (user/admin/superadmin)

Note: Simple authentication is for testing only. Production uses Azure AD MSAL.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-27 20:05:54 +00:00

45 lines
1.6 KiB
Python

"""
Conversation model for storing chat conversations
"""
from sqlalchemy import Column, String, Boolean, DateTime, JSON, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import uuid
from app.database import Base
class Conversation(Base):
"""
Conversation model representing a chat conversation between user and bot
"""
__tablename__ = "conversations"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
# OpenAI Responses API response_id for multi-turn conversations
last_response_id = Column(String(255), index=True)
# Conversation metadata
title = Column(String(500)) # Auto-generated or user-defined
is_archived = Column(Boolean, default=False, nullable=False)
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), index=True)
last_message_at = Column(DateTime(timezone=True))
# JSON field for additional metadata
meta_data = Column(JSON, default=dict, nullable=False)
# Relationships
user = relationship("User", back_populates="conversations")
messages = relationship("Message", back_populates="conversation", cascade="all, delete-orphan", order_by="Message.created_at")
token_usage = relationship("TokenUsage", back_populates="conversation")
def __repr__(self):
return f"<Conversation {self.id} - {self.title}>"