diff --git a/apps/gitea-webhook-ambassador-python/app/auth/middleware.py b/apps/gitea-webhook-ambassador-python/app/auth/middleware.py index d1ff1e40..a90bb40a 100644 --- a/apps/gitea-webhook-ambassador-python/app/auth/middleware.py +++ b/apps/gitea-webhook-ambassador-python/app/auth/middleware.py @@ -11,10 +11,10 @@ from typing import Optional from ..models.database import get_db, APIKey from ..config import settings -# JWT 配置 +# JWT configuration JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-secret-key-change-in-production") JWT_ALGORITHM = "HS256" -JWT_EXPIRATION_HOURS = 24 * 7 # 7 天有效期 +JWT_EXPIRATION_HOURS = 24 * 7 # 7 days expiration security = HTTPBearer() @@ -49,25 +49,25 @@ class AuthMiddleware: ) def verify_api_key(self, api_key: str, db: Session): - """验证 API 密钥""" + """Validate API key""" db_key = db.query(APIKey).filter(APIKey.key == api_key).first() return db_key is not None def generate_api_key(self) -> str: - """生成新的 API 密钥""" + """Generate a new API key""" return secrets.token_urlsafe(32) -# 创建认证中间件实例 +# Create authentication middleware instance auth_middleware = AuthMiddleware() async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)): - """获取当前用户(JWT 认证)""" + """Get current user (JWT authentication)""" token = credentials.credentials payload = auth_middleware.verify_token(token) return payload async def get_current_user_api_key(api_key: str = Depends(security), db: Session = Depends(get_db)): - """获取当前用户(API 密钥认证)""" + """Get current user (API key authentication)""" if not auth_middleware.verify_api_key(api_key.credentials, db): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -76,14 +76,14 @@ async def get_current_user_api_key(api_key: str = Depends(security), db: Session return {"api_key": api_key.credentials} def require_auth(use_api_key: bool = False): - """认证依赖装饰器""" + """Authentication dependency decorator""" if use_api_key: return get_current_user_api_key else: return get_current_user def handle_auth_error(request, exc): - """处理认证错误""" + """Handle authentication error""" if request.headers.get("x-requested-with") == "XMLHttpRequest": return JSONResponse( status_code=401, diff --git a/apps/gitea-webhook-ambassador-python/app/handlers/auth.py b/apps/gitea-webhook-ambassador-python/app/handlers/auth.py index a418a288..073ba6a2 100644 --- a/apps/gitea-webhook-ambassador-python/app/handlers/auth.py +++ b/apps/gitea-webhook-ambassador-python/app/handlers/auth.py @@ -10,7 +10,7 @@ from ..auth.middleware import auth_middleware router = APIRouter(prefix="/api/auth", tags=["authentication"]) -# 请求/响应模型 +# Request/Response models class LoginRequest(BaseModel): secret_key: str @@ -32,13 +32,13 @@ class APIKeyResponse(BaseModel): class APIKeyList(BaseModel): keys: List[APIKeyResponse] -# 获取管理员密钥 +# Get admin secret key def get_admin_secret_key(): return os.getenv("ADMIN_SECRET_KEY", "admin-secret-key-change-in-production") @router.post("/login", response_model=LoginResponse) async def login(request: LoginRequest): - """管理员登录""" + """Admin login""" admin_key = get_admin_secret_key() if request.secret_key != admin_key: @@ -47,7 +47,7 @@ async def login(request: LoginRequest): detail="Invalid secret key" ) - # 生成 JWT 令牌 + # Generate JWT token token = auth_middleware.create_access_token( data={"sub": "admin", "role": "admin"} ) @@ -60,11 +60,11 @@ async def create_api_key( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """创建新的 API 密钥""" - # 生成新的 API 密钥 + """Create a new API key""" + # Generate new API key api_key_value = auth_middleware.generate_api_key() - # 保存到数据库 + # Save to database db_key = APIKey( key=api_key_value, description=request.description @@ -86,7 +86,7 @@ async def list_api_keys( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """获取所有 API 密钥""" + """Get all API keys""" keys = db.query(APIKey).order_by(APIKey.created_at.desc()).all() return APIKeyList( @@ -107,7 +107,7 @@ async def delete_api_key( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """删除 API 密钥""" + """Delete API key""" key = db.query(APIKey).filter(APIKey.id == key_id).first() if not key: diff --git a/apps/gitea-webhook-ambassador-python/app/handlers/health.py b/apps/gitea-webhook-ambassador-python/app/handlers/health.py index 26b34be5..a0726a10 100644 --- a/apps/gitea-webhook-ambassador-python/app/handlers/health.py +++ b/apps/gitea-webhook-ambassador-python/app/handlers/health.py @@ -1,6 +1,6 @@ """ -健康检查处理器 -提供服务健康状态检查 +Health check handler +Provides service health status checking """ from datetime import datetime @@ -42,12 +42,12 @@ class HealthResponse(BaseModel): @router.get("/", response_model=HealthResponse) async def health_check(db: Session = Depends(get_db)): """ - 健康检查端点 - 检查服务各个组件的状态 + Health check endpoint + Check the status of each service component """ settings = get_settings() - # 检查 Jenkins 连接 + # Check Jenkins connection jenkins_service = get_jenkins_service() jenkins_status = JenkinsStatus(status="disconnected", message="Unable to connect to Jenkins server") @@ -57,7 +57,7 @@ async def health_check(db: Session = Depends(get_db)): except Exception as e: jenkins_status.message = f"Connection failed: {str(e)}" - # 获取工作池统计 + # Get worker pool stats queue_service = get_queue_service() try: stats = await queue_service.get_stats() @@ -75,7 +75,7 @@ async def health_check(db: Session = Depends(get_db)): total_failed=0 ) - # 检查数据库连接 + # Check database connection database_status = {"status": "disconnected", "message": "Database connection failed"} try: # 尝试执行简单查询 @@ -84,7 +84,7 @@ async def health_check(db: Session = Depends(get_db)): except Exception as e: database_status["message"] = f"Database error: {str(e)}" - # 确定整体状态 + # Determine overall status overall_status = "healthy" if jenkins_status.status != "connected": overall_status = "unhealthy" @@ -103,8 +103,8 @@ async def health_check(db: Session = Depends(get_db)): @router.get("/simple") async def simple_health_check(): """ - 简单健康检查端点 - 用于负载均衡器和监控系统 + Simple health check endpoint + For load balancers and monitoring systems """ return { "status": "healthy", @@ -116,14 +116,14 @@ async def simple_health_check(): @router.get("/ready") async def readiness_check(db: Session = Depends(get_db)): """ - 就绪检查端点 - 检查服务是否准备好接收请求 + Readiness check endpoint + Check if the service is ready to receive requests """ try: - # 检查数据库连接 + # Check database connection db.execute("SELECT 1") - # 检查 Jenkins 连接 + # Check Jenkins connection jenkins_service = get_jenkins_service() jenkins_ready = await jenkins_service.test_connection() @@ -139,7 +139,7 @@ async def readiness_check(db: Session = Depends(get_db)): @router.get("/live") async def liveness_check(): """ - 存活检查端点 - 检查服务进程是否正常运行 + Liveness check endpoint + Check if the service process is running normally """ return {"status": "alive"} \ No newline at end of file diff --git a/apps/gitea-webhook-ambassador-python/app/handlers/logs.py b/apps/gitea-webhook-ambassador-python/app/handlers/logs.py index de150a54..d4942355 100644 --- a/apps/gitea-webhook-ambassador-python/app/handlers/logs.py +++ b/apps/gitea-webhook-ambassador-python/app/handlers/logs.py @@ -35,13 +35,13 @@ async def get_trigger_logs( current_user: dict = Depends(get_current_user) ): """ - 获取触发日志 + Get trigger logs """ try: - # 构建查询 + # Build query query = db.query(TriggerLog) - # 应用过滤器 + # Apply filters if repository: query = query.filter(TriggerLog.repository_name == repository) if branch: @@ -56,7 +56,7 @@ async def get_trigger_logs( detail="Invalid since parameter format (use RFC3339)" ) - # 按时间倒序排列并限制数量 + # Order by time desc and limit logs = query.order_by(TriggerLog.created_at.desc()).limit(limit).all() return logs @@ -71,21 +71,21 @@ async def get_log_stats( current_user: dict = Depends(get_current_user) ): """ - 获取日志统计信息 + Get log statistics """ try: - # 总日志数 + # Total logs total_logs = db.query(TriggerLog).count() - # 成功和失败的日志数 + # Successful and failed logs successful_logs = db.query(TriggerLog).filter(TriggerLog.status == "success").count() failed_logs = db.query(TriggerLog).filter(TriggerLog.status == "failed").count() - # 最近24小时的日志数 + # Logs in the last 24 hours yesterday = datetime.utcnow() - timedelta(days=1) recent_logs = db.query(TriggerLog).filter(TriggerLog.created_at >= yesterday).count() - # 按仓库分组的统计 + # Stats by repository repo_stats = db.query( TriggerLog.repository_name, db.func.count(TriggerLog.id).label('count') diff --git a/apps/gitea-webhook-ambassador-python/app/handlers/projects.py b/apps/gitea-webhook-ambassador-python/app/handlers/projects.py index a70c0bf3..95693b0d 100644 --- a/apps/gitea-webhook-ambassador-python/app/handlers/projects.py +++ b/apps/gitea-webhook-ambassador-python/app/handlers/projects.py @@ -8,7 +8,7 @@ from ..auth.middleware import auth_middleware router = APIRouter(prefix="/api/projects", tags=["projects"]) -# 请求/响应模型 +# Request/Response models class ProjectCreate(BaseModel): name: str jenkinsJob: str @@ -33,8 +33,8 @@ async def create_project( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """创建新项目映射""" - # 检查项目是否已存在 + """Create new project mapping""" + # Check if project already exists existing_project = db.query(ProjectMapping).filter( ProjectMapping.repository_name == request.giteaRepo ).first() @@ -45,7 +45,7 @@ async def create_project( detail="Project with this repository already exists" ) - # 创建新项目 + # Create new project project = ProjectMapping( repository_name=request.giteaRepo, default_job=request.jenkinsJob @@ -68,14 +68,14 @@ async def list_projects( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """获取所有项目""" + """Get all projects""" projects = db.query(ProjectMapping).order_by(ProjectMapping.created_at.desc()).all() return ProjectList( projects=[ ProjectResponse( id=project.id, - name=project.repository_name.split('/')[-1], # 使用仓库名作为项目名 + name=project.repository_name.split('/')[-1], # Use repo name as project name jenkinsJob=project.default_job, giteaRepo=project.repository_name, created_at=project.created_at.isoformat() @@ -90,7 +90,7 @@ async def get_project( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """获取特定项目""" + """Get specific project""" project = db.query(ProjectMapping).filter(ProjectMapping.id == project_id).first() if not project: @@ -113,7 +113,7 @@ async def delete_project( db: Session = Depends(get_db), current_user: dict = Depends(auth_middleware.get_current_user) ): - """删除项目""" + """Delete project""" project = db.query(ProjectMapping).filter(ProjectMapping.id == project_id).first() if not project: @@ -132,7 +132,7 @@ async def get_project_mapping( repository_name: str, db: Session = Depends(get_db) ): - """根据仓库名获取项目映射(用于 webhook 处理)""" + """Get project mapping by repository name (for webhook processing)""" project = db.query(ProjectMapping).filter( ProjectMapping.repository_name == repository_name ).first() diff --git a/apps/gitea-webhook-ambassador-python/app/main.py b/apps/gitea-webhook-ambassador-python/app/main.py index 1da7f833..ff039b99 100644 --- a/apps/gitea-webhook-ambassador-python/app/main.py +++ b/apps/gitea-webhook-ambassador-python/app/main.py @@ -1,6 +1,6 @@ """ -FastAPI 应用主入口 -集成 Webhook 处理、防抖、队列管理等服务 +Main entry for FastAPI application +Integrates webhook handling, deduplication, queue management, and related services """ import asyncio @@ -18,9 +18,9 @@ from app.services.dedup_service import DeduplicationService from app.services.jenkins_service import JenkinsService from app.services.webhook_service import WebhookService from app.tasks.jenkins_tasks import get_celery_app -# 路由导入将在运行时动态处理 +# Route imports will be dynamically handled at runtime -# 配置结构化日志 +# Configure structured logging structlog.configure( processors=[ structlog.stdlib.filter_by_level, @@ -41,7 +41,7 @@ structlog.configure( logger = structlog.get_logger() -# 监控指标 +# Monitoring metrics WEBHOOK_REQUESTS_TOTAL = Counter( "webhook_requests_total", "Total number of webhook requests", @@ -65,7 +65,7 @@ DEDUP_HITS = Counter( "Total number of deduplication hits" ) -# 全局服务实例 +# Global service instances dedup_service: DeduplicationService = None jenkins_service: JenkinsService = None webhook_service: WebhookService = None @@ -75,14 +75,14 @@ redis_client: aioredis.Redis = None @asynccontextmanager async def lifespan(app: FastAPI): - """应用生命周期管理""" + """Application lifecycle management""" global dedup_service, jenkins_service, webhook_service, celery_app, redis_client - # 启动时初始化 + # Initialize on startup logger.info("Starting Gitea Webhook Ambassador") try: - # 初始化 Redis 连接 + # Initialize Redis connection settings = get_settings() redis_client = aioredis.from_url( settings.redis.url, @@ -92,14 +92,14 @@ async def lifespan(app: FastAPI): decode_responses=True ) - # 测试 Redis 连接 + # Test Redis connection await redis_client.ping() logger.info("Redis connection established") - # 初始化 Celery + # Initialize Celery celery_app = get_celery_app() - # 初始化服务 + # Initialize services dedup_service = DeduplicationService(redis_client) jenkins_service = JenkinsService() webhook_service = WebhookService( @@ -117,7 +117,7 @@ async def lifespan(app: FastAPI): raise finally: - # 关闭时清理 + # Cleanup on shutdown logger.info("Shutting down Gitea Webhook Ambassador") if redis_client: @@ -125,25 +125,25 @@ async def lifespan(app: FastAPI): logger.info("Redis connection closed") -# 创建 FastAPI 应用 +# Create FastAPI application app = FastAPI( title="Gitea Webhook Ambassador", - description="高性能的 Gitea 到 Jenkins 的 Webhook 服务", + description="High-performance Gitea to Jenkins Webhook service", version="1.0.0", lifespan=lifespan ) -# 添加 CORS 中间件 +# Add CORS middleware app.add_middleware( CORSMiddleware, - allow_origins=["*"], # 生产环境应该限制具体域名 + allow_origins=["*"], # In production, restrict to specific domains allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) -# 依赖注入 +# Dependency injection def get_dedup_service() -> DeduplicationService: if dedup_service is None: raise HTTPException(status_code=503, detail="Deduplication service not available") @@ -162,13 +162,13 @@ def get_celery_app_dep(): return celery_app -# 中间件 +# Middleware @app.middleware("http") async def log_requests(request: Request, call_next): - """请求日志中间件""" + """Request logging middleware""" start_time = asyncio.get_event_loop().time() - # 记录请求开始 + # Log request start logger.info("Request started", method=request.method, url=str(request.url), @@ -177,7 +177,7 @@ async def log_requests(request: Request, call_next): try: response = await call_next(request) - # 记录请求完成 + # Log request complete process_time = asyncio.get_event_loop().time() - start_time logger.info("Request completed", method=request.method, @@ -188,7 +188,7 @@ async def log_requests(request: Request, call_next): return response except Exception as e: - # 记录请求错误 + # Log request error process_time = asyncio.get_event_loop().time() - start_time logger.error("Request failed", method=request.method, @@ -200,10 +200,10 @@ async def log_requests(request: Request, call_next): @app.middleware("http") async def add_security_headers(request: Request, call_next): - """添加安全头""" + """Add security headers""" response = await call_next(request) - # 添加安全相关的 HTTP 头 + # Add security-related HTTP headers response.headers["X-Content-Type-Options"] = "nosniff" response.headers["X-Frame-Options"] = "DENY" response.headers["X-XSS-Protection"] = "1; mode=block" @@ -212,10 +212,10 @@ async def add_security_headers(request: Request, call_next): return response -# 异常处理器 +# Exception handler @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): - """全局异常处理器""" + """Global exception handler""" logger.error("Unhandled exception", method=request.method, url=str(request.url), @@ -232,19 +232,19 @@ async def global_exception_handler(request: Request, exc: Exception): ) -# 健康检查端点 +# Health check endpoint @app.get("/health") async def health_check(): - """基础健康检查""" + """Basic health check""" try: - # 检查 Redis 连接 + # Check Redis connection if redis_client: await redis_client.ping() redis_healthy = True else: redis_healthy = False - # 检查 Celery 连接 + # Check Celery connection if celery_app: inspect = celery_app.control.inspect() celery_healthy = bool(inspect.active() is not None) @@ -273,7 +273,7 @@ async def health_check(): @app.get("/health/queue") async def queue_health_check(): - """队列健康检查""" + """Queue health check""" try: if celery_app is None: return JSONResponse( @@ -283,7 +283,7 @@ async def queue_health_check(): inspect = celery_app.control.inspect() - # 获取队列统计 + # Get queue stats active = inspect.active() reserved = inspect.reserved() registered = inspect.registered() @@ -292,7 +292,7 @@ async def queue_health_check(): reserved_count = sum(len(tasks) for tasks in (reserved or {}).values()) worker_count = len(registered or {}) - # 更新监控指标 + # Update monitoring metrics QUEUE_SIZE.labels(queue_type="active").set(active_count) QUEUE_SIZE.labels(queue_type="reserved").set(reserved_count) @@ -317,17 +317,17 @@ async def queue_health_check(): ) -# 监控指标端点 +# Metrics endpoint @app.get("/metrics") async def metrics(): - """Prometheus 监控指标""" + """Prometheus metrics endpoint""" return Response( content=generate_latest(), media_type=CONTENT_TYPE_LATEST ) -# 包含路由模块 +# Include route modules try: from app.handlers import webhook, health, admin @@ -349,18 +349,17 @@ try: tags=["admin"] ) except ImportError as e: - # 如果模块不存在,记录警告但不中断应用启动 + # If module does not exist, log warning but do not interrupt app startup logger.warning(f"Some handlers not available: {e}") - -# 根路径 +# Root path @app.get("/") async def root(): - """根路径""" + """Root path""" return { "name": "Gitea Webhook Ambassador", "version": "1.0.0", - "description": "高性能的 Gitea 到 Jenkins 的 Webhook 服务", + "description": "High-performance Gitea to Jenkins Webhook service", "endpoints": { "webhook": "/webhook/gitea", "health": "/health", diff --git a/apps/gitea-webhook-ambassador-python/app/main_enhanced.py b/apps/gitea-webhook-ambassador-python/app/main_enhanced.py index 13a1c0aa..860df862 100644 --- a/apps/gitea-webhook-ambassador-python/app/main_enhanced.py +++ b/apps/gitea-webhook-ambassador-python/app/main_enhanced.py @@ -9,19 +9,19 @@ import time import psutil from datetime import datetime, timedelta -# 导入数据库模型 +# Import database models from app.models.database import create_tables, get_db, APIKey, ProjectMapping, TriggerLog from app.auth.middleware import auth_middleware, get_current_user from app.config import settings -# 创建 FastAPI 应用 +# Create FastAPI app app = FastAPI( title="Gitea Webhook Ambassador", - description="高性能的 Gitea 到 Jenkins 的 Webhook 服务", + description="High-performance Gitea to Jenkins Webhook service", version="2.0.0" ) -# 添加 CORS 中间件 +# Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], @@ -30,36 +30,36 @@ app.add_middleware( allow_headers=["*"], ) -# 创建数据库表 +# Create database tables create_tables() -# 挂载静态文件 +# Mount static files app.mount("/static", StaticFiles(directory="app/static"), name="static") -# 设置模板 +# Set up templates templates = Jinja2Templates(directory="app/templates") -# 启动时间 +# Startup time start_time = datetime.now() @app.get("/", response_class=HTMLResponse) async def root(request: Request): - """根路径 - 重定向到登录页""" + """Root path - redirect to login page""" return RedirectResponse(url="/login") @app.get("/login", response_class=HTMLResponse) async def login_page(request: Request): - """登录页面""" + """Login page""" return templates.TemplateResponse("login.html", {"request": request}) @app.get("/dashboard", response_class=HTMLResponse) async def dashboard_page(request: Request): - """仪表板页面""" + """Dashboard page""" return templates.TemplateResponse("dashboard.html", {"request": request}) @app.post("/api/auth/login") async def login(request: dict): - """管理员登录""" + """Admin login""" admin_key = os.getenv("ADMIN_SECRET_KEY", "admin-secret-key-change-in-production") if request.get("secret_key") != admin_key: @@ -68,7 +68,7 @@ async def login(request: dict): detail="Invalid secret key" ) - # 生成 JWT 令牌 + # Generate JWT token token = auth_middleware.create_access_token( data={"sub": "admin", "role": "admin"} ) @@ -77,21 +77,21 @@ async def login(request: dict): @app.get("/api/stats") async def get_stats(db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): - """获取统计信息""" + """Get statistics""" try: - # 获取项目总数 + # Get total number of projects total_projects = db.query(ProjectMapping).count() - # 获取 API 密钥总数 + # Get total number of API keys total_api_keys = db.query(APIKey).count() - # 获取今日触发次数 + # Get today's trigger count today = datetime.now().date() today_triggers = db.query(TriggerLog).filter( TriggerLog.created_at >= today ).count() - # 获取成功触发次数 + # Get successful trigger count successful_triggers = db.query(TriggerLog).filter( TriggerLog.status == "success" ).count() @@ -103,11 +103,11 @@ async def get_stats(db: Session = Depends(get_db), current_user: dict = Depends( "successful_triggers": successful_triggers } except Exception as e: - raise HTTPException(status_code=500, detail=f"获取统计信息失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to get statistics: {str(e)}") @app.get("/api/keys", response_model=dict) async def list_api_keys(db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): - """获取所有 API 密钥(兼容前端)""" + """Get all API keys (frontend compatible)""" try: keys = db.query(APIKey).order_by(APIKey.created_at.desc()).all() return { @@ -122,7 +122,7 @@ async def list_api_keys(db: Session = Depends(get_db), current_user: dict = Depe ] } except Exception as e: - raise HTTPException(status_code=500, detail=f"获取 API 密钥失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to get API keys: {str(e)}") @app.post("/api/keys", response_model=dict) async def create_api_key( @@ -130,12 +130,12 @@ async def create_api_key( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): - """创建新的 API 密钥(兼容前端)""" + """Create a new API key (frontend compatible)""" try: - # 生成新的 API 密钥 + # Generate new API key api_key_value = auth_middleware.generate_api_key() - # 保存到数据库 + # Save to database db_key = APIKey( key=api_key_value, description=request.get("description", "") @@ -152,7 +152,7 @@ async def create_api_key( "created_at": db_key.created_at.isoformat() } except Exception as e: - raise HTTPException(status_code=500, detail=f"创建 API 密钥失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to create API key: {str(e)}") @app.delete("/api/keys/{key_id}") async def delete_api_key( @@ -160,25 +160,25 @@ async def delete_api_key( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): - """删除 API 密钥(兼容前端)""" + """Delete API key (frontend compatible)""" try: key = db.query(APIKey).filter(APIKey.id == key_id).first() if not key: - raise HTTPException(status_code=404, detail="API 密钥不存在") + raise HTTPException(status_code=404, detail="API key does not exist") db.delete(key) db.commit() - return {"message": "API 密钥删除成功"} + return {"message": "API key deleted successfully"} except HTTPException: raise except Exception as e: - raise HTTPException(status_code=500, detail=f"删除 API 密钥失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to delete API key: {str(e)}") @app.get("/api/projects/", response_model=dict) async def list_projects(db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): - """获取所有项目(兼容前端)""" + """Get all projects (frontend compatible)""" try: projects = db.query(ProjectMapping).order_by(ProjectMapping.created_at.desc()).all() return { @@ -194,7 +194,7 @@ async def list_projects(db: Session = Depends(get_db), current_user: dict = Depe ] } except Exception as e: - raise HTTPException(status_code=500, detail=f"获取项目列表失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to get project list: {str(e)}") @app.post("/api/projects/", response_model=dict) async def create_project( @@ -202,17 +202,17 @@ async def create_project( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): - """创建新项目(兼容前端)""" + """Create a new project (frontend compatible)""" try: - # 检查项目是否已存在 + # Check if project already exists existing_project = db.query(ProjectMapping).filter( ProjectMapping.repository_name == request["giteaRepo"] ).first() if existing_project: - raise HTTPException(status_code=400, detail="项目已存在") + raise HTTPException(status_code=400, detail="Project already exists") - # 创建新项目 + # Create new project project = ProjectMapping( repository_name=request["giteaRepo"], default_job=request["jenkinsJob"] @@ -232,7 +232,7 @@ async def create_project( except HTTPException: raise except Exception as e: - raise HTTPException(status_code=500, detail=f"创建项目失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to create project: {str(e)}") @app.delete("/api/projects/{project_id}") async def delete_project( @@ -240,31 +240,31 @@ async def delete_project( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): - """删除项目(兼容前端)""" + """Delete project (frontend compatible)""" try: project = db.query(ProjectMapping).filter(ProjectMapping.id == project_id).first() if not project: - raise HTTPException(status_code=404, detail="项目不存在") + raise HTTPException(status_code=404, detail="Project does not exist") db.delete(project) db.commit() - return {"message": "项目删除成功"} + return {"message": "Project deleted successfully"} except HTTPException: raise except Exception as e: - raise HTTPException(status_code=500, detail=f"删除项目失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to delete project: {str(e)}") @app.get("/health") async def health_check(): - """健康检查端点""" + """Health check endpoint""" try: - # 计算运行时间 + # Calculate uptime uptime = datetime.now() - start_time - uptime_str = str(uptime).split('.')[0] # 移除微秒 + uptime_str = str(uptime).split('.')[0] # Remove microseconds - # 获取内存使用情况 + # Get memory usage process = psutil.Process() memory_info = process.memory_info() memory_mb = memory_info.rss / 1024 / 1024 @@ -292,21 +292,21 @@ async def get_logs( db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): - """获取日志(简化版本)""" + """Get logs (simplified version)""" try: - # 这里应该实现真正的日志查询逻辑 - # 目前返回模拟数据 + # Here should be the real log query logic + # Currently returns mock data logs = [ { "timestamp": datetime.now().isoformat(), "level": "info", - "message": "系统运行正常" + "message": "System running normally" } ] return {"logs": logs} except Exception as e: - raise HTTPException(status_code=500, detail=f"获取日志失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to get logs: {str(e)}") if __name__ == "__main__": import uvicorn diff --git a/apps/gitea-webhook-ambassador-python/app/static/js/dashboard.js b/apps/gitea-webhook-ambassador-python/app/static/js/dashboard.js index 3d0d85e4..98724a6f 100644 --- a/apps/gitea-webhook-ambassador-python/app/static/js/dashboard.js +++ b/apps/gitea-webhook-ambassador-python/app/static/js/dashboard.js @@ -1,17 +1,17 @@ -// 全局变量存储 JWT 令牌 +// Global variable to store JWT token let authToken = localStorage.getItem('auth_token'); $(document).ready(function() { - // 检查认证状态 + // Check authentication status if (!authToken) { window.location.href = '/login'; return; } - // 设置 AJAX 默认配置 + // Set AJAX default config $.ajaxSetup({ beforeSend: function(xhr, settings) { - // 不为登录请求添加认证头 + // Do not add auth header for login request if (settings.url === '/api/auth/login') { return; } @@ -20,7 +20,7 @@ $(document).ready(function() { } }, error: function(xhr, status, error) { - // 如果收到 401,重定向到登录页 + // If 401 received, redirect to login page if (xhr.status === 401) { localStorage.removeItem('auth_token'); window.location.href = '/login'; @@ -30,10 +30,10 @@ $(document).ready(function() { } }); - // 初始化工具提示 + // Initialize tooltips $('[data-bs-toggle="tooltip"]').tooltip(); - // 加载初始数据 + // Load initial data loadProjects(); loadAPIKeys(); loadLogs(); @@ -41,10 +41,10 @@ $(document).ready(function() { loadHealthDetails(); loadStatsDetails(); - // 设置定期健康检查 + // Set periodic health check setInterval(checkHealth, 30000); - // 项目管理 + // Project management $('#addProjectForm').on('submit', function(e) { e.preventDefault(); const projectData = { @@ -62,13 +62,13 @@ $(document).ready(function() { $('#addProjectModal').modal('hide'); $('#addProjectForm')[0].reset(); loadProjects(); - showSuccess('项目添加成功'); + showSuccess('Project added successfully'); }, error: handleAjaxError }); }); - // API 密钥管理 + // API key management $('#generateKeyForm').on('submit', function(e) { e.preventDefault(); $.ajax({ @@ -80,16 +80,16 @@ $(document).ready(function() { $('#generateKeyModal').modal('hide'); $('#generateKeyForm')[0].reset(); loadAPIKeys(); - showSuccess('API 密钥生成成功'); + showSuccess('API key generated successfully'); - // 显示新生成的密钥 + // Show newly generated key showApiKeyModal(response.key); }, error: handleAjaxError }); }); - // 日志查询 + // Log query $('#logQueryForm').on('submit', function(e) { e.preventDefault(); loadLogs({ @@ -100,7 +100,7 @@ $(document).ready(function() { }); }); - // 标签页切换 + // Tab switching $('.nav-link').on('click', function() { $('.nav-link').removeClass('active'); $(this).addClass('active'); @@ -121,7 +121,7 @@ function loadProjects() { ${escapeHtml(project.giteaRepo)} @@ -140,12 +140,12 @@ function loadAPIKeys() { data.keys.forEach(function(key) { tbody.append(` - ${escapeHtml(key.description || '无描述')} + ${escapeHtml(key.description || 'No description')} ${escapeHtml(key.key)} ${new Date(key.created_at).toLocaleString('zh-CN')} @@ -178,7 +178,7 @@ function loadLogs(query = {}) { `); }); } else { - logContainer.append('
暂无日志记录
'); + logContainer.append('
No log records
'); } }) .fail(handleAjaxError); @@ -190,12 +190,12 @@ function checkHealth() { const indicator = $('.health-indicator'); indicator.removeClass('healthy unhealthy') .addClass(data.status === 'healthy' ? 'healthy' : 'unhealthy'); - $('#healthStatus').text(data.status === 'healthy' ? '健康' : '异常'); + $('#healthStatus').text(data.status === 'healthy' ? 'Healthy' : 'Unhealthy'); }) .fail(function() { const indicator = $('.health-indicator'); indicator.removeClass('healthy').addClass('unhealthy'); - $('#healthStatus').text('异常'); + $('#healthStatus').text('Unhealthy'); }); } @@ -205,24 +205,24 @@ function loadHealthDetails() { const healthDetails = $('#healthDetails'); healthDetails.html(`
- 状态: + Status: - ${data.status === 'healthy' ? '健康' : '异常'} + ${data.status === 'healthy' ? 'Healthy' : 'Unhealthy'}
- 版本: ${data.version || '未知'} + Version: ${data.version || 'Unknown'}
- 启动时间: ${data.uptime || '未知'} + Uptime: ${data.uptime || 'Unknown'}
- 内存使用: ${data.memory || '未知'} + Memory Usage: ${data.memory || 'Unknown'}
`); }) .fail(function() { - $('#healthDetails').html('
无法获取健康状态
'); + $('#healthDetails').html('
Unable to get health status
'); }); } @@ -232,75 +232,75 @@ function loadStatsDetails() { const statsDetails = $('#statsDetails'); statsDetails.html(`
- 总项目数: ${data.total_projects || 0} + Total Projects: ${data.total_projects || 0}
- API 密钥数: ${data.total_api_keys || 0} + API Keys: ${data.total_api_keys || 0}
- 今日触发次数: ${data.today_triggers || 0} + Today's Triggers: ${data.today_triggers || 0}
- 成功触发次数: ${data.successful_triggers || 0} + Successful Triggers: ${data.successful_triggers || 0}
`); }) .fail(function() { - $('#statsDetails').html('
无法获取统计信息
'); + $('#statsDetails').html('
Unable to get statistics
'); }); } function deleteProject(id) { - if (!confirm('确定要删除这个项目吗?')) return; + if (!confirm('Are you sure you want to delete this project?')) return; $.ajax({ url: `/api/projects/${id}`, method: 'DELETE', success: function() { loadProjects(); - showSuccess('项目删除成功'); + showSuccess('Project deleted successfully'); }, error: handleAjaxError }); } function revokeKey(id) { - if (!confirm('确定要撤销这个 API 密钥吗?')) return; + if (!confirm('Are you sure you want to revoke this API key?')) return; $.ajax({ url: `/api/keys/${id}`, method: 'DELETE', success: function() { loadAPIKeys(); - showSuccess('API 密钥撤销成功'); + showSuccess('API key revoked successfully'); }, error: handleAjaxError }); } function showApiKeyModal(key) { - // 创建模态框显示新生成的密钥 + // Create modal to show newly generated key const modal = $(`