mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
122 lines
5.2 KiB
Go
122 lines
5.2 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// Poll represents a voting poll
|
|
type Poll struct {
|
|
ID uint `gorm:"primarykey" json:"id"`
|
|
Title string `gorm:"size:255;not null" json:"title"`
|
|
Description string `gorm:"type:text" json:"description"`
|
|
Type string `gorm:"size:50;not null;default:'single'" json:"type"` // single, multiple, rating
|
|
Status string `gorm:"size:20;not null;default:'draft'" json:"status"` // draft, active, closed, archived
|
|
StartDate *time.Time `json:"start_date"`
|
|
EndDate *time.Time `json:"end_date"`
|
|
AllowMultiple bool `gorm:"default:false" json:"allow_multiple"` // Allow voting for multiple options
|
|
MaxChoices int `gorm:"default:1" json:"max_choices"` // Max number of choices if allow_multiple
|
|
ShowResults string `gorm:"size:20;default:'after_vote'" json:"show_results"` // always, after_vote, after_end, never
|
|
RequireAuth bool `gorm:"default:false" json:"require_auth"` // Require login to vote
|
|
AllowGuestVote bool `gorm:"default:true" json:"allow_guest_vote"` // Allow anonymous voting
|
|
Featured bool `gorm:"default:false" json:"featured"` // Show on homepage
|
|
CategoryID *uint `json:"category_id"` // Optional category
|
|
Category *Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
|
|
RelatedMatchID *uint `json:"related_match_id"` // Link to specific match (for MOTM voting)
|
|
RelatedArticleID *uint `json:"related_article_id"` // Link to blog article
|
|
RelatedArticle *Article `gorm:"foreignKey:RelatedArticleID" json:"related_article,omitempty"`
|
|
RelatedEventID *uint `json:"related_event_id"` // Link to event/activity
|
|
RelatedEvent *Event `gorm:"foreignKey:RelatedEventID" json:"related_event,omitempty"`
|
|
RelatedVideoURL string `gorm:"size:500" json:"related_video_url"` // YouTube video URL/ID
|
|
ImageURL string `gorm:"size:500" json:"image_url"`
|
|
TotalVotes int `gorm:"default:0" json:"total_votes"`
|
|
Options []PollOption `gorm:"foreignKey:PollID;constraint:OnDelete:CASCADE" json:"options"`
|
|
Votes []PollVote `gorm:"foreignKey:PollID;constraint:OnDelete:CASCADE" json:"votes,omitempty"`
|
|
CreatedBy uint `json:"created_by"`
|
|
Creator *User `gorm:"foreignKey:CreatedBy" json:"creator,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
DeletedAt *time.Time `gorm:"index" json:"deleted_at,omitempty"`
|
|
}
|
|
|
|
// PollOption represents a single option in a poll
|
|
type PollOption struct {
|
|
ID uint `gorm:"primarykey" json:"id"`
|
|
PollID uint `gorm:"not null;index" json:"poll_id"`
|
|
Poll *Poll `gorm:"foreignKey:PollID" json:"poll,omitempty"`
|
|
Text string `gorm:"size:255;not null" json:"text"`
|
|
Description string `gorm:"type:text" json:"description"`
|
|
ImageURL string `gorm:"size:500" json:"image_url"`
|
|
DisplayOrder int `gorm:"default:0" json:"display_order"`
|
|
VoteCount int `gorm:"default:0" json:"vote_count"`
|
|
PlayerID *uint `json:"player_id"` // Optional link to player (for MOTM)
|
|
Player *Player `gorm:"foreignKey:PlayerID" json:"player,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// PollVote represents a user's vote
|
|
type PollVote struct {
|
|
ID uint `gorm:"primarykey" json:"id"`
|
|
PollID uint `gorm:"not null;index" json:"poll_id"`
|
|
Poll *Poll `gorm:"foreignKey:PollID" json:"poll,omitempty"`
|
|
OptionID uint `gorm:"not null;index" json:"option_id"`
|
|
Option *PollOption `gorm:"foreignKey:OptionID" json:"option,omitempty"`
|
|
UserID *uint `gorm:"index" json:"user_id"` // Null for guest votes
|
|
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
|
|
IPHash string `gorm:"size:64;index" json:"ip_hash"` // Hashed IP for duplicate prevention
|
|
UserAgent string `gorm:"size:500" json:"user_agent"`
|
|
SessionToken string `gorm:"size:100;index" json:"session_token"` // For guest vote tracking
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// TableName overrides the table name
|
|
func (Poll) TableName() string {
|
|
return "polls"
|
|
}
|
|
|
|
func (PollOption) TableName() string {
|
|
return "poll_options"
|
|
}
|
|
|
|
func (PollVote) TableName() string {
|
|
return "poll_votes"
|
|
}
|
|
|
|
// IsActive checks if poll is currently accepting votes
|
|
func (p *Poll) IsActive() bool {
|
|
if p.Status != "active" {
|
|
return false
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
if p.StartDate != nil && now.Before(*p.StartDate) {
|
|
return false
|
|
}
|
|
|
|
if p.EndDate != nil && now.After(*p.EndDate) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// CanShowResults checks if results should be displayed
|
|
func (p *Poll) CanShowResults(hasVoted bool) bool {
|
|
switch p.ShowResults {
|
|
case "always":
|
|
return true
|
|
case "after_vote":
|
|
return hasVoted
|
|
case "after_end":
|
|
if p.EndDate != nil {
|
|
return time.Now().After(*p.EndDate)
|
|
}
|
|
return p.Status == "closed" || p.Status == "archived"
|
|
case "never":
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|