mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 18:52:56 +00:00
dev day #89
This commit is contained in:
@@ -20,31 +20,35 @@ type SweepstakesController struct {
|
||||
Email email.EmailService
|
||||
}
|
||||
|
||||
func NewSweepstakesController(db *gorm.DB, es email.EmailService) *SweepstakesController {
|
||||
return &SweepstakesController{DB: db, Email: es}
|
||||
}
|
||||
|
||||
// Public: visualization data for a specific sweepstake (within visibility window)
|
||||
// GET /api/v1/sweepstakes/:id/visual
|
||||
func (sc *SweepstakesController) PublicVisualData(c *gin.Context) {
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
var s models.Sweepstake
|
||||
if err := sc.DB.First(&s, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error":"Not found"}); return }
|
||||
now := time.Now()
|
||||
if s.VisibilityUntil == nil || now.After(*s.VisibilityUntil) || now.Before(s.EndAt) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error":"Not available"}); return
|
||||
}
|
||||
var winners []struct{ UserID uint `json:"user_id"`; PrizeName string `json:"prize_name"` }
|
||||
_ = sc.DB.Table("sweepstake_winners").Select("user_id, prize_name").Where("sweepstake_id = ?", id).Order("id ASC").Scan(&winners).Error
|
||||
type entryRow struct {
|
||||
UserID uint `json:"user_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}
|
||||
var entries []entryRow
|
||||
q := sc.DB.Table("sweepstake_entries AS e").
|
||||
Select("e.user_id, TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))) AS display_name, COALESCE(up.animated_avatar_url, up.avatar_url, '') AS avatar_url").
|
||||
Joins("JOIN users u ON u.id = e.user_id").
|
||||
Joins("LEFT JOIN user_profiles up ON up.user_id = u.id").
|
||||
Where("e.sweepstake_id = ?", id)
|
||||
_ = q.Scan(&entries).Error
|
||||
c.JSON(http.StatusOK, gin.H{ "sweepstake": s, "entries": entries, "winners": winners })
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
var s models.Sweepstake
|
||||
if err := sc.DB.First(&s, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error":"Not found"}); return }
|
||||
now := time.Now()
|
||||
if s.VisibilityUntil == nil || now.After(*s.VisibilityUntil) || now.Before(s.EndAt) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error":"Not available"}); return
|
||||
}
|
||||
var winners []struct{ UserID uint `json:"user_id"`; PrizeName string `json:"prize_name"` }
|
||||
_ = sc.DB.Table("sweepstake_winners").Select("user_id, prize_name").Where("sweepstake_id = ?", id).Order("id ASC").Scan(&winners).Error
|
||||
type entryRow struct {
|
||||
UserID uint `json:"user_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}
|
||||
var entries []entryRow
|
||||
q := sc.DB.Table("sweepstake_entries AS e").
|
||||
Select("e.user_id, TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))) AS display_name, COALESCE(up.animated_avatar_url, up.avatar_url, '') AS avatar_url").
|
||||
Joins("JOIN users u ON u.id = e.user_id").
|
||||
Joins("LEFT JOIN user_profiles up ON up.user_id = u.id").
|
||||
Where("e.sweepstake_id = ?", id)
|
||||
_ = q.Scan(&entries).Error
|
||||
c.JSON(http.StatusOK, gin.H{ "sweepstake": s, "entries": entries, "winners": winners })
|
||||
}
|
||||
|
||||
// Admin: set or change prize for a specific winner
|
||||
@@ -234,169 +238,187 @@ func (sc *SweepstakesController) AdminVisualData(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
func NewSweepstakesController(db *gorm.DB, es email.EmailService) *SweepstakesController {
|
||||
return &SweepstakesController{DB: db, Email: es}
|
||||
}
|
||||
|
||||
// Public: get current visible sweepstake (upcoming/active/finalized within visibility window)
|
||||
func (sc *SweepstakesController) GetCurrent(c *gin.Context) {
|
||||
now := time.Now()
|
||||
var s models.Sweepstake
|
||||
q := sc.DB.Where("start_at <= ? AND (visibility_until IS NULL OR visibility_until >= ?)", now, now).
|
||||
Order("start_at DESC")
|
||||
if err := q.First(&s).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
c.JSON(http.StatusOK, gin.H{"sweepstake": nil})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load sweepstake"})
|
||||
return
|
||||
}
|
||||
// Compute state
|
||||
state := "upcoming"
|
||||
if now.After(s.StartAt) && now.Before(s.EndAt) {
|
||||
state = "active"
|
||||
} else if now.After(s.EndAt) {
|
||||
state = "finalized"
|
||||
}
|
||||
// Load prizes (public info)
|
||||
var prizes []models.SweepstakePrize
|
||||
_ = sc.DB.Where("sweepstake_id = ?", s.ID).Order("display_order ASC, id ASC").Find(&prizes).Error
|
||||
// Winners if selected
|
||||
var winners []models.SweepstakeWinner
|
||||
if s.WinnersSelectedAt != nil {
|
||||
_ = sc.DB.Where("sweepstake_id = ?", s.ID).Find(&winners).Error
|
||||
}
|
||||
// Current user status
|
||||
hasEntered := false
|
||||
visualPlayedAt := (*time.Time)(nil)
|
||||
if uid, ok := c.Get("userID"); ok && uid != nil {
|
||||
var e models.SweepstakeEntry
|
||||
if err := sc.DB.Where("sweepstake_id = ? AND user_id = ?", s.ID, uid.(uint)).First(&e).Error; err == nil {
|
||||
hasEntered = true
|
||||
visualPlayedAt = e.VisualPlayedAt
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"sweepstake": s,
|
||||
"prizes": prizes,
|
||||
"winners": winners,
|
||||
"state": state,
|
||||
"has_entered": hasEntered,
|
||||
"visual_played_at": visualPlayedAt,
|
||||
})
|
||||
}
|
||||
|
||||
// Protected: enter/join sweepstake (idempotent)
|
||||
func (sc *SweepstakesController) Enter(c *gin.Context) {
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
// Load sweepstake
|
||||
var s models.Sweepstake
|
||||
if err := sc.DB.First(&s, id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound { c.JSON(http.StatusNotFound, gin.H{"error":"Not found"}); return }
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to load"}); return
|
||||
}
|
||||
now := time.Now()
|
||||
if !(now.After(s.StartAt) && now.Before(s.EndAt)) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error":"Soutěž není aktivní"}); return
|
||||
}
|
||||
// Idempotent create
|
||||
entry := models.SweepstakeEntry{ SweepstakeID: s.ID, UserID: userID, Status: "valid" }
|
||||
if err := sc.DB.Where("sweepstake_id = ? AND user_id = ?", s.ID, userID).FirstOrCreate(&entry).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to join"}); return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Protected: mark visualization as played (only once)
|
||||
func (sc *SweepstakesController) MarkVisualPlayed(c *gin.Context) {
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
var s models.Sweepstake
|
||||
if err := sc.DB.First(&s, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error":"Not found"}); return }
|
||||
now := time.Now()
|
||||
if !(now.After(s.EndAt) && (s.VisibilityUntil == nil || now.Before(*s.VisibilityUntil))) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error":"Vizualizace není dostupná"}); return
|
||||
}
|
||||
_ = sc.DB.Model(&models.SweepstakeEntry{}).
|
||||
Where("sweepstake_id = ? AND user_id = ? AND visual_played_at IS NULL", s.ID, userID).
|
||||
Updates(map[string]interface{}{"visual_played_at": time.Now(), "view_count": gorm.Expr("view_count + 1")}).Error
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Protected: my wins list
|
||||
func (sc *SweepstakesController) MyWinnings(c *gin.Context) {
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
var wins []models.SweepstakeWinner
|
||||
if err := sc.DB.Where("user_id = ?", userID).Order("created_at DESC").Find(&wins).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to load"}); return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"items": wins})
|
||||
}
|
||||
|
||||
// Admin: list sweepstakes
|
||||
// Admin: list sweepstakes with optional status filter
|
||||
func (sc *SweepstakesController) AdminList(c *gin.Context) {
|
||||
var items []models.Sweepstake
|
||||
q := sc.DB.Model(&models.Sweepstake{})
|
||||
if v := strings.TrimSpace(c.Query("status")); v != "" { q = q.Where("status = ?", v) }
|
||||
if err := q.Order("created_at DESC").Find(&items).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"items": items})
|
||||
status := strings.TrimSpace(c.Query("status"))
|
||||
var items []models.Sweepstake
|
||||
q := sc.DB.Model(&models.Sweepstake{}).Order("start_at DESC, id DESC")
|
||||
if status != "" { q = q.Where("status = ?", status) }
|
||||
if err := q.Find(&items).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"items": items})
|
||||
}
|
||||
|
||||
// Admin: create sweepstake
|
||||
func (sc *SweepstakesController) AdminCreate(c *gin.Context) {
|
||||
var body struct{
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
ImageURL string `json:"image_url"`
|
||||
RulesURL string `json:"rules_url"`
|
||||
StartAt time.Time `json:"start_at"`
|
||||
EndAt time.Time `json:"end_at"`
|
||||
PickerStyle string `json:"picker_style"`
|
||||
TotalPrizes int `json:"total_prizes"`
|
||||
PrizeSummary string `json:"prize_summary"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil || strings.TrimSpace(body.Title) == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error":"Invalid payload"}); return
|
||||
}
|
||||
item := models.Sweepstake{
|
||||
Title: strings.TrimSpace(body.Title),
|
||||
Description: strings.TrimSpace(body.Description),
|
||||
ImageURL: strings.TrimSpace(body.ImageURL),
|
||||
RulesURL: strings.TrimSpace(body.RulesURL),
|
||||
StartAt: body.StartAt, EndAt: body.EndAt,
|
||||
PickerStyle: ifEmpty(body.PickerStyle, "wheel"),
|
||||
TotalPrizes: ifZero(body.TotalPrizes, 1),
|
||||
PrizeSummary: strings.TrimSpace(body.PrizeSummary),
|
||||
Status: "scheduled",
|
||||
}
|
||||
if time.Now().After(item.StartAt) { item.Status = "active" }
|
||||
if err := sc.DB.Create(&item).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to create"}); return }
|
||||
c.JSON(http.StatusOK, item)
|
||||
var body struct{
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
ImageURL string `json:"image_url"`
|
||||
RulesURL string `json:"rules_url"`
|
||||
StartAt time.Time `json:"start_at"`
|
||||
EndAt time.Time `json:"end_at"`
|
||||
PickerStyle string `json:"picker_style"`
|
||||
TotalPrizes int `json:"total_prizes"`
|
||||
PrizeSummary string `json:"prize_summary"`
|
||||
EntryCostPoints int `json:"entry_cost_points"`
|
||||
EntryFeeCZK float64 `json:"entry_fee_czk"`
|
||||
MaxEntriesPerUser int `json:"max_entries_per_user"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil || strings.TrimSpace(body.Title) == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error":"Invalid payload"}); return
|
||||
}
|
||||
item := models.Sweepstake{
|
||||
Title: strings.TrimSpace(body.Title),
|
||||
Description: strings.TrimSpace(body.Description),
|
||||
ImageURL: strings.TrimSpace(body.ImageURL),
|
||||
RulesURL: strings.TrimSpace(body.RulesURL),
|
||||
StartAt: body.StartAt, EndAt: body.EndAt,
|
||||
PickerStyle: ifEmpty(body.PickerStyle, "wheel"),
|
||||
TotalPrizes: func(v int) int { if v < 1 { return 1 }; if v > 100 { return 100 }; return v }(ifZero(body.TotalPrizes, 1)),
|
||||
PrizeSummary: strings.TrimSpace(body.PrizeSummary),
|
||||
EntryCostPoints: func(v int) int { if v < 0 { return 0 }; return v }(body.EntryCostPoints),
|
||||
EntryFeeCZK: func(v float64) float64 { if v < 0 { return 0 }; return v }(body.EntryFeeCZK),
|
||||
MaxEntriesPerUser: func(v int) int { if v <= 0 { return 1 }; return v }(body.MaxEntriesPerUser),
|
||||
Status: "scheduled",
|
||||
}
|
||||
if time.Now().After(item.StartAt) { item.Status = "active" }
|
||||
if err := sc.DB.Create(&item).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to create"}); return }
|
||||
c.JSON(http.StatusOK, item)
|
||||
}
|
||||
|
||||
// Admin: update sweepstake
|
||||
func (sc *SweepstakesController) AdminUpdate(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var body map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error":"Invalid payload"}); return }
|
||||
allowed := map[string]bool{"title":true,"description":true,"image_url":true,"rules_url":true,"start_at":true,"end_at":true,"picker_style":true,"total_prizes":true,"prize_summary":true,"status":true}
|
||||
upd := map[string]interface{}{}
|
||||
for k,v := range body { if allowed[k] { upd[k] = v } }
|
||||
if len(upd)==0 { c.JSON(http.StatusBadRequest, gin.H{"error":"No changes"}); return }
|
||||
if err := sc.DB.Model(&models.Sweepstake{}).Where("id = ?", id).Updates(upd).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
id := c.Param("id")
|
||||
var body map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error":"Invalid payload"}); return }
|
||||
allowed := map[string]bool{"title":true,"description":true,"image_url":true,"rules_url":true,"start_at":true,"end_at":true,"picker_style":true,"total_prizes":true,"prize_summary":true,"status":true,"entry_cost_points":true,"entry_fee_czk":true,"max_entries_per_user":true}
|
||||
upd := map[string]interface{}{}
|
||||
for k,v := range body { if allowed[k] { upd[k] = v } }
|
||||
if len(upd)==0 { c.JSON(http.StatusBadRequest, gin.H{"error":"No changes"}); return }
|
||||
// Clamp total_prizes if provided
|
||||
if v, ok := upd["total_prizes"]; ok {
|
||||
// Coerce to integer first
|
||||
vv := 1
|
||||
switch t := v.(type) {
|
||||
case int:
|
||||
vv = t
|
||||
case int64:
|
||||
vv = int(t)
|
||||
case float64:
|
||||
vv = int(t)
|
||||
case string:
|
||||
if n, err := strconv.Atoi(strings.TrimSpace(t)); err == nil { vv = n }
|
||||
default:
|
||||
// leave default 1
|
||||
}
|
||||
if vv < 1 { vv = 1 }
|
||||
if vv > 100 { vv = 100 }
|
||||
upd["total_prizes"] = vv
|
||||
}
|
||||
if err := sc.DB.Model(&models.Sweepstake{}).Where("id = ?", id).Updates(upd).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Admin: delete sweepstake
|
||||
func (sc *SweepstakesController) AdminDelete(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if err := sc.DB.Delete(&models.Sweepstake{}, "id = ?", id).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
id := c.Param("id")
|
||||
if err := sc.DB.Delete(&models.Sweepstake{}, "id = ?", id).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Protected: enter sweepstake (deduct points if needed, enforce max entries)
|
||||
func (sc *SweepstakesController) Enter(c *gin.Context) {
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
var s models.Sweepstake
|
||||
if err := sc.DB.First(&s, id).Error; err != nil { if err == gorm.ErrRecordNotFound { c.JSON(http.StatusNotFound, gin.H{"error":"Not found"}); return }; c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to load"}); return }
|
||||
now := time.Now()
|
||||
if !(now.After(s.StartAt) && now.Before(s.EndAt)) { c.JSON(http.StatusBadRequest, gin.H{"error":"Soutěž není aktivní"}); return }
|
||||
maxPerUser := s.MaxEntriesPerUser
|
||||
if maxPerUser <= 0 { maxPerUser = 1 }
|
||||
var existingCount int64
|
||||
if err := sc.DB.Model(&models.SweepstakeEntry{}).Where("sweepstake_id = ? AND user_id = ? AND status = ?", s.ID, userID, "valid").Count(&existingCount).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to check entries"}); return }
|
||||
if existingCount >= int64(maxPerUser) { c.JSON(http.StatusBadRequest, gin.H{"error":"Dosáhli jste limitu účastí v této soutěži"}); return }
|
||||
costPoints := s.EntryCostPoints
|
||||
if costPoints < 0 { costPoints = 0 }
|
||||
if costPoints > 0 {
|
||||
svc := services.NewEngagementService(sc.DB)
|
||||
up, err := svc.EnsureProfile(userID)
|
||||
if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Nelze načíst profil"}); return }
|
||||
if up.Points < int64(costPoints) { c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Nemáte dostatek bodů (potřeba: %d)", costPoints)}); return }
|
||||
if _, err := svc.AwardPointsAndXP(userID, -int64(costPoints), 0, "sweepstake_entry", map[string]interface{}{"sweepstake_id": s.ID}); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Nelze odečíst body"}); return }
|
||||
e := models.SweepstakeEntry{ SweepstakeID: s.ID, UserID: userID, Status: "valid" }
|
||||
if err := sc.DB.Create(&e).Error; err != nil { _, _ = svc.AwardPointsAndXP(userID, int64(costPoints), 0, "sweepstake_entry_refund", map[string]interface{}{"sweepstake_id": s.ID}); c.JSON(http.StatusInternalServerError, gin.H{"error":"Nelze vytvořit účast"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
return
|
||||
}
|
||||
entry := models.SweepstakeEntry{ SweepstakeID: s.ID, UserID: userID, Status: "valid" }
|
||||
if existingCount == 0 {
|
||||
if err := sc.DB.Where("sweepstake_id = ? AND user_id = ?", s.ID, userID).FirstOrCreate(&entry).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to join"}); return }
|
||||
} else {
|
||||
if err := sc.DB.Create(&entry).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed to join"}); return }
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Protected: mark visual played time for current user's entry
|
||||
func (sc *SweepstakesController) MarkVisualPlayed(c *gin.Context) {
|
||||
id := strings.TrimSpace(c.Param("id"))
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
now := time.Now()
|
||||
var e models.SweepstakeEntry
|
||||
if err := sc.DB.Where("sweepstake_id = ? AND user_id = ?", id, userID).Order("id ASC").First(&e).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error":"Entry not found"}); return }
|
||||
_ = sc.DB.Model(&models.SweepstakeEntry{}).Where("id = ?", e.ID).Update("visual_played_at", &now).Error
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Protected: list my winnings
|
||||
func (sc *SweepstakesController) MyWinnings(c *gin.Context) {
|
||||
uid, _ := c.Get("userID")
|
||||
userID := uid.(uint)
|
||||
var items []models.SweepstakeWinner
|
||||
if err := sc.DB.Where("user_id = ?", userID).Order("created_at DESC").Find(&items).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error":"Failed"}); return }
|
||||
c.JSON(http.StatusOK, gin.H{"items": items})
|
||||
}
|
||||
|
||||
// Public: get current visible sweepstake (upcoming/active/finalized within visibility window)
|
||||
func (sc *SweepstakesController) GetCurrent(c *gin.Context) {
|
||||
now := time.Now()
|
||||
var s models.Sweepstake
|
||||
q := sc.DB.Where("start_at <= ? AND (visibility_until IS NULL OR visibility_until >= ?)", now, now).Order("start_at DESC")
|
||||
if err := q.First(&s).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
c.JSON(http.StatusOK, gin.H{"sweepstake": nil})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load sweepstake"})
|
||||
return
|
||||
}
|
||||
state := "upcoming"
|
||||
if now.After(s.StartAt) && now.Before(s.EndAt) { state = "active" } else if now.After(s.EndAt) { state = "finalized" }
|
||||
var prizes []models.SweepstakePrize
|
||||
_ = sc.DB.Where("sweepstake_id = ?", s.ID).Order("display_order ASC, id ASC").Find(&prizes).Error
|
||||
var winners []models.SweepstakeWinner
|
||||
if s.WinnersSelectedAt != nil { _ = sc.DB.Where("sweepstake_id = ?", s.ID).Find(&winners).Error }
|
||||
hasEntered := false
|
||||
visualPlayedAt := (*time.Time)(nil)
|
||||
if uid, ok := c.Get("userID"); ok && uid != nil {
|
||||
var e models.SweepstakeEntry
|
||||
if err := sc.DB.Where("sweepstake_id = ? AND user_id = ?", s.ID, uid.(uint)).First(&e).Error; err == nil {
|
||||
hasEntered = true
|
||||
visualPlayedAt = e.VisualPlayedAt
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"sweepstake": s,
|
||||
"prizes": prizes,
|
||||
"winners": winners,
|
||||
"state": state,
|
||||
"has_entered": hasEntered,
|
||||
"visual_played_at": visualPlayedAt,
|
||||
})
|
||||
}
|
||||
|
||||
// Admin: list entries
|
||||
|
||||
Reference in New Issue
Block a user