833c604fd7
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 32s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 38s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 58s
CI/CD Pipeline / Frontend Lint (push) Successful in 1m4s
CI/CD Pipeline / Integration Tests (push) Successful in 1m0s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m12s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m51s
CI/CD Pipeline / Build Staging API Image (push) Failing after 2m6s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 2m10s
CI/CD Pipeline / Unit Tests (push) Successful in 2m39s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 1325h48m24s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 1325h48m24s
CI/CD Pipeline / Build Production Web Image (push) Failing after 1325h49m33s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 1325h48m26s
CI/CD Pipeline / Build Production API Image (push) Failing after 1325h49m35s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1325h49m29s
CI/CD Pipeline / Deploy Production (push) Failing after 1325h49m31s
CI/CD Pipeline / PR Build Web Image (push) Failing after 1325h50m35s
CI/CD Pipeline / PR Build API Image (push) Failing after 1325h50m37s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 1325h50m37s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 1326h21m52s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 1326h22m54s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1325h48m26s
49 lines
1.7 KiB
Python
Executable File
49 lines
1.7 KiB
Python
Executable File
"""#P3-2 - 视频分享表 video_shares
|
|
|
|
Revision ID: 050
|
|
Revises: 049
|
|
Create Date: 2026-07-22
|
|
|
|
Changes:
|
|
1. 新建 video_shares 表,支持视频匿名分享链接
|
|
2. share_token 唯一索引,用于公开分享URL
|
|
3. 支持密码保护、有效期、浏览/下载计数
|
|
"""
|
|
|
|
import sqlalchemy as sa
|
|
|
|
from alembic import context, op
|
|
|
|
revision = "050_video_shares"
|
|
down_revision = "049_wechat_login_phone"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
conn = op.get_bind()
|
|
if context.get_context().dialect.name == "postgresql":
|
|
# 检查表是否已存在(幂等)
|
|
result = conn.execute(sa.text("SELECT to_regclass('public.video_shares')"))
|
|
if result.scalar() is not None:
|
|
return
|
|
|
|
op.create_table(
|
|
"video_shares",
|
|
sa.Column("id", sa.String(32), primary_key=True),
|
|
sa.Column("video_id", sa.String(32), nullable=False, index=True),
|
|
sa.Column("user_id", sa.String(32), nullable=False, index=True),
|
|
sa.Column("share_token", sa.String(16), nullable=False, unique=True),
|
|
sa.Column("password_hash", sa.String(255), nullable=True),
|
|
sa.Column("expires_at", sa.DateTime(timezone=True), nullable=True),
|
|
sa.Column("view_count", sa.Integer, nullable=False, server_default="0"),
|
|
sa.Column("download_count", sa.Integer, nullable=False, server_default="0"),
|
|
sa.Column("is_active", sa.Boolean, nullable=False, server_default=sa.true()),
|
|
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
|
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_table("video_shares")
|