267 lines
7.8 KiB
Go
267 lines
7.8 KiB
Go
package transport
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/geo-platform/tenant-api/internal/ops/app"
|
|
"github.com/geo-platform/tenant-api/internal/shared/response"
|
|
)
|
|
|
|
type setMediaSupplyPriceRequest struct {
|
|
PriceType string `json:"price_type"`
|
|
SellPriceCents int64 `json:"sell_price_cents"`
|
|
Enabled *bool `json:"enabled,omitempty"`
|
|
}
|
|
|
|
type setMediaSupplyVisibilityRequest struct {
|
|
CustomerVisible bool `json:"customer_visible"`
|
|
}
|
|
|
|
type adjustMediaSupplyWalletRequest struct {
|
|
TenantID int64 `json:"tenant_id" binding:"required"`
|
|
UserID int64 `json:"user_id" binding:"required"`
|
|
DeltaCents int64 `json:"delta_cents" binding:"required"`
|
|
Note string `json:"note"`
|
|
}
|
|
|
|
func listMediaSupplyResourcesHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
modelID, err := parseOptionalOpsIntQuery(c, "model_id")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_model_id", "媒体资源类型参数必须是数字"))
|
|
return
|
|
}
|
|
minPriceCents, err := parseOptionalOpsInt64Query(c, "min_price_cents")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_min_price_cents", "最低价格参数必须是数字"))
|
|
return
|
|
}
|
|
maxPriceCents, err := parseOptionalOpsInt64Query(c, "max_price_cents")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_max_price_cents", "最高价格参数必须是数字"))
|
|
return
|
|
}
|
|
page, _ := parseOptionalOpsIntQuery(c, "page")
|
|
size, _ := parseOptionalOpsIntQuery(c, "page_size")
|
|
result, err := svc.ListResources(c.Request.Context(), app.ListMediaSupplyResourcesInput{
|
|
ModelID: modelID,
|
|
Keyword: c.Query("keyword"),
|
|
RemarkKeyword: c.Query("remark_keyword"),
|
|
ChannelType: c.Query("channel_type"),
|
|
Region: c.Query("region"),
|
|
InclusionEffect: c.Query("inclusion_effect"),
|
|
LinkType: c.Query("link_type"),
|
|
MinPriceCents: minPriceCents,
|
|
MaxPriceCents: maxPriceCents,
|
|
Visibility: c.Query("visibility"),
|
|
Page: page,
|
|
Size: size,
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, result)
|
|
}
|
|
}
|
|
|
|
func setMediaSupplyResourcePriceHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
id, err := parseIDParam(c)
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
var body setMediaSupplyPriceRequest
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_payload", "价格参数不正确"))
|
|
return
|
|
}
|
|
enabled := true
|
|
if body.Enabled != nil {
|
|
enabled = *body.Enabled
|
|
}
|
|
if err := svc.SetResourcePrice(c.Request.Context(), actorFromGin(c), id, app.SetMediaSupplyPriceInput{
|
|
PriceType: body.PriceType,
|
|
SellPriceCents: body.SellPriceCents,
|
|
Enabled: enabled,
|
|
}); err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"updated": true})
|
|
}
|
|
}
|
|
|
|
func setMediaSupplyResourceVisibilityHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
id, err := parseIDParam(c)
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
var body setMediaSupplyVisibilityRequest
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_payload", "展示状态参数不正确"))
|
|
return
|
|
}
|
|
if err := svc.SetResourceVisibility(c.Request.Context(), actorFromGin(c), id, app.SetMediaSupplyVisibilityInput{
|
|
CustomerVisible: body.CustomerVisible,
|
|
}); err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"updated": true})
|
|
}
|
|
}
|
|
|
|
func queueMediaSupplySyncHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
var body struct {
|
|
ModelID int `json:"model_id"`
|
|
}
|
|
if c.Request.Body != nil {
|
|
_ = c.ShouldBindJSON(&body)
|
|
}
|
|
jobID, err := svc.QueueSync(c.Request.Context(), actorFromGin(c), body.ModelID)
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"job_id": jobID})
|
|
}
|
|
}
|
|
|
|
func listMediaSupplyWalletsHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
tenantID, err := parseOptionalOpsInt64Query(c, "tenant_id")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_tenant_id", "租户参数必须是数字"))
|
|
return
|
|
}
|
|
page, _ := parseOptionalOpsIntQuery(c, "page")
|
|
size, _ := parseOptionalOpsIntQuery(c, "page_size")
|
|
result, err := svc.ListWallets(c.Request.Context(), app.ListMediaSupplyWalletsInput{
|
|
Keyword: c.Query("keyword"),
|
|
TenantID: tenantID,
|
|
Page: page,
|
|
Size: size,
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, result)
|
|
}
|
|
}
|
|
|
|
func listMediaSupplyBillingsHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
tenantID, err := parseOptionalOpsInt64Query(c, "tenant_id")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_tenant_id", "租户参数必须是数字"))
|
|
return
|
|
}
|
|
userID, err := parseOptionalOpsInt64Query(c, "user_id")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_user_id", "用户参数必须是数字"))
|
|
return
|
|
}
|
|
orderID, err := parseOptionalOpsInt64Query(c, "order_id")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_order_id", "订单参数必须是数字"))
|
|
return
|
|
}
|
|
startAt, err := parseOptionalOpsTimeQuery(c, "start_at")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40003, "invalid_start_at", "start_at 必须是 RFC3339"))
|
|
return
|
|
}
|
|
endAt, err := parseOptionalOpsTimeQuery(c, "end_at")
|
|
if err != nil {
|
|
response.Error(c, response.ErrBadRequest(40004, "invalid_end_at", "end_at 必须是 RFC3339"))
|
|
return
|
|
}
|
|
if startAt != nil && endAt != nil && !startAt.Before(*endAt) {
|
|
response.Error(c, response.ErrBadRequest(40005, "invalid_billing_time_range", "结束时间必须晚于开始时间"))
|
|
return
|
|
}
|
|
page, _ := parseOptionalOpsIntQuery(c, "page")
|
|
size, _ := parseOptionalOpsIntQuery(c, "page_size")
|
|
result, err := svc.ListBillings(c.Request.Context(), app.ListMediaSupplyBillingsInput{
|
|
Keyword: c.Query("keyword"),
|
|
TenantID: tenantID,
|
|
UserID: userID,
|
|
OrderID: orderID,
|
|
Reason: c.Query("reason"),
|
|
StartAt: startAt,
|
|
EndAt: endAt,
|
|
Page: page,
|
|
Size: size,
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, result)
|
|
}
|
|
}
|
|
|
|
func adjustMediaSupplyWalletHandler(svc *app.MediaSupplyService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
var body adjustMediaSupplyWalletRequest
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|
response.Error(c, response.ErrBadRequest(40001, "invalid_payload", "余额调整参数不正确"))
|
|
return
|
|
}
|
|
actor := actorFromGin(c)
|
|
operatorTag := "ops manual adjustment"
|
|
if actor != nil && actor.DisplayName != "" {
|
|
operatorTag = "ops " + actor.DisplayName
|
|
}
|
|
result, err := svc.AdjustWallet(c.Request.Context(), actor, app.AdjustMediaSupplyWalletInput{
|
|
TenantID: body.TenantID,
|
|
UserID: body.UserID,
|
|
DeltaCents: body.DeltaCents,
|
|
Note: body.Note,
|
|
OperatorTag: operatorTag,
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, result)
|
|
}
|
|
}
|
|
|
|
func parseOptionalOpsIntQuery(c *gin.Context, key string) (int, error) {
|
|
raw := c.Query(key)
|
|
if raw == "" {
|
|
return 0, nil
|
|
}
|
|
return strconv.Atoi(raw)
|
|
}
|
|
|
|
func parseOptionalOpsInt64Query(c *gin.Context, key string) (int64, error) {
|
|
raw := c.Query(key)
|
|
if raw == "" {
|
|
return 0, nil
|
|
}
|
|
return strconv.ParseInt(raw, 10, 64)
|
|
}
|
|
|
|
func parseOptionalOpsTimeQuery(c *gin.Context, key string) (*time.Time, error) {
|
|
raw := c.Query(key)
|
|
if raw == "" {
|
|
return nil, nil
|
|
}
|
|
parsed, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &parsed, nil
|
|
}
|