2025-07-28 01:46:39 +08:00
|
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
"tyapi-server/internal/application/api"
|
|
|
|
|
|
"tyapi-server/internal/application/api/commands"
|
|
|
|
|
|
"tyapi-server/internal/application/api/dto"
|
|
|
|
|
|
"tyapi-server/internal/shared/crypto"
|
|
|
|
|
|
"tyapi-server/internal/shared/interfaces"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ApiHandler API调用HTTP处理器
|
|
|
|
|
|
type ApiHandler struct {
|
|
|
|
|
|
appService api.ApiApplicationService
|
|
|
|
|
|
responseBuilder interfaces.ResponseBuilder
|
|
|
|
|
|
validator interfaces.RequestValidator
|
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewApiHandler 创建API调用HTTP处理器
|
|
|
|
|
|
func NewApiHandler(
|
|
|
|
|
|
appService api.ApiApplicationService,
|
|
|
|
|
|
responseBuilder interfaces.ResponseBuilder,
|
|
|
|
|
|
validator interfaces.RequestValidator,
|
|
|
|
|
|
logger *zap.Logger,
|
|
|
|
|
|
) *ApiHandler {
|
|
|
|
|
|
return &ApiHandler{
|
|
|
|
|
|
appService: appService,
|
|
|
|
|
|
responseBuilder: responseBuilder,
|
|
|
|
|
|
validator: validator,
|
|
|
|
|
|
logger: logger,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// HandleApiCall 统一API调用入口
|
|
|
|
|
|
// @Summary API调用
|
|
|
|
|
|
// @Description 统一API调用入口,参数加密传输
|
|
|
|
|
|
// @Tags API调用
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Param request body commands.ApiCallCommand true "API调用请求"
|
|
|
|
|
|
// @Success 200 {object} dto.ApiCallResponse "调用成功"
|
|
|
|
|
|
// @Failure 400 {object} dto.ApiCallResponse "请求参数错误"
|
|
|
|
|
|
// @Failure 401 {object} dto.ApiCallResponse "未授权"
|
|
|
|
|
|
// @Failure 429 {object} dto.ApiCallResponse "请求过于频繁"
|
|
|
|
|
|
// @Failure 500 {object} dto.ApiCallResponse "服务器内部错误"
|
|
|
|
|
|
// @Router /api/v1/:api_name [post]
|
|
|
|
|
|
func (h *ApiHandler) HandleApiCall(c *gin.Context) {
|
|
|
|
|
|
// 1. 基础参数校验
|
|
|
|
|
|
accessId := c.GetHeader("Access-Id")
|
|
|
|
|
|
if accessId == "" {
|
|
|
|
|
|
response := dto.NewErrorResponse(1005, "缺少Access-Id", "")
|
|
|
|
|
|
c.JSON(200, response)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 绑定和校验请求参数
|
|
|
|
|
|
var cmd commands.ApiCallCommand
|
|
|
|
|
|
cmd.ClientIP = c.ClientIP()
|
|
|
|
|
|
cmd.AccessId = accessId
|
|
|
|
|
|
cmd.ApiName = c.Param("api_name")
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|
|
|
|
|
response := dto.NewErrorResponse(1003, "请求参数结构不正确", "")
|
|
|
|
|
|
c.JSON(200, response)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 调用应用服务
|
|
|
|
|
|
transactionId, encryptedResp, err := h.appService.CallApi(c.Request.Context(), &cmd)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 根据错误类型返回对应的错误码
|
|
|
|
|
|
errorCode := api.GetErrorCode(err)
|
|
|
|
|
|
response := dto.NewErrorResponse(errorCode, err.Error(), transactionId)
|
|
|
|
|
|
c.JSON(200, response) // API调用接口统一返回200状态码
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 返回成功响应
|
|
|
|
|
|
response := dto.NewSuccessResponse(transactionId, encryptedResp)
|
|
|
|
|
|
c.JSON(200, response)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserApiKeys 获取用户API密钥
|
|
|
|
|
|
func (h *ApiHandler) GetUserApiKeys(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result, err := h.appService.GetUserApiKeys(c.Request.Context(), userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("获取用户API密钥失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, result, "获取API密钥成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserWhiteList 获取用户白名单列表
|
|
|
|
|
|
func (h *ApiHandler) GetUserWhiteList(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result, err := h.appService.GetUserWhiteList(c.Request.Context(), userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("获取用户白名单失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, result, "获取白名单成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AddWhiteListIP 添加白名单IP
|
|
|
|
|
|
func (h *ApiHandler) AddWhiteListIP(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var req dto.WhiteListRequest
|
2025-08-02 02:54:21 +08:00
|
|
|
|
if err := h.validator.BindAndValidate(c, &req); err != nil {
|
2025-07-28 01:46:39 +08:00
|
|
|
|
h.responseBuilder.BadRequest(c, "请求参数错误")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err := h.appService.AddWhiteListIP(c.Request.Context(), userID, req.IPAddress)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("添加白名单IP失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, nil, "添加白名单IP成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DeleteWhiteListIP 删除白名单IP
|
|
|
|
|
|
func (h *ApiHandler) DeleteWhiteListIP(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ipAddress := c.Param("ip")
|
|
|
|
|
|
if ipAddress == "" {
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "IP地址不能为空")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err := h.appService.DeleteWhiteListIP(c.Request.Context(), userID, ipAddress)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("删除白名单IP失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, nil, "删除白名单IP成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EncryptParams 加密参数接口(用于前端调试)
|
|
|
|
|
|
// @Summary 加密参数
|
|
|
|
|
|
// @Description 用于前端调试时加密API调用参数
|
|
|
|
|
|
// @Tags API调试
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Param request body commands.EncryptCommand true "加密请求"
|
|
|
|
|
|
// @Success 200 {object} dto.EncryptResponse "加密成功"
|
|
|
|
|
|
// @Failure 400 {object} dto.EncryptResponse "请求参数错误"
|
|
|
|
|
|
// @Failure 401 {object} dto.EncryptResponse "未授权"
|
|
|
|
|
|
// @Router /api/v1/encrypt [post]
|
|
|
|
|
|
func (h *ApiHandler) EncryptParams(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var cmd commands.EncryptCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "请求参数错误")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取用户的SecretKey
|
|
|
|
|
|
apiKeys, err := h.appService.GetUserApiKeys(c.Request.Context(), userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("获取用户API密钥失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "获取API密钥失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将JSON对象转换为字节数组
|
|
|
|
|
|
jsonData, err := json.Marshal(cmd.Data)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("序列化参数失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "参数序列化失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密参数
|
|
|
|
|
|
encryptedData, err := crypto.AesEncrypt(jsonData, apiKeys.SecretKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("加密参数失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "加密参数失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response := dto.EncryptResponse{
|
|
|
|
|
|
EncryptedData: encryptedData,
|
|
|
|
|
|
}
|
|
|
|
|
|
h.responseBuilder.Success(c, response, "加密成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getCurrentUserID 获取当前用户ID
|
|
|
|
|
|
func (h *ApiHandler) getCurrentUserID(c *gin.Context) string {
|
|
|
|
|
|
if userID, exists := c.Get("user_id"); exists {
|
|
|
|
|
|
if id, ok := userID.(string); ok {
|
|
|
|
|
|
return id
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserApiCalls 获取用户API调用记录
|
|
|
|
|
|
// @Summary 获取用户API调用记录
|
|
|
|
|
|
// @Description 获取当前用户的API调用记录列表,支持分页和筛选
|
|
|
|
|
|
// @Tags API管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security Bearer
|
|
|
|
|
|
// @Param page query int false "页码" default(1)
|
|
|
|
|
|
// @Param page_size query int false "每页数量" default(10)
|
|
|
|
|
|
// @Param start_time query string false "开始时间 (格式: 2006-01-02 15:04:05)"
|
|
|
|
|
|
// @Param end_time query string false "结束时间 (格式: 2006-01-02 15:04:05)"
|
|
|
|
|
|
// @Param transaction_id query string false "交易ID"
|
|
|
|
|
|
// @Param product_name query string false "产品名称"
|
|
|
|
|
|
// @Param status query string false "状态 (pending/success/failed)"
|
|
|
|
|
|
// @Success 200 {object} dto.ApiCallListResponse "获取成功"
|
|
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
|
|
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
|
|
|
|
// @Router /api/v1/my/api-calls [get]
|
|
|
|
|
|
func (h *ApiHandler) GetUserApiCalls(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
|
|
|
|
|
h.responseBuilder.Unauthorized(c, "用户未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析查询参数
|
|
|
|
|
|
page := h.getIntQuery(c, "page", 1)
|
|
|
|
|
|
pageSize := h.getIntQuery(c, "page_size", 10)
|
|
|
|
|
|
|
|
|
|
|
|
// 构建筛选条件
|
|
|
|
|
|
filters := make(map[string]interface{})
|
|
|
|
|
|
|
|
|
|
|
|
// 时间范围筛选
|
|
|
|
|
|
if startTime := c.Query("start_time"); startTime != "" {
|
|
|
|
|
|
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
|
|
|
|
|
filters["start_time"] = t
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if endTime := c.Query("end_time"); endTime != "" {
|
|
|
|
|
|
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
|
|
|
|
|
filters["end_time"] = t
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 交易ID筛选
|
|
|
|
|
|
if transactionId := c.Query("transaction_id"); transactionId != "" {
|
|
|
|
|
|
filters["transaction_id"] = transactionId
|
|
|
|
|
|
}
|
2025-07-28 23:44:01 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 产品名称筛选
|
|
|
|
|
|
if productName := c.Query("product_name"); productName != "" {
|
|
|
|
|
|
filters["product_name"] = productName
|
|
|
|
|
|
}
|
2025-07-28 23:44:01 +08:00
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// 状态筛选
|
|
|
|
|
|
if status := c.Query("status"); status != "" {
|
|
|
|
|
|
filters["status"] = status
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建分页选项
|
|
|
|
|
|
options := interfaces.ListOptions{
|
|
|
|
|
|
Page: page,
|
|
|
|
|
|
PageSize: pageSize,
|
|
|
|
|
|
Sort: "created_at",
|
|
|
|
|
|
Order: "desc",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result, err := h.appService.GetUserApiCalls(c.Request.Context(), userID, filters, options)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("获取用户API调用记录失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "获取API调用记录失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, result, "获取API调用记录成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-02 02:54:21 +08:00
|
|
|
|
// GetAdminApiCalls 获取管理端API调用记录
|
|
|
|
|
|
// @Summary 获取管理端API调用记录
|
|
|
|
|
|
// @Description 管理员获取API调用记录,支持筛选和分页
|
|
|
|
|
|
// @Tags API管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security Bearer
|
|
|
|
|
|
// @Param page query int false "页码" default(1)
|
|
|
|
|
|
// @Param page_size query int false "每页数量" default(10)
|
|
|
|
|
|
// @Param user_id query string false "用户ID"
|
|
|
|
|
|
// @Param transaction_id query string false "交易ID"
|
|
|
|
|
|
// @Param product_name query string false "产品名称"
|
|
|
|
|
|
// @Param status query string false "状态"
|
|
|
|
|
|
// @Param start_time query string false "开始时间" format(date-time)
|
|
|
|
|
|
// @Param end_time query string false "结束时间" format(date-time)
|
|
|
|
|
|
// @Param sort_by query string false "排序字段"
|
|
|
|
|
|
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
|
|
|
|
|
// @Success 200 {object} dto.ApiCallListResponse "获取API调用记录成功"
|
|
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
|
|
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
|
|
|
|
// @Router /api/v1/admin/api-calls [get]
|
|
|
|
|
|
func (h *ApiHandler) GetAdminApiCalls(c *gin.Context) {
|
|
|
|
|
|
// 解析查询参数
|
|
|
|
|
|
page := h.getIntQuery(c, "page", 1)
|
|
|
|
|
|
pageSize := h.getIntQuery(c, "page_size", 10)
|
|
|
|
|
|
|
|
|
|
|
|
// 构建筛选条件
|
|
|
|
|
|
filters := make(map[string]interface{})
|
|
|
|
|
|
|
|
|
|
|
|
// 用户ID筛选
|
|
|
|
|
|
if userId := c.Query("user_id"); userId != "" {
|
|
|
|
|
|
filters["user_id"] = userId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 时间范围筛选
|
|
|
|
|
|
if startTime := c.Query("start_time"); startTime != "" {
|
|
|
|
|
|
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
|
|
|
|
|
filters["start_time"] = t
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if endTime := c.Query("end_time"); endTime != "" {
|
|
|
|
|
|
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
|
|
|
|
|
filters["end_time"] = t
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 交易ID筛选
|
|
|
|
|
|
if transactionId := c.Query("transaction_id"); transactionId != "" {
|
|
|
|
|
|
filters["transaction_id"] = transactionId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 产品名称筛选
|
|
|
|
|
|
if productName := c.Query("product_name"); productName != "" {
|
|
|
|
|
|
filters["product_name"] = productName
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 状态筛选
|
|
|
|
|
|
if status := c.Query("status"); status != "" {
|
|
|
|
|
|
filters["status"] = status
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建分页选项
|
|
|
|
|
|
options := interfaces.ListOptions{
|
|
|
|
|
|
Page: page,
|
|
|
|
|
|
PageSize: pageSize,
|
|
|
|
|
|
Sort: "created_at",
|
|
|
|
|
|
Order: "desc",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result, err := h.appService.GetAdminApiCalls(c.Request.Context(), filters, options)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
h.logger.Error("获取管理端API调用记录失败", zap.Error(err))
|
|
|
|
|
|
h.responseBuilder.BadRequest(c, "获取API调用记录失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.responseBuilder.Success(c, result, "获取API调用记录成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 01:46:39 +08:00
|
|
|
|
// getIntQuery 获取整数查询参数
|
|
|
|
|
|
func (h *ApiHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
|
|
|
|
|
|
if value := c.Query(key); value != "" {
|
|
|
|
|
|
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
|
|
|
|
|
|
return intValue
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return defaultValue
|
|
|
|
|
|
}
|