Files
RenewCMS/internal/infrastructure/persistence/repositories/imageRepository.go
T
2026-09-30 18:35:28 +02:00

175 lines
4.5 KiB
Go

package persistence
import (
domain "RenewCMS/internal/domain/image"
"RenewCMS/internal/infrastructure/persistence/mappers"
entity "RenewCMS/internal/infrastructure/persistence/models"
"errors"
"io"
"os"
"path/filepath"
"strings"
"github.com/google/uuid"
"gorm.io/gorm"
)
const uploadedImagesURLPrefix = "/static/uploadedImages/"
type ImageRepository struct {
db *gorm.DB
uploadDir string
}
func NewImageRepository(db *gorm.DB, uploadDir string) *ImageRepository {
return &ImageRepository{db, uploadDir}
}
var contentTypeExtensions = map[string]string{
"image/png": ".png",
"image/jpeg": ".jpeg",
"image/webp": ".webp",
"image/svg+xml": ".svg",
}
func (i ImageRepository) Create(input domain.ImageInput) (domain.Image, error) {
fileBytes, err := io.ReadAll(input.Content)
if err != nil {
return domain.Image{}, err
}
err = os.MkdirAll(i.uploadDir, 0755)
if err != nil {
return domain.Image{}, err
}
newName := uuid.NewString() + contentTypeExtensions[input.ContentType]
finalPath := filepath.Join(i.uploadDir, newName)
err = os.WriteFile(finalPath, fileBytes, 0666)
if err != nil {
return domain.Image{}, err
}
model := mappers.ImageToModel(domain.Image{
Path: uploadedImagesURLPrefix + newName,
Filename: input.Filename,
Size: input.Size,
ContentType: input.ContentType,
Width: input.Width,
Height: input.Height,
SHA256: input.SHA256,
UploadedByID: input.UploadedByID,
})
if err := i.db.Create(&model).Error; err != nil {
_ = os.Remove(finalPath)
return domain.Image{}, err
}
return mappers.ImageToDomain(model), nil
}
func (i ImageRepository) Get(id uint32) (domain.Image, error) {
var model entity.Image
err := i.db.First(&model, id).Error
if err != nil {
return domain.Image{}, mapNotFoundErr(err, domain.ErrImageNotFound)
}
return mappers.ImageToDomain(model), nil
}
func (i ImageRepository) Delete(id uint32) error {
var model entity.Image
err := i.db.First(&model, id).Error
if err != nil {
return mapNotFoundErr(err, domain.ErrImageNotFound)
}
err = os.Remove(filepath.Join(i.uploadDir, filepath.Base(model.Path)))
if err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
return i.db.Delete(&entity.Image{}, id).Error
}
func (i ImageRepository) List(query domain.SearchQuery) ([]domain.Image, error) {
statement := i.db.Model(&entity.Image{})
if query.Search != "" {
statement = statement.Where("instr(lower(filename), ?) > 0", strings.ToLower(query.Search))
}
if query.Hash != "" {
statement = statement.Where("sha256 = ?", query.Hash)
}
var models []entity.Image
if err := statement.Order("id asc").Find(&models).Error; err != nil {
return nil, err
}
return imagesToDomain(models), nil
}
func (i ImageRepository) FindByHash(hash string) ([]domain.Image, error) {
if hash == "" {
return []domain.Image{}, nil
}
var models []entity.Image
if err := i.db.Where("sha256 = ?", hash).Order("id asc").Find(&models).Error; err != nil {
return nil, err
}
return imagesToDomain(models), nil
}
func (i ImageRepository) Rename(id uint32, filename string) (domain.Image, error) {
var model entity.Image
err := i.db.First(&model, id).Error
if err != nil {
return domain.Image{}, mapNotFoundErr(err, domain.ErrImageNotFound)
}
model.Filename = filename
if err := i.db.Save(&model).Error; err != nil {
return domain.Image{}, err
}
return mappers.ImageToDomain(model), nil
}
func (i ImageRepository) ListDuplicates() ([]domain.Image, error) {
var models []entity.Image
err := i.db.Where("sha256 IN (?)", i.duplicatedHashes()).Order("sha256 asc, id asc").Find(&models).Error
if err != nil {
return nil, err
}
return imagesToDomain(models), nil
}
func (i ImageRepository) Counts() (domain.Counts, error) {
var all int64
if err := i.db.Model(&entity.Image{}).Count(&all).Error; err != nil {
return domain.Counts{}, err
}
var groups int64
if err := i.db.Table("(?) as duplicated", i.duplicatedHashes()).Count(&groups).Error; err != nil {
return domain.Counts{}, err
}
return domain.Counts{All: int(all), DuplicateGroups: int(groups)}, nil
}
func (i ImageRepository) duplicatedHashes() *gorm.DB {
return i.db.Model(&entity.Image{}).
Select("sha256").
Where("sha256 <> ''").
Group("sha256").
Having("COUNT(*) > 1")
}
func imagesToDomain(models []entity.Image) []domain.Image {
images := make([]domain.Image, 0, len(models))
for _, model := range models {
images = append(images, mappers.ImageToDomain(model))
}
return images
}
var _ domain.Repository = &ImageRepository{}