feat(chat): share a chat by link — anonymous read-only /shared/<token> page, share/unshare
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""saved_chats.share_token: the anonymous share link (phase 51)
|
||||
|
||||
Revision ID: 0009
|
||||
Revises: 0008
|
||||
Create Date: 2026-08-29
|
||||
|
||||
Phase 51 (share-a-chat-by-link, owner-locked 2026-08-29): a saved chat
|
||||
can be turned into a public link — ``/shared/<token>`` — that anyone
|
||||
with the URL can read anonymously (no admin session); unsharing sets
|
||||
the token back to NULL and revokes the link.
|
||||
|
||||
* ``saved_chats.share_token`` — ``UUID`` (a 128-bit ``uuid4``), NULL =
|
||||
not shared. One column, no new table (A10 extension unchanged —
|
||||
sharing reuses the already-stored row).
|
||||
* ``ix_saved_chats_share_token`` — UNIQUE index on the column. A unique
|
||||
index on a NULLable column: Postgres treats NULLs as distinct, so any
|
||||
number of unshared chats coexist while two identical non-NULL tokens
|
||||
can never exist (the ``git_sources.path`` house precedent, phase 38).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision = "0009"
|
||||
down_revision = "0008"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"saved_chats",
|
||||
sa.Column("share_token", postgresql.UUID(as_uuid=True), nullable=True),
|
||||
)
|
||||
op.create_index(
|
||||
"ix_saved_chats_share_token", "saved_chats", ["share_token"], unique=True
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index("ix_saved_chats_share_token", table_name="saved_chats")
|
||||
op.drop_column("saved_chats", "share_token")
|
||||
Reference in New Issue
Block a user