Files
IT_Ticket_System/migrations/versions/003_render_existing_comment_bodies.py
2026-03-31 10:55:40 -04:00

99 lines
3.0 KiB
Python

"""Render existing plain-text comment bodies to sanitized HTML.
Revision ID: 003_render_comments
Revises: 002_add_system_settings
Create Date: 2026-03-31
Rationale
---------
Feature #8 (Markdown rendering) stores rendered HTML in Comment.body at
write time. Comments created before this feature are stored as plain text
and must be migrated so all bodies are consistently sanitized HTML.
Also widens alembic_version.version_num from VARCHAR(32) to VARCHAR(64)
to accommodate longer revision ID strings.
Apply
-----
flask db upgrade
Rollback
--------
flask db downgrade
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.orm import Session
revision = '003_render_comments'
down_revision = '002_add_system_settings'
branch_labels = None
depends_on = None
def upgrade():
bind = op.get_bind()
inspector = sa.inspect(bind)
# ── 1. Widen alembic_version.version_num to VARCHAR(64) ──────────────────
# Flask-Migrate creates this column as VARCHAR(32). Long revision IDs
# (>32 chars) cause DataError when Alembic tries to record the new head.
# This widen is idempotent — safe to run even if already widened.
op.execute(
"ALTER TABLE alembic_version "
"MODIFY COLUMN version_num VARCHAR(64) NOT NULL"
)
# ── 2. Add body_plain_backup column (idempotent) ──────────────────────────
existing_cols = [c['name'] for c in inspector.get_columns('comments')]
if 'body_plain_backup' not in existing_cols:
op.add_column(
'comments',
sa.Column('body_plain_backup', sa.Text(), nullable=True),
)
# ── 3. Render plain-text comment bodies to sanitized HTML ─────────────────
session = Session(bind=bind)
from app.services.validation_service import render_comment_body
rows = session.execute(sa.text('SELECT id, body FROM comments')).fetchall()
updated = 0
for row in rows:
comment_id, body = row[0], row[1]
if not body:
continue
# Skip bodies already rendered as HTML (start with an opening tag).
if body.lstrip().startswith('<'):
continue
rendered = render_comment_body(body)
session.execute(
sa.text(
'UPDATE comments '
'SET body_plain_backup = :plain, body = :rendered '
'WHERE id = :id'
),
{'plain': body, 'rendered': rendered, 'id': comment_id},
)
updated += 1
session.commit()
print(f'[MIGRATION 003] Rendered {updated} plain-text comment bodies to HTML.')
def downgrade():
bind = op.get_bind()
session = Session(bind=bind)
session.execute(sa.text(
'UPDATE comments '
'SET body = body_plain_backup '
'WHERE body_plain_backup IS NOT NULL'
))
session.commit()
op.drop_column('comments', 'body_plain_backup')
print('[MIGRATION 003] Downgrade complete — plain-text bodies restored.')