111 lines
4.6 KiB
Python
111 lines
4.6 KiB
Python
"""Add source, document, review and audit management."""
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = "0002_catalog"
|
|
down_revision = "0001_baseline"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def version_columns():
|
|
return [
|
|
sa.Column("version", sa.Integer(), server_default="1", nullable=False),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
sa.Column(
|
|
"updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
sa.Column("is_deleted", sa.Boolean(), server_default=sa.false(), nullable=False),
|
|
]
|
|
|
|
|
|
def upgrade():
|
|
op.create_table(
|
|
"sources",
|
|
sa.Column("id", sa.Integer(), primary_key=True),
|
|
sa.Column("name", sa.String(250), nullable=False),
|
|
sa.Column("source_url", sa.String(1000)),
|
|
sa.Column("notes", sa.Text(), nullable=False),
|
|
*version_columns(),
|
|
)
|
|
op.create_table(
|
|
"documents",
|
|
sa.Column("id", sa.Integer(), primary_key=True),
|
|
sa.Column("source_id", sa.Integer(), sa.ForeignKey("sources.id"), nullable=False),
|
|
sa.Column("title", sa.String(250), nullable=False),
|
|
sa.Column("category", sa.String(80), nullable=False),
|
|
sa.Column("content", sa.Text(), nullable=False),
|
|
sa.Column("collected_at", sa.DateTime(timezone=True), nullable=False),
|
|
sa.Column("notes", sa.Text(), nullable=False),
|
|
*version_columns(),
|
|
)
|
|
op.create_index("ix_documents_source_id", "documents", ["source_id"])
|
|
op.create_table(
|
|
"audit_events",
|
|
sa.Column("id", sa.Integer(), primary_key=True),
|
|
sa.Column("entity_type", sa.String(30), nullable=False),
|
|
sa.Column("entity_id", sa.Integer(), nullable=False),
|
|
sa.Column("action", sa.String(30), nullable=False),
|
|
sa.Column("actor", sa.String(100)),
|
|
sa.Column("notes", sa.Text(), nullable=False),
|
|
sa.Column("snapshot", sa.JSON(), nullable=False),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
)
|
|
op.create_index("ix_audit_events_entity_type", "audit_events", ["entity_type"])
|
|
op.create_index("ix_audit_events_entity_id", "audit_events", ["entity_id"])
|
|
for column in version_columns():
|
|
if column.name != "created_at":
|
|
op.add_column("knowledge_items", column)
|
|
for name, kind in [
|
|
("source_id", sa.Integer()),
|
|
("document_id", sa.Integer()),
|
|
("collected_at", sa.DateTime(timezone=True)),
|
|
("reviewer", sa.String(100)),
|
|
("reviewed_at", sa.DateTime(timezone=True)),
|
|
("verification_notes", sa.Text()),
|
|
]:
|
|
op.add_column("knowledge_items", sa.Column(name, kind))
|
|
for name, parent in [("source_id", "sources"), ("document_id", "documents")]:
|
|
op.create_foreign_key(f"fk_knowledge_{name}", "knowledge_items", parent, [name], ["id"])
|
|
op.create_index(f"ix_knowledge_items_{name}", "knowledge_items", [name])
|
|
op.create_check_constraint(
|
|
"ck_knowledge_verification_status",
|
|
"knowledge_items",
|
|
"verification_status IN ('pending', 'verified', 'rejected')",
|
|
)
|
|
op.execute("""INSERT INTO audit_events (entity_type, entity_id, action, notes, snapshot)
|
|
SELECT 'knowledge_items', id, 'import', '保留基础版本数据及原状态',
|
|
json_build_object('item', row_to_json(k)) FROM knowledge_items k""")
|
|
op.execute("""UPDATE knowledge_items SET verification_status = 'pending', version = version + 1
|
|
WHERE verification_status = 'verified'""")
|
|
op.execute("""INSERT INTO audit_events (entity_type, entity_id, action, notes, snapshot)
|
|
SELECT 'knowledge_items', id, 'invalidate', '旧版本没有完整审核记录,需要重新核验',
|
|
json_build_object('item', row_to_json(k)) FROM knowledge_items k WHERE version = 2""")
|
|
|
|
|
|
def downgrade():
|
|
op.drop_constraint("ck_knowledge_verification_status", "knowledge_items", type_="check")
|
|
for name in ["source_id", "document_id"]:
|
|
op.drop_index(f"ix_knowledge_items_{name}", table_name="knowledge_items")
|
|
op.drop_constraint(f"fk_knowledge_{name}", "knowledge_items", type_="foreignkey")
|
|
for name in [
|
|
"source_id",
|
|
"document_id",
|
|
"collected_at",
|
|
"reviewer",
|
|
"reviewed_at",
|
|
"verification_notes",
|
|
"version",
|
|
"updated_at",
|
|
"is_deleted",
|
|
]:
|
|
op.drop_column("knowledge_items", name)
|
|
op.drop_table("audit_events")
|
|
op.drop_table("documents")
|
|
op.drop_table("sources")
|