package developer import ( "bytes" "crypto/rand" "encoding/hex" "encoding/json" "fmt" "net/http" "strconv" "time" "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" "verification-platform-backend/internal/service" "verification-platform-backend/pkg/response" "github.com/gin-gonic/gin" ) func handleGetWebhooks(c *gin.Context) { userID := c.GetUint("user_id") appID := c.Query("application_id") var webhooks []struct { model.WebhookConfig ApplicationName string `json:"application_name"` } query := database.DB.Model(&model.WebhookConfig{}). Select("webhook_configs.*, applications.name as application_name"). Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("applications.user_id = ?", userID) if appID != "" && appID != "all" { query = query.Where("webhook_configs.application_id = ?", appID) } if err := query.Find(&webhooks).Error; err != nil { response.Error(c, 500, "获取Webhook配置失败") return } response.Success(c, webhooks) } func handleCreateWebhook(c *gin.Context) { userID := c.GetUint("user_id") var req struct { ApplicationID uint `json:"application_id" binding:"required"` Name string `json:"name" binding:"required"` URL string `json:"url" binding:"required,url"` SecretKey string `json:"secret_key"` Events []string `json:"events" binding:"required"` RetryCount int `json:"retry_count"` Timeout int `json:"timeout"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var app model.Application if err := database.DB.Where("id = ? AND user_id = ?", req.ApplicationID, userID).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } eventsJSON, _ := json.Marshal(req.Events) if req.RetryCount == 0 { req.RetryCount = 3 } if req.Timeout == 0 { req.Timeout = 10 } webhook := model.WebhookConfig{ ApplicationID: req.ApplicationID, Name: req.Name, URL: req.URL, SecretKey: req.SecretKey, Events: string(eventsJSON), Status: "active", RetryCount: req.RetryCount, Timeout: req.Timeout, } if err := database.DB.Create(&webhook).Error; err != nil { response.Error(c, 500, "创建Webhook配置失败") return } service.LogOperation(c, "create", "webhook", &webhook.ID, fmt.Sprintf("创建Webhook: %s", webhook.Name), nil) response.Success(c, webhook) } func handleUpdateWebhook(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var req struct { Name string `json:"name"` URL string `json:"url" binding:"omitempty,url"` SecretKey string `json:"secret_key"` Events []string `json:"events"` Status string `json:"status"` RetryCount int `json:"retry_count"` Timeout int `json:"timeout"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var webhook model.WebhookConfig if err := database.DB.Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("webhook_configs.id = ? AND applications.user_id = ?", id, userID). First(&webhook).Error; err != nil { response.Error(c, 404, "Webhook配置不存在") return } updates := make(map[string]interface{}) if req.Name != "" { updates["name"] = req.Name } if req.URL != "" { updates["url"] = req.URL } if req.SecretKey != "" { updates["secret_key"] = req.SecretKey } if len(req.Events) > 0 { eventsJSON, _ := json.Marshal(req.Events) updates["events"] = string(eventsJSON) } if req.Status != "" { updates["status"] = req.Status } if req.RetryCount > 0 { updates["retry_count"] = req.RetryCount } if req.Timeout > 0 { updates["timeout"] = req.Timeout } if err := database.DB.Model(&webhook).Updates(updates).Error; err != nil { response.Error(c, 500, "更新Webhook配置失败") return } response.Success(c, webhook) } func handleDeleteWebhook(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var webhook model.WebhookConfig if err := database.DB.Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("webhook_configs.id = ? AND applications.user_id = ?", id, userID). First(&webhook).Error; err != nil { response.Error(c, 404, "Webhook配置不存在") return } webhookName := webhook.Name webhookID := webhook.ID if err := database.DB.Delete(&webhook).Error; err != nil { response.Error(c, 500, "删除Webhook配置失败") return } service.LogOperation(c, "delete", "webhook", &webhookID, fmt.Sprintf("删除Webhook: %s", webhookName), nil) response.Success(c, nil) } func handleGetWebhookLogs(c *gin.Context) { userID := c.GetUint("user_id") webhookID := c.Query("webhook_id") page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var logs []model.WebhookLog var total int64 query := database.DB.Model(&model.WebhookLog{}). Joins("JOIN webhook_configs ON webhook_logs.webhook_id = webhook_configs.id"). Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("applications.user_id = ?", userID) if webhookID != "" { query = query.Where("webhook_logs.webhook_id = ?", webhookID) } query.Count(&total) offset := (page - 1) * pageSize if err := query.Order("webhook_logs.created_at DESC"). Offset(offset).Limit(pageSize). Find(&logs).Error; err != nil { response.Error(c, 500, "获取Webhook日志失败") return } response.Success(c, gin.H{ "logs": logs, "total": total, "page": page, "page_size": pageSize, "total_page": (total + int64(pageSize) - 1) / int64(pageSize), }) } func handleTestWebhook(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var webhook model.WebhookConfig if err := database.DB.Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("webhook_configs.id = ? AND applications.user_id = ?", id, userID). First(&webhook).Error; err != nil { response.Error(c, 404, "Webhook配置不存在") return } testData := map[string]interface{}{ "event": "test", "timestamp": time.Now().Unix(), "data": map[string]interface{}{ "message": "This is a test webhook", }, } go sendWebhook(&webhook, testData) response.Success(c, gin.H{"message": "测试请求已发送"}) } func handleGetAPIKeys(c *gin.Context) { userID := c.GetUint("user_id") appID := c.Query("application_id") var apiKeys []struct { model.ExtensionAPIKey ApplicationName string `json:"application_name"` } query := database.DB.Model(&model.ExtensionAPIKey{}). Select("extension_api_keys.*, applications.name as application_name"). Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("applications.user_id = ?", userID) if appID != "" && appID != "all" { query = query.Where("extension_api_keys.application_id = ?", appID) } if err := query.Find(&apiKeys).Error; err != nil { response.Error(c, 500, "获取API密钥失败") return } response.Success(c, apiKeys) } func handleCreateAPIKey(c *gin.Context) { userID := c.GetUint("user_id") var req struct { ApplicationID uint `json:"application_id" binding:"required"` Name string `json:"name" binding:"required"` Permissions []string `json:"permissions"` ExpiresAt *string `json:"expires_at"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var app model.Application if err := database.DB.Where("id = ? AND user_id = ?", req.ApplicationID, userID).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } accessKey := generateRandomKey(32) secretKey := generateRandomKey(32) permissionsJSON, _ := json.Marshal(req.Permissions) apiKey := model.ExtensionAPIKey{ ApplicationID: req.ApplicationID, Name: req.Name, AccessKey: accessKey, SecretKey: secretKey, Permissions: string(permissionsJSON), Status: "active", } if req.ExpiresAt != nil { expiresAt, err := time.Parse(time.RFC3339, *req.ExpiresAt) if err == nil { apiKey.ExpiresAt = &expiresAt } } if err := database.DB.Create(&apiKey).Error; err != nil { response.Error(c, 500, "创建API密钥失败") return } response.Success(c, apiKey) } func handleUpdateAPIKey(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var req struct { Name string `json:"name"` Permissions []string `json:"permissions"` Status string `json:"status"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var apiKey model.ExtensionAPIKey if err := database.DB.Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("extension_api_keys.id = ? AND applications.user_id = ?", id, userID). First(&apiKey).Error; err != nil { response.Error(c, 404, "API密钥不存在") return } updates := make(map[string]interface{}) if req.Name != "" { updates["name"] = req.Name } if len(req.Permissions) > 0 { permissionsJSON, _ := json.Marshal(req.Permissions) updates["permissions"] = string(permissionsJSON) } if req.Status != "" { updates["status"] = req.Status } if err := database.DB.Model(&apiKey).Updates(updates).Error; err != nil { response.Error(c, 500, "更新API密钥失败") return } response.Success(c, apiKey) } func handleDeleteAPIKey(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var apiKey model.ExtensionAPIKey if err := database.DB.Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("extension_api_keys.id = ? AND applications.user_id = ?", id, userID). First(&apiKey).Error; err != nil { response.Error(c, 404, "API密钥不存在") return } if err := database.DB.Delete(&apiKey).Error; err != nil { response.Error(c, 500, "删除API密钥失败") return } response.Success(c, nil) } func handleRegenerateAPIKey(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var apiKey model.ExtensionAPIKey if err := database.DB.Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("extension_api_keys.id = ? AND applications.user_id = ?", id, userID). First(&apiKey).Error; err != nil { response.Error(c, 404, "API密钥不存在") return } newSecretKey := generateRandomKey(32) if err := database.DB.Model(&apiKey).Update("secret_key", newSecretKey).Error; err != nil { response.Error(c, 500, "重新生成密钥失败") return } apiKey.SecretKey = newSecretKey response.Success(c, apiKey) } func generateRandomKey(length int) string { bytes := make([]byte, length) if _, err := rand.Read(bytes); err != nil { return "" } return hex.EncodeToString(bytes)[:length*2] } func sendWebhook(webhook *model.WebhookConfig, data map[string]interface{}) { jsonData, _ := json.Marshal(data) startTime := time.Now() client := &http.Client{ Timeout: time.Duration(webhook.Timeout) * time.Second, } req, err := http.NewRequest("POST", webhook.URL, bytes.NewReader(jsonData)) if err != nil { logWebhookError(webhook.ID, data, err, time.Since(startTime).Milliseconds()) return } req.Header.Set("Content-Type", "application/json") if webhook.SecretKey != "" { req.Header.Set("X-Webhook-Secret", webhook.SecretKey) } resp, err := client.Do(req) duration := time.Since(startTime).Milliseconds() if err != nil { logWebhookError(webhook.ID, data, err, duration) return } defer resp.Body.Close() logWebhookSuccess(webhook.ID, data, resp.StatusCode, duration) } func logWebhookSuccess(webhookID uint, requestData map[string]interface{}, statusCode int, duration int64) { requestJSON, _ := json.Marshal(requestData) log := model.WebhookLog{ WebhookID: webhookID, Event: requestData["event"].(string), RequestData: string(requestJSON), ResponseCode: statusCode, Status: "success", Duration: int(duration), } database.DB.Create(&log) } func logWebhookError(webhookID uint, requestData map[string]interface{}, err error, duration int64) { requestJSON, _ := json.Marshal(requestData) log := model.WebhookLog{ WebhookID: webhookID, Event: requestData["event"].(string), RequestData: string(requestJSON), Status: "failed", ErrorMessage: err.Error(), Duration: int(duration), } database.DB.Create(&log) } func handleUpdateWebhookStatus(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var req struct { Status string `json:"status" binding:"required,oneof=active inactive"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var webhook model.WebhookConfig if err := database.DB.Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("webhook_configs.id = ? AND applications.user_id = ?", id, userID). First(&webhook).Error; err != nil { response.Error(c, 404, "Webhook配置不存在") return } if err := database.DB.Model(&webhook).Update("status", req.Status).Error; err != nil { response.Error(c, 500, "更新状态失败") return } response.Success(c, webhook) } func handleBatchUpdateWebhookStatus(c *gin.Context) { userID := c.GetUint("user_id") var req struct { IDs []uint `json:"ids" binding:"required"` Status string `json:"status" binding:"required,oneof=active inactive"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } if len(req.IDs) == 0 { response.Error(c, 400, "请选择要更新的Webhook") return } result := database.DB.Model(&model.WebhookConfig{}). Joins("JOIN applications ON webhook_configs.application_id = applications.id"). Where("applications.user_id = ? AND webhook_configs.id IN ?", userID, req.IDs). Update("status", req.Status) if result.Error != nil { response.Error(c, 500, "批量更新状态失败") return } response.Success(c, gin.H{"updated_count": result.RowsAffected}) } func handleBatchDeleteWebhooks(c *gin.Context) { userID := c.GetUint("user_id") var req struct { IDs []uint `json:"ids" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } if len(req.IDs) == 0 { response.Error(c, 400, "请选择要删除的Webhook") return } result := database.DB.Where("id IN (?) AND application_id IN (SELECT id FROM applications WHERE user_id = ?)", req.IDs, userID). Delete(&model.WebhookConfig{}) if result.Error != nil { response.Error(c, 500, "批量删除失败") return } response.Success(c, gin.H{"deleted_count": result.RowsAffected}) } func handleUpdateAPIKeyStatus(c *gin.Context) { userID := c.GetUint("user_id") id := c.Param("id") var req struct { Status string `json:"status" binding:"required,oneof=active inactive"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var apiKey model.ExtensionAPIKey if err := database.DB.Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("extension_api_keys.id = ? AND applications.user_id = ?", id, userID). First(&apiKey).Error; err != nil { response.Error(c, 404, "API密钥不存在") return } if err := database.DB.Model(&apiKey).Update("status", req.Status).Error; err != nil { response.Error(c, 500, "更新状态失败") return } response.Success(c, apiKey) } func handleBatchUpdateAPIKeyStatus(c *gin.Context) { userID := c.GetUint("user_id") var req struct { IDs []uint `json:"ids" binding:"required"` Status string `json:"status" binding:"required,oneof=active inactive"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } if len(req.IDs) == 0 { response.Error(c, 400, "请选择要更新的API密钥") return } result := database.DB.Model(&model.ExtensionAPIKey{}). Joins("JOIN applications ON extension_api_keys.application_id = applications.id"). Where("applications.user_id = ? AND extension_api_keys.id IN ?", userID, req.IDs). Update("status", req.Status) if result.Error != nil { response.Error(c, 500, "批量更新状态失败") return } response.Success(c, gin.H{"updated_count": result.RowsAffected}) } func handleBatchDeleteAPIKeys(c *gin.Context) { userID := c.GetUint("user_id") var req struct { IDs []uint `json:"ids" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } if len(req.IDs) == 0 { response.Error(c, 400, "请选择要删除的API密钥") return } result := database.DB.Where("id IN (?) AND application_id IN (SELECT id FROM applications WHERE user_id = ?)", req.IDs, userID). Delete(&model.ExtensionAPIKey{}) if result.Error != nil { response.Error(c, 500, "批量删除失败") return } response.Success(c, gin.H{"deleted_count": result.RowsAffected}) }