package controller import ( "net/http" "strconv" "strings" "unicode/utf8" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/i18n" "github.com/QuantumNous/new-api/model" "github.com/gin-gonic/gin" ) func GetAllRedemptions(c *gin.Context) { pageInfo := common.GetPageQuery(c) redemptions, total, err := model.GetAllRedemptions(pageInfo.GetStartIdx(), pageInfo.GetPageSize()) if err != nil { common.ApiError(c, err) return } enrichRedemptions(redemptions) pageInfo.SetTotal(int(total)) pageInfo.SetItems(redemptions) common.ApiSuccess(c, pageInfo) } func SearchRedemptions(c *gin.Context) { keyword := c.Query("keyword") pageInfo := common.GetPageQuery(c) redemptions, total, err := model.SearchRedemptions(keyword, pageInfo.GetStartIdx(), pageInfo.GetPageSize()) if err != nil { common.ApiError(c, err) return } enrichRedemptions(redemptions) pageInfo.SetTotal(int(total)) pageInfo.SetItems(redemptions) common.ApiSuccess(c, pageInfo) } func GetRedemption(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil { common.ApiError(c, err) return } redemption, err := model.GetRedemptionById(id) if err != nil { common.ApiError(c, err) return } enrichRedemption(redemption) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": redemption, }) } func AddRedemption(c *gin.Context) { redemption := model.Redemption{} err := c.ShouldBindJSON(&redemption) if err != nil { common.ApiError(c, err) return } if !validateRedemptionPayload(c, &redemption, true) { return } if redemption.Count <= 0 { common.ApiErrorI18n(c, i18n.MsgRedemptionCountPositive) return } if redemption.Count > 100 { common.ApiErrorI18n(c, i18n.MsgRedemptionCountMax) return } var keys []string for i := 0; i < redemption.Count; i++ { key := common.GetUUID() cleanRedemption := model.Redemption{ UserId: c.GetInt("id"), Name: redemption.Name, Key: key, CreatedTime: common.GetTimestamp(), Quota: redemption.Quota, RedeemType: redemption.RedeemType, PlanId: redemption.PlanId, SourceNote: redemption.SourceNote, ExpiredTime: redemption.ExpiredTime, } err = cleanRedemption.Insert() if err != nil { common.SysError("failed to insert redemption: " + err.Error()) c.JSON(http.StatusOK, gin.H{ "success": false, "message": i18n.T(c, i18n.MsgRedemptionCreateFailed), "data": keys, }) return } keys = append(keys, key) } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": keys, }) } func DeleteRedemption(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) err := model.DeleteRedemptionById(id) if err != nil { common.ApiError(c, err) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) } func UpdateRedemption(c *gin.Context) { statusOnly := c.Query("status_only") redemption := model.Redemption{} err := c.ShouldBindJSON(&redemption) if err != nil { common.ApiError(c, err) return } cleanRedemption, err := model.GetRedemptionById(redemption.Id) if err != nil { common.ApiError(c, err) return } if statusOnly == "" { if !validateRedemptionPayload(c, &redemption, true) { return } cleanRedemption.Name = redemption.Name cleanRedemption.Quota = redemption.Quota cleanRedemption.RedeemType = redemption.RedeemType cleanRedemption.PlanId = redemption.PlanId cleanRedemption.SourceNote = redemption.SourceNote cleanRedemption.ExpiredTime = redemption.ExpiredTime } if statusOnly != "" { cleanRedemption.Status = redemption.Status } err = cleanRedemption.Update() if err != nil { common.ApiError(c, err) return } enrichRedemption(cleanRedemption) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": cleanRedemption, }) } func DeleteInvalidRedemption(c *gin.Context) { rows, err := model.DeleteInvalidRedemptions() if err != nil { common.ApiError(c, err) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": rows, }) } func validateExpiredTime(c *gin.Context, expired int64) (bool, string) { if expired != 0 && expired < common.GetTimestamp() { return false, i18n.T(c, i18n.MsgRedemptionExpireTimeInvalid) } return true, "" } func validateRedemptionPayload(c *gin.Context, redemption *model.Redemption, requireName bool) bool { if redemption == nil { common.ApiErrorMsg(c, "invalid redemption payload") return false } redemption.Name = strings.TrimSpace(redemption.Name) redemption.SourceNote = strings.TrimSpace(redemption.SourceNote) redemption.RedeemType = model.NormalizeRedemptionType(redemption.RedeemType) if redemption.RedeemType == "" { common.ApiErrorMsg(c, "invalid redeem type") return false } if requireName && (utf8.RuneCountInString(redemption.Name) == 0 || utf8.RuneCountInString(redemption.Name) > 20) { common.ApiErrorI18n(c, i18n.MsgRedemptionNameLength) return false } if valid, msg := validateExpiredTime(c, redemption.ExpiredTime); !valid { c.JSON(http.StatusOK, gin.H{"success": false, "message": msg}) return false } switch redemption.RedeemType { case model.RedemptionTypeQuota: if redemption.Quota <= 0 { common.ApiErrorMsg(c, "quota must be greater than 0") return false } redemption.PlanId = 0 case model.RedemptionTypeSubscription: if redemption.PlanId <= 0 { common.ApiErrorMsg(c, "plan_id is required") return false } plan, err := model.GetSubscriptionPlanById(redemption.PlanId) if err != nil || plan == nil { common.ApiErrorMsg(c, "subscription plan not found") return false } redemption.Quota = 0 } return true } func enrichRedemptions(redemptions []*model.Redemption) { if len(redemptions) == 0 { return } planTitles := make(map[int]string) for _, redemption := range redemptions { if redemption == nil || model.NormalizeRedemptionType(redemption.RedeemType) != model.RedemptionTypeSubscription || redemption.PlanId <= 0 { continue } if _, ok := planTitles[redemption.PlanId]; ok { redemption.PlanTitle = planTitles[redemption.PlanId] continue } plan, err := model.GetSubscriptionPlanById(redemption.PlanId) if err != nil || plan == nil { continue } planTitles[redemption.PlanId] = plan.Title redemption.PlanTitle = plan.Title } } func enrichRedemption(redemption *model.Redemption) { if redemption == nil || model.NormalizeRedemptionType(redemption.RedeemType) != model.RedemptionTypeSubscription || redemption.PlanId <= 0 { return } plan, err := model.GetSubscriptionPlanById(redemption.PlanId) if err != nil || plan == nil { return } redemption.PlanTitle = plan.Title }