106 lines
2.5 KiB
Go
106 lines
2.5 KiB
Go
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
|
|
}
|
|
}
|