Kamixitong/init_db.py
2025-11-11 21:39:12 +08:00

550 lines
19 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库初始化脚本
KaMiXiTong 软件授权管理系统
功能:
1. 创建数据库表结构
2. 插入初始数据
3. 创建默认管理员账号
4. 插入示例产品和许可证
使用方法:
python init_db.py
"""
import os
import sys
from datetime import datetime, timedelta
# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# 导入应用创建函数(在文件顶部是安全的)
from app import create_app, db
# 注意:模型导入在函数内部进行,确保在应用上下文中
def init_database():
"""初始化数据库"""
print("=" * 50)
print("KaMiXiTong 数据库初始化开始...")
print("=" * 50)
# 创建应用实例
app = create_app()
# 显示数据库配置信息
print(f"数据库类型: {app.config['SQLALCHEMY_DATABASE_URI'].split('+')[0].split(':')[0]}")
print(f"数据库连接: {app.config['SQLALCHEMY_DATABASE_URI']}")
with app.app_context():
try:
# 0. 测试数据库连接
print("\n0. 测试数据库连接...")
with db.engine.connect() as connection:
result = connection.execute(db.text('SELECT 1'))
print(" ✓ 数据库连接成功")
# 1. 删除所有表(如果存在)
print("\n1. 清理现有数据库表...")
db.drop_all()
print(" ✓ 已删除所有现有表")
# 2. 创建所有表
print("\n2. 创建数据库表结构...")
db.create_all()
print(" ✓ 已创建所有数据表")
# 2.1 验证表创建
print("\n2.1 验证表创建...")
from sqlalchemy import inspect
inspector = inspect(db.engine)
tables = inspector.get_table_names()
print(f" ✓ 成功创建 {len(tables)} 个表: {', '.join(tables)}")
if not tables:
raise Exception("表创建失败,没有找到任何表")
# 3. 插入初始数据
print("\n3. 插入初始数据...")
insert_initial_data()
# 4. 显示数据库信息
print("\n4. 数据库初始化完成!")
show_database_info()
except Exception as e:
print(f"\n❌ 数据库初始化失败: {e}")
db.session.rollback()
raise
def insert_initial_data():
"""插入初始数据"""
# 在应用上下文中导入模型
from app.models import Admin, Product, Version, License, Device, Ticket
from app.models.license import License
# 1. 创建默认管理员账号
print(" 创建默认管理员账号...")
admin = Admin(
username='admin',
email='admin@kamaxitong.com',
role=1, # 超级管理员
status=1 # 正常
)
admin.set_password('admin123')
db.session.add(admin)
# 创建测试管理员账号
test_admin = Admin(
username='test_admin',
email='test@kamaxitong.com',
role=0, # 普通管理员
status=1 # 正常
)
test_admin.set_password('test123')
db.session.add(test_admin)
print(" ✓ 已创建管理员账号 (admin/admin123, test_admin/test123)")
# 2. 创建示例产品
print(" 创建示例产品...")
products = [
Product(
product_id='KMX001',
product_name='KaMiXiTong 专业版',
description='专业的软件授权管理系统,支持多种授权模式和完整的设备管理',
status=1
),
Product(
product_id='KMX002',
product_name='KaMiXiTong 企业版',
description='企业级软件授权管理解决方案,支持分布式部署和高并发访问',
status=1
),
Product(
product_id='KMX003',
product_name='KaMiXiTong 云端版',
description='云端SaaS版本的软件授权管理系统无需本地部署',
status=0 # 禁用状态
)
]
for product in products:
db.session.add(product)
print(" ✓ 已创建3个示例产品")
# 3. 创建版本信息
print(" 创建版本信息...")
versions = [
# KaMiXiTong 专业版版本
Version(
product_id='KMX001',
version_num='1.0.0',
update_log='初始版本发布\n- 基础授权管理功能\n- 设备绑定验证\n- Web管理界面',
download_url='https://download.kamaxitong.com/v1.0.0/professional.exe',
min_license_version='1.0.0',
force_update=0,
download_status=1,
publish_status=1
),
Version(
product_id='KMX001',
version_num='1.1.0',
update_log='功能增强版本\n- 新增批量许可证生成\n- 优化设备验证算法\n- 修复已知bug',
download_url='https://download.kamaxitong.com/v1.1.0/professional.exe',
min_license_version='1.0.0',
force_update=0,
download_status=1,
publish_status=1
),
Version(
product_id='KMX001',
version_num='1.2.0',
update_log='重要更新版本\n- 支持云端同步\n- 增强安全性\n- 新增API接口',
download_url='https://download.kamaxitong.com/v1.2.0/professional.exe',
min_license_version='1.0.0',
force_update=1, # 强制更新
download_status=1,
publish_status=1
),
# KaMiXiTong 企业版版本
Version(
product_id='KMX002',
version_num='2.0.0',
update_log='企业版初始版本\n- 支持分布式部署\n- 高并发处理\n- 企业级安全认证',
download_url='https://download.kamaxitong.com/v2.0.0/enterprise.exe',
min_license_version='2.0.0',
force_update=0,
download_status=1,
publish_status=1
),
Version(
product_id='KMX002',
version_num='2.1.0',
update_log='企业版功能增强\n- 集群部署支持\n- 负载均衡优化\n- 监控面板',
download_url='https://download.kamaxitong.com/v2.1.0/enterprise.exe',
min_license_version='2.0.0',
force_update=0,
download_status=1,
publish_status=0 # 草稿状态
),
# KaMiXiTong 云端版版本
Version(
product_id='KMX003',
version_num='3.0.0',
update_log='云端版Beta版本\n- 完全云端部署\n- 自动备份\n- 弹性扩容',
download_url='https://cloud.kamaxitong.com/download/v3.0.0/',
min_license_version='3.0.0',
force_update=0,
download_status=0, # 下载不可用
publish_status=0 # 草稿状态
)
]
for version in versions:
db.session.add(version)
print(" ✓ 已创建6个版本信息")
# 4. 创建示例许可证
print(" 创建示例许可证...")
current_time = datetime.utcnow()
licenses = [
# 永久许可证
License(
license_key=License.generate_license_key(),
product_id='KMX001',
type=1, # 正式版
status=1, # 已激活
valid_days=-1, # 永久
bind_machine_code='DEMO-MACHINE-CODE-001',
activate_time=current_time - timedelta(days=30),
expire_time=None, # 永久不过期
last_verify_time=current_time - timedelta(days=1),
unbind_count=0
),
# 1年试用期许可证
License(
license_key=License.generate_license_key(),
product_id='KMX001',
type=0, # 试用版
status=1, # 已激活
valid_days=365, # 1年
bind_machine_code='DEMO-MACHINE-CODE-002',
activate_time=current_time - timedelta(days=15),
expire_time=current_time + timedelta(days=350), # 还有350天过期
last_verify_time=current_time - timedelta(hours=6),
unbind_count=1
),
# 30天试用许可证即将过期
License(
license_key=License.generate_license_key(),
product_id='KMX002',
type=0, # 试用版
status=1, # 已激活
valid_days=30, # 30天
bind_machine_code='DEMO-MACHINE-CODE-003',
activate_time=current_time - timedelta(days=25),
expire_time=current_time + timedelta(days=5), # 还有5天过期
last_verify_time=current_time - timedelta(hours=12),
unbind_count=2
),
# 未激活许可证
License(
license_key=License.generate_license_key(),
product_id='KMX002',
type=1, # 正式版
status=0, # 未激活
valid_days=365, # 1年
bind_machine_code=None,
activate_time=None,
expire_time=None,
last_verify_time=None,
unbind_count=0
),
# 已过期许可证
License(
license_key=License.generate_license_key(),
product_id='KMX001',
type=0, # 试用版
status=2, # 已过期
valid_days=30, # 30天
bind_machine_code='DEMO-MACHINE-CODE-004',
activate_time=current_time - timedelta(days=60),
expire_time=current_time - timedelta(days=30), # 已过期30天
last_verify_time=current_time - timedelta(days=35),
unbind_count=0
),
# 已禁用许可证
License(
license_key=License.generate_license_key(),
product_id='KMX003',
type=1, # 正式版
status=3, # 已禁用
valid_days=-1, # 永久
bind_machine_code='DEMO-MACHINE-CODE-005',
activate_time=current_time - timedelta(days=45),
expire_time=None,
last_verify_time=current_time - timedelta(days=10),
unbind_count=1
)
]
for license_obj in licenses:
db.session.add(license_obj)
print(" ✓ 已创建6个示例许可证")
# 5. 创建示例设备
print(" 创建示例设备...")
devices = [
Device(
machine_code='DEMO-MACHINE-CODE-001',
license_id=1, # 对应第一个许可证
product_id='KMX001',
software_version='1.2.0',
status=1, # 正常
activate_time=current_time - timedelta(days=30),
last_verify_time=current_time - timedelta(days=1)
),
Device(
machine_code='DEMO-MACHINE-CODE-002',
license_id=2, # 对应第二个许可证
product_id='KMX001',
software_version='1.1.0',
status=1, # 正常
activate_time=current_time - timedelta(days=15),
last_verify_time=current_time - timedelta(hours=6)
),
Device(
machine_code='DEMO-MACHINE-CODE-003',
license_id=3, # 对应第三个许可证
product_id='KMX002',
software_version='2.0.0',
status=1, # 正常
activate_time=current_time - timedelta(days=25),
last_verify_time=current_time - timedelta(hours=12)
),
Device(
machine_code='DEMO-MACHINE-CODE-004',
license_id=5, # 对应第五个许可证(已过期)
product_id='KMX001',
software_version='1.0.0',
status=0, # 禁用
activate_time=current_time - timedelta(days=60),
last_verify_time=current_time - timedelta(days=35)
),
Device(
machine_code='DEMO-MACHINE-CODE-005',
license_id=6, # 对应第六个许可证(已禁用)
product_id='KMX003',
software_version='3.0.0-beta',
status=0, # 禁用
activate_time=current_time - timedelta(days=45),
last_verify_time=current_time - timedelta(days=10)
),
# 未绑定的设备
Device(
machine_code='DEMO-MACHINE-CODE-UNBOUND',
license_id=None, # 未绑定许可证
product_id='KMX001',
software_version='1.2.0',
status=1, # 正常
activate_time=None,
last_verify_time=None
)
]
for device in devices:
db.session.add(device)
print(" ✓ 已创建6个示例设备")
# 6. 创建示例工单
print(" 创建示例工单...")
tickets = [
Ticket(
title='许可证激活失败',
product_id='KMX001',
software_version='1.1.0',
machine_code='CUSTOMER-MACHINE-001',
license_key='DEMO-LICENSE-KEY-001',
description='客户反馈在Windows Server 2019系统上无法激活许可证提示"许可证验证失败"错误。已尝试重新安装软件和清理注册表,问题仍然存在。',
priority=2, # 高优先级
status=2, # 已解决
operator='admin',
remark='问题已解决,原因是系统时间不正确导致许可证验证失败。指导客户同步系统时间后问题解决。',
create_time=current_time - timedelta(days=5),
update_time=current_time - timedelta(days=4),
resolve_time=current_time - timedelta(days=4)
),
Ticket(
title='设备解绑次数限制问题',
product_id='KMX002',
software_version='2.0.0',
machine_code='CUSTOMER-MACHINE-002',
license_key='DEMO-LICENSE-KEY-002',
description='客户需要更换硬件,但许可证解绑次数已达到上限。希望能够重置解绑次数或提供新的许可证。',
priority=1, # 中优先级
status=1, # 处理中
operator='test_admin',
remark='正在核实客户身份和购买记录,预计今天内处理完成。',
create_time=current_time - timedelta(days=2),
update_time=current_time - timedelta(days=1)
),
Ticket(
title='软件更新后功能异常',
product_id='KMX001',
software_version='1.2.0',
machine_code='CUSTOMER-MACHINE-003',
license_key='DEMO-LICENSE-KEY-003',
description='更新到1.2.0版本后,许可证验证功能出现异常,经常性提示连接服务器失败。网络连接正常,防火墙已关闭。',
priority=2, # 高优先级
status=0, # 待处理
operator=None,
remark=None,
create_time=current_time - timedelta(hours=6),
update_time=current_time - timedelta(hours=6)
),
Ticket(
title='批量许可证申请',
product_id='KMX002',
software_version='2.0.0',
machine_code=None,
license_key=None,
description='我公司需要采购100个企业版许可证用于公司内部项目管理。希望能够提供批量购买优惠和技术支持。',
priority=1, # 中优先级
status=0, # 待处理
operator=None,
remark=None,
create_time=current_time - timedelta(hours=12),
update_time=current_time - timedelta(hours=12)
),
Ticket(
title='API接口使用咨询',
product_id='KMX001',
software_version='1.1.0',
machine_code='CUSTOMER-MACHINE-004',
license_key='DEMO-LICENSE-KEY-004',
description='希望能够了解如何使用API接口进行许可证验证需要相关的技术文档和示例代码。',
priority=0, # 低优先级
status=3, # 已关闭
operator='admin',
remark='已发送API文档和示例代码给客户客户确认问题已解决。',
create_time=current_time - timedelta(days=10),
update_time=current_time - timedelta(days=8),
resolve_time=current_time - timedelta(days=8),
close_time=current_time - timedelta(days=8)
)
]
for ticket in tickets:
db.session.add(ticket)
print(" ✓ 已创建5个示例工单")
# 提交所有更改
db.session.commit()
print(" ✓ 所有初始数据插入完成")
def show_database_info():
"""显示数据库初始化后的信息"""
# 在应用上下文中导入模型
from app.models import Admin, Product, Version, License, Device, Ticket
print("\n" + "=" * 50)
print("数据库初始化信息统计")
print("=" * 50)
# 统计各表的记录数
tables_info = [
('管理员账号', Admin.query.count()),
('产品', Product.query.count()),
('版本', Version.query.count()),
('许可证', License.query.count()),
('设备', Device.query.count()),
('工单', Ticket.query.count())
]
for table_name, count in tables_info:
print(f" {table_name:8} : {count:3} 条记录")
print("\n" + "=" * 50)
print("默认登录信息")
print("=" * 50)
print(" 超级管理员: admin / admin123")
print(" 普通管理员: test_admin / test123")
print("\n注意事项:")
print(" 1. 请在生产环境中修改默认密码")
print(" 2. 根据实际需求配置数据库连接")
print(" 3. 定期备份数据库数据")
print("=" * 50)
def reset_database():
"""重置数据库(仅删除数据,保留表结构)"""
print("警告:此操作将删除所有数据,但保留表结构")
confirm = input("确认重置数据库?(y/N): ")
if confirm.lower() != 'y':
print("操作已取消")
return
app = create_app()
with app.app_context():
# 在应用上下文中导入模型
from app.models import Ticket, Device, License, Version, Product, Admin
try:
# 删除所有数据
db.session.query(Ticket).delete()
db.session.query(Device).delete()
db.session.query(License).delete()
db.session.query(Version).delete()
db.session.query(Product).delete()
db.session.query(Admin).delete()
db.session.commit()
print("✓ 数据库重置完成")
# 重新插入初始数据
insert_initial_data()
print("✓ 初始数据重新插入完成")
except Exception as e:
print(f"❌ 数据库重置失败: {e}")
db.session.rollback()
raise
def main():
"""主函数"""
if len(sys.argv) > 1:
command = sys.argv[1].lower()
if command == 'reset':
reset_database()
elif command == 'init':
init_database()
else:
print("用法:")
print(" python init_db.py init - 初始化数据库(删除并重建)")
print(" python init_db.py reset - 重置数据库(仅删除数据)")
else:
# 默认执行初始化
init_database()
if __name__ == '__main__':
main()