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 UserRole(str, Enum): USER = "user" ADMIN = "admin" SUPERADMIN = "superadmin" 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) role: UserRole = Field(default=UserRole.USER) 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") kanban_board: Optional["KanbanBoard"] = 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) # Kanban Board Models class KanbanBoard(SQLModel, table=True): __tablename__ = "kanban_board" id: Optional[int] = Field(default=None, primary_key=True) channel_id: int = Field(foreign_key="channel.id") name: str = Field(default="Kanban Board") created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships channel: Channel = Relationship(back_populates="kanban_board") columns: List["KanbanColumn"] = Relationship(back_populates="board") class KanbanColumn(SQLModel, table=True): __tablename__ = "kanban_column" id: Optional[int] = Field(default=None, primary_key=True) board_id: int = Field(foreign_key="kanban_board.id") name: str position: int = Field(default=0) # For ordering columns color: Optional[str] = Field(default=None) # Hex color for the column created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships board: KanbanBoard = Relationship(back_populates="columns") cards: List["KanbanCard"] = Relationship(back_populates="column") class KanbanCard(SQLModel, table=True): __tablename__ = "kanban_card" id: Optional[int] = Field(default=None, primary_key=True) column_id: int = Field(foreign_key="kanban_column.id") title: str description: Optional[str] = Field(default=None) assignee_id: Optional[int] = Field(default=None, foreign_key="user.id") position: int = Field(default=0) # For ordering cards within a column due_date: Optional[datetime] = Field(default=None) priority: Optional[str] = Field(default="medium") # low, medium, high labels: Optional[str] = Field(default=None) # JSON string for labels/tags created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships column: KanbanColumn = Relationship(back_populates="cards") assignee: Optional[User] = Relationship() checklists: List["KanbanChecklist"] = Relationship(back_populates="card") class KanbanChecklist(SQLModel, table=True): __tablename__ = "kanban_checklist" id: Optional[int] = Field(default=None, primary_key=True) card_id: int = Field(foreign_key="kanban_card.id") title: str position: int = Field(default=0) # For ordering checklists within a card created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships card: KanbanCard = Relationship(back_populates="checklists") items: List["KanbanChecklistItem"] = Relationship(back_populates="checklist") class KanbanChecklistItem(SQLModel, table=True): __tablename__ = "kanban_checklist_item" id: Optional[int] = Field(default=None, primary_key=True) checklist_id: int = Field(foreign_key="kanban_checklist.id") title: str is_completed: bool = Field(default=False) position: int = Field(default=0) # For ordering items within a checklist created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) # Relationships checklist: KanbanChecklist = Relationship(back_populates="items")