package services import ( "fotbal-club/internal/models" "strings" "gorm.io/gorm" ) // FileTracker provides utilities for tracking file usage type FileTracker struct { DB *gorm.DB } // NewFileTracker creates a new file tracker instance func NewFileTracker(db *gorm.DB) *FileTracker { return &FileTracker{DB: db} } // TrackFileUpload records a new uploaded file func (ft *FileTracker) TrackFileUpload(filePath, fileURL, filename, mimeType string, fileSize int64, uploadedByID *uint) error { file := models.UploadedFile{ Filename: filename, FilePath: filePath, FileURL: fileURL, FileSize: fileSize, MimeType: mimeType, UploadedByID: uploadedByID, } return ft.DB.Create(&file).Error } // TrackFileUsage records or updates file usage for an entity func (ft *FileTracker) TrackFileUsage(fileURL, entityType string, entityID uint, fieldName string) error { if fileURL == "" { return nil } // Find the file by URL var file models.UploadedFile if err := ft.DB.Where("file_url = ?", fileURL).First(&file).Error; err != nil { // File not found in database - skip tracking return nil } // Check if usage already exists var existingUsage models.FileUsage err := ft.DB.Where("file_id = ? AND entity_type = ? AND entity_id = ? AND field_name = ?", file.ID, entityType, entityID, fieldName).First(&existingUsage).Error if err == gorm.ErrRecordNotFound { // Create new usage record usage := models.FileUsage{ FileID: file.ID, EntityType: entityType, EntityID: entityID, FieldName: fieldName, } return ft.DB.Create(&usage).Error } return err } // RemoveFileUsage removes a file usage record func (ft *FileTracker) RemoveFileUsage(fileURL, entityType string, entityID uint, fieldName string) error { if fileURL == "" { return nil } // Find the file by URL var file models.UploadedFile if err := ft.DB.Where("file_url = ?", fileURL).First(&file).Error; err != nil { return nil } return ft.DB.Where("file_id = ? AND entity_type = ? AND entity_id = ? AND field_name = ?", file.ID, entityType, entityID, fieldName).Delete(&models.FileUsage{}).Error } // UpdateFileUsages updates all file usages for an entity (removes old, adds new) func (ft *FileTracker) UpdateFileUsages(entityType string, entityID uint, fieldURLMap map[string]string) error { // Get all current usages for this entity var currentUsages []models.FileUsage ft.DB.Where("entity_type = ? AND entity_id = ?", entityType, entityID).Find(¤tUsages) // Create a map of current usages currentMap := make(map[string]models.FileUsage) for _, usage := range currentUsages { key := usage.FieldName currentMap[key] = usage } // Track new usages for fieldName, fileURL := range fieldURLMap { if fileURL != "" { // Check if already tracked if _, exists := currentMap[fieldName]; !exists { ft.TrackFileUsage(fileURL, entityType, entityID, fieldName) } delete(currentMap, fieldName) // Remove from current map } } // Remove usages that are no longer present for fieldName := range currentMap { ft.DB.Where("entity_type = ? AND entity_id = ? AND field_name = ?", entityType, entityID, fieldName).Delete(&models.FileUsage{}) } return nil } // TrackArticleFiles tracks all file usages in an article func (ft *FileTracker) TrackArticleFiles(article *models.Article) error { fieldURLMap := map[string]string{ "image_url": article.ImageURL, "og_image_url": article.OGImageURL, } // Track attachments if present if article.Attachments != "" { // Attachments is a JSON array of URLs // For simplicity, we'll track each attachment URL separately // You might want to parse the JSON properly in production attachments := strings.Split(article.Attachments, ",") for i, attachment := range attachments { attachment = strings.Trim(attachment, `[]" `) if attachment != "" { fieldName := "attachments" if i > 0 { // If multiple attachments, differentiate them fieldName = "attachments" } fieldURLMap[fieldName] = attachment } } } return ft.UpdateFileUsages("article", article.ID, fieldURLMap) } // TrackPlayerFiles tracks all file usages in a player func (ft *FileTracker) TrackPlayerFiles(player *models.Player) error { fieldURLMap := map[string]string{ "image_url": player.ImageURL, } return ft.UpdateFileUsages("player", player.ID, fieldURLMap) } // TrackSponsorFiles tracks all file usages in a sponsor func (ft *FileTracker) TrackSponsorFiles(sponsor *models.Sponsor) error { fieldURLMap := map[string]string{ "logo_url": sponsor.LogoURL, } return ft.UpdateFileUsages("sponsor", sponsor.ID, fieldURLMap) } // TrackEventFiles tracks all file usages in an event func (ft *FileTracker) TrackEventFiles(event *models.Event) error { fieldURLMap := map[string]string{ "image_url": event.ImageURL, "file_url": event.FileURL, } return ft.UpdateFileUsages("event", event.ID, fieldURLMap) } // TrackContactFiles tracks all file usages in a contact func (ft *FileTracker) TrackContactFiles(contact *models.Contact) error { fieldURLMap := map[string]string{ "image_url": contact.ImageURL, } return ft.UpdateFileUsages("contact", contact.ID, fieldURLMap) } // TrackSettingsFiles tracks all file usages in settings func (ft *FileTracker) TrackSettingsFiles(settings *models.Settings) error { fieldURLMap := map[string]string{ "default_og_image_url": settings.DefaultOGImageURL, "club_logo_url": settings.ClubLogoURL, } return ft.UpdateFileUsages("settings", settings.ID, fieldURLMap) } // TrackTeamFiles tracks all file usages in a team func (ft *FileTracker) TrackTeamFiles(team *models.Team) error { fieldURLMap := map[string]string{ "logo_url": team.LogoURL, } return ft.UpdateFileUsages("team", team.ID, fieldURLMap) }