160 lines
4.4 KiB
Go
160 lines
4.4 KiB
Go
package repositories
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"whimsoc/vindn-backend/models"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type EventRepository interface {
|
|
Save(event *models.Event) error
|
|
FindAll() ([]models.Event, error)
|
|
SoftDeleteEndedBefore(cutoffDate string) (int64, error)
|
|
}
|
|
|
|
type eventRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewEventRepository(db *gorm.DB) EventRepository {
|
|
return &eventRepository{db}
|
|
}
|
|
|
|
func (r *eventRepository) Save(event *models.Event) error {
|
|
if event.Geo != nil && event.Geo.Main != nil {
|
|
event.Latitude = event.Geo.Main.Latitude
|
|
event.Longitude = event.Geo.Main.Longitude
|
|
}
|
|
|
|
var categories []models.Category
|
|
for _, name := range event.CategoryNames {
|
|
if name == "" {
|
|
continue
|
|
}
|
|
var cat models.Category
|
|
if err := r.db.FirstOrCreate(&cat, models.Category{Name: name}).Error; err != nil {
|
|
return err
|
|
}
|
|
categories = append(categories, cat)
|
|
}
|
|
|
|
event.Categories = categories
|
|
|
|
var mediaObjects []models.MediaObject
|
|
for _, rawMediaObject := range event.RawMediaObjects {
|
|
if rawMediaObject.Name == "" {
|
|
continue
|
|
}
|
|
var mediaObject models.MediaObject
|
|
h := md5.New()
|
|
io.WriteString(h, rawMediaObject.Rel)
|
|
io.WriteString(h, rawMediaObject.Name)
|
|
io.WriteString(h, rawMediaObject.URL)
|
|
|
|
if err := r.db.FirstOrCreate(&mediaObject, models.MediaObject{
|
|
Hash: fmt.Sprintf("%x", h.Sum(nil)),
|
|
RefID: rawMediaObject.RefID,
|
|
Name: rawMediaObject.Name,
|
|
URL: rawMediaObject.URL,
|
|
Type: rawMediaObject.Type,
|
|
Rel: rawMediaObject.Rel,
|
|
Alt: rawMediaObject.Alt,
|
|
Source: rawMediaObject.Source,
|
|
Description: rawMediaObject.Description,
|
|
Prio: rawMediaObject.Prio,
|
|
AiOptimized: rawMediaObject.AiOptimized,
|
|
License: rawMediaObject.License,
|
|
Ext: filepath.Ext(rawMediaObject.URL),
|
|
}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if mediaObject.Type != "" {
|
|
mediaType, _, mediaTypeFound := strings.Cut(mediaObject.Type, "/")
|
|
if err := r.saveMediaFile(mediaObject.Hash, mediaObject.URL, mediaType, mediaObject.Ext); mediaTypeFound && err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
mediaObjects = append(mediaObjects, mediaObject)
|
|
}
|
|
|
|
event.MediaObjects = mediaObjects
|
|
|
|
return r.db.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "external_id"}},
|
|
UpdateAll: true,
|
|
}).Create(event).Error
|
|
}
|
|
|
|
func (r *eventRepository) FindAll() ([]models.Event, error) {
|
|
var events []models.Event
|
|
result := r.db.Find(&events)
|
|
return events, result.Error
|
|
}
|
|
|
|
// SoftDeleteEndedBefore marks events whose end_date is before cutoffDate
|
|
// (an exclusive "YYYY-MM-DD" boundary, the same lexicographic string
|
|
// comparison the frontend uses for its own date filtering) as deleted.
|
|
// .Delete() on a gorm.Model sets deleted_at rather than removing the row,
|
|
// consistent with how the frontend already treats soft-deleted events.
|
|
// Events with a blank end_date are left alone — there's nothing to
|
|
// compare, so leaving them is safer than guessing they're stale.
|
|
func (r *eventRepository) SoftDeleteEndedBefore(cutoffDate string) (int64, error) {
|
|
result := r.db.Where("end_date <> '' AND end_date < ?", cutoffDate).Delete(&models.Event{})
|
|
return result.RowsAffected, result.Error
|
|
}
|
|
|
|
func (r *eventRepository) saveMediaFile(filename string, url string, mediaType string, extension string) error {
|
|
mediaFilePath := fmt.Sprintf("./public/storage/%s/%s%s", strings.ToLower(mediaType), filename, extension)
|
|
|
|
log.Printf("Get file %s and save it to %s", url, mediaFilePath)
|
|
|
|
// Check if the directory exists
|
|
if _, err := os.Stat(filepath.Dir(mediaFilePath)); os.IsNotExist(err) {
|
|
// Create the directory if it doesn't exist
|
|
err := os.MkdirAll(filepath.Dir(mediaFilePath), 0755) // 0755 is a common permission for directories
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create directory: %v", err)
|
|
}
|
|
}
|
|
|
|
fileInfo, err := os.Stat(mediaFilePath)
|
|
|
|
if errors.Is(err, os.ErrNotExist) || fileInfo.Size() == 0 {
|
|
// Create the file
|
|
out, err := os.Create(mediaFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
// Get the data
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Write the body to file
|
|
_, err = io.Copy(out, resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
} else {
|
|
log.Printf("File already exists, do not download again. Stats: Name: %s, Size: %d", fileInfo.Name(), fileInfo.Size())
|
|
}
|
|
|
|
return nil
|
|
}
|