CRITICAL fixes: - Race condition (TOCTOU) in payout/refund with SELECT FOR UPDATE (CRITICAL-001/002) - IDOR on analytics endpoint — ownership check enforced (CRITICAL-003) - CSWSH on all WebSocket endpoints — origin whitelist (CRITICAL-004) - Mass assignment on user self-update — strip privileged fields (CRITICAL-005) HIGH fixes: - Path traversal in marketplace upload — UUID filenames (HIGH-001) - IP spoofing — use Gin trusted proxy c.ClientIP() (HIGH-002) - Popularity metrics (followers, likes) set to json:"-" (HIGH-003) - bcrypt cost hardened to 12 everywhere (HIGH-004) - Refresh token lock made mandatory (HIGH-005) - Stream token replay prevention with access_count (HIGH-006) - Subscription trial race condition fixed (HIGH-007) - License download expiration check (HIGH-008) - Webhook amount validation (HIGH-009) - pprof endpoint removed from production (HIGH-010) MEDIUM fixes: - WebSocket message size limit 64KB (MEDIUM-010) - HSTS header in nginx production (MEDIUM-001) - CORS origin restricted in nginx-rtmp (MEDIUM-002) - Docker alpine pinned to 3.21 (MEDIUM-003/004) - Redis authentication enforced (MEDIUM-005) - GDPR account deletion expanded (MEDIUM-006) - .gitignore hardened (MEDIUM-007) LOW/INFO fixes: - GitHub Actions SHA pinning on all workflows (LOW-001) - .env.example security documentation (INFO-001) - Production CORS set to HTTPS (LOW-002) All tests pass. Go and Rust compile clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
3.6 KiB
Go
97 lines
3.6 KiB
Go
package social
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// PostType définit le type de post
|
|
type PostType string
|
|
|
|
const (
|
|
PostTypeStatus PostType = "status"
|
|
PostTypeShare PostType = "share"
|
|
PostTypeRelease PostType = "release"
|
|
PostTypeActivity PostType = "activity" // Pour les activités automatiques (ex: achat)
|
|
)
|
|
|
|
// Post représente une publication sociale d'un utilisateur
|
|
type Post struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
|
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"`
|
|
Content string `gorm:"type:text" json:"content"`
|
|
Type PostType `gorm:"default:'status'" json:"type"`
|
|
|
|
// Attachments (Optionnel)
|
|
TrackID *uuid.UUID `gorm:"type:uuid" json:"track_id,omitempty"`
|
|
PlaylistID *uuid.UUID `gorm:"type:uuid" json:"playlist_id,omitempty"`
|
|
|
|
// Metrics (Cached)
|
|
LikeCount int `gorm:"default:0" json:"-"` // SECURITY(REM-007): Hidden — popularity metrics are private
|
|
CommentCount int `gorm:"default:0" json:"comment_count"` // comment_count is interaction metadata, not popularity
|
|
|
|
CreatedAt time.Time `gorm:"autoCreateTime;index" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
}
|
|
|
|
// Like représente une interaction "J'aime"
|
|
// Polymorphisme via TargetType + TargetID
|
|
type Like struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
|
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"`
|
|
TargetID uuid.UUID `gorm:"type:uuid;not null;index" json:"target_id"`
|
|
TargetType string `gorm:"not null" json:"target_type"` // "post", "track", "playlist"
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
}
|
|
|
|
// Comment représente un commentaire
|
|
type Comment struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
|
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"`
|
|
TargetID uuid.UUID `gorm:"type:uuid;not null;index" json:"target_id"`
|
|
TargetType string `gorm:"not null" json:"target_type"` // "post", "track", "playlist"
|
|
Content string `gorm:"type:text;not null" json:"content"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
}
|
|
|
|
// ActivityType définit le type d'activité
|
|
type ActivityType string
|
|
|
|
const (
|
|
ActivityPost ActivityType = "post"
|
|
ActivityLike ActivityType = "like"
|
|
ActivityComment ActivityType = "comment"
|
|
ActivityFollow ActivityType = "follow"
|
|
ActivityPurchase ActivityType = "purchase" // Nouveau
|
|
)
|
|
|
|
// FeedItemTrack is a minimal track payload for feed items (S1.2)
|
|
type FeedItemTrack struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
Artist string `json:"artist"`
|
|
CoverURL string `json:"cover_url"`
|
|
Duration string `json:"duration"`
|
|
Genre string `json:"genre"`
|
|
}
|
|
|
|
// FeedItem représente un élément agrégé pour le flux d'actualité
|
|
type FeedItem struct {
|
|
ID string `json:"id"`
|
|
Type ActivityType `json:"type"`
|
|
ActorID uuid.UUID `json:"actor_id"`
|
|
TargetID uuid.UUID `json:"target_id"`
|
|
TargetType string `json:"target_type"`
|
|
Content string `json:"content,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
// Embedded objects (S1.2)
|
|
ActorName string `json:"actor_name,omitempty"`
|
|
ActorAvatar string `json:"actor_avatar,omitempty"`
|
|
Track *FeedItemTrack `json:"track,omitempty"`
|
|
}
|