Первоначальная версия VidConf
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""conference invitees and avatars
|
||||
|
||||
Реализует раздел «Модель данных» ADR-003
|
||||
(`docs/architecture/adr/003-conference-invitees.md`):
|
||||
- новая таблица `conference_invitees` — приглашённые НА КОНФЕРЕНЦИЮ
|
||||
(зарегистрированный `user_id` ИЛИ внешний `email`, ровно одна identity);
|
||||
организатор в таблице не хранится (выводится из `conferences.owner_id`);
|
||||
- `users.avatar_path` — путь к загруженному аватару,
|
||||
`NULL` — заглушка с инициалами на фронте.
|
||||
|
||||
Revision ID: d87681e12784
|
||||
Revises: 504791847d4f
|
||||
Create Date: 2026-07-19 12:03:06.294730
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'd87681e12784'
|
||||
down_revision: Union[str, Sequence[str], None] = '504791847d4f'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
op.create_table(
|
||||
'conference_invitees',
|
||||
sa.Column('id', sa.UUID(), server_default=sa.text('gen_random_uuid()'), nullable=False),
|
||||
sa.Column('conference_id', sa.UUID(), nullable=False),
|
||||
sa.Column('user_id', sa.UUID(), nullable=True),
|
||||
sa.Column('email', sa.String(length=255), nullable=True),
|
||||
sa.Column(
|
||||
'created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'),
|
||||
nullable=False,
|
||||
),
|
||||
sa.CheckConstraint(
|
||||
'(user_id IS NOT NULL)::int + (email IS NOT NULL)::int = 1',
|
||||
name='ck_conference_invitees_single_identity',
|
||||
),
|
||||
sa.ForeignKeyConstraint(['conference_id'], ['conferences.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
# Частичные уникальные индексы (ADR-003, п.1): дубль по зарегистрированному
|
||||
# пользователю или по email (регистронезависимо — `lower(email)`, email
|
||||
# приложение хранит уже в lower-case, индекс — доп. страховка).
|
||||
op.create_index(
|
||||
'uq_conference_invitees_user',
|
||||
'conference_invitees',
|
||||
['conference_id', 'user_id'],
|
||||
unique=True,
|
||||
postgresql_where=sa.text('user_id IS NOT NULL'),
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
CREATE UNIQUE INDEX uq_conference_invitees_email
|
||||
ON conference_invitees (conference_id, lower(email))
|
||||
WHERE email IS NOT NULL
|
||||
"""
|
||||
)
|
||||
|
||||
op.add_column('users', sa.Column('avatar_path', sa.String(length=512), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
op.drop_column('users', 'avatar_path')
|
||||
|
||||
op.execute('DROP INDEX IF EXISTS uq_conference_invitees_email')
|
||||
op.drop_index('uq_conference_invitees_user', table_name='conference_invitees')
|
||||
op.drop_table('conference_invitees')
|
||||
Reference in New Issue
Block a user