You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Koito/engine/handlers/replace_image.go

180 lines
4.6 KiB

package handlers
import (
"io"
"net/http"
"strconv"
"strings"
"github.com/gabehf/koito/internal/catalog"
"github.com/gabehf/koito/internal/cfg"
"github.com/gabehf/koito/internal/db"
"github.com/gabehf/koito/internal/logger"
"github.com/gabehf/koito/internal/utils"
"github.com/google/uuid"
)
type ReplaceImageResponse struct {
Success bool `json:"success"`
Image string `json:"image"`
Message string `json:"message,omitempty"`
}
func ReplaceImageHandler(store db.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
l := logger.FromContext(ctx)
artistIdStr := r.FormValue("artist_id")
artistId, _ := strconv.Atoi(artistIdStr)
albumIdStr := r.FormValue("album_id")
albumId, _ := strconv.Atoi(albumIdStr)
if artistId != 0 && albumId != 0 {
utils.WriteError(w, "Only one of artist_id and album_id can be set", http.StatusBadRequest)
return
} else if artistId == 0 && albumId == 0 {
utils.WriteError(w, "One of artist_id and album_id must be set", http.StatusBadRequest)
return
}
var oldImage *uuid.UUID
if artistId != 0 {
a, err := store.GetArtist(ctx, db.GetArtistOpts{
ID: int32(artistId),
})
if err != nil {
utils.WriteError(w, "Artist with specified id could not be found", http.StatusBadRequest)
return
}
oldImage = a.Image
} else if albumId != 0 {
a, err := store.GetAlbum(ctx, db.GetAlbumOpts{
ID: int32(albumId),
})
if err != nil {
utils.WriteError(w, "Album with specified id could not be found", http.StatusBadRequest)
return
}
oldImage = a.Image
}
l.Debug().Msgf("Getting image from request...")
var id uuid.UUID
var err error
fileUrl := r.FormValue("image_url")
if fileUrl != "" {
l.Debug().Msg("Image identified as remote file")
err = catalog.ValidateImageURL(fileUrl)
if err != nil {
l.Debug().AnErr("error", err).Msg("Invalid image")
utils.WriteError(w, "url is invalid or not an image file", http.StatusBadRequest)
return
}
id = uuid.New()
var dlSize catalog.ImageSize
if cfg.FullImageCacheEnabled() {
dlSize = catalog.ImageSizeFull
} else {
dlSize = catalog.ImageSizeLarge
}
l.Debug().Msg("Downloading album image from source...")
err = catalog.DownloadAndCacheImage(ctx, id, fileUrl, dlSize)
if err != nil {
l.Err(err).Msg("Failed to cache image")
}
} else {
file, _, err := r.FormFile("image")
if err != nil {
utils.WriteError(w, "Invalid file", http.StatusBadRequest)
return
}
defer file.Close()
buf := make([]byte, 512)
if _, err := file.Read(buf); err != nil {
utils.WriteError(w, "Could not read file", http.StatusInternalServerError)
return
}
contentType := http.DetectContentType(buf)
if !strings.HasPrefix(contentType, "image/") {
utils.WriteError(w, "Only image uploads are allowed", http.StatusBadRequest)
return
}
if _, err := file.Seek(0, io.SeekStart); err != nil {
utils.WriteError(w, "Could not seek file", http.StatusInternalServerError)
return
}
l.Debug().Msgf("Saving image to cache...")
id = uuid.New()
var dlSize catalog.ImageSize
if cfg.FullImageCacheEnabled() {
dlSize = catalog.ImageSizeFull
} else {
dlSize = catalog.ImageSizeLarge
}
err = catalog.CompressAndSaveImage(ctx, id.String(), dlSize, file)
if err != nil {
utils.WriteError(w, "Could not save file", http.StatusInternalServerError)
return
}
}
l.Debug().Msgf("Updating database...")
var imgsrc string
if fileUrl != "" {
imgsrc = fileUrl
} else {
imgsrc = catalog.ImageSourceUserUpload
}
if artistId != 0 {
err := store.UpdateArtist(ctx, db.UpdateArtistOpts{
ID: int32(artistId),
Image: id,
ImageSrc: imgsrc,
})
if err != nil {
l.Err(err).Msg("Artist image could not be updated")
utils.WriteError(w, "Artist image could not be updated", http.StatusInternalServerError)
return
}
} else if albumId != 0 {
err := store.UpdateAlbum(ctx, db.UpdateAlbumOpts{
ID: int32(albumId),
Image: id,
ImageSrc: imgsrc,
})
if err != nil {
l.Err(err).Msg("Album image could not be updated")
utils.WriteError(w, "Album image could not be updated", http.StatusInternalServerError)
return
}
}
if oldImage != nil {
l.Debug().Msg("Cleaning up old image file...")
err = catalog.DeleteImage(*oldImage)
if err != nil {
l.Err(err).Msg("Failed to delete old image file")
utils.WriteError(w, "Could not delete old image file", http.StatusInternalServerError)
return
}
}
utils.WriteJSON(w, http.StatusOK, ReplaceImageResponse{
Success: true,
Image: id.String(),
})
}
}