mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 17:56:37 +08:00
压缩历史至 95081aff
This commit is contained in:
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
Copyright 2025 linux.do
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package redenvelope
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/linux-do/credit/internal/apps/oauth"
|
||||
"github.com/linux-do/credit/internal/common"
|
||||
"github.com/linux-do/credit/internal/db"
|
||||
"github.com/linux-do/credit/internal/db/idgen"
|
||||
"github.com/linux-do/credit/internal/model"
|
||||
"github.com/linux-do/credit/internal/service"
|
||||
"github.com/linux-do/credit/internal/util"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// CreateRequest 创建红包请求
|
||||
type CreateRequest struct {
|
||||
Type model.RedEnvelopeType `json:"type" binding:"required,oneof=fixed random"`
|
||||
TotalAmount decimal.Decimal `json:"total_amount" binding:"required"`
|
||||
TotalCount int `json:"total_count" binding:"required,min=1"`
|
||||
Greeting string `json:"greeting" binding:"max=100"`
|
||||
PayKey string `json:"pay_key" binding:"required,max=10"`
|
||||
CoverUploadID *uint64 `json:"cover_upload_id,string" binding:"omitempty"`
|
||||
HeterotypicUploadID *uint64 `json:"heterotypic_upload_id,string" binding:"omitempty"`
|
||||
}
|
||||
|
||||
// CreateResponse 创建红包响应
|
||||
type CreateResponse struct {
|
||||
ID uint64 `json:"id,string"`
|
||||
}
|
||||
|
||||
// ClaimRequest 领取红包请求
|
||||
type ClaimRequest struct {
|
||||
ID uint64 `json:"id,string" binding:"required"`
|
||||
}
|
||||
|
||||
// ClaimResponse 领取红包响应
|
||||
type ClaimResponse struct {
|
||||
Amount decimal.Decimal `json:"amount"`
|
||||
RedEnvelope model.RedEnvelope `json:"red_envelope"`
|
||||
}
|
||||
|
||||
// DetailResponse 红包详情响应
|
||||
type DetailResponse struct {
|
||||
RedEnvelope model.RedEnvelope `json:"red_envelope"`
|
||||
Claims []model.RedEnvelopeClaim `json:"claims"`
|
||||
UserClaimed *model.RedEnvelopeClaim `json:"user_claimed,omitempty"`
|
||||
}
|
||||
|
||||
// ListRequest 红包列表请求
|
||||
type ListRequest struct {
|
||||
Page int `json:"page" binding:"required,min=1"`
|
||||
PageSize int `json:"page_size" binding:"required,min=1,max=100"`
|
||||
Type string `json:"type" binding:"omitempty,oneof=sent received"`
|
||||
}
|
||||
|
||||
// ListResponse 红包列表响应
|
||||
type ListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
RedEnvelopes []model.RedEnvelope `json:"red_envelopes"`
|
||||
}
|
||||
|
||||
// Create 创建红包
|
||||
// @Tags redenvelope
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body CreateRequest true "创建红包请求"
|
||||
// @Success 200 {object} util.ResponseAny
|
||||
// @Router /api/v1/redenvelope/create [post]
|
||||
func Create(c *gin.Context) {
|
||||
var req CreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if err := util.ValidateAmount(req.TotalAmount); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查红包最低金额限制(1 LDC)
|
||||
if req.TotalAmount.LessThan(decimal.NewFromInt(1)) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.RedEnvelopeMinAmountRequired))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查单个红包最大金额限制
|
||||
maxAmount, err := model.GetDecimalByKey(c.Request.Context(), model.ConfigKeyRedEnvelopeMaxAmount, 2)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
if req.TotalAmount.GreaterThan(maxAmount) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.RedEnvelopeAmountExceeded))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查红包最大领取人数限制
|
||||
maxRecipients, err := model.GetIntByKey(c.Request.Context(), model.ConfigKeyRedEnvelopeMaxRecipients)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
if req.TotalCount > maxRecipients {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.RedEnvelopeRecipientsExceeded))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查每个红包平均金额不能小于0.01(避免前面领取者获得0 LDC)
|
||||
perAmount := req.TotalAmount.Div(decimal.NewFromInt(int64(req.TotalCount)))
|
||||
if perAmount.LessThan(decimal.NewFromFloat(0.01)) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(AmountTooSmall))
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
|
||||
// 检查每日红包发送数量限制
|
||||
dailyLimit, err := model.GetIntByKey(c.Request.Context(), model.ConfigKeyRedEnvelopeDailyLimit)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询今日已发送的红包数量
|
||||
var todayCount int64
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if err := db.DB(c.Request.Context()).Model(&model.RedEnvelope{}).
|
||||
Where("creator_id = ? AND created_at >= ?", currentUser.ID, today).
|
||||
Count(&todayCount).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if todayCount >= int64(dailyLimit) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.RedEnvelopeDailyLimitExceeded))
|
||||
return
|
||||
}
|
||||
|
||||
if !currentUser.VerifyPayKey(req.PayKey) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.PayKeyIncorrect))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取红包手续费率并计算手续费
|
||||
feeRate, err := model.GetDecimalByKey(c.Request.Context(), model.ConfigKeyRedEnvelopeFeeRate, 2)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 计算手续费(红包金额 * 费率)
|
||||
feeAmount := req.TotalAmount.Mul(feeRate).Round(2)
|
||||
|
||||
// 总扣款金额 = 红包金额 + 手续费
|
||||
totalDeduction := req.TotalAmount.Add(feeAmount)
|
||||
|
||||
// 提前检查余额,避免不必要的事务
|
||||
if currentUser.AvailableBalance.LessThan(totalDeduction) {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.InsufficientBalance))
|
||||
return
|
||||
}
|
||||
|
||||
var redEnvelope model.RedEnvelope
|
||||
|
||||
if err := db.DB(c.Request.Context()).Transaction(func(tx *gorm.DB) error {
|
||||
var coverUploadID *uint64
|
||||
var heterotypicUploadID *uint64
|
||||
|
||||
if req.CoverUploadID != nil {
|
||||
var coverUpload model.Upload
|
||||
if err := tx.Where("id = ? AND status IN (?, ?) AND user_id = ? AND type = ?", *req.CoverUploadID, model.UploadStatusPending, model.UploadStatusUsed, currentUser.ID, model.UploadTypeCover).
|
||||
First(&coverUpload).Error; err != nil {
|
||||
return errors.New(InvalidCoverImage)
|
||||
}
|
||||
|
||||
if coverUpload.Status == model.UploadStatusPending {
|
||||
if err := tx.Model(&model.Upload{}).
|
||||
Where("id = ? AND status = ?", coverUpload.ID, model.UploadStatusPending).
|
||||
Update("status", model.UploadStatusUsed).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
coverUploadID = &coverUpload.ID
|
||||
}
|
||||
|
||||
if req.HeterotypicUploadID != nil {
|
||||
var heterotypicUpload model.Upload
|
||||
if err := tx.Where("id = ? AND status IN (?, ?) AND user_id = ? AND type = ?", *req.HeterotypicUploadID, model.UploadStatusPending, model.UploadStatusUsed, currentUser.ID, model.UploadTypeHeterotypic).
|
||||
First(&heterotypicUpload).Error; err != nil {
|
||||
return errors.New(InvalidHeterotypicImage)
|
||||
}
|
||||
|
||||
if heterotypicUpload.Status == model.UploadStatusPending {
|
||||
if err := tx.Model(&model.Upload{}).
|
||||
Where("id = ? AND status = ?", heterotypicUpload.ID, model.UploadStatusPending).
|
||||
Update("status", model.UploadStatusUsed).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
heterotypicUploadID = &heterotypicUpload.ID
|
||||
}
|
||||
|
||||
// 扣减发送者余额并更新total_payment
|
||||
if err := service.UpdateBalance(tx, service.BalanceUpdateOptions{
|
||||
UserID: currentUser.ID,
|
||||
Amount: totalDeduction,
|
||||
Operation: service.BalanceDeduct,
|
||||
TotalField: "total_payment",
|
||||
CheckBalance: true,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建红包
|
||||
redEnvelope = model.RedEnvelope{
|
||||
ID: idgen.NextUint64ID(),
|
||||
CreatorID: currentUser.ID,
|
||||
Type: req.Type,
|
||||
TotalAmount: req.TotalAmount,
|
||||
RemainingAmount: req.TotalAmount,
|
||||
TotalCount: req.TotalCount,
|
||||
RemainingCount: req.TotalCount,
|
||||
Greeting: req.Greeting,
|
||||
Status: model.RedEnvelopeStatusActive,
|
||||
CoverUploadID: coverUploadID,
|
||||
HeterotypicUploadID: heterotypicUploadID,
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
if err := tx.Create(&redEnvelope).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建订单记录(红包支出)
|
||||
remarkMsg := fmt.Sprintf("创建红包,共%d个", req.TotalCount)
|
||||
if feeAmount.GreaterThan(decimal.Zero) {
|
||||
remarkMsg = fmt.Sprintf("%s,手续费: %s", remarkMsg, feeAmount.String())
|
||||
}
|
||||
if req.Greeting != "" {
|
||||
remarkMsg = fmt.Sprintf("%s,祝福语: %s", remarkMsg, req.Greeting)
|
||||
}
|
||||
|
||||
order := model.Order{
|
||||
OrderName: "红包支出",
|
||||
PayerUserID: currentUser.ID,
|
||||
PayeeUserID: 0,
|
||||
Amount: totalDeduction,
|
||||
Status: model.OrderStatusSuccess,
|
||||
Type: model.OrderTypeRedEnvelopeSend,
|
||||
Remark: remarkMsg,
|
||||
TradeTime: time.Now(),
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
return tx.Create(&order).Error
|
||||
}); err != nil {
|
||||
if err.Error() == common.InsufficientBalance {
|
||||
c.JSON(http.StatusBadRequest, util.Err(common.InsufficientBalance))
|
||||
} else if err.Error() == InvalidCoverImage || err.Error() == InvalidHeterotypicImage {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(CreateResponse{
|
||||
ID: redEnvelope.ID,
|
||||
}))
|
||||
}
|
||||
|
||||
// Claim 领取红包
|
||||
// @Tags redenvelope
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body ClaimRequest true "领取红包请求"
|
||||
// @Success 200 {object} util.ResponseAny
|
||||
// @Router /api/v1/redenvelope/claim [post]
|
||||
func Claim(c *gin.Context) {
|
||||
var req ClaimRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
|
||||
var claimedAmount decimal.Decimal
|
||||
var redEnvelope model.RedEnvelope
|
||||
|
||||
if err := db.DB(c.Request.Context()).Transaction(func(tx *gorm.DB) error {
|
||||
// 使用 FOR UPDATE 锁定红包记录,防止并发领取
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE", Options: "NOWAIT"}).
|
||||
Where("id = ?", req.ID).First(&redEnvelope).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New(RedEnvelopeNotFound)
|
||||
}
|
||||
// 捕获锁等待超时错误,返回友好提示
|
||||
return errors.New(RedEnvelopeTooPopular)
|
||||
}
|
||||
|
||||
// 检查红包状态
|
||||
if redEnvelope.Status == model.RedEnvelopeStatusExpired || redEnvelope.ExpiresAt.Before(time.Now()) {
|
||||
return errors.New(RedEnvelopeExpired)
|
||||
}
|
||||
|
||||
if redEnvelope.Status == model.RedEnvelopeStatusFinished || redEnvelope.RemainingCount <= 0 {
|
||||
return errors.New(RedEnvelopeFinished)
|
||||
}
|
||||
|
||||
// 检查是否已领取
|
||||
var existingClaim model.RedEnvelopeClaim
|
||||
if err := tx.Where("red_envelope_id = ? AND user_id = ?", redEnvelope.ID, currentUser.ID).
|
||||
First(&existingClaim).Error; err == nil {
|
||||
return errors.New(RedEnvelopeAlreadyClaimed)
|
||||
}
|
||||
|
||||
// 计算领取金额
|
||||
if redEnvelope.Type == model.RedEnvelopeTypeFixed {
|
||||
// 固定金额:如果是最后一个,给全部剩余金额(避免舍入误差)
|
||||
if redEnvelope.RemainingCount == 1 {
|
||||
claimedAmount = redEnvelope.RemainingAmount
|
||||
} else {
|
||||
claimedAmount = redEnvelope.TotalAmount.Div(decimal.NewFromInt(int64(redEnvelope.TotalCount))).Round(2)
|
||||
}
|
||||
} else {
|
||||
// 拼手气红包:使用二倍均值算法
|
||||
claimedAmount = calculateRandomAmount(redEnvelope.RemainingAmount, redEnvelope.RemainingCount)
|
||||
}
|
||||
|
||||
// 创建领取记录
|
||||
claim := model.RedEnvelopeClaim{
|
||||
ID: idgen.NextUint64ID(),
|
||||
RedEnvelopeID: redEnvelope.ID,
|
||||
UserID: currentUser.ID,
|
||||
Amount: claimedAmount,
|
||||
}
|
||||
if err := tx.Create(&claim).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新红包状态
|
||||
newRemainingCount := redEnvelope.RemainingCount - 1
|
||||
newRemainingAmount := redEnvelope.RemainingAmount.Sub(claimedAmount)
|
||||
newStatus := redEnvelope.Status
|
||||
if newRemainingCount <= 0 {
|
||||
newStatus = model.RedEnvelopeStatusFinished
|
||||
}
|
||||
|
||||
if err := tx.Model(&model.RedEnvelope{}).Where("id = ?", redEnvelope.ID).
|
||||
Updates(map[string]interface{}{
|
||||
"remaining_count": newRemainingCount,
|
||||
"remaining_amount": newRemainingAmount,
|
||||
"status": newStatus,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新红包对象用于返回
|
||||
redEnvelope.RemainingCount = newRemainingCount
|
||||
redEnvelope.RemainingAmount = newRemainingAmount
|
||||
redEnvelope.Status = newStatus
|
||||
|
||||
// 增加领取者余额并更新total_receive
|
||||
if err := service.UpdateBalance(tx, service.BalanceUpdateOptions{
|
||||
UserID: currentUser.ID,
|
||||
Amount: claimedAmount,
|
||||
Operation: service.BalanceAdd,
|
||||
TotalField: "total_receive",
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建订单记录(红包收入)
|
||||
order := model.Order{
|
||||
OrderName: "红包收入",
|
||||
PayerUserID: redEnvelope.CreatorID,
|
||||
PayeeUserID: currentUser.ID,
|
||||
Amount: claimedAmount,
|
||||
Status: model.OrderStatusSuccess,
|
||||
Type: model.OrderTypeRedEnvelopeReceive,
|
||||
Remark: fmt.Sprintf("祝福语: %s", redEnvelope.Greeting),
|
||||
TradeTime: time.Now(),
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
return tx.Create(&order).Error
|
||||
}); err != nil {
|
||||
errMsg := err.Error()
|
||||
switch errMsg {
|
||||
case RedEnvelopeNotFound:
|
||||
c.JSON(http.StatusNotFound, util.Err(errMsg))
|
||||
case RedEnvelopeExpired, RedEnvelopeFinished, RedEnvelopeAlreadyClaimed, CannotClaimOwnRedEnvelope:
|
||||
c.JSON(http.StatusBadRequest, util.Err(errMsg))
|
||||
default:
|
||||
c.JSON(http.StatusInternalServerError, util.Err(errMsg))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var redEnvelopeView model.RedEnvelope
|
||||
if err := db.DB(c.Request.Context()).
|
||||
Model(&model.RedEnvelope{}).
|
||||
Select("red_envelopes.*, users.username as creator_username, users.avatar_url as creator_avatar_url").
|
||||
Joins("LEFT JOIN users ON red_envelopes.creator_id = users.id").
|
||||
Where("red_envelopes.id = ?", redEnvelope.ID).First(&redEnvelopeView).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(ClaimResponse{
|
||||
Amount: claimedAmount,
|
||||
RedEnvelope: redEnvelopeView,
|
||||
}))
|
||||
}
|
||||
|
||||
// GetDetail 获取红包详情
|
||||
// @Tags redenvelope
|
||||
// @Produce json
|
||||
// @Param id path string true "红包ID"
|
||||
// @Success 200 {object} util.ResponseAny
|
||||
// @Router /api/v1/redenvelope/{id} [get]
|
||||
func GetDetail(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
redEnvelopeID, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(InvalidRedEnvelopeID))
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
|
||||
var redEnvelope model.RedEnvelope
|
||||
if err := db.DB(c.Request.Context()).
|
||||
Model(&model.RedEnvelope{}).
|
||||
Select("red_envelopes.*, users.username as creator_username, users.avatar_url as creator_avatar_url").
|
||||
Joins("LEFT JOIN users ON red_envelopes.creator_id = users.id").
|
||||
Where("red_envelopes.id = ?", redEnvelopeID).First(&redEnvelope).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
c.JSON(http.StatusNotFound, util.Err(RedEnvelopeNotFound))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
var claims []model.RedEnvelopeClaim
|
||||
db.DB(c.Request.Context()).
|
||||
Select("red_envelope_claims.*, users.username, users.avatar_url").
|
||||
Joins("LEFT JOIN users ON red_envelope_claims.user_id = users.id").
|
||||
Where("red_envelope_claims.red_envelope_id = ?", redEnvelope.ID).
|
||||
Order("red_envelope_claims.claimed_at DESC").
|
||||
Find(&claims)
|
||||
|
||||
var userClaimed *model.RedEnvelopeClaim
|
||||
if currentUser != nil {
|
||||
for i := range claims {
|
||||
if claims[i].UserID == currentUser.ID {
|
||||
userClaimed = &claims[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(DetailResponse{
|
||||
RedEnvelope: redEnvelope,
|
||||
Claims: claims,
|
||||
UserClaimed: userClaimed,
|
||||
}))
|
||||
}
|
||||
|
||||
// List 获取红包列表
|
||||
// @Tags redenvelope
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body ListRequest true "列表请求"
|
||||
// @Success 200 {object} util.ResponseAny
|
||||
// @Router /api/v1/redenvelope/list [post]
|
||||
func List(c *gin.Context) {
|
||||
var req ListRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
|
||||
query := db.DB(c.Request.Context()).Model(&model.RedEnvelope{}).
|
||||
Select("red_envelopes.*, users.username as creator_username, users.avatar_url as creator_avatar_url").
|
||||
Joins("LEFT JOIN users ON red_envelopes.creator_id = users.id")
|
||||
switch req.Type {
|
||||
case "sent":
|
||||
query = query.Where("red_envelopes.creator_id = ?", currentUser.ID)
|
||||
case "received":
|
||||
query = query.Joins("INNER JOIN red_envelope_claims ON red_envelopes.id = red_envelope_claims.red_envelope_id").
|
||||
Where("red_envelope_claims.user_id = ?", currentUser.ID)
|
||||
default:
|
||||
query = query.Where("red_envelopes.creator_id = ?", currentUser.ID)
|
||||
}
|
||||
|
||||
var total int64
|
||||
query.Count(&total)
|
||||
|
||||
var redEnvelopes []model.RedEnvelope
|
||||
query.Order("red_envelopes.created_at DESC").
|
||||
Offset((req.Page - 1) * req.PageSize).
|
||||
Limit(req.PageSize).
|
||||
Find(&redEnvelopes)
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(ListResponse{
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
RedEnvelopes: redEnvelopes,
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user