970 lines
27 KiB
Go
970 lines
27 KiB
Go
package developer
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"time"
|
|
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/pkg/response"
|
|
"verification-platform-backend/pkg/utils"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func SetupCardRoutes(r *gin.RouterGroup) {
|
|
cardTypes := r.Group("/card-types")
|
|
{
|
|
cardTypes.GET("", handleGetCardTypes)
|
|
cardTypes.GET("/:id", handleGetCardType)
|
|
cardTypes.POST("", handleCreateCardType)
|
|
cardTypes.PUT("/:id", handleUpdateCardType)
|
|
cardTypes.DELETE("/:id", handleDeleteCardType)
|
|
}
|
|
|
|
cards := r.Group("/cards")
|
|
{
|
|
cards.GET("", handleGetCards)
|
|
cards.POST("", handleCreateCards)
|
|
cards.GET("/:id", handleGetCard)
|
|
cards.PUT("/:id", handleUpdateCard)
|
|
cards.DELETE("/:id", handleDeleteCard)
|
|
cards.PUT("/:id/status", handleUpdateCardStatus)
|
|
cards.PUT("/batch/status", handleBatchUpdateCardStatus)
|
|
cards.DELETE("/batch", handleBatchDeleteCards)
|
|
cards.POST("/use", handleUseCard)
|
|
cards.GET("/export", handleExportCards)
|
|
}
|
|
}
|
|
|
|
func SetupCardRoutesWithoutPackage(r *gin.RouterGroup) {
|
|
cards := r.Group("/cards")
|
|
{
|
|
cards.POST("/batch", handleBatchGenerateCards)
|
|
}
|
|
}
|
|
|
|
func checkDeveloperPackageValid(developerID uint) bool {
|
|
var user model.User
|
|
if err := database.DB.First(&user, developerID).Error; err != nil {
|
|
return false
|
|
}
|
|
|
|
if user.CurrentPackageID == nil {
|
|
return false
|
|
}
|
|
|
|
var userPackage model.UserPackage
|
|
if err := database.DB.Where("user_id = ? AND package_id = ? AND status = ?",
|
|
developerID, user.CurrentPackageID, "active").First(&userPackage).Error; err != nil {
|
|
return false
|
|
}
|
|
|
|
if userPackage.ExpiredAt != nil && userPackage.ExpiredAt.Before(time.Now()) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func handleGetCardTypes(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
applicationID := c.Query("application_id")
|
|
|
|
log.Printf("[DEBUG] handleGetCardTypes called: userID=%d, applicationID=%s\n", userID, applicationID)
|
|
|
|
var cardTypes []model.CardType
|
|
var query *gorm.DB
|
|
|
|
if applicationID != "" {
|
|
appID, err := strconv.ParseUint(applicationID, 10, 32)
|
|
if err == nil {
|
|
var authorizedApps []model.AgentApplication
|
|
database.DB.Where("agent_id = ? AND application_id = ? AND status = ?", userID, uint(appID), "active").
|
|
Preload("CardTypes").
|
|
Find(&authorizedApps)
|
|
|
|
log.Printf("[DEBUG] Found %d authorized apps for user %d and application %d\n", len(authorizedApps), userID, uint(appID))
|
|
|
|
var authorizedCardTypeIDs []uint
|
|
for _, aa := range authorizedApps {
|
|
for _, ct := range aa.CardTypes {
|
|
if ct.CanGenerate {
|
|
authorizedCardTypeIDs = append(authorizedCardTypeIDs, ct.CardTypeID)
|
|
log.Printf("[DEBUG] Authorized card type - ID: %d\n", ct.CardTypeID)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(authorizedCardTypeIDs) > 0 {
|
|
query = database.DB.Where("(user_id = ? AND application_id = ?) OR (id IN (?))", userID, uint(appID), authorizedCardTypeIDs)
|
|
log.Printf("[DEBUG] Querying card types with authorizedCardTypeIDs: %v\n", authorizedCardTypeIDs)
|
|
} else {
|
|
query = database.DB.Where("user_id = ? AND application_id = ?", userID, uint(appID))
|
|
}
|
|
} else {
|
|
query = database.DB.Where("user_id = ?", userID)
|
|
}
|
|
} else {
|
|
query = database.DB.Where("user_id = ?", userID)
|
|
}
|
|
|
|
if err := query.Preload("Application").Find(&cardTypes).Error; err != nil {
|
|
log.Printf("[ERROR] Failed to query card types: %v\n", err)
|
|
response.Error(c, 500, "获取卡密类型失败")
|
|
return
|
|
}
|
|
|
|
log.Printf("[DEBUG] Found %d card types\n", len(cardTypes))
|
|
for i, ct := range cardTypes {
|
|
log.Printf("[DEBUG] CardType %d: ID=%d, Name=%s, ApplicationID=%v\n", i, ct.ID, ct.Name, ct.ApplicationID)
|
|
}
|
|
|
|
var cardTypesWithCount []map[string]interface{}
|
|
for _, ct := range cardTypes {
|
|
var count int64
|
|
database.DB.Model(&model.Card{}).Where("card_type_id = ?", ct.ID).Count(&count)
|
|
log.Printf("[DEBUG] CardType ID=%d, Name=%s, GeneratedCount=%d\n", ct.ID, ct.Name, count)
|
|
|
|
cardTypeMap := map[string]interface{}{
|
|
"id": ct.ID,
|
|
"user_id": ct.UserID,
|
|
"application_id": ct.ApplicationID,
|
|
"name": ct.Name,
|
|
"value": ct.Value,
|
|
"price": ct.Price,
|
|
"description": ct.Description,
|
|
"status": ct.Status,
|
|
"created_at": ct.CreatedAt,
|
|
"updated_at": ct.UpdatedAt,
|
|
"generatedCount": count,
|
|
}
|
|
if ct.Application != nil {
|
|
cardTypeMap["application"] = ct.Application
|
|
}
|
|
cardTypesWithCount = append(cardTypesWithCount, cardTypeMap)
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"card_types": cardTypesWithCount,
|
|
})
|
|
}
|
|
|
|
func handleGetCardType(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
var cardType model.CardType
|
|
if err := database.DB.Preload("Application").First(&cardType, id).Error; err != nil {
|
|
response.Error(c, 404, "卡类不存在")
|
|
return
|
|
}
|
|
|
|
if cardType.UserID != userID {
|
|
var app model.Application
|
|
if err := database.DB.First(&app, cardType.ApplicationID).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该卡类")
|
|
return
|
|
}
|
|
|
|
if app.UserID != userID {
|
|
var agentApp model.AgentApplication
|
|
if err := database.DB.Where("application_id = ? AND agent_id = ? AND is_received = ?", cardType.ApplicationID, userID, true).First(&agentApp).Error; err != nil {
|
|
response.Error(c, 403, "无权限查看该卡类")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"card_type": cardType,
|
|
})
|
|
}
|
|
|
|
func handleCreateCardType(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
RechargeType string `json:"recharge_type"`
|
|
Value float64 `json:"value"`
|
|
ValueUnit string `json:"value_unit"`
|
|
Price float64 `json:"price"`
|
|
ApplicationID uint `json:"application_id"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
fmt.Printf("创建卡密类型参数错误: %v\n", err)
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("创建卡密类型请求: Name=%s, RechargeType=%s, Value=%f, ValueUnit=%s, Price=%f, ApplicationID=%d\n",
|
|
req.Name, req.RechargeType, req.Value, req.ValueUnit, req.Price, req.ApplicationID)
|
|
|
|
if req.Name == "" {
|
|
response.Error(c, 400, "卡密类型名称不能为空")
|
|
return
|
|
}
|
|
|
|
if req.ApplicationID == 0 {
|
|
response.Error(c, 400, "所属应用不能为空")
|
|
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, 400, "所属应用不存在或无权限")
|
|
return
|
|
}
|
|
|
|
if req.Price < 0 {
|
|
response.Error(c, 400, "价格不能为负数")
|
|
return
|
|
}
|
|
|
|
if req.Value == 0 {
|
|
response.Error(c, 400, "面值不能为0")
|
|
return
|
|
}
|
|
|
|
if req.Value < -1 {
|
|
response.Error(c, 400, "面值无效,必须大于0或为-1(表示永久有效)")
|
|
return
|
|
}
|
|
|
|
rechargeType := req.RechargeType
|
|
if rechargeType == "" {
|
|
rechargeType = "balance"
|
|
}
|
|
|
|
valueUnit := req.ValueUnit
|
|
if rechargeType == "subscription" && valueUnit == "" {
|
|
valueUnit = "day"
|
|
}
|
|
|
|
cardType := model.CardType{
|
|
UserID: userID,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
RechargeType: rechargeType,
|
|
Value: req.Value,
|
|
ValueUnit: valueUnit,
|
|
Price: req.Price,
|
|
ApplicationID: req.ApplicationID,
|
|
}
|
|
|
|
if err := database.DB.Create(&cardType).Error; err != nil {
|
|
response.Error(c, 500, "创建卡密类型失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "create", "card_type", &cardType.ID, fmt.Sprintf("创建卡密类型: %s", cardType.Name), nil)
|
|
|
|
response.Success(c, cardType)
|
|
}
|
|
|
|
func handleUpdateCardType(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
RechargeType string `json:"recharge_type"`
|
|
Value float64 `json:"value"`
|
|
ValueUnit string `json:"value_unit"`
|
|
Price float64 `json:"price"`
|
|
ApplicationID uint `json:"application_id"`
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
id := c.Param("id")
|
|
var cardType model.CardType
|
|
if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&cardType).Error; err != nil {
|
|
response.Error(c, 404, "卡密类型不存在")
|
|
return
|
|
}
|
|
|
|
if req.Name != "" {
|
|
cardType.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
cardType.Description = req.Description
|
|
}
|
|
if req.RechargeType != "" {
|
|
cardType.RechargeType = req.RechargeType
|
|
}
|
|
if req.ValueUnit != "" {
|
|
cardType.ValueUnit = req.ValueUnit
|
|
}
|
|
if req.Price >= 0 {
|
|
cardType.Price = req.Price
|
|
}
|
|
if req.Value > 0 || req.Value == -1 {
|
|
cardType.Value = req.Value
|
|
}
|
|
if req.Price > 0 {
|
|
cardType.Price = req.Price
|
|
}
|
|
if req.ApplicationID > 0 {
|
|
var app model.Application
|
|
if err := database.DB.Where("id = ? AND user_id = ?", req.ApplicationID, userID).First(&app).Error; err != nil {
|
|
response.Error(c, 400, "所属应用不存在或无权限")
|
|
return
|
|
}
|
|
cardType.ApplicationID = req.ApplicationID
|
|
}
|
|
if req.Status != "" {
|
|
cardType.Status = req.Status
|
|
}
|
|
|
|
if err := database.DB.Save(&cardType).Error; err != nil {
|
|
response.Error(c, 500, "更新卡密类型失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "update", "card_type", &cardType.ID, fmt.Sprintf("更新卡密类型: %s", cardType.Name), nil)
|
|
|
|
response.Success(c, cardType)
|
|
}
|
|
|
|
func handleDeleteCardType(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
var cardType model.CardType
|
|
if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&cardType).Error; err != nil {
|
|
response.Error(c, 404, "卡密类型不存在")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Where("id = ? AND user_id = ?", id, userID).Delete(&model.CardType{}).Error; err != nil {
|
|
response.Error(c, 500, "删除卡密类型失败")
|
|
return
|
|
}
|
|
|
|
service.LogOperation(c, "delete", "card_type", &cardType.ID, fmt.Sprintf("删除卡密类型: %s", cardType.Name), nil)
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
func handleGetCards(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
fmt.Printf("[DEBUG] handleGetCards called, userID: %d\n", userID)
|
|
|
|
applicationID := c.Query("application_id")
|
|
cardTypeID := c.Query("card_type_id")
|
|
status := c.Query("status")
|
|
search := c.Query("search")
|
|
startDate := c.Query("start_date")
|
|
endDate := c.Query("end_date")
|
|
|
|
var cards []model.Card
|
|
|
|
var authorizedAppIDs []uint
|
|
database.DB.Model(&model.AgentApplication{}).
|
|
Where("agent_id = ? AND status = ?", userID, "active").
|
|
Pluck("application_id", &authorizedAppIDs)
|
|
|
|
fmt.Printf("[DEBUG] Authorized app IDs: %v\n", authorizedAppIDs)
|
|
|
|
query := database.DB.Model(&model.Card{}).
|
|
Joins("JOIN card_types ON cards.card_type_id = card_types.id").
|
|
Joins("JOIN applications ON card_types.application_id = applications.id").
|
|
Preload("Application").
|
|
Preload("CardType").
|
|
Preload("Creator").
|
|
Preload("AppUser")
|
|
|
|
if len(authorizedAppIDs) > 0 {
|
|
query = query.Where("applications.user_id = ? OR (cards.application_id IN ? AND cards.creator_id = ?)", userID, authorizedAppIDs, userID)
|
|
} else {
|
|
query = query.Where("applications.user_id = ?", userID)
|
|
}
|
|
|
|
if applicationID != "" {
|
|
appID, err := strconv.ParseUint(applicationID, 10, 32)
|
|
if err == nil {
|
|
query = query.Where("cards.application_id = ?", uint(appID))
|
|
}
|
|
}
|
|
|
|
if cardTypeID != "" {
|
|
ctID, err := strconv.ParseUint(cardTypeID, 10, 32)
|
|
if err == nil {
|
|
query = query.Where("cards.card_type_id = ?", uint(ctID))
|
|
}
|
|
}
|
|
|
|
if status != "" {
|
|
query = query.Where("cards.status = ?", status)
|
|
}
|
|
|
|
if search != "" {
|
|
searchPattern := "%" + search + "%"
|
|
query = query.Where("cards.card_key LIKE ? OR card_types.name LIKE ? OR applications.name LIKE ?", searchPattern, searchPattern, searchPattern)
|
|
}
|
|
|
|
if startDate != "" {
|
|
query = query.Where("cards.created_at >= ?", startDate+" 00:00:00")
|
|
}
|
|
|
|
if endDate != "" {
|
|
query = query.Where("cards.created_at <= ?", endDate+" 23:59:59")
|
|
}
|
|
|
|
if err := query.Order("cards.created_at DESC").Find(&cards).Error; err != nil {
|
|
fmt.Printf("[DEBUG] Error fetching cards: %v\n", err)
|
|
response.Error(c, 500, "获取卡密列表失败")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] Found %d cards for user %d\n", len(cards), userID)
|
|
|
|
response.Success(c, cards)
|
|
}
|
|
|
|
func handleCreateCards(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
CardTypeID uint `json:"card_type_id"`
|
|
Count int `json:"count"`
|
|
Prefix string `json:"prefix"`
|
|
Length int `json:"length"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var cardType model.CardType
|
|
if err := database.DB.Where("id = ? AND user_id = ?", req.CardTypeID, userID).First(&cardType).Error; err != nil {
|
|
response.Error(c, 404, "卡密类型不存在")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "卡密创建成功",
|
|
"count": req.Count,
|
|
})
|
|
}
|
|
|
|
func handleUpdateCard(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
var req struct {
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
id := c.Param("id")
|
|
var card model.Card
|
|
if err := database.DB.Joins("JOIN card_types ON cards.card_type_id = card_types.id").
|
|
Joins("JOIN applications ON card_types.application_id = applications.id").
|
|
Where("cards.id = ? AND applications.user_id = ?", id, userID).First(&card).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
card.Status = req.Status
|
|
|
|
if err := database.DB.Save(&card).Error; err != nil {
|
|
response.Error(c, 500, "更新卡密失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, card)
|
|
}
|
|
|
|
func handleDeleteCard(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
fmt.Printf("删除卡密请求: ID=%s, UserID=%d\n", id, userID)
|
|
|
|
var card model.Card
|
|
if err := database.DB.Preload("CardType").Preload("CardType.Application").First(&card, id).Error; err != nil {
|
|
fmt.Printf("卡密不存在: %v\n", err)
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("查询到的卡密: ID=%d, CardTypeID=%d, CreatorID=%d\n", card.ID, card.CardTypeID, card.CreatorID)
|
|
|
|
// 如果创建者是当前用户,直接允许删除
|
|
if card.CreatorID == userID {
|
|
fmt.Printf("创建者匹配,允许删除\n")
|
|
if err := database.DB.Delete(&card).Error; err != nil {
|
|
fmt.Printf("删除卡密失败: %v\n", err)
|
|
response.Error(c, 500, "删除卡密失败")
|
|
return
|
|
}
|
|
fmt.Printf("删除卡密成功: ID=%s\n", id)
|
|
response.Success(c, nil)
|
|
return
|
|
}
|
|
|
|
// 如果创建者不匹配,检查应用的所有者
|
|
if card.CardType.ID > 0 && card.CardType.Application != nil {
|
|
fmt.Printf("卡密类型和应用存在,检查应用所有者\n")
|
|
if card.CardType.Application.UserID == userID {
|
|
fmt.Printf("应用所有者匹配,允许删除\n")
|
|
if err := database.DB.Delete(&card).Error; err != nil {
|
|
fmt.Printf("删除卡密失败: %v\n", err)
|
|
response.Error(c, 500, "删除卡密失败")
|
|
return
|
|
}
|
|
fmt.Printf("删除卡密成功: ID=%s\n", id)
|
|
response.Success(c, nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
// 如果卡密类型或应用不存在,尝试通过ApplicationID查询应用(包括软删除的)
|
|
if card.CardType.ID == 0 || card.CardType.Application == nil {
|
|
fmt.Printf("卡密类型或应用不存在,尝试查询应用\n")
|
|
if card.CardType.ID == 0 {
|
|
// 卡密类型不存在,直接通过CardTypeID查询卡密类型(包括软删除的)
|
|
var cardType model.CardType
|
|
if err := database.DB.Unscoped().First(&cardType, card.CardTypeID).Error; err != nil {
|
|
fmt.Printf("卡密类型不存在: %v\n", err)
|
|
response.Error(c, 404, "卡密类型不存在")
|
|
return
|
|
}
|
|
card.CardType = cardType
|
|
}
|
|
|
|
if card.CardType.Application == nil {
|
|
// 应用不存在,直接通过ApplicationID查询应用(包括软删除的)
|
|
var app model.Application
|
|
if err := database.DB.Unscoped().First(&app, card.CardType.ApplicationID).Error; err != nil {
|
|
fmt.Printf("应用不存在: %v\n", err)
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
card.CardType.Application = &app
|
|
}
|
|
|
|
fmt.Printf("查询到的应用: ID=%d, UserID=%d\n", card.CardType.Application.ID, card.CardType.Application.UserID)
|
|
if card.CardType.Application.UserID == userID {
|
|
fmt.Printf("应用所有者匹配,允许删除\n")
|
|
if err := database.DB.Delete(&card).Error; err != nil {
|
|
fmt.Printf("删除卡密失败: %v\n", err)
|
|
response.Error(c, 500, "删除卡密失败")
|
|
return
|
|
}
|
|
fmt.Printf("删除卡密成功: ID=%s\n", id)
|
|
response.Success(c, nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
fmt.Printf("无权限删除此卡密\n")
|
|
response.Error(c, 403, "无权限删除此卡密")
|
|
}
|
|
|
|
func handleGetCard(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
var card model.Card
|
|
if err := database.DB.Joins("JOIN card_types ON cards.card_type_id = card_types.id").
|
|
Joins("JOIN applications ON card_types.application_id = applications.id").
|
|
Where("cards.id = ? AND applications.user_id = ?", id, userID).First(&card).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
response.Success(c, card)
|
|
}
|
|
|
|
func handleUseCard(c *gin.Context) {
|
|
var req struct {
|
|
CardKey string `json:"card_key"`
|
|
Username string `json:"username"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("card_key = ?", req.CardKey).First(&card).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
if card.Status != "unused" {
|
|
response.Error(c, 400, "卡密已被使用或已禁用")
|
|
return
|
|
}
|
|
|
|
card.Status = "used"
|
|
database.DB.Save(&card)
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "卡密使用成功",
|
|
})
|
|
}
|
|
|
|
func handleBatchGenerateCards(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
fmt.Printf("[DEBUG] handleBatchGenerateCards called, userID: %d\n", userID)
|
|
|
|
var req struct {
|
|
ApplicationID uint `json:"application_id"`
|
|
CardTypeID uint `json:"card_type_id"`
|
|
Count int `json:"count"`
|
|
Prefix string `json:"prefix"`
|
|
Length int `json:"length"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
fmt.Printf("[DEBUG] JSON bind error: %v\n", err)
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] Received parameters - ApplicationID: %v, CardTypeID: %d, Count: %d, Prefix: %s, Length: %d\n",
|
|
req.ApplicationID, req.CardTypeID, req.Count, req.Prefix, req.Length)
|
|
|
|
if req.Count <= 0 || req.Count > 1000 {
|
|
response.Error(c, 400, "生成数量需在1-1000之间")
|
|
return
|
|
}
|
|
|
|
if req.Length <= 0 {
|
|
req.Length = 16
|
|
}
|
|
if req.Prefix == "" {
|
|
req.Prefix = "CK"
|
|
}
|
|
|
|
var cardType model.CardType
|
|
if err := database.DB.Where("id = ?", req.CardTypeID).First(&cardType).Error; err != nil {
|
|
fmt.Printf("[DEBUG] CardType not found error: %v\n", err)
|
|
response.Error(c, 404, "卡密类型不存在")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] CardType found - ID: %d, Name: %s, UserID: %d\n", cardType.ID, cardType.Name, cardType.UserID)
|
|
|
|
if req.ApplicationID == 0 {
|
|
req.ApplicationID = cardType.ApplicationID
|
|
}
|
|
|
|
var agentApp *model.AgentApplication
|
|
var effectiveUserID uint = userID
|
|
|
|
if cardType.UserID != userID {
|
|
fmt.Printf("[DEBUG] CardType belongs to another user, checking authorization...\n")
|
|
|
|
if req.ApplicationID == 0 {
|
|
fmt.Printf("[DEBUG] ApplicationID is required for authorized card types\n")
|
|
response.Error(c, 400, "生成授权应用的卡密需要指定应用ID")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Where("agent_id = ? AND application_id = ? AND status = ?", userID, req.ApplicationID, "active").
|
|
Preload("CardTypes", "card_type_id = ?", req.CardTypeID).
|
|
First(&agentApp).Error; err != nil {
|
|
fmt.Printf("[DEBUG] Authorization not found error: %v\n", err)
|
|
response.Error(c, 403, "您没有权限生成此卡密类型")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] AgentApp found - ID: %d, DeveloperID: %d\n", agentApp.ID, agentApp.DeveloperID)
|
|
|
|
var cardTypePerm *model.AgentApplicationCardType
|
|
for _, ct := range agentApp.CardTypes {
|
|
if ct.CardTypeID == req.CardTypeID {
|
|
cardTypePerm = &ct
|
|
break
|
|
}
|
|
}
|
|
|
|
if cardTypePerm == nil || !cardTypePerm.CanGenerate {
|
|
fmt.Printf("[DEBUG] No permission to generate this card type\n")
|
|
response.Error(c, 403, "您没有权限生成此卡密类型")
|
|
return
|
|
}
|
|
|
|
var agentUser model.User
|
|
if err := database.DB.First(&agentUser, userID).Error; err != nil {
|
|
response.Error(c, 500, "获取代理信息失败")
|
|
return
|
|
}
|
|
|
|
totalCost := float64(req.Count) * cardType.Price
|
|
fmt.Printf("[DEBUG] Total cost: %f, Balance: %f\n", totalCost, agentUser.Balance)
|
|
|
|
if agentUser.Balance < totalCost {
|
|
fmt.Printf("[DEBUG] Insufficient balance\n")
|
|
response.Error(c, 400, "余额不足")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Model(&agentUser).Update("balance", agentUser.Balance-totalCost).Error; err != nil {
|
|
fmt.Printf("[DEBUG] Update balance error: %v\n", err)
|
|
response.Error(c, 500, "扣款失败")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] Balance updated successfully\n")
|
|
}
|
|
|
|
cards := make([]model.Card, 0, req.Count)
|
|
for i := 0; i < req.Count; i++ {
|
|
cardKey := req.Prefix + utils.GenerateRandomString(req.Length)
|
|
card := model.Card{
|
|
ApplicationID: req.ApplicationID,
|
|
CardTypeID: req.CardTypeID,
|
|
CardKey: cardKey,
|
|
CreatorID: effectiveUserID,
|
|
Status: "unused",
|
|
}
|
|
cards = append(cards, card)
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] Generated %d cards, saving to database...\n", len(cards))
|
|
|
|
if err := database.DB.Create(&cards).Error; err != nil {
|
|
fmt.Printf("[DEBUG] Database create error: %v\n", err)
|
|
response.Error(c, 500, "生成卡密失败")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] Successfully created %d cards\n", len(cards))
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "批量生成成功",
|
|
"count": req.Count,
|
|
})
|
|
}
|
|
|
|
func handleExportCards(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
|
|
applicationID := c.Query("application_id")
|
|
cardTypeID := c.Query("card_type_id")
|
|
status := c.Query("status")
|
|
search := c.Query("search")
|
|
startDate := c.Query("start_date")
|
|
endDate := c.Query("end_date")
|
|
|
|
var cards []model.Card
|
|
query := database.DB.Model(&model.Card{}).
|
|
Joins("JOIN card_types ON cards.card_type_id = card_types.id").
|
|
Joins("JOIN applications ON card_types.application_id = applications.id").
|
|
Preload("Application").
|
|
Preload("CardType").
|
|
Where("applications.user_id = ?", userID)
|
|
|
|
if applicationID != "" {
|
|
appID, err := strconv.ParseUint(applicationID, 10, 32)
|
|
if err == nil {
|
|
query = query.Where("cards.application_id = ?", uint(appID))
|
|
}
|
|
}
|
|
|
|
if cardTypeID != "" {
|
|
ctID, err := strconv.ParseUint(cardTypeID, 10, 32)
|
|
if err == nil {
|
|
query = query.Where("cards.card_type_id = ?", uint(ctID))
|
|
}
|
|
}
|
|
|
|
if status != "" {
|
|
query = query.Where("cards.status = ?", status)
|
|
}
|
|
|
|
if search != "" {
|
|
searchPattern := "%" + search + "%"
|
|
query = query.Where("cards.card_key LIKE ? OR card_types.name LIKE ? OR applications.name LIKE ?", searchPattern, searchPattern, searchPattern)
|
|
}
|
|
|
|
if startDate != "" {
|
|
query = query.Where("cards.created_at >= ?", startDate+" 00:00:00")
|
|
}
|
|
|
|
if endDate != "" {
|
|
query = query.Where("cards.created_at <= ?", endDate+" 23:59:59")
|
|
}
|
|
|
|
if err := query.Order("cards.created_at DESC").Find(&cards).Error; err != nil {
|
|
response.Error(c, 500, "导出卡密失败")
|
|
return
|
|
}
|
|
|
|
c.Header("Content-Type", "text/csv; charset=utf-8")
|
|
c.Header("Content-Disposition", "attachment; filename=cards_export.csv")
|
|
|
|
csv := "卡密,应用,卡类,状态,创建时间,使用时间\n"
|
|
for _, card := range cards {
|
|
statusMap := map[string]string{
|
|
"unused": "未使用",
|
|
"used": "已使用",
|
|
"banned": "已禁用",
|
|
}
|
|
statusText := statusMap[card.Status]
|
|
if statusText == "" {
|
|
statusText = card.Status
|
|
}
|
|
|
|
appName := ""
|
|
if card.Application != nil {
|
|
appName = card.Application.Name
|
|
}
|
|
|
|
cardTypeName := card.CardType.Name
|
|
|
|
usedAt := ""
|
|
if card.UsedAt != nil {
|
|
usedAt = card.UsedAt.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
csv += fmt.Sprintf("%s,%s,%s,%s,%s,%s\n",
|
|
card.CardKey,
|
|
appName,
|
|
cardTypeName,
|
|
statusText,
|
|
card.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
usedAt,
|
|
)
|
|
}
|
|
|
|
c.String(200, csv)
|
|
}
|
|
|
|
func handleUpdateCardStatus(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
id := c.Param("id")
|
|
|
|
var req struct {
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if req.Status != "unused" && req.Status != "used" && req.Status != "banned" {
|
|
response.Error(c, 400, "无效的状态")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Preload("CardType").Preload("CardType.Application").First(&card, id).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
if card.CreatorID != userID && (card.CardType.Application == nil || card.CardType.Application.UserID != userID) {
|
|
response.Error(c, 403, "无权限修改此卡密")
|
|
return
|
|
}
|
|
|
|
card.Status = req.Status
|
|
if err := database.DB.Save(&card).Error; err != nil {
|
|
response.Error(c, 500, "更新状态失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, card)
|
|
}
|
|
|
|
func handleBatchUpdateCardStatus(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
|
|
var req struct {
|
|
IDs []uint `json:"ids"`
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if req.Status != "unused" && req.Status != "used" && req.Status != "banned" {
|
|
response.Error(c, 400, "无效的状态")
|
|
return
|
|
}
|
|
|
|
if len(req.IDs) == 0 {
|
|
response.Error(c, 400, "请选择要更新的卡密")
|
|
return
|
|
}
|
|
|
|
var cards []model.Card
|
|
if err := database.DB.Preload("CardType").Preload("CardType.Application").Where("id IN ?", req.IDs).Find(&cards).Error; err != nil {
|
|
response.Error(c, 500, "查询卡密失败")
|
|
return
|
|
}
|
|
|
|
var validIDs []uint
|
|
for _, card := range cards {
|
|
if card.CreatorID == userID || (card.CardType.Application != nil && card.CardType.Application.UserID == userID) {
|
|
validIDs = append(validIDs, card.ID)
|
|
}
|
|
}
|
|
|
|
if len(validIDs) == 0 {
|
|
response.Error(c, 403, "无权限修改选中的卡密")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Model(&model.Card{}).Where("id IN ?", validIDs).Update("status", req.Status).Error; err != nil {
|
|
response.Error(c, 500, "批量更新状态失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{"updated_count": len(validIDs)})
|
|
}
|
|
|
|
func handleBatchDeleteCards(c *gin.Context) {
|
|
userID := c.GetUint("user_id")
|
|
|
|
var req struct {
|
|
IDs []uint `json:"ids"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if len(req.IDs) == 0 {
|
|
response.Error(c, 400, "请选择要删除的卡密")
|
|
return
|
|
}
|
|
|
|
var cards []model.Card
|
|
if err := database.DB.Preload("CardType").Preload("CardType.Application").Where("id IN ?", req.IDs).Find(&cards).Error; err != nil {
|
|
response.Error(c, 500, "查询卡密失败")
|
|
return
|
|
}
|
|
|
|
var validIDs []uint
|
|
for _, card := range cards {
|
|
if card.CreatorID == userID || (card.CardType.Application != nil && card.CardType.Application.UserID == userID) {
|
|
validIDs = append(validIDs, card.ID)
|
|
}
|
|
}
|
|
|
|
if len(validIDs) == 0 {
|
|
response.Error(c, 403, "无权限删除选中的卡密")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Where("id IN ?", validIDs).Delete(&model.Card{}).Error; err != nil {
|
|
response.Error(c, 500, "批量删除失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{"deleted_count": len(validIDs)})
|
|
}
|