feat: 新增告警、成本、配额、微信模块及缓存服务
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- 新增告警模块 (alerts): 告警规则配置与触发 - 新增成本管理模块 (cost): 成本统计与分析 - 新增配额模块 (quota): 配额管理与限制 - 新增微信模块 (wechat): 微信相关功能接口 - 新增缓存服务 (cache): Redis 缓存封装 - 新增请求日志中间件 (request_logger) - 新增异常处理和链路追踪中间件 - 更新 dashboard 前端展示 - 更新 SDK stats_client 功能
This commit is contained in:
264
backend/app/routers/wechat.py
Normal file
264
backend/app/routers/wechat.py
Normal file
@@ -0,0 +1,264 @@
|
||||
"""企业微信JS-SDK路由"""
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..database import get_db
|
||||
from ..models.tenant_app import TenantApp
|
||||
from ..models.tenant_wechat_app import TenantWechatApp
|
||||
from ..services.wechat import WechatService, get_wechat_service_by_id
|
||||
|
||||
router = APIRouter(prefix="/wechat", tags=["企业微信"])
|
||||
|
||||
|
||||
class JssdkSignatureRequest(BaseModel):
|
||||
"""JS-SDK签名请求"""
|
||||
url: str # 当前页面URL(不含#及其后面部分)
|
||||
|
||||
|
||||
class JssdkSignatureResponse(BaseModel):
|
||||
"""JS-SDK签名响应"""
|
||||
appId: str
|
||||
agentId: str
|
||||
timestamp: int
|
||||
nonceStr: str
|
||||
signature: str
|
||||
|
||||
|
||||
class OAuth2UrlRequest(BaseModel):
|
||||
"""OAuth2授权URL请求"""
|
||||
redirect_uri: str
|
||||
scope: str = "snsapi_base"
|
||||
state: str = ""
|
||||
|
||||
|
||||
class UserInfoRequest(BaseModel):
|
||||
"""用户信息请求"""
|
||||
code: str
|
||||
|
||||
|
||||
@router.post("/jssdk/signature")
|
||||
async def get_jssdk_signature(
|
||||
request: JssdkSignatureRequest,
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取JS-SDK签名
|
||||
|
||||
用于前端初始化企业微信JS-SDK
|
||||
|
||||
Args:
|
||||
request: 包含当前页面URL
|
||||
tenant_id: 租户ID
|
||||
app_code: 应用代码
|
||||
|
||||
Returns:
|
||||
JS-SDK签名信息
|
||||
"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 生成签名
|
||||
signature_data = await wechat_service.get_jssdk_signature(request.url)
|
||||
if not signature_data:
|
||||
raise HTTPException(status_code=500, detail="获取JS-SDK签名失败")
|
||||
|
||||
return signature_data
|
||||
|
||||
|
||||
@router.get("/jssdk/signature")
|
||||
async def get_jssdk_signature_get(
|
||||
url: str = Query(..., description="当前页面URL"),
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取JS-SDK签名(GET方式)
|
||||
|
||||
方便前端JSONP调用
|
||||
"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 生成签名
|
||||
signature_data = await wechat_service.get_jssdk_signature(url)
|
||||
if not signature_data:
|
||||
raise HTTPException(status_code=500, detail="获取JS-SDK签名失败")
|
||||
|
||||
return signature_data
|
||||
|
||||
|
||||
@router.post("/oauth2/url")
|
||||
async def get_oauth2_url(
|
||||
request: OAuth2UrlRequest,
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取OAuth2授权URL
|
||||
|
||||
用于企业微信内网页获取用户身份
|
||||
"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 生成OAuth2 URL
|
||||
oauth_url = wechat_service.get_oauth2_url(
|
||||
redirect_uri=request.redirect_uri,
|
||||
scope=request.scope,
|
||||
state=request.state
|
||||
)
|
||||
|
||||
return {"url": oauth_url}
|
||||
|
||||
|
||||
@router.post("/oauth2/userinfo")
|
||||
async def get_user_info(
|
||||
request: UserInfoRequest,
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""通过OAuth2 code获取用户信息
|
||||
|
||||
在OAuth2回调后,用code换取用户信息
|
||||
"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 获取用户信息
|
||||
user_info = await wechat_service.get_user_info_by_code(request.code)
|
||||
if not user_info:
|
||||
raise HTTPException(status_code=400, detail="获取用户信息失败,code可能已过期")
|
||||
|
||||
return user_info
|
||||
|
||||
|
||||
@router.get("/oauth2/userinfo")
|
||||
async def get_user_info_get(
|
||||
code: str = Query(..., description="OAuth2回调的code"),
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""通过OAuth2 code获取用户信息(GET方式)"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 获取用户信息
|
||||
user_info = await wechat_service.get_user_info_by_code(code)
|
||||
if not user_info:
|
||||
raise HTTPException(status_code=400, detail="获取用户信息失败,code可能已过期")
|
||||
|
||||
return user_info
|
||||
|
||||
|
||||
@router.get("/user/{user_id}")
|
||||
async def get_user_detail(
|
||||
user_id: str,
|
||||
tenant_id: str = Query(..., alias="tid"),
|
||||
app_code: str = Query(..., alias="aid"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取企业微信成员详细信息"""
|
||||
# 查找租户应用配置
|
||||
tenant_app = db.query(TenantApp).filter(
|
||||
TenantApp.tenant_id == tenant_id,
|
||||
TenantApp.app_code == app_code,
|
||||
TenantApp.status == 1
|
||||
).first()
|
||||
|
||||
if not tenant_app:
|
||||
raise HTTPException(status_code=404, detail="租户应用配置不存在")
|
||||
|
||||
if not tenant_app.wechat_app_id:
|
||||
raise HTTPException(status_code=400, detail="该应用未配置企业微信")
|
||||
|
||||
# 获取企微服务
|
||||
wechat_service = await get_wechat_service_by_id(tenant_app.wechat_app_id, db)
|
||||
if not wechat_service:
|
||||
raise HTTPException(status_code=404, detail="企业微信应用不存在或已禁用")
|
||||
|
||||
# 获取用户详情
|
||||
user_detail = await wechat_service.get_user_detail(user_id)
|
||||
if not user_detail:
|
||||
raise HTTPException(status_code=404, detail="用户不存在")
|
||||
|
||||
return user_detail
|
||||
Reference in New Issue
Block a user