package models import ( "database/sql" "fmt" "os" "path/filepath" "strings" ) const ProfileImageExtension = ".png" type File struct { ID int OriginalName string Hash string HashAlgorithm string } func GetFileByID(db *sql.DB, id int64) (*File, error) { query := "SELECT id, original_name, hash, hash_algorithm FROM files WHERE id = ?" row := db.QueryRow(query, id) file := &File{} err := row.Scan(&file.ID, &file.OriginalName, &file.Hash, &file.HashAlgorithm) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } return file, nil } func IsProfileImageFile(db *sql.DB, id int64) (bool, error) { var exists bool err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE pfp_file_id = ?)", id).Scan(&exists) if err != nil { return false, err } return exists, nil } func CreateFile(db *sql.DB, file File) (int64, error) { query := "INSERT INTO files (original_name, hash, hash_algorithm) VALUES (?, ?, ?)" result, err := db.Exec(query, file.OriginalName, file.Hash, file.HashAlgorithm) if err != nil { return 0, err } return result.LastInsertId() } func DeleteFileByID(db *sql.DB, id int64) error { _, err := db.Exec("DELETE FROM files WHERE id = ?", id) return err } func ProfileImageStorageName(id int64) string { return fmt.Sprintf("%d%s", id, ProfileImageExtension) } func LegacyImageStorageName(id int64, originalName string) (string, bool) { ext := strings.ToLower(filepath.Ext(originalName)) if !allowedImageExtension(ext) { return "", false } return fmt.Sprintf("%d%s", id, ext), true } func ProfileImageContentType(fileName string) string { switch strings.ToLower(filepath.Ext(fileName)) { case ".jpg", ".jpeg": return "image/jpeg" case ".gif": return "image/gif" default: return "image/png" } } func ResolveStoredImagePath(storageDir string, file *File) (string, string, bool) { currentPath := filepath.Join(storageDir, ProfileImageStorageName(int64(file.ID))) if _, err := os.Stat(currentPath); err == nil { return currentPath, ProfileImageContentType(currentPath), true } legacyName, ok := LegacyImageStorageName(int64(file.ID), file.OriginalName) if !ok { return "", "", false } legacyPath := filepath.Join(storageDir, legacyName) if _, err := os.Stat(legacyPath); err == nil { return legacyPath, ProfileImageContentType(legacyPath), true } return "", "", false } func allowedImageExtension(ext string) bool { switch ext { case ".png", ".jpg", ".jpeg", ".gif": return true default: return false } }