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", "protection_discriminator", name="uq_file_blobs_tenant_checksum_size_protection", ), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(String(36), 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) protection_discriminator: Mapped[str] = mapped_column( String(320), default="plaintext", nullable=False, index=True ) encryption_envelope_id: Mapped[str | None] = mapped_column( String(255), nullable=True, index=True ) storage_checksum_sha256: Mapped[str | None] = mapped_column( String(64), nullable=True ) storage_size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True) 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)) integrity_status: Mapped[str] = mapped_column( String(30), default="unchecked", nullable=False, index=True ) integrity_checked_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, index=True ) integrity_failure: Mapped[str | None] = mapped_column(String(100), nullable=True) quarantined_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, index=True ) class FileIntegrityScan(Base, TimestampMixin): __tablename__ = "file_integrity_scans" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) storage_backend: Mapped[str] = mapped_column(String(50), nullable=False) storage_prefix: Mapped[str] = mapped_column(String(1000), nullable=False) status: Mapped[str] = mapped_column( String(30), default="pending", nullable=False, index=True ) revision: Mapped[int] = mapped_column(Integer, default=1, nullable=False) phase: Mapped[str] = mapped_column(String(30), default="blobs", nullable=False) verify_checksums: Mapped[bool] = mapped_column( Boolean, default=True, nullable=False ) batch_size: Mapped[int] = mapped_column(Integer, default=100, nullable=False) blob_cursor: Mapped[str | None] = mapped_column(String(36), nullable=True) object_cursor: Mapped[str | None] = mapped_column(String(1000), nullable=True) scanned_blob_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) verified_blob_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) quarantined_blob_count: Mapped[int] = mapped_column( Integer, default=0, nullable=False ) scanned_object_count: Mapped[int] = mapped_column( Integer, default=0, nullable=False ) orphan_object_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) created_by_user_id: Mapped[str | None] = mapped_column( ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=True ) started_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) completed_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) last_error: Mapped[str | None] = mapped_column(String(255), nullable=True) class FileIntegrityFinding(Base, TimestampMixin): __tablename__ = "file_integrity_findings" __table_args__ = ( Index("ix_file_integrity_findings_scan_state", "scan_id", "state"), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) scan_id: Mapped[str] = mapped_column( ForeignKey("file_integrity_scans.id", ondelete="CASCADE"), nullable=False, index=True, ) tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) kind: Mapped[str] = mapped_column(String(40), nullable=False, index=True) state: Mapped[str] = mapped_column( String(30), default="open", nullable=False, index=True ) revision: Mapped[int] = mapped_column(Integer, default=1, nullable=False) blob_id: Mapped[str | None] = mapped_column( ForeignKey("file_blobs.id", ondelete="SET NULL"), nullable=True, index=True ) storage_key: Mapped[str] = mapped_column(String(1000), nullable=False) expected_size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True) observed_size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True) expected_checksum_sha256: Mapped[str | None] = mapped_column( String(64), nullable=True ) observed_checksum_sha256: Mapped[str | None] = mapped_column( String(64), nullable=True ) resolved_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) resolved_by_user_id: Mapped[str | None] = mapped_column( ForeignKey("access_users.id", ondelete="SET NULL"), nullable=True, index=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(String(36), 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(String(36), 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 ) retained_until: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, index=True ) legal_hold: Mapped[bool] = mapped_column( Boolean, default=False, nullable=False, index=True ) lifecycle_revision: Mapped[int] = mapped_column( Integer, default=1, nullable=False ) lifecycle_reason: Mapped[str | None] = mapped_column(String(500), nullable=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(String(36), 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 FileFormEvidenceGrant(Base, TimestampMixin): __tablename__ = "file_form_evidence_grants" __table_args__ = ( UniqueConstraint( "tenant_id", "idempotency_key", name="uq_file_form_evidence_grants_idempotency", ), Index( "ix_file_form_evidence_grants_form", "tenant_id", "form_instance_id", "form_definition_id", "form_definition_revision", ), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) form_instance_id: Mapped[str] = mapped_column( String(36), nullable=False, index=True ) form_definition_id: Mapped[str] = mapped_column(String(255), nullable=False) form_definition_revision: Mapped[str] = mapped_column(String(255), nullable=False) token_sha256: Mapped[str] = mapped_column(String(64), nullable=False, unique=True) idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False) request_sha256: Mapped[str] = mapped_column(String(64), nullable=False) custodian_user_id: Mapped[str] = mapped_column( ForeignKey("access_users.id", ondelete="RESTRICT"), nullable=False, index=True, ) evidence_kind: Mapped[str] = mapped_column(String(30), nullable=False) purpose: Mapped[str] = mapped_column(String(500), nullable=False) status: Mapped[str] = mapped_column( String(30), default="issued", nullable=False, index=True ) expires_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, index=True ) max_size_bytes: Mapped[int] = mapped_column(Integer, nullable=False) allowed_content_types: Mapped[list[str]] = mapped_column( JSON, default=list, nullable=False ) file_asset_id: Mapped[str | None] = mapped_column( ForeignKey("file_assets.id", ondelete="RESTRICT"), nullable=True, index=True ) file_version_id: Mapped[str | None] = mapped_column( ForeignKey("file_versions.id", ondelete="RESTRICT"), nullable=True, index=True ) uploaded_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) revoked_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) metadata_: Mapped[dict[str, Any]] = mapped_column( "metadata", JSON, default=dict, nullable=False ) 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(String(36), 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 ) expires_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, index=True ) revoked_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, index=True ) revoked_by_user_id: Mapped[str | None] = mapped_column( ForeignKey("access_users.id", ondelete="SET NULL"), 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(String(36), 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(String(36), 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(String(36), 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(String(36), 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(String(36), 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", "FileFormEvidenceGrant", "FileShare", "FileVersion", ]