This commit is contained in:
Tomas Dvorak
2025-11-02 01:04:02 +01:00
parent ac886502e0
commit b9cea0cd77
153 changed files with 43713 additions and 1700 deletions
+92 -8
View File
@@ -9,6 +9,7 @@ import (
"time"
"fotbal-club/internal/models"
"fotbal-club/internal/services"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
@@ -421,11 +422,30 @@ func (pc *PollController) Vote(c *gin.Context) {
return
}
// If not authenticated, don't persist personal info even if provided
if !hasUser {
input.VoterName = ""
input.VoterEmail = ""
}
// Normalize voter info. Allow guests to optionally provide name/email.
// If authenticated and no voter_name/email provided, fallback to user's profile.
var derivedName string
var derivedEmail string
if hasUser {
if uID, ok := userID.(uint); ok {
var u models.User
if err := pc.DB.First(&u, uID).Error; err == nil {
if u.FirstName != "" || u.LastName != "" {
derivedName = fmt.Sprintf("%s %s", u.FirstName, u.LastName)
}
derivedEmail = u.Email
}
}
}
// Final values to persist
voterName := input.VoterName
voterEmail := input.VoterEmail
if voterName == "" && derivedName != "" {
voterName = derivedName
}
if voterEmail == "" && derivedEmail != "" {
voterEmail = derivedEmail
}
// Check if already voted
ipHash := pc.hashIP(c.ClientIP())
@@ -477,8 +497,8 @@ func (pc *PollController) Vote(c *gin.Context) {
IPHash: ipHash,
UserAgent: userAgent,
SessionToken: sessionToken,
VoterName: input.VoterName,
VoterEmail: input.VoterEmail,
VoterName: voterName,
VoterEmail: voterEmail,
}
if hasUser {
@@ -513,7 +533,15 @@ func (pc *PollController) Vote(c *gin.Context) {
pc.DB.Preload("Options", func(db *gorm.DB) *gorm.DB {
return db.Order("display_order ASC, id ASC")
}).First(&poll, poll.ID)
// Engagement: award points to authenticated user
if hasUser {
uid := userID.(uint)
svc := services.NewEngagementService(pc.DB)
_, _ = svc.AwardPointsCapped(uid, 3, "poll_vote", map[string]interface{}{"poll_id": poll.ID})
_ = svc.CheckAndAwardAchievements(uid)
}
c.JSON(http.StatusOK, gin.H{
"message": "Vote recorded successfully",
"poll": poll,
@@ -637,3 +665,59 @@ func (pc *PollController) GetPollStats(c *gin.Context) {
"guest_votes": guestVotes,
})
}
// AdminListVotes returns detailed list of votes for a poll (admin only)
func (pc *PollController) AdminListVotes(c *gin.Context) {
id := c.Param("id")
var votes []models.PollVote
if err := pc.DB.Preload("Option").Preload("User").Where("poll_id = ?", id).Order("created_at DESC").Find(&votes).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch votes"})
return
}
type VoteDTO struct {
ID uint `json:"id"`
PollID uint `json:"poll_id"`
OptionID uint `json:"option_id"`
OptionText string `json:"option_text"`
UserID *uint `json:"user_id"`
UserEmail string `json:"user_email"`
UserFirstName string `json:"user_first_name"`
UserLastName string `json:"user_last_name"`
VoterName string `json:"voter_name"`
VoterEmail string `json:"voter_email"`
SessionToken string `json:"session_token"`
CreatedAt time.Time `json:"created_at"`
}
result := make([]VoteDTO, 0, len(votes))
for _, v := range votes {
optionText := ""
if v.Option != nil {
optionText = v.Option.Text
}
var userEmail, firstName, lastName string
if v.User != nil {
userEmail = v.User.Email
firstName = v.User.FirstName
lastName = v.User.LastName
}
result = append(result, VoteDTO{
ID: v.ID,
PollID: v.PollID,
OptionID: v.OptionID,
OptionText: optionText,
UserID: v.UserID,
UserEmail: userEmail,
UserFirstName: firstName,
UserLastName: lastName,
VoterName: v.VoterName,
VoterEmail: v.VoterEmail,
SessionToken: v.SessionToken,
CreatedAt: v.CreatedAt,
})
}
c.JSON(http.StatusOK, gin.H{"votes": result})
}