veza/veza-backend-api/internal/models/contest.go

313 lines
13 KiB
Go

package models
import (
"database/sql"
"time"
"github.com/google/uuid"
"github.com/lib/pq"
"gorm.io/gorm"
)
// Contest représente un concours musical
type Contest struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
Title string `json:"title" gorm:"not null"`
Description string `json:"description" gorm:"not null"`
Type string `json:"type" gorm:"not null;index"` // remix, production, sound_design, collaboration
Status string `json:"status" gorm:"not null;default:'draft'"` // draft, active, voting, completed, cancelled
CreatorID uuid.UUID `json:"creator_id" gorm:"type:uuid;not null;index"`
OriginalTrackID *uuid.UUID `json:"original_track_id,omitempty" gorm:"type:uuid"`
Genre sql.NullString `json:"genre,omitempty"`
BPM sql.NullInt32 `json:"bpm,omitempty"`
Key sql.NullString `json:"key,omitempty"`
Requirements pq.StringArray `json:"requirements" gorm:"type:jsonb"`
Rules pq.StringArray `json:"rules" gorm:"type:jsonb"`
Timeline ContestTimeline `json:"timeline" gorm:"type:jsonb"`
Prizes []ContestPrize `json:"prizes" gorm:"type:jsonb"`
JudgingCriteria []JudgingCriterion `json:"judging_criteria" gorm:"type:jsonb"`
Settings map[string]interface{} `json:"settings" gorm:"type:jsonb"`
CoverImage sql.NullString `json:"cover_image,omitempty"`
IsPublic bool `json:"is_public" gorm:"not null;default:true"`
IsFeatured bool `json:"is_featured" gorm:"not null;default:false"`
MaxParticipants sql.NullInt32 `json:"max_participants,omitempty"`
EntryCount int64 `json:"entry_count" gorm:"not null;default:0"`
ViewCount int64 `json:"view_count" gorm:"not null;default:0"`
VoteCount int64 `json:"vote_count" gorm:"not null;default:0"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Creator *User `json:"creator,omitempty"`
OriginalTrack *SellableContent `json:"original_track,omitempty"`
Entries []ContestEntry `json:"entries,omitempty"`
Judges []ContestJudge `json:"judges,omitempty"`
Sponsors []ContestSponsor `json:"sponsors,omitempty"`
}
// ContestTimeline représente la timeline d'un concours
type ContestTimeline struct {
StartDate time.Time `json:"start_date"`
SubmissionDeadline time.Time `json:"submission_deadline"`
VotingStart time.Time `json:"voting_start"`
VotingEnd time.Time `json:"voting_end"`
ResultsAnnouncement time.Time `json:"results_announcement"`
}
// ContestPrize représente un prix dans un concours
type ContestPrize struct {
Position int `json:"position"`
Prize string `json:"prize"`
Description string `json:"description"`
CashAmount float64 `json:"cash_amount,omitempty"`
Currency string `json:"currency,omitempty"`
Badge string `json:"badge,omitempty"`
Distribution string `json:"distribution,omitempty"`
}
// JudgingCriterion représente un critère de jugement
type JudgingCriterion struct {
Name string `json:"name"`
Description string `json:"description"`
Weight float64 `json:"weight"`
MaxScore int `json:"max_score"`
}
// ContestEntry représente une participation à un concours
type ContestEntry struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;index"`
UserID uuid.UUID `json:"user_id" gorm:"type:uuid;not null;index"`
Title string `json:"title" gorm:"not null"`
Description string `json:"description"`
AudioFile string `json:"audio_file" gorm:"not null"`
Metadata map[string]interface{} `json:"metadata" gorm:"type:jsonb"`
Status string `json:"status" gorm:"not null;default:'submitted'"` // submitted, approved, disqualified, winner
Position sql.NullInt32 `json:"position,omitempty"`
Score sql.NullFloat64 `json:"score,omitempty"`
VoteCount int64 `json:"vote_count" gorm:"not null;default:0"`
ViewCount int64 `json:"view_count" gorm:"not null;default:0"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
User *User `json:"user,omitempty"`
Votes []ContestVote `json:"votes,omitempty"`
}
// ContestJudge représente un juge dans un concours
type ContestJudge struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;index"`
UserID uuid.UUID `json:"user_id" gorm:"type:uuid;not null;index"`
Role string `json:"role" gorm:"not null"` // head_judge, expert_judge, community_judge
Weight float64 `json:"weight" gorm:"not null;default:1.0"`
Credentials sql.NullString `json:"credentials,omitempty"`
IsActive bool `json:"is_active" gorm:"not null;default:true"`
JoinedAt time.Time `json:"joined_at" gorm:"autoCreateTime"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
User *User `json:"user,omitempty"`
}
// ContestVote représente un vote dans un concours
type ContestVote struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;index"`
EntryID uuid.UUID `json:"entry_id" gorm:"type:uuid;not null;index"`
UserID uuid.UUID `json:"user_id" gorm:"type:uuid;not null;index"`
JudgeID *uuid.UUID `json:"judge_id,omitempty" gorm:"type:uuid"`
VoteType string `json:"vote_type" gorm:"not null"` // expert, community
Score float64 `json:"score" gorm:"not null"`
Criteria map[string]float64 `json:"criteria" gorm:"type:jsonb"`
Comment sql.NullString `json:"comment,omitempty"`
IsValid bool `json:"is_valid" gorm:"not null;default:true"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
Entry *ContestEntry `json:"entry,omitempty"`
User *User `json:"user,omitempty"`
Judge *ContestJudge `json:"judge,omitempty"`
}
// ContestSponsor représente un sponsor d'un concours
type ContestSponsor struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;index"`
Name string `json:"name" gorm:"not null"`
Description sql.NullString `json:"description,omitempty"`
Logo sql.NullString `json:"logo,omitempty"`
Website sql.NullString `json:"website,omitempty"`
Contribution float64 `json:"contribution" gorm:"not null"`
Currency string `json:"currency" gorm:"not null;default:'EUR'"`
Benefits pq.StringArray `json:"benefits" gorm:"type:jsonb"`
IsActive bool `json:"is_active" gorm:"not null;default:true"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
}
// ContestStems représente les stems d'un concours (pour remix contests)
type ContestStems struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;uniqueIndex"`
VocalsPath string `json:"vocals_path" gorm:"not null"`
DrumsPath string `json:"drums_path" gorm:"not null"`
BassPath string `json:"bass_path" gorm:"not null"`
OtherPath string `json:"other_path" gorm:"not null"`
DownloadURL string `json:"download_url" gorm:"not null"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
}
// ContestAnalytics représente les analytics d'un concours
type ContestAnalytics struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;uniqueIndex"`
TotalEntries int64 `json:"total_entries" gorm:"not null;default:0"`
UniqueParticipants int64 `json:"unique_participants" gorm:"not null;default:0"`
TotalVotes int64 `json:"total_votes" gorm:"not null;default:0"`
UniqueVoters int64 `json:"unique_voters" gorm:"not null;default:0"`
AverageScore float64 `json:"average_score" gorm:"not null;default:0"`
CompletionRate float64 `json:"completion_rate" gorm:"not null;default:0"`
EngagementRate float64 `json:"engagement_rate" gorm:"not null;default:0"`
SocialShares int64 `json:"social_shares" gorm:"not null;default:0"`
Comments int64 `json:"comments" gorm:"not null;default:0"`
Countries int64 `json:"countries" gorm:"not null;default:0"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
}
// ContestBadge représente un badge de concours
type ContestBadge struct {
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
ContestID uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;index"`
UserID uuid.UUID `json:"user_id" gorm:"type:uuid;not null;index"`
BadgeType string `json:"badge_type" gorm:"not null"` // winner, participant, judge, sponsor
Position sql.NullInt32 `json:"position,omitempty"`
Description string `json:"description" gorm:"not null"`
Icon string `json:"icon" gorm:"not null"`
Rarity string `json:"rarity" gorm:"not null;default:'common'"` // common, rare, epic, legendary
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
// Relations
Contest *Contest `json:"contest,omitempty"`
User *User `json:"user,omitempty"`
}
// TableName spécifie le nom de la table pour Contest
func (Contest) TableName() string {
return "contests"
}
// TableName spécifie le nom de la table pour ContestEntry
func (ContestEntry) TableName() string {
return "contest_entries"
}
// TableName spécifie le nom de la table pour ContestJudge
func (ContestJudge) TableName() string {
return "contest_judges"
}
// TableName spécifie le nom de la table pour ContestVote
func (ContestVote) TableName() string {
return "contest_votes"
}
// TableName spécifie le nom de la table pour ContestSponsor
func (ContestSponsor) TableName() string {
return "contest_sponsors"
}
// TableName spécifie le nom de la table pour ContestStems
func (ContestStems) TableName() string {
return "contest_stems"
}
// TableName spécifie le nom de la table pour ContestAnalytics
func (ContestAnalytics) TableName() string {
return "contest_analytics"
}
// TableName spécifie le nom de la table pour ContestBadge
func (ContestBadge) TableName() string {
return "contest_badges"
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *Contest) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestEntry) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestJudge) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestVote) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestSponsor) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestStems) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestAnalytics) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestBadge) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}