All checks were successful
continuous-integration/drone/push Build is passing
- 新增告警模块 (alerts): 告警规则配置与触发 - 新增成本管理模块 (cost): 成本统计与分析 - 新增配额模块 (quota): 配额管理与限制 - 新增微信模块 (wechat): 微信相关功能接口 - 新增缓存服务 (cache): Redis 缓存封装 - 新增请求日志中间件 (request_logger) - 新增异常处理和链路追踪中间件 - 更新 dashboard 前端展示 - 更新 SDK stats_client 功能
265 lines
8.5 KiB
Python
265 lines
8.5 KiB
Python
"""企业微信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
|