后端:
- AuditRule 新增 value 字段, rule_type 扩展 DDL/DML
- MySQL/PG/Redis 预设规则种子接口 POST /audit-rules/seed/{db_type}
- 公告管理 CRUD (announcements)
- 消息推送 CRUD+测试 (notifications: 钉钉/飞书/邮件)
- LDAP 配置 CRUD+测试连接 (ldap-config)
- 164 tests passing (+31 新增)
前端:
- AuditRulesPage 重写: DB类型Tab+DDL/DML分组+参数编辑
- SettingsPage: 系统设置主页(审核规则/公告/推送/LDAP)
- NotificationPage: 钉钉/飞书/SMTP配置
- LdapConfigPage: LDAP设置+测试连接
- AnnouncementPage: 公告Markdown编辑
- 去掉左下角角色切换demo
- 侧边栏合并为: 系统设置(含审核规则+公告+推送+LDAP)
88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
import asyncio
|
|
from contextlib import asynccontextmanager
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from sqlalchemy import select
|
|
|
|
from app.core.config import get_settings
|
|
from app.core.database import init_db, async_session
|
|
from app.core.security import hash_password
|
|
from app.models.user import User
|
|
from app.models.instance import Instance
|
|
from app.models.ticket import Ticket
|
|
from app.models.audit_log import AuditLog
|
|
from app.api.v1.router import api_router
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
async def seed_data():
|
|
"""Create default admin user and seed data."""
|
|
async with async_session() as db:
|
|
result = await db.execute(select(User).where(User.username == settings.ADMIN_USERNAME))
|
|
if not result.scalar_one_or_none():
|
|
users = [
|
|
User(username="admin", display_name="管理员", role="admin",
|
|
hashed_password=hash_password("123456")),
|
|
User(username="dba", display_name="DBA 张三", role="dba",
|
|
hashed_password=hash_password("123456")),
|
|
User(username="dev1", display_name="开发者 李四", role="developer",
|
|
hashed_password=hash_password("123456")),
|
|
User(username="dev2", display_name="开发者 王五", role="developer",
|
|
hashed_password=hash_password("123456")),
|
|
User(username="auditor", display_name="审计员 赵六", role="developer",
|
|
email="auditor@example.com", hashed_password=hash_password("123456")),
|
|
]
|
|
db.add_all(users)
|
|
await db.commit()
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
# Startup
|
|
from app.core.database import Base
|
|
# Import all models so create_all picks them up
|
|
import app.models.user # noqa
|
|
import app.models.instance # noqa
|
|
import app.models.ticket # noqa
|
|
import app.models.audit_log # noqa
|
|
import app.models.audit_rule # noqa
|
|
import app.models.announcement # noqa
|
|
import app.models.notification # noqa
|
|
import app.models.ldap_config # noqa
|
|
|
|
await init_db()
|
|
await seed_data()
|
|
yield
|
|
|
|
|
|
app = FastAPI(
|
|
title="SQL-Platform API",
|
|
version="1.0.0",
|
|
description="数据审核平台 API",
|
|
lifespan=lifespan,
|
|
docs_url="/docs" if settings.DEBUG else None,
|
|
)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"] if settings.DEBUG else [],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
app.include_router(api_router)
|
|
|
|
|
|
@app.get("/health")
|
|
async def health_check():
|
|
return {"status": "ok", "version": "1.0.0", "time": datetime.now(timezone.utc).isoformat()}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
uvicorn.run("app.main:app", host="0.0.0.0", port=9000, reload=True)
|