diff --git a/app/utils/db_migrate.py b/app/utils/db_migrate.py index 5d11ee36..3424009d 100644 --- a/app/utils/db_migrate.py +++ b/app/utils/db_migrate.py @@ -35,6 +35,7 @@ _TABLE_ORDER = [ "audit_logs", "saved_searches", "webhook_configs", + "shared_links", ] diff --git a/migrations/env.py b/migrations/env.py index d421d3c7..67fc3ad3 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -20,14 +20,29 @@ from app.database import Base # Ensure all models are imported so Base.metadata is populated. from app.models import ( # noqa: F401 + ApiToken, ApplicationSettings, AuditLog, + BackupRecord, DocumentMetadata, FileProcessingStep, FileRecord, + InAppNotification, + LocalUser, + Pipeline, + PipelineStep, ProcessingLog, SavedSearch, + ScheduledJob, SettingsAuditLog, + SharedLink, + SubscriptionPlan, + UserImapAccount, + UserIntegration, + UserNotificationPreference, + UserNotificationTarget, + UserProfile, + WebhookConfig, ) # Alembic Config object – provides access to values in alembic.ini. diff --git a/migrations/versions/027_ensure_shared_links_table.py b/migrations/versions/027_ensure_shared_links_table.py new file mode 100644 index 00000000..2a333582 --- /dev/null +++ b/migrations/versions/027_ensure_shared_links_table.py @@ -0,0 +1,62 @@ +"""Ensure shared_links table exists for databases that skipped migration 025. + +Databases that were already at revision 025_add_user_notifications or +026_add_scheduled_jobs before 025_add_shared_links was inserted into the +migration chain will never have had the ``shared_links`` table created. +This migration creates the table idempotently so those databases are +repaired on the next ``alembic upgrade head``. + +Revision ID: 027_ensure_shared_links_table +Revises: 026_add_scheduled_jobs +Create Date: 2026-03-09 +""" + +from typing import Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "027_ensure_shared_links_table" +down_revision: Union[str, None] = "026_add_scheduled_jobs" +depends_on: Union[str, None] = None + + +def upgrade() -> None: + """Create shared_links table if it does not already exist.""" + conn = op.get_bind() + inspector = sa.inspect(conn) + if "shared_links" not in inspector.get_table_names(): + op.create_table( + "shared_links", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("token", sa.String(64), nullable=False), + sa.Column("file_id", sa.Integer(), nullable=False), + sa.Column("owner_id", sa.String(), nullable=False), + sa.Column("label", sa.String(255), nullable=True), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("max_views", sa.Integer(), nullable=True), + sa.Column("view_count", sa.Integer(), nullable=False, server_default="0"), + sa.Column("password_hash", sa.String(128), nullable=True), + sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), + sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), + sa.ForeignKeyConstraint(["file_id"], ["files.id"]), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("token"), + ) + op.create_index("ix_shared_links_id", "shared_links", ["id"]) + op.create_index("ix_shared_links_token", "shared_links", ["token"]) + op.create_index("ix_shared_links_file_id", "shared_links", ["file_id"]) + op.create_index("ix_shared_links_owner_id", "shared_links", ["owner_id"]) + + +def downgrade() -> None: + """Drop shared_links table only if this migration created it.""" + conn = op.get_bind() + inspector = sa.inspect(conn) + if "shared_links" in inspector.get_table_names(): + op.drop_index("ix_shared_links_owner_id", "shared_links") + op.drop_index("ix_shared_links_file_id", "shared_links") + op.drop_index("ix_shared_links_token", "shared_links") + op.drop_index("ix_shared_links_id", "shared_links") + op.drop_table("shared_links") diff --git a/migrations/versions/027_add_audit_logs.py b/migrations/versions/028_add_audit_logs.py similarity index 90% rename from migrations/versions/027_add_audit_logs.py rename to migrations/versions/028_add_audit_logs.py index 5fe0280c..58114e7a 100644 --- a/migrations/versions/027_add_audit_logs.py +++ b/migrations/versions/028_add_audit_logs.py @@ -1,7 +1,7 @@ """Add audit_logs table for comprehensive compliance audit logging. -Revision ID: 027_add_audit_logs -Revises: 026_add_scheduled_jobs +Revision ID: 028_add_audit_logs +Revises: 027_ensure_shared_links_table Create Date: 2026-03-09 """ @@ -10,8 +10,8 @@ from typing import Union import sqlalchemy as sa from alembic import op -revision: str = "027_add_audit_logs" -down_revision: Union[str, None] = "026_add_scheduled_jobs" +revision: str = "028_add_audit_logs" +down_revision: Union[str, None] = "027_ensure_shared_links_table" depends_on: Union[str, None] = None