#!/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()