from typing import Optional, List from sqlmodel import SQLModel, Field, Relationship from datetime import datetime from enum import Enum class SnippetVisibility(str, Enum): PRIVATE = "private" DEPARTMENT = "department" ORGANIZATION = "organization" class Language(SQLModel, table=True): __tablename__ = "language" id: Optional[int] = Field(default=None, primary_key=True) code: str = Field(unique=True, index=True) name: str is_default: bool = Field(default=False) created_at: datetime = Field(default_factory=datetime.utcnow) translations: List["Translation"] = Relationship(back_populates="language") class Translation(SQLModel, table=True): __tablename__ = "translation" id: Optional[int] = Field(default=None, primary_key=True) key: str = Field(index=True) value: str = Field(default="") language_id: int = Field(foreign_key="language.id") created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) language: Language = Relationship(back_populates="translations") # Association table for User-Department many-to-many relationship class UserDepartmentLink(SQLModel, table=True): __tablename__ = "user_department" user_id: Optional[int] = Field(default=None, foreign_key="user.id", primary_key=True) department_id: Optional[int] = Field(default=None, foreign_key="department.id", primary_key=True) # Association table for Snippet-Department access control class SnippetDepartmentLink(SQLModel, table=True): __tablename__ = "snippet_department" snippet_id: Optional[int] = Field(default=None, foreign_key="snippet.id", primary_key=True) department_id: Optional[int] = Field(default=None, foreign_key="department.id", primary_key=True) enabled: bool = Field(default=True) # Can be toggled by admins created_at: datetime = Field(default_factory=datetime.utcnow) class User(SQLModel, table=True): __tablename__ = "user" id: Optional[int] = Field(default=None, primary_key=True) username: str = Field(unique=True, index=True) email: str = Field(unique=True, index=True) hashed_password: str full_name: Optional[str] = None profile_picture: Optional[str] = None theme: str = Field(default="light") # 'light' or 'dark' is_active: bool = Field(default=True) is_admin: bool = Field(default=False) created_at: datetime = Field(default_factory=datetime.utcnow) # Relationships departments: List["Department"] = Relationship(back_populates="users", link_model=UserDepartmentLink) messages: List["Message"] = Relationship(back_populates="sender") snippets: List["Snippet"] = Relationship(back_populates="owner") sent_direct_messages: List["DirectMessage"] = Relationship(back_populates="sender", sa_relationship_kwargs={"foreign_keys": "DirectMessage.sender_id"}) received_direct_messages: List["DirectMessage"] = Relationship(back_populates="receiver", sa_relationship_kwargs={"foreign_keys": "DirectMessage.receiver_id"}) uploaded_files: List["FileAttachment"] = Relationship(back_populates="uploader") file_permissions: List["FilePermission"] = Relationship(back_populates="user") class Department(SQLModel, table=True): __tablename__ = "department" id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(unique=True, index=True) description: Optional[str] = None snippets_enabled: bool = Field(default=True) # Master switch for snippet access created_at: datetime = Field(default_factory=datetime.utcnow) # Relationships users: List[User] = Relationship(back_populates="departments", link_model=UserDepartmentLink) channels: List["Channel"] = Relationship(back_populates="department") allowed_snippets: List["Snippet"] = Relationship(link_model=SnippetDepartmentLink) class Channel(SQLModel, table=True): __tablename__ = "channel" id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(index=True) description: Optional[str] = None department_id: int = Field(foreign_key="department.id") created_at: datetime = Field(default_factory=datetime.utcnow) # Relationships department: Department = Relationship(back_populates="channels") messages: List["Message"] = Relationship(back_populates="channel") class Message(SQLModel, table=True): __tablename__ = "message" id: Optional[int] = Field(default=None, primary_key=True) content: str sender_id: int = Field(foreign_key="user.id") channel_id: int = Field(foreign_key="channel.id") snippet_id: Optional[int] = Field(default=None, foreign_key="snippet.id") reply_to_id: Optional[int] = Field(default=None, foreign_key="message.id") # Reply to another message is_deleted: bool = Field(default=False) created_at: datetime = Field(default_factory=datetime.utcnow) # Relationships sender: User = Relationship(back_populates="messages") channel: Channel = Relationship(back_populates="messages") attachments: List["FileAttachment"] = Relationship(back_populates="message") snippet: Optional["Snippet"] = Relationship() class DirectMessage(SQLModel, table=True): __tablename__ = "direct_message" id: Optional[int] = Field(default=None, primary_key=True) content: str sender_id: int = Field(foreign_key="user.id") receiver_id: int = Field(foreign_key="user.id") snippet_id: Optional[int] = Field(default=None, foreign_key="snippet.id") reply_to_id: Optional[int] = Field(default=None, foreign_key="direct_message.id") # Reply to another DM created_at: datetime = Field(default_factory=datetime.utcnow) is_read: bool = Field(default=False) # Relationships sender: User = Relationship(back_populates="sent_direct_messages", sa_relationship_kwargs={"foreign_keys": "DirectMessage.sender_id"}) receiver: User = Relationship(back_populates="received_direct_messages", sa_relationship_kwargs={"foreign_keys": "DirectMessage.receiver_id"}) snippet: Optional["Snippet"] = Relationship() class FileAttachment(SQLModel, table=True): __tablename__ = "file_attachment" id: Optional[int] = Field(default=None, primary_key=True) filename: str original_filename: str mime_type: str file_size: int file_path: str message_id: int = Field(foreign_key="message.id") uploader_id: Optional[int] = Field(default=None, foreign_key="user.id") webdav_path: Optional[str] = None upload_permission: str = Field(default="read") # "read" or "write" is_editable: bool = Field(default=False) uploaded_at: datetime = Field(default_factory=datetime.utcnow) # Relationships message: Message = Relationship(back_populates="attachments") uploader: Optional[User] = Relationship(back_populates="uploaded_files") permissions: List["FilePermission"] = Relationship(back_populates="file") class FilePermission(SQLModel, table=True): __tablename__ = "file_permission" id: Optional[int] = Field(default=None, primary_key=True) file_id: int = Field(foreign_key="file_attachment.id") user_id: int = Field(foreign_key="user.id") permission: str = Field(default="read") # "read" or "write" granted_at: datetime = Field(default_factory=datetime.utcnow) # Relationships file: FileAttachment = Relationship(back_populates="permissions") user: User = Relationship(back_populates="file_permissions") class Snippet(SQLModel, table=True): __tablename__ = "snippet" id: Optional[int] = Field(default=None, primary_key=True) title: str = Field(index=True) language: str = Field(index=True) content: str tags: Optional[str] = None # Comma-separated visibility: SnippetVisibility = Field(default=SnippetVisibility.PRIVATE) owner_id: int = Field(foreign_key="user.id") department_id: Optional[int] = Field(default=None, foreign_key="department.id") created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships owner: User = Relationship(back_populates="snippets") department: Optional[Department] = Relationship() allowed_departments: List["Department"] = Relationship(link_model=SnippetDepartmentLink)