package handler import ( "encoding/json" "net/http" "sort" "strconv" "strings" "time" "xboard-go/internal/database" "xboard-go/internal/model" "github.com/gin-gonic/gin" ) func Success(c *gin.Context, data any) { c.JSON(http.StatusOK, gin.H{"data": data}) } func SuccessMessage(c *gin.Context, message string, data any) { c.JSON(http.StatusOK, gin.H{ "message": message, "data": data, }) } func Fail(c *gin.Context, status int, message string) { c.JSON(status, gin.H{"message": message}) } func NotImplemented(endpoint string) gin.HandlerFunc { return func(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{ "message": "not implemented yet", "endpoint": endpoint, }) } } func intFromAny(value any) int { switch typed := value.(type) { case int: return typed case int8: return int(typed) case int16: return int(typed) case int32: return int(typed) case int64: return int(typed) case float32: return int(typed) case float64: return int(typed) case json.Number: parsed, _ := typed.Int64() return int(parsed) case string: parsed, _ := strconv.Atoi(strings.TrimSpace(typed)) return parsed default: return 0 } } func stringFromAny(value any) string { switch typed := value.(type) { case string: return typed case json.Number: return typed.String() case float64: return strconv.FormatFloat(typed, 'f', -1, 64) case float32: return strconv.FormatFloat(float64(typed), 'f', -1, 32) case int: return strconv.Itoa(typed) case int64: return strconv.FormatInt(typed, 10) case bool: if typed { return "true" } return "false" default: return "" } } func boolFromAny(value any) bool { switch typed := value.(type) { case bool: return typed case int: return typed != 0 case int64: return typed != 0 case float64: return typed != 0 case string: text := strings.TrimSpace(strings.ToLower(typed)) return text == "1" || text == "true" || text == "yes" || text == "on" default: return false } } func intValue(value *int) any { if value == nil { return nil } return *value } func int64Value(value *int64) any { if value == nil { return nil } return *value } func stringValue(value *string) string { if value == nil { return "" } return *value } func unixTimeValue(value *time.Time) any { if value == nil { return nil } return value.Unix() } func marshalJSON(value any, fallbackEmptyArray bool) (*string, error) { if value == nil { if fallbackEmptyArray { empty := "[]" return &empty, nil } return nil, nil } if text, ok := value.(string); ok { text = strings.TrimSpace(text) if text == "" { if fallbackEmptyArray { empty := "[]" return &empty, nil } return nil, nil } if json.Valid([]byte(text)) { return &text, nil } } payload, err := json.Marshal(value) if err != nil { return nil, err } text := string(payload) return &text, nil } func sanitizePositiveIDs(ids []int) []int { unique := make(map[int]struct{}, len(ids)) result := make([]int, 0, len(ids)) for _, id := range ids { if id <= 0 { continue } if _, exists := unique[id]; exists { continue } unique[id] = struct{}{} result = append(result, id) } sort.Ints(result) return result } func loadServerGroupNameMap() map[int]string { var groups []model.ServerGroup _ = database.DB.Find(&groups).Error result := make(map[int]string, len(groups)) for _, group := range groups { result[group.ID] = group.Name } return result } func loadUserEmailMap(userIDs []int) map[int]string { result := make(map[int]string) if len(userIDs) == 0 { return result } var users []model.User if err := database.DB.Select("id", "email").Where("id IN ?", sanitizePositiveIDs(userIDs)).Find(&users).Error; err != nil { return result } for _, user := range users { result[user.ID] = user.Email } return result } func loadTicketMessageCountMap(ticketIDs []int) map[int]int64 { result := make(map[int]int64) if len(ticketIDs) == 0 { return result } type ticketCount struct { TicketID int Total int64 } var counts []ticketCount if err := database.DB.Model(&model.TicketMessage{}). Select("ticket_id, COUNT(*) AS total"). Where("ticket_id IN ?", sanitizePositiveIDs(ticketIDs)). Group("ticket_id"). Scan(&counts).Error; err != nil { return result } for _, item := range counts { result[item.TicketID] = item.Total } return result } func parsePositiveInt(raw string, defaultValue int) int { value, err := strconv.Atoi(strings.TrimSpace(raw)) if err != nil || value <= 0 { return defaultValue } return value } func calculateLastPage(total int64, perPage int) int { if perPage <= 0 { return 1 } last := int((total + int64(perPage) - 1) / int64(perPage)) if last == 0 { return 1 } return last } func formatUnixValue(value int64) string { if value <= 0 { return "-" } return time.Unix(value, 0).Format("2006-01-02 15:04:05") } func formatTimeValue(value *time.Time) string { if value == nil { return "-" } return value.Format("2006-01-02 15:04:05") }