"""Collaboration tables (comments, mentions, notifications, blockers) Revision ID: 004 Revises: 003 Create Date: 2024-01-XX """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = '004' down_revision = '003' branch_labels = None depends_on = None def upgrade() -> None: # Create notification_type_enum notification_type_enum = sa.Enum( 'mention', 'assignment', 'blocker', 'status_change', 'comment', 'blocker_resolved', name='notification_type_enum' ) notification_type_enum.create(op.get_bind(), checkfirst=True) # Create pjctrl_comments table op.create_table( 'pjctrl_comments', sa.Column('id', sa.String(36), primary_key=True), sa.Column('task_id', sa.String(36), sa.ForeignKey('pjctrl_tasks.id', ondelete='CASCADE'), nullable=False), sa.Column('parent_comment_id', sa.String(36), sa.ForeignKey('pjctrl_comments.id', ondelete='CASCADE'), nullable=True), sa.Column('author_id', sa.String(36), sa.ForeignKey('pjctrl_users.id'), nullable=False), sa.Column('content', sa.Text, nullable=False), sa.Column('is_edited', sa.Boolean, server_default='0', nullable=False), sa.Column('is_deleted', sa.Boolean, server_default='0', nullable=False), sa.Column('created_at', sa.DateTime, server_default=sa.func.now(), nullable=False), sa.Column('updated_at', sa.DateTime, server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False), ) op.create_index('idx_comments_task', 'pjctrl_comments', ['task_id']) op.create_index('idx_comments_author', 'pjctrl_comments', ['author_id']) op.create_index('idx_comments_parent', 'pjctrl_comments', ['parent_comment_id']) # Create pjctrl_mentions table op.create_table( 'pjctrl_mentions', sa.Column('id', sa.String(36), primary_key=True), sa.Column('comment_id', sa.String(36), sa.ForeignKey('pjctrl_comments.id', ondelete='CASCADE'), nullable=False), sa.Column('mentioned_user_id', sa.String(36), sa.ForeignKey('pjctrl_users.id'), nullable=False), sa.Column('created_at', sa.DateTime, server_default=sa.func.now(), nullable=False), ) op.create_index('idx_mentions_comment', 'pjctrl_mentions', ['comment_id']) op.create_index('idx_mentions_user', 'pjctrl_mentions', ['mentioned_user_id']) # Create pjctrl_notifications table op.create_table( 'pjctrl_notifications', sa.Column('id', sa.String(36), primary_key=True), sa.Column('user_id', sa.String(36), sa.ForeignKey('pjctrl_users.id', ondelete='CASCADE'), nullable=False), sa.Column('type', notification_type_enum, nullable=False), sa.Column('reference_type', sa.String(50), nullable=False), sa.Column('reference_id', sa.String(36), nullable=False), sa.Column('title', sa.String(200), nullable=False), sa.Column('message', sa.Text, nullable=True), sa.Column('is_read', sa.Boolean, server_default='0', nullable=False), sa.Column('created_at', sa.DateTime, server_default=sa.func.now(), nullable=False), sa.Column('read_at', sa.DateTime, nullable=True), ) op.create_index('idx_notifications_user', 'pjctrl_notifications', ['user_id']) op.create_index('idx_notifications_user_unread', 'pjctrl_notifications', ['user_id', 'is_read']) op.create_index('idx_notifications_reference', 'pjctrl_notifications', ['reference_type', 'reference_id']) # Create pjctrl_blockers table op.create_table( 'pjctrl_blockers', sa.Column('id', sa.String(36), primary_key=True), sa.Column('task_id', sa.String(36), sa.ForeignKey('pjctrl_tasks.id', ondelete='CASCADE'), nullable=False), sa.Column('reported_by', sa.String(36), sa.ForeignKey('pjctrl_users.id'), nullable=False), sa.Column('reason', sa.Text, nullable=False), sa.Column('resolved_by', sa.String(36), sa.ForeignKey('pjctrl_users.id'), nullable=True), sa.Column('resolution_note', sa.Text, nullable=True), sa.Column('created_at', sa.DateTime, server_default=sa.func.now(), nullable=False), sa.Column('resolved_at', sa.DateTime, nullable=True), ) op.create_index('idx_blockers_task', 'pjctrl_blockers', ['task_id']) op.create_index('idx_blockers_reported_by', 'pjctrl_blockers', ['reported_by']) def downgrade() -> None: op.drop_table('pjctrl_blockers') op.drop_table('pjctrl_notifications') op.drop_table('pjctrl_mentions') op.drop_table('pjctrl_comments') # Drop enum type notification_type_enum = sa.Enum(name='notification_type_enum') notification_type_enum.drop(op.get_bind(), checkfirst=True)