Kamixitong/migrations/versions/20251212_add_security_constraints.py
2025-12-12 11:35:14 +08:00

146 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""添加安全约束
Revision ID: 20251212_add_security_constraints
Revises:
Create Date: 2025-12-12 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers
revision = '20251212_add_security_constraints'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
"""
添加数据库层面的安全约束
"""
# 为License表添加约束
# 1. 解绑次数约束
op.create_check_constraint(
'chk_license_unbind_count',
'license',
'unbind_count >= 0 AND unbind_count <= 10' # 解绑次数不能超过10次
)
# 2. 有效天数约束
op.create_check_constraint(
'chk_license_valid_days',
'license',
'valid_days > 0 OR valid_days = -1' # 有效天数必须为正数或-1永久有效
)
# 3. 状态值约束
op.create_check_constraint(
'chk_license_status',
'license',
'status IN (0, 1, 2, 3)' # 0=未激活1=已激活2=已过期3=已禁用
)
# 4. 绑定次数约束
op.create_check_constraint(
'chk_license_max_bind_times',
'license',
'max_bind_times > 0 AND max_bind_times <= 100' # 最大绑定次数限制
)
# 为Product表添加约束
# 1. 价格约束
op.create_check_constraint(
'chk_product_price',
'product',
'price >= 0' # 价格不能为负数
)
# 2. 状态值约束
op.create_check_constraint(
'chk_product_status',
'product',
'status IN (0, 1)' # 0=禁用1=启用
)
# 为Order表添加约束
# 1. 金额约束
op.create_check_constraint(
'chk_order_amount',
'order',
'amount > 0' # 订单金额必须为正数
)
# 2. 状态值约束
op.create_check_constraint(
'chk_order_status',
'order',
'status IN (0, 1, 2, 3, 4)' # 0=待支付1=已支付2=已取消3=已退款4=已完成
)
# 为Ticket表添加约束
# 1. 优先级约束
op.create_check_constraint(
'chk_ticket_priority',
'ticket',
'priority IN (1, 2, 3, 4, 5)' # 1=低2=中3=高4=紧急5=非常重要
)
# 2. 状态值约束
op.create_check_constraint(
'chk_ticket_status',
'ticket',
'status IN (0, 1, 2, 3)' # 0=待处理1=处理中2=已解决3=已关闭
)
# 添加索引优化查询性能
# 1. License表的索引
op.create_index('idx_license_product_status', 'license', ['product_id', 'status'])
op.create_index('idx_license_type_status', 'license', ['type', 'status'])
op.create_index('idx_license_key', 'license', ['license_key'], unique=True)
# 2. Product表的索引
op.create_index('idx_product_status_type', 'product', ['status', 'product_type'])
# 3. Order表的索引
op.create_index('idx_order_user_phone', 'order', ['user_phone'])
op.create_index('idx_order_status_time', 'order', ['status', 'create_time'])
# 4. Ticket表的索引
op.create_index('idx_ticket_user_phone', 'ticket', ['user_phone'])
op.create_index('idx_ticket_status_priority', 'ticket', ['status', 'priority'])
# 5. Device表的索引
op.create_index('idx_device_machine_code', 'device', ['machine_code'])
op.create_index('idx_device_license', 'device', ['license_id'])
def downgrade():
"""
删除安全约束
"""
# 删除索引
op.drop_index('idx_device_license', 'device')
op.drop_index('idx_device_machine_code', 'device')
op.drop_index('idx_ticket_status_priority', 'ticket')
op.drop_index('idx_ticket_user_phone', 'ticket')
op.drop_index('idx_order_status_time', 'order')
op.drop_index('idx_order_user_phone', 'order')
op.drop_index('idx_product_status_type', 'product')
op.drop_index('idx_license_key', 'license')
op.drop_index('idx_license_type_status', 'license')
op.drop_index('idx_license_product_status', 'license')
# 删除约束
op.drop_constraint('chk_ticket_status', 'ticket', type_='check')
op.drop_constraint('chk_ticket_priority', 'ticket', type_='check')
op.drop_constraint('chk_order_status', 'order', type_='check')
op.drop_constraint('chk_order_amount', 'order', type_='check')
op.drop_constraint('chk_product_status', 'product', type_='check')
op.drop_constraint('chk_product_price', 'product', type_='check')
op.drop_constraint('chk_license_max_bind_times', 'license', type_='check')
op.drop_constraint('chk_license_status', 'license', type_='check')
op.drop_constraint('chk_license_valid_days', 'license', type_='check')
op.drop_constraint('chk_license_unbind_count', 'license', type_='check')