"""Add status + accepted_at to heap_shares and folder_shares Revision ID: 0014_share_status Revises: 0013_drop_old_ct Create Date: 2026-04-21 Shares used to activate instantly on the owner's side. We now want a pending/accepted lifecycle so the recipient gets a notification bell and chooses to accept or decline before the shared item shows up in their sidebar. Backfill note: every pre-existing row is treated as `accepted` with accepted_at = created_at. This is a pragmatic fiction — it keeps the sidebar populated after the migration without anyone having to click accept on shares that were already live. Any future "accepted X ago" UI inheriting this backfilled timestamp should be aware it's not a real user-action moment. The one-migration trick: we add `status` with `server_default="accepted"` so the backfill happens in-place, then drop the default so new inserts fall through to the Python-side model default ("pending"). """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0014_share_status" down_revision: Union[str, None] = "0013_drop_old_ct" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: for table in ("heap_shares", "folder_shares"): op.add_column( table, sa.Column( "status", sa.String(), nullable=False, server_default="accepted", ), ) op.add_column( table, sa.Column("accepted_at", sa.DateTime(), nullable=True), ) op.execute( f"UPDATE {table} SET accepted_at = created_at " "WHERE accepted_at IS NULL" ) # Drop the DB default so new rows inherit the Python-side # model default ("pending") instead of silently auto-accepting. op.alter_column(table, "status", server_default=None) op.create_index( f"ix_{table}_shared_with_status", table, ["shared_with_id", "status"], ) def downgrade() -> None: for table in ("heap_shares", "folder_shares"): op.drop_index(f"ix_{table}_shared_with_status", table_name=table) op.drop_column(table, "accepted_at") op.drop_column(table, "status")