Files
TimeTracker/migrations/versions/013_add_comments_table.py
T
Dries Peeters e385abf016 feat: Add Enhanced Comments System for projects and tasks
- Add Comment model with threaded replies and user attribution
- Create Alembic migration (013_add_comments_table.py) for database schema
- Implement complete CRUD operations via comments routes
- Add responsive UI with inline editing and real-time interactions
- Include permission system (users edit own, admins manage all)
- Support soft delete for comments with replies to preserve structure
- Add comprehensive CSS styling with dark theme support
- Integrate comments sections into project and task detail views
- Fix modal z-index and context issues for delete confirmations
- Update README with detailed feature documentation

Technical details:
- Threaded comment structure with parent-child relationships
- API endpoints for comment operations and retrieval
- Mobile-responsive design with touch-friendly interactions
- Internationalization support via Flask-Babel
- Bootstrap 5 modal integration with proper event handling
2025-09-19 09:56:34 +02:00

68 lines
2.6 KiB
Python

"""add comments table for project and task discussions
Revision ID: 013
Revises: 012
Create Date: 2025-09-19 00:00:00
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '013'
down_revision = '012'
branch_labels = None
depends_on = None
def upgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
# Check if comments table already exists
if 'comments' not in inspector.get_table_names():
op.create_table('comments',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('content', sa.Text(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=True),
sa.Column('task_id', sa.Integer(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.Column('parent_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['parent_id'], ['comments.id'], ),
sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ),
sa.ForeignKeyConstraint(['task_id'], ['tasks.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
# Create indexes for better performance
op.create_index('ix_comments_project_id', 'comments', ['project_id'], unique=False)
op.create_index('ix_comments_task_id', 'comments', ['task_id'], unique=False)
op.create_index('ix_comments_user_id', 'comments', ['user_id'], unique=False)
op.create_index('ix_comments_parent_id', 'comments', ['parent_id'], unique=False)
op.create_index('ix_comments_created_at', 'comments', ['created_at'], unique=False)
def downgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
# Check if comments table exists before trying to drop it
if 'comments' in inspector.get_table_names():
try:
# Drop indexes first
op.drop_index('ix_comments_created_at', table_name='comments')
op.drop_index('ix_comments_parent_id', table_name='comments')
op.drop_index('ix_comments_user_id', table_name='comments')
op.drop_index('ix_comments_task_id', table_name='comments')
op.drop_index('ix_comments_project_id', table_name='comments')
# Drop the table
op.drop_table('comments')
except Exception:
# If dropping fails, just pass
pass