from __future__ import annotations import uuid from datetime import datetime from typing import Any from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, JSON, String, Text, UniqueConstraint, text from sqlalchemy.orm import Mapped, mapped_column from govoplan_core.db.base import Base, TimestampMixin def new_uuid() -> str: return str(uuid.uuid4()) class FileBlob(Base, TimestampMixin): __tablename__ = "file_blobs" __table_args__ = (UniqueConstraint("tenant_id", "checksum_sha256", "size_bytes", name="uq_file_blobs_tenant_checksum_size"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) storage_backend: Mapped[str] = mapped_column(String(50), nullable=False) storage_bucket: Mapped[str | None] = mapped_column(String(255)) storage_key: Mapped[str] = mapped_column(String(1000), nullable=False) checksum_sha256: Mapped[str] = mapped_column(String(64), nullable=False, index=True) size_bytes: Mapped[int] = mapped_column(Integer, nullable=False) content_type: Mapped[str | None] = mapped_column(String(255)) ref_count: Mapped[int] = mapped_column(Integer, default=1, nullable=False) retained_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) class FileFolder(Base, TimestampMixin): __tablename__ = "file_folders" __table_args__ = ( Index( "uq_file_folders_active_user_path", "tenant_id", "owner_user_id", "path", unique=True, sqlite_where=text("owner_type = 'user' AND deleted_at IS NULL"), postgresql_where=text("owner_type = 'user' AND deleted_at IS NULL"), ), Index( "uq_file_folders_active_group_path", "tenant_id", "owner_group_id", "path", unique=True, sqlite_where=text("owner_type = 'group' AND deleted_at IS NULL"), postgresql_where=text("owner_type = 'group' AND deleted_at IS NULL"), ), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) owner_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True) owner_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) owner_group_id: Mapped[str | None] = mapped_column(ForeignKey("access_groups.id", ondelete="SET NULL"), nullable=True, index=True) path: Mapped[str] = mapped_column(String(1000), nullable=False, index=True) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True) class FileAsset(Base, TimestampMixin): __tablename__ = "file_assets" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) owner_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True) owner_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) owner_group_id: Mapped[str | None] = mapped_column(ForeignKey("access_groups.id", ondelete="SET NULL"), nullable=True, index=True) current_version_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) display_path: Mapped[str] = mapped_column(String(1000), nullable=False, index=True) filename: Mapped[str] = mapped_column(String(500), nullable=False, index=True) description: Mapped[str | None] = mapped_column(Text) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True) class FileVersion(Base, TimestampMixin): __tablename__ = "file_versions" __table_args__ = (UniqueConstraint("file_asset_id", "version_number", name="uq_file_versions_asset_number"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) file_asset_id: Mapped[str] = mapped_column(ForeignKey("file_assets.id", ondelete="CASCADE"), nullable=False, index=True) blob_id: Mapped[str] = mapped_column(ForeignKey("file_blobs.id", ondelete="RESTRICT"), nullable=False, index=True) version_number: Mapped[int] = mapped_column(Integer, nullable=False) filename_at_upload: Mapped[str] = mapped_column(String(500), nullable=False) display_path_at_upload: Mapped[str] = mapped_column(String(1000), nullable=False) content_type: Mapped[str | None] = mapped_column(String(255)) size_bytes: Mapped[int] = mapped_column(Integer, nullable=False) checksum_sha256: Mapped[str] = mapped_column(String(64), nullable=False, index=True) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) class FileShare(Base, TimestampMixin): __tablename__ = "file_shares" __table_args__ = (UniqueConstraint("file_asset_id", "target_type", "target_id", "revoked_at", name="uq_file_shares_active_target"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) file_asset_id: Mapped[str] = mapped_column(ForeignKey("file_assets.id", ondelete="CASCADE"), nullable=False, index=True) target_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True) target_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) permission: Mapped[str] = mapped_column(String(20), default="read", nullable=False) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) class FileConnectorProfile(Base, TimestampMixin): __tablename__ = "file_connector_profiles" __table_args__ = ( Index("ix_file_connector_profiles_scope", "scope_type", "scope_id"), ) id: Mapped[str] = mapped_column(String(255), primary_key=True) tenant_id: Mapped[str | None] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=True, index=True) scope_type: Mapped[str] = mapped_column(String(20), default="tenant", nullable=False, index=True) scope_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) label: Mapped[str] = mapped_column(String(255), nullable=False) provider: Mapped[str] = mapped_column(String(50), nullable=False, index=True) endpoint_url: Mapped[str | None] = mapped_column(String(1000), nullable=True) base_path: Mapped[str | None] = mapped_column(String(1000), nullable=True) enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False, index=True) credential_profile_id: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True) credential_mode: Mapped[str] = mapped_column(String(30), default="none", nullable=False) username: Mapped[str | None] = mapped_column(String(320), nullable=True) password_encrypted: Mapped[str | None] = mapped_column(Text, nullable=True) token_encrypted: Mapped[str | None] = mapped_column(Text, nullable=True) password_env: Mapped[str | None] = mapped_column(String(255), nullable=True) token_env: Mapped[str | None] = mapped_column(String(255), nullable=True) secret_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True) capabilities: Mapped[list[str] | None] = mapped_column(JSON, nullable=True) policy: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True) metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) updated_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) class FileConnectorCredential(Base, TimestampMixin): __tablename__ = "file_connector_credentials" __table_args__ = ( Index("ix_file_connector_credentials_scope", "scope_type", "scope_id"), ) id: Mapped[str] = mapped_column(String(255), primary_key=True) tenant_id: Mapped[str | None] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=True, index=True) scope_type: Mapped[str] = mapped_column(String(20), default="tenant", nullable=False, index=True) scope_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) label: Mapped[str] = mapped_column(String(255), nullable=False) provider: Mapped[str | None] = mapped_column(String(50), nullable=True, index=True) enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False, index=True) credential_mode: Mapped[str] = mapped_column(String(30), default="none", nullable=False) username: Mapped[str | None] = mapped_column(String(320), nullable=True) password_encrypted: Mapped[str | None] = mapped_column(Text, nullable=True) token_encrypted: Mapped[str | None] = mapped_column(Text, nullable=True) password_env: Mapped[str | None] = mapped_column(String(255), nullable=True) token_env: Mapped[str | None] = mapped_column(String(255), nullable=True) secret_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True) policy: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True) metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) updated_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) class FileConnectorPolicy(Base, TimestampMixin): __tablename__ = "file_connector_policies" __table_args__ = ( UniqueConstraint("tenant_id", "scope_type", "scope_id", name="uq_file_connector_policies_scope"), Index("ix_file_connector_policies_scope", "scope_type", "scope_id"), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str | None] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=True, index=True) scope_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True) scope_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) policy: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, nullable=False) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) updated_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) class FileConnectorSpace(Base, TimestampMixin): __tablename__ = "file_connector_spaces" __table_args__ = ( Index("ix_file_connector_spaces_owner", "tenant_id", "owner_type", "owner_user_id", "owner_group_id"), Index( "uq_file_connector_spaces_active_user_label", "tenant_id", "owner_user_id", "label", unique=True, sqlite_where=text("owner_type = 'user' AND deleted_at IS NULL"), postgresql_where=text("owner_type = 'user' AND deleted_at IS NULL"), ), Index( "uq_file_connector_spaces_active_group_label", "tenant_id", "owner_group_id", "label", unique=True, sqlite_where=text("owner_type = 'group' AND deleted_at IS NULL"), postgresql_where=text("owner_type = 'group' AND deleted_at IS NULL"), ), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) owner_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True) owner_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) owner_group_id: Mapped[str | None] = mapped_column(ForeignKey("access_groups.id", ondelete="SET NULL"), nullable=True, index=True) label: Mapped[str] = mapped_column(String(255), nullable=False) connector_profile_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True) provider: Mapped[str] = mapped_column(String(50), nullable=False, index=True) library_id: Mapped[str | None] = mapped_column(String(255), nullable=True) remote_path: Mapped[str] = mapped_column(String(1000), default="", nullable=False) sync_mode: Mapped[str] = mapped_column(String(30), default="manual", nullable=False) read_only: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False, index=True) created_by_user_id: Mapped[str | None] = mapped_column(ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True) deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True) class CampaignAttachmentUse(Base, TimestampMixin): __tablename__ = "campaign_attachment_uses" __table_args__ = (UniqueConstraint("campaign_job_id", "file_version_id", "filename_used", "use_stage", name="uq_campaign_attachment_uses_job_file_stage"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(ForeignKey("tenancy_tenants.id", ondelete="CASCADE"), nullable=False, index=True) campaign_id: Mapped[str] = mapped_column(ForeignKey("campaigns.id", ondelete="CASCADE"), nullable=False, index=True) campaign_version_id: Mapped[str] = mapped_column(ForeignKey("campaign_versions.id", ondelete="CASCADE"), nullable=False, index=True) campaign_job_id: Mapped[str | None] = mapped_column(ForeignKey("campaign_jobs.id", ondelete="SET NULL"), nullable=True, index=True) entry_index: Mapped[int | None] = mapped_column(Integer) entry_id: Mapped[str | None] = mapped_column(String(255), index=True) file_asset_id: Mapped[str] = mapped_column(ForeignKey("file_assets.id", ondelete="RESTRICT"), nullable=False, index=True) file_version_id: Mapped[str] = mapped_column(ForeignKey("file_versions.id", ondelete="RESTRICT"), nullable=False, index=True) file_blob_id: Mapped[str] = mapped_column(ForeignKey("file_blobs.id", ondelete="RESTRICT"), nullable=False, index=True) filename_used: Mapped[str] = mapped_column(String(500), nullable=False) checksum_sha256: Mapped[str] = mapped_column(String(64), nullable=False) size_bytes: Mapped[int] = mapped_column(Integer, nullable=False) content_type: Mapped[str | None] = mapped_column(String(255)) use_stage: Mapped[str] = mapped_column(String(20), default="built", nullable=False, index=True) used_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) __all__ = [ "CampaignAttachmentUse", "FileAsset", "FileBlob", "FileConnectorCredential", "FileConnectorPolicy", "FileConnectorProfile", "FileConnectorSpace", "FileFolder", "FileShare", "FileVersion", ]