feat(admin): add watermark table list APIs (#44)
This commit is contained in:
@@ -0,0 +1,211 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
adminservice "wx_service/internal/admin/service"
|
||||||
|
"wx_service/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) ListVideoParseLogs(c *gin.Context) {
|
||||||
|
page, err := parsePage(c.DefaultQuery("page", "1"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pageSize, err := parsePageSize(c.DefaultQuery("page_size", "20"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page_size"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
miniProgramID, err := parseOptionalUint(c.Query("mini_program_id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid mini_program_id"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userID, err := parseOptionalUint(c.Query("user_id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid user_id"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
freeQuotaUsed, err := parseOptionalBool(c.Query("free_quota_used"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid free_quota_used"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateFrom, err := parseOptionalDateBoundary(c.Query("date_from"), false)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_from, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateTo, err := parseOptionalDateBoundary(c.Query("date_to"), true)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_to, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := h.svc.ListVideoParseLogs(c.Request.Context(), adminservice.ListVideoParseLogsQuery{
|
||||||
|
Page: page,
|
||||||
|
PageSize: pageSize,
|
||||||
|
MiniProgramID: miniProgramID,
|
||||||
|
UserID: userID,
|
||||||
|
FreeQuotaUsed: freeQuotaUsed,
|
||||||
|
Keyword: c.Query("keyword"),
|
||||||
|
DateFrom: dateFrom,
|
||||||
|
DateTo: dateTo,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "load video parse logs failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, model.Success(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) ListVideoParseUnlocks(c *gin.Context) {
|
||||||
|
page, err := parsePage(c.DefaultQuery("page", "1"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pageSize, err := parsePageSize(c.DefaultQuery("page_size", "20"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page_size"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
miniProgramID, err := parseOptionalUint(c.Query("mini_program_id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid mini_program_id"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userID, err := parseOptionalUint(c.Query("user_id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid user_id"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateFrom, err := parseOptionalDateBoundary(c.Query("date_from"), false)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_from, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateTo, err := parseOptionalDateBoundary(c.Query("date_to"), true)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_to, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := h.svc.ListVideoParseUnlocks(c.Request.Context(), adminservice.ListVideoParseUnlocksQuery{
|
||||||
|
Page: page,
|
||||||
|
PageSize: pageSize,
|
||||||
|
MiniProgramID: miniProgramID,
|
||||||
|
UserID: userID,
|
||||||
|
DateFrom: dateFrom,
|
||||||
|
DateTo: dateTo,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "load video parse unlocks failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, model.Success(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) ListVideoDownloadFailures(c *gin.Context) {
|
||||||
|
page, err := parsePage(c.DefaultQuery("page", "1"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pageSize, err := parsePageSize(c.DefaultQuery("page_size", "20"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid page_size"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateFrom, err := parseOptionalDateBoundary(c.Query("date_from"), false)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_from, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dateTo, err := parseOptionalDateBoundary(c.Query("date_to"), true)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "invalid date_to, expected YYYY-MM-DD"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := h.svc.ListVideoDownloadFailures(c.Request.Context(), adminservice.ListVideoDownloadFailuresQuery{
|
||||||
|
Page: page,
|
||||||
|
PageSize: pageSize,
|
||||||
|
Domain: c.Query("domain"),
|
||||||
|
Keyword: c.Query("keyword"),
|
||||||
|
DateFrom: dateFrom,
|
||||||
|
DateTo: dateTo,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "load video download failures failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, model.Success(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePage(raw string) (int, error) {
|
||||||
|
value, err := strconv.Atoi(strings.TrimSpace(raw))
|
||||||
|
if err != nil || value < 1 {
|
||||||
|
return 0, fmt.Errorf("invalid page")
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePageSize(raw string) (int, error) {
|
||||||
|
value, err := strconv.Atoi(strings.TrimSpace(raw))
|
||||||
|
if err != nil || value < 1 {
|
||||||
|
return 0, fmt.Errorf("invalid page_size")
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOptionalUint(raw string) (uint, error) {
|
||||||
|
text := strings.TrimSpace(raw)
|
||||||
|
if text == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
value, err := strconv.ParseUint(text, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOptionalBool(raw string) (*bool, error) {
|
||||||
|
text := strings.TrimSpace(strings.ToLower(raw))
|
||||||
|
if text == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if text == "1" || text == "true" {
|
||||||
|
v := true
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
|
if text == "0" || text == "false" {
|
||||||
|
v := false
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("invalid bool")
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOptionalDateBoundary(raw string, endOfDay bool) (*time.Time, error) {
|
||||||
|
text := strings.TrimSpace(raw)
|
||||||
|
if text == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
parsed, err := time.ParseInLocation("2006-01-02", text, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if endOfDay {
|
||||||
|
parsed = parsed.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||||||
|
}
|
||||||
|
return &parsed, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"wx_service/internal/model"
|
||||||
|
rmmodel "wx_service/internal/remove_watermark/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListVideoParseLogsQuery struct {
|
||||||
|
Page int
|
||||||
|
PageSize int
|
||||||
|
MiniProgramID uint
|
||||||
|
UserID uint
|
||||||
|
FreeQuotaUsed *bool
|
||||||
|
Keyword string
|
||||||
|
DateFrom *time.Time
|
||||||
|
DateTo *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoParseLogItem struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
MiniProgramID uint `json:"mini_program_id"`
|
||||||
|
MiniProgramName string `json:"mini_program_name"`
|
||||||
|
UserID uint `json:"user_id"`
|
||||||
|
RequestContent string `json:"request_content"`
|
||||||
|
ParsedURL string `json:"parsed_url"`
|
||||||
|
ThirdPartyStatus int `json:"third_party_status"`
|
||||||
|
FreeQuotaUsed bool `json:"free_quota_used"`
|
||||||
|
DurationMs int `json:"duration_ms"`
|
||||||
|
ErrorMessage string `json:"error_message"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
ThirdPartyPayload string `json:"third_party_payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVideoParseLogsResult struct {
|
||||||
|
List []VideoParseLogItem `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVideoParseUnlocksQuery struct {
|
||||||
|
Page int
|
||||||
|
PageSize int
|
||||||
|
MiniProgramID uint
|
||||||
|
UserID uint
|
||||||
|
DateFrom *time.Time
|
||||||
|
DateTo *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoParseUnlockItem struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
MiniProgramID uint `json:"mini_program_id"`
|
||||||
|
MiniProgramName string `json:"mini_program_name"`
|
||||||
|
UserID uint `json:"user_id"`
|
||||||
|
UnlockDate time.Time `json:"unlock_date"`
|
||||||
|
AdWatchedAt time.Time `json:"ad_watched_at"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVideoParseUnlocksResult struct {
|
||||||
|
List []VideoParseUnlockItem `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVideoDownloadFailuresQuery struct {
|
||||||
|
Page int
|
||||||
|
PageSize int
|
||||||
|
Domain string
|
||||||
|
Keyword string
|
||||||
|
DateFrom *time.Time
|
||||||
|
DateTo *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoDownloadFailureItem struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
FailedURL string `json:"failed_url"`
|
||||||
|
ErrorMessage string `json:"error_message"`
|
||||||
|
ReportedAt time.Time `json:"reported_at"`
|
||||||
|
UserAgent string `json:"user_agent"`
|
||||||
|
ClientIP string `json:"client_ip"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVideoDownloadFailuresResult struct {
|
||||||
|
List []VideoDownloadFailureItem `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListVideoParseLogs(ctx context.Context, query ListVideoParseLogsQuery) (*ListVideoParseLogsResult, error) {
|
||||||
|
query.Page, query.PageSize = normalizePage(query.Page, query.PageSize)
|
||||||
|
query.Keyword = strings.TrimSpace(query.Keyword)
|
||||||
|
|
||||||
|
dbQuery := s.db.WithContext(ctx).Model(&rmmodel.VideoParseLog{})
|
||||||
|
if query.MiniProgramID > 0 {
|
||||||
|
dbQuery = dbQuery.Where("mini_program_id = ?", query.MiniProgramID)
|
||||||
|
}
|
||||||
|
if query.UserID > 0 {
|
||||||
|
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||||
|
}
|
||||||
|
if query.FreeQuotaUsed != nil {
|
||||||
|
dbQuery = dbQuery.Where("free_quota_used = ?", *query.FreeQuotaUsed)
|
||||||
|
}
|
||||||
|
if query.Keyword != "" {
|
||||||
|
likeKeyword := "%" + query.Keyword + "%"
|
||||||
|
dbQuery = dbQuery.Where("request_content LIKE ? OR parsed_url LIKE ? OR error_message LIKE ?", likeKeyword, likeKeyword, likeKeyword)
|
||||||
|
}
|
||||||
|
if query.DateFrom != nil {
|
||||||
|
dbQuery = dbQuery.Where("created_at >= ?", *query.DateFrom)
|
||||||
|
}
|
||||||
|
if query.DateTo != nil {
|
||||||
|
dbQuery = dbQuery.Where("created_at <= ?", *query.DateTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
if err := dbQuery.Count(&total).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]rmmodel.VideoParseLog, 0)
|
||||||
|
if total > 0 {
|
||||||
|
if err := dbQuery.Order("id DESC").
|
||||||
|
Limit(query.PageSize).
|
||||||
|
Offset((query.Page - 1) * query.PageSize).
|
||||||
|
Find(&rows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
miniProgramNameMap, err := s.loadMiniProgramNameMap(ctx, extractMiniProgramIDsFromLogs(rows))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
items := make([]VideoParseLogItem, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
items = append(items, VideoParseLogItem{
|
||||||
|
ID: row.ID,
|
||||||
|
MiniProgramID: row.MiniProgramID,
|
||||||
|
MiniProgramName: miniProgramNameMap[row.MiniProgramID],
|
||||||
|
UserID: row.UserID,
|
||||||
|
RequestContent: row.RequestContent,
|
||||||
|
ParsedURL: row.ParsedURL,
|
||||||
|
ThirdPartyStatus: row.ThirdPartyStatus,
|
||||||
|
FreeQuotaUsed: row.FreeQuotaUsed,
|
||||||
|
DurationMs: row.DurationMs,
|
||||||
|
ErrorMessage: row.ErrorMessage,
|
||||||
|
CreatedAt: row.CreatedAt,
|
||||||
|
ThirdPartyPayload: string(row.ThirdPartyPayload),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListVideoParseLogsResult{
|
||||||
|
List: items,
|
||||||
|
Total: total,
|
||||||
|
Page: query.Page,
|
||||||
|
PageSize: query.PageSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListVideoParseUnlocks(ctx context.Context, query ListVideoParseUnlocksQuery) (*ListVideoParseUnlocksResult, error) {
|
||||||
|
query.Page, query.PageSize = normalizePage(query.Page, query.PageSize)
|
||||||
|
|
||||||
|
dbQuery := s.db.WithContext(ctx).Model(&rmmodel.VideoParseUnlock{})
|
||||||
|
if query.MiniProgramID > 0 {
|
||||||
|
dbQuery = dbQuery.Where("mini_program_id = ?", query.MiniProgramID)
|
||||||
|
}
|
||||||
|
if query.UserID > 0 {
|
||||||
|
dbQuery = dbQuery.Where("user_id = ?", query.UserID)
|
||||||
|
}
|
||||||
|
if query.DateFrom != nil {
|
||||||
|
dbQuery = dbQuery.Where("unlock_date >= ?", query.DateFrom.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
if query.DateTo != nil {
|
||||||
|
dbQuery = dbQuery.Where("unlock_date <= ?", query.DateTo.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
if err := dbQuery.Count(&total).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]rmmodel.VideoParseUnlock, 0)
|
||||||
|
if total > 0 {
|
||||||
|
if err := dbQuery.Order("id DESC").
|
||||||
|
Limit(query.PageSize).
|
||||||
|
Offset((query.Page - 1) * query.PageSize).
|
||||||
|
Find(&rows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
miniProgramNameMap, err := s.loadMiniProgramNameMap(ctx, extractMiniProgramIDsFromUnlocks(rows))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
items := make([]VideoParseUnlockItem, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
items = append(items, VideoParseUnlockItem{
|
||||||
|
ID: row.ID,
|
||||||
|
MiniProgramID: row.MiniProgramID,
|
||||||
|
MiniProgramName: miniProgramNameMap[row.MiniProgramID],
|
||||||
|
UserID: row.UserID,
|
||||||
|
UnlockDate: row.UnlockDate,
|
||||||
|
AdWatchedAt: row.AdWatchedAt,
|
||||||
|
CreatedAt: row.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListVideoParseUnlocksResult{
|
||||||
|
List: items,
|
||||||
|
Total: total,
|
||||||
|
Page: query.Page,
|
||||||
|
PageSize: query.PageSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListVideoDownloadFailures(ctx context.Context, query ListVideoDownloadFailuresQuery) (*ListVideoDownloadFailuresResult, error) {
|
||||||
|
query.Page, query.PageSize = normalizePage(query.Page, query.PageSize)
|
||||||
|
query.Domain = strings.TrimSpace(query.Domain)
|
||||||
|
query.Keyword = strings.TrimSpace(query.Keyword)
|
||||||
|
|
||||||
|
dbQuery := s.db.WithContext(ctx).Model(&rmmodel.VideoDownloadFailure{})
|
||||||
|
if query.Domain != "" {
|
||||||
|
dbQuery = dbQuery.Where("domain = ?", query.Domain)
|
||||||
|
}
|
||||||
|
if query.Keyword != "" {
|
||||||
|
likeKeyword := "%" + query.Keyword + "%"
|
||||||
|
dbQuery = dbQuery.Where("failed_url LIKE ? OR error_message LIKE ? OR user_agent LIKE ?", likeKeyword, likeKeyword, likeKeyword)
|
||||||
|
}
|
||||||
|
if query.DateFrom != nil {
|
||||||
|
dbQuery = dbQuery.Where("reported_at >= ?", *query.DateFrom)
|
||||||
|
}
|
||||||
|
if query.DateTo != nil {
|
||||||
|
dbQuery = dbQuery.Where("reported_at <= ?", *query.DateTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
if err := dbQuery.Count(&total).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]rmmodel.VideoDownloadFailure, 0)
|
||||||
|
if total > 0 {
|
||||||
|
if err := dbQuery.Order("id DESC").
|
||||||
|
Limit(query.PageSize).
|
||||||
|
Offset((query.Page - 1) * query.PageSize).
|
||||||
|
Find(&rows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items := make([]VideoDownloadFailureItem, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
items = append(items, VideoDownloadFailureItem{
|
||||||
|
ID: row.ID,
|
||||||
|
Domain: row.Domain,
|
||||||
|
FailedURL: row.FailedURL,
|
||||||
|
ErrorMessage: row.ErrorMessage,
|
||||||
|
ReportedAt: row.ReportedAt,
|
||||||
|
UserAgent: row.UserAgent,
|
||||||
|
ClientIP: row.ClientIP,
|
||||||
|
CreatedAt: row.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListVideoDownloadFailuresResult{
|
||||||
|
List: items,
|
||||||
|
Total: total,
|
||||||
|
Page: query.Page,
|
||||||
|
PageSize: query.PageSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) loadMiniProgramNameMap(ctx context.Context, ids []uint) (map[uint]string, error) {
|
||||||
|
nameMap := map[uint]string{}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nameMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]model.MiniProgram, 0)
|
||||||
|
if err := s.db.WithContext(ctx).
|
||||||
|
Select("id", "name").
|
||||||
|
Where("id IN ?", ids).
|
||||||
|
Find(&rows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
nameMap[row.ID] = row.Name
|
||||||
|
}
|
||||||
|
return nameMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractMiniProgramIDsFromLogs(rows []rmmodel.VideoParseLog) []uint {
|
||||||
|
set := map[uint]struct{}{}
|
||||||
|
ids := make([]uint, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
if row.MiniProgramID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := set[row.MiniProgramID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set[row.MiniProgramID] = struct{}{}
|
||||||
|
ids = append(ids, row.MiniProgramID)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractMiniProgramIDsFromUnlocks(rows []rmmodel.VideoParseUnlock) []uint {
|
||||||
|
set := map[uint]struct{}{}
|
||||||
|
ids := make([]uint, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
if row.MiniProgramID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := set[row.MiniProgramID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set[row.MiniProgramID] = struct{}{}
|
||||||
|
ids = append(ids, row.MiniProgramID)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizePage(page, pageSize int) (int, int) {
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
if pageSize < 1 {
|
||||||
|
pageSize = 20
|
||||||
|
}
|
||||||
|
if pageSize > 100 {
|
||||||
|
pageSize = 100
|
||||||
|
}
|
||||||
|
return page, pageSize
|
||||||
|
}
|
||||||
@@ -48,6 +48,10 @@ func registerAdminRoutes(
|
|||||||
protected.PUT("/settings/system", handler.UpdateSystemConfig)
|
protected.PUT("/settings/system", handler.UpdateSystemConfig)
|
||||||
protected.PUT("/settings/password", handler.UpdatePassword)
|
protected.PUT("/settings/password", handler.UpdatePassword)
|
||||||
|
|
||||||
|
protected.GET("/watermark/video-parse-logs", handler.ListVideoParseLogs)
|
||||||
|
protected.GET("/watermark/video-parse-unlocks", handler.ListVideoParseUnlocks)
|
||||||
|
protected.GET("/watermark/video-download-failures", handler.ListVideoDownloadFailures)
|
||||||
|
|
||||||
protected.GET("/memberships/overview", handler.MembershipOverview)
|
protected.GET("/memberships/overview", handler.MembershipOverview)
|
||||||
protected.GET("/memberships/redeem-codes", handler.ListMembershipRedeemCodes)
|
protected.GET("/memberships/redeem-codes", handler.ListMembershipRedeemCodes)
|
||||||
protected.POST("/memberships/redeem-codes", handler.CreateMembershipRedeemCodes)
|
protected.POST("/memberships/redeem-codes", handler.CreateMembershipRedeemCodes)
|
||||||
|
|||||||
Reference in New Issue
Block a user