Skip to main content
Glama
database.py14.6 kB
"""Database ORM models. This module defines all SQLAlchemy ORM models for the application. """ from datetime import datetime from typing import Any from uuid import uuid4 from sqlalchemy import ( Boolean, DateTime, Enum, ForeignKey, Integer, String, Text, func, ) from sqlalchemy.dialects.postgresql import JSON from sqlalchemy.orm import Mapped, mapped_column, relationship from src.core.enums import ( AuditAction, CommentStatus, DocumentStatus, RevisionAction, UserRole, ) from src.database.base import Base class User(Base): """User account model. Attributes: id: Unique identifier. uuid: Public UUID for API references. email: User email address. username: User display name. hashed_password: Bcrypt hashed password. role: User role (admin, editor, etc.). is_active: Whether the user is active. is_verified: Whether email is verified. created_at: Account creation timestamp. updated_at: Last update timestamp. last_login: Last login timestamp. """ __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) uuid: Mapped[str] = mapped_column( String(36), unique=True, nullable=False, default=lambda: str(uuid4()) ) email: Mapped[str] = mapped_column( String(255), unique=True, nullable=False, index=True ) username: Mapped[str] = mapped_column(String(100), nullable=False) hashed_password: Mapped[str] = mapped_column(String(255), nullable=False) role: Mapped[UserRole] = mapped_column( Enum(UserRole), default=UserRole.VIEWER, nullable=False ) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) is_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) last_login: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) # Relationships documents: Mapped[list["Document"]] = relationship( "Document", back_populates="owner", cascade="all, delete-orphan" ) comments: Mapped[list["Comment"]] = relationship( "Comment", back_populates="author", cascade="all, delete-orphan" ) revisions: Mapped[list["Revision"]] = relationship( "Revision", back_populates="author", cascade="all, delete-orphan" ) audit_logs: Mapped[list["AuditLog"]] = relationship( "AuditLog", back_populates="user", cascade="all, delete-orphan" ) class Document(Base): """Document model for storing DOCX documents. Attributes: id: Unique identifier. uuid: Public UUID for API references. title: Document title. description: Document description. file_path: Path to the stored file. file_size: File size in bytes. mime_type: File MIME type. status: Document status. version: Current version number. doc_metadata: Additional metadata as JSON. owner_id: Reference to the owner user. created_at: Creation timestamp. updated_at: Last update timestamp. deleted_at: Soft delete timestamp. """ __tablename__ = "documents" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) uuid: Mapped[str] = mapped_column( String(36), unique=True, nullable=False, default=lambda: str(uuid4()) ) title: Mapped[str] = mapped_column(String(255), nullable=False, index=True) description: Mapped[str | None] = mapped_column(Text, nullable=True) file_path: Mapped[str] = mapped_column(String(500), nullable=False) file_size: Mapped[int] = mapped_column(Integer, nullable=False, default=0) mime_type: Mapped[str] = mapped_column(String(100), nullable=False) status: Mapped[DocumentStatus] = mapped_column( Enum(DocumentStatus), default=DocumentStatus.DRAFT, nullable=False ) version: Mapped[int] = mapped_column(Integer, default=1, nullable=False) doc_metadata: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True) owner_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) deleted_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) # Relationships owner: Mapped["User"] = relationship("User", back_populates="documents") versions: Mapped[list["DocumentVersion"]] = relationship( "DocumentVersion", back_populates="document", cascade="all, delete-orphan" ) comments: Mapped[list["Comment"]] = relationship( "Comment", back_populates="document", cascade="all, delete-orphan" ) revisions: Mapped[list["Revision"]] = relationship( "Revision", back_populates="document", cascade="all, delete-orphan" ) class DocumentVersion(Base): """Document version history model. Attributes: id: Unique identifier. document_id: Reference to the parent document. version_number: Version number. file_path: Path to the version file. file_size: File size in bytes. change_summary: Summary of changes. created_by_id: User who created this version. created_at: Version creation timestamp. """ __tablename__ = "document_versions" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) document_id: Mapped[int] = mapped_column( Integer, ForeignKey("documents.id", ondelete="CASCADE"), nullable=False ) version_number: Mapped[int] = mapped_column(Integer, nullable=False) file_path: Mapped[str] = mapped_column(String(500), nullable=False) file_size: Mapped[int] = mapped_column(Integer, nullable=False, default=0) change_summary: Mapped[str | None] = mapped_column(Text, nullable=True) created_by_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) # Relationships document: Mapped["Document"] = relationship("Document", back_populates="versions") class Comment(Base): """Document comment/annotation model. Attributes: id: Unique identifier. uuid: Public UUID for API references. document_id: Reference to the document. author_id: Reference to the comment author. content: Comment text content. status: Comment status. paragraph_index: Paragraph where comment is attached. start_offset: Character offset start. end_offset: Character offset end. parent_id: Parent comment for replies. created_at: Creation timestamp. updated_at: Last update timestamp. resolved_at: Resolution timestamp. """ __tablename__ = "comments" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) uuid: Mapped[str] = mapped_column( String(36), unique=True, nullable=False, default=lambda: str(uuid4()) ) document_id: Mapped[int] = mapped_column( Integer, ForeignKey("documents.id", ondelete="CASCADE"), nullable=False ) author_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) content: Mapped[str] = mapped_column(Text, nullable=False) status: Mapped[CommentStatus] = mapped_column( Enum(CommentStatus), default=CommentStatus.OPEN, nullable=False ) paragraph_index: Mapped[int | None] = mapped_column(Integer, nullable=True) start_offset: Mapped[int | None] = mapped_column(Integer, nullable=True) end_offset: Mapped[int | None] = mapped_column(Integer, nullable=True) parent_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("comments.id", ondelete="CASCADE"), nullable=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) resolved_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) # Relationships document: Mapped["Document"] = relationship("Document", back_populates="comments") author: Mapped["User"] = relationship("User", back_populates="comments") replies: Mapped[list["Comment"]] = relationship( "Comment", backref="parent", remote_side=[id], cascade="all, delete-orphan" ) class Revision(Base): """Document revision tracking model. Attributes: id: Unique identifier. uuid: Public UUID for API references. document_id: Reference to the document. author_id: Reference to the revision author. action: Type of revision action. paragraph_index: Affected paragraph index. original_content: Original content before change. new_content: New content after change. is_accepted: Whether revision is accepted. created_at: Revision creation timestamp. accepted_at: Acceptance timestamp. accepted_by_id: User who accepted the revision. """ __tablename__ = "revisions" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) uuid: Mapped[str] = mapped_column( String(36), unique=True, nullable=False, default=lambda: str(uuid4()) ) document_id: Mapped[int] = mapped_column( Integer, ForeignKey("documents.id", ondelete="CASCADE"), nullable=False ) author_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) action: Mapped[RevisionAction] = mapped_column(Enum(RevisionAction), nullable=False) paragraph_index: Mapped[int | None] = mapped_column(Integer, nullable=True) original_content: Mapped[str | None] = mapped_column(Text, nullable=True) new_content: Mapped[str | None] = mapped_column(Text, nullable=True) is_accepted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) accepted_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) accepted_by_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True ) # Relationships document: Mapped["Document"] = relationship("Document", back_populates="revisions") author: Mapped["User"] = relationship("User", back_populates="revisions") class Template(Base): """Document template model. Attributes: id: Unique identifier. uuid: Public UUID for API references. name: Template name. description: Template description. file_path: Path to template file. category: Template category. is_public: Whether template is public. template_metadata: Additional metadata as JSON. created_by_id: User who created the template. created_at: Creation timestamp. updated_at: Last update timestamp. """ __tablename__ = "templates" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) uuid: Mapped[str] = mapped_column( String(36), unique=True, nullable=False, default=lambda: str(uuid4()) ) name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) description: Mapped[str | None] = mapped_column(Text, nullable=True) file_path: Mapped[str] = mapped_column(String(500), nullable=False) category: Mapped[str | None] = mapped_column(String(100), nullable=True) is_public: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) template_metadata: Mapped[dict[str, Any] | None] = mapped_column( JSON, nullable=True ) created_by_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) class AuditLog(Base): """Audit log for tracking user actions. Attributes: id: Unique identifier. user_id: Reference to the user. action: Type of action performed. resource_type: Type of resource affected. resource_id: ID of the affected resource. details: Additional action details as JSON. ip_address: Client IP address. user_agent: Client user agent. created_at: Action timestamp. """ __tablename__ = "audit_logs" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True ) action: Mapped[AuditAction] = mapped_column(Enum(AuditAction), nullable=False) resource_type: Mapped[str] = mapped_column(String(50), nullable=False) resource_id: Mapped[str | None] = mapped_column(String(50), nullable=True) details: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True) ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True) user_agent: Mapped[str | None] = mapped_column(String(500), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, index=True ) # Relationships user: Mapped["User"] = relationship("User", back_populates="audit_logs")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Fu-Jie/MCP-OPENAPI-DOCX'

If you have feedback or need assistance with the MCP directory API, please join our Discord server